Giter Site home page Giter Site logo

Comments (6)

derat avatar derat commented on September 20, 2024 1

Thanks for investigating the SystemUI code and figuring out what's triggering the extra fetches, @tianyif! It's good to know that they at least won't happen for network URIs.

from media.

tianyif avatar tianyif commented on September 20, 2024

Hi @derat,

Thanks for reporting! May I have the android version information you tested with? Also for double checking:

You saw three requests when pausing but one request when unpausing, that's correct? Upon pausing and unpausing, the MediaSessionService will update the notification in react of the playback state change, during which the BitmapLoader will be requested to load the bitmap, so in theory there should be one request to BitmapLoader every time when you pause and unpause. I'm double checking because I immediately think of a case, where unpausing can introduce two requests to BitmapLoader, but that should be on Android 12 only. But you said pausing introducing more requests, so let's verify this and see if there is any other causes.

Also for mitigating the redundant requests to BitmapLoader, you may want to use CacheBitmapLoader (if you haven't already). Having to admit that this CacheBitmapLoader is very simple though, with only storing the last request and reusing the loading result if the current request matches the last one, this should benefit the case when multiple same requests come to the BitmapLoader by allowing actually loading for only once. You can simply wrap your BitmapLoader with the CacheBitmapLoader, and injecting that CacheBitmapLoader via the session builder.

from media.

marcbaechinger avatar marcbaechinger commented on September 20, 2024

If an app is using content:// URIs, I think we could actually leave fetching the bitmap to the controller. This would be more efficient because we only send the URI over the binder and the controller/browser can handle download and caching on its own.

Using CacheBitmapLoader is best for now as recommended above, but we should think about handling content://-URIs differently.

from media.

derat avatar derat commented on September 20, 2024

Thanks for the quick replies! I'm seeing this on a Pixel 7a running Android 14 (UQ1A.231205.015), and my dependency is on androidx.media3:media3-session:1.2.0. To confirm, yes, I see three requests to the content provider whenever I pause and one request when I unpause.

I saw CacheBitmapLoader, but it looks like the requests are coming from somewhere other than the BitmapLoader that I'm injecting into the session, since I see them even when my loader returns an already-decoded bitmap.

Here's some hacky code that I added (the getCoverBitmapIfDecoded method just checks a local map for the bitmap; it doesn't contact the content provider):

        mediaSession = MediaLibrarySession.Builder(this, core.playerImpl, mediaHelper)
            .setBitmapLoader(object : BitmapLoader {
                val loader = DataSourceBitmapLoader(this@NupService)
                override fun decodeBitmap(data: ByteArray) = loader.decodeBitmap(data)
                override fun loadBitmap(
                    uri: Uri,
                    options: BitmapFactory.Options?,
                ): ListenableFuture<Bitmap> {
                    Timber.d("XXX loadBitmap: $uri $options")
                    val filename = uri.path?.removePrefix("/")
                    if (!filename.isNullOrEmpty() && options == null) {
                        Timber.d("XXX checking for $filename")
                        core.getCoverBitmapIfDecoded(filename)?.let {
                            return Futures.immediateFuture(it)
                        }
                    }
                    Timber.d("XXX falling back to real loader")
                    return loader.loadBitmap(uri, options)
                }
        }).setSessionActivity(...

Here are some slightly-condensed logs where you can see the above code returning an already decoded-bitmap (note the lack of the falling back line) but then the provider getting called three times anyway:

15:16:47.492 Core$_playerImpl: Media session request to pause
15:16:47.534 NupService$onCreate: XXX loadBitmap: content://org.erat.nup.covers/c1460768-b2ad-41e0-ba2c-df3a9531d6e8.jpg null
15:16:47.538 NupService$onCreate: XXX checking for c1460768-b2ad-41e0-ba2c-df3a9531d6e8.jpg
15:16:47.822 CoverProvider: XXX openFile: uri=content://org.erat.nup.covers/c1460768-b2ad-41e0-ba2c-df3a9531d6e8.jpg mode=r
15:16:47.897 CoverProvider: XXX openFile: uri=content://org.erat.nup.covers/c1460768-b2ad-41e0-ba2c-df3a9531d6e8.jpg mode=r
15:16:48.023 CoverProvider: XXX openFile: uri=content://org.erat.nup.covers/c1460768-b2ad-41e0-ba2c-df3a9531d6e8.jpg mode=r

from media.

derat avatar derat commented on September 20, 2024

Just to follow up on this, I hacked up a local copy of Media3 to log stack traces in DataSourceBitmapLoader.loadBitmap and ContentDataSource.open. I see three loadBitmap calls at startup that seem like they're probably expected (one when my service calls SimpleBasePlayer.invalidateState after updating the playlist, one when my activity loads the bitmap, and one from MediaSessionImpl$PlayerInfoChangedHandler.handleMessage).

I don't see any stack traces get logged before the weird content requests I described above (still one when unpausing and three when pausing), though. Presumably this is outside of Media3's purview, but is it expected that some part of the OS would be making requests to load artwork from random media sessions? Based on the earlier com.android.systemui package name, I'm guessing that these are coming from https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/. I don't think I ever saw these extra requests before switching to Media3, oddly.

from media.

tianyif avatar tianyif commented on September 20, 2024

Hi @derat,

Thanks for the analysis! I could also reproduce your issue with using a content uri. This log from System UI code was hit for three times when pausing, and once when resuming, which matches with your observation.

It looks like SystemUI prioritizing to load the bitmap from URI for content, resource URIs or local files, so even we have fetched the same bitmaps from our BitmapLoader and updated the metadata with the bitmaps , they will ignore those. But looks like for the other cases (eg. network URI), they should still prioritize to use the artworkBitmap sent via the metadata.

Upon pausing, on media3 side, we have these two calls to the system:

  • notificationManagerCompat.notify(notificationId, notification);
  • service.stopForeground(STOP_FOREGROUND_DETACH).

The first causes the SystemUI to load bitmap for once, and the second causes them to load bitmap for another twice. I roughly traced how the bitmap loading can finally happen when calling the above two methods:

When media3 calls notificationManagerCompat.notify(notificationId, notification), system NotificationManagerService enqueues the notification and posts the notification, and SystemUI who listens to the onNotificationPosted event will let the MediaDataManager react to onNotificationAdded, which finally has the bitmap loaded for once.

When media3 calls service.stopForeground(STOP_FOREGROUND_DETACH), the ActivityManagerService will setServiceForeground with a zero notification id, which means exiting the foreground for the given service, and the foreground service flag will be stripped from the notification, then the listeners will be notified. The rest of the flow could be the same as above. This should finally has the bitmap loaded for another one time. I couldn't find a clear path of its second time triggering bitmap loading though.

So back to media3, I think calling service.stopForeground(STOP_FOREGROUND_DETACH) is because we want to take the service out of the foreground state when pausing to make the system better manage the resources. And calling notificationManagerCompat.notify(notificationId, notification) is to have NotificationManager to be updated first, otherwise we are likely to run into an issue that the play/pause button doesn't match the player state (#192).

So I'm not sure if there is anything we can do from the media3, but do hope the explanation help a bit :)

from media.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.