androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.55k stars 373 forks source link

Playback resumption - How to opt-out at runtime? #770

Open TomasValenta opened 10 months ago

TomasValenta commented 10 months ago

Version

Media3 1.1.1

More version details

No response

Devices that reproduce the issue

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

  1. Checkout my demo-session fork with the MediaButtonReceiver declared in the manifest and simple stop button added to the PlayableFolderActivity (full diff here).
  2. Build and run the demo-session sample.
  3. Play any song (or songs) from the example playlist.
  4. Go back to the PlayableFolderActivity and hit STOP button.
  5. A dead silent notification will appear.

Expected result

Dead silent notification should not be displayed (as it behaves when no MediaButtonReceiver is declared).

I know, I can handle the play event from the dead silent notification in the onPlaybackResumption() method (and that's how I do it too), but if I understand it correctly, this notification shouldn't show at all after calling stop() method on MediaController or not? (as it behaves when no MediaButtonReceiver is declared)

Actual result

A dead silent notification will appear.

Media

My fork - https://github.com/TomasValenta/media

Dead silent notification

image

Bug Report

marcbaechinger commented 10 months ago

Thanks for the detailed report and the text fixture.

The notification in the screenshot is not posted by Media3. This is the playback resumption notification posted by system UI (see for instance the ExoPlayer logo as the app icon at the top left, the demo app uses a different icon). After calling stop, the player transitions into STATE_IDLE which is mapped to the platform session that system UI reads.

When we do a adb shell dumpsys media_session in this state, then we see the following state of the platform session of the demo app:

androidx.media3.session.id. androidx.media3.demo.session/androidx.media3.session.id. (userId=0)
[...]
      state=PlaybackState {state=0, position=0, buffered position=0, speed=0.0, updated=479973, actions=7339655, custom actions=[Action:mName='Disable shuffle mode, mIcon=2131230888, mExtras=Bundle[EMPTY_PARCEL]], active item id=0, error=null}
[...]

Idle is mapped to STATE_NONE and from the JavDoc of that state I think this is correct. It indicates that nothing is playing and the player is not prepared.

In this situation system UI posts the playback resumption notification and Media3 expects the app to have Callback.onPlaybackResumption() implemented. With adding the MediaButtonReceiver to the manifest, an app opts-in to playback resumption. It's documented that if the receiver is declared the callback needs to be implemented (to be fair: that documentation is fairly new, newer than your report, so sorry for my late reply :)).

if I understand it correctly, this notification shouldn't show at all after calling stop() method on MediaController or not?

I think this is working as intended. Can you let me know, what you are trying to achieve?

TomasValenta commented 10 months ago

Thank you for your answer Marc,

The notification in the screenshot is not posted by Media3. This is the playback resumption notification posted by system UI (see for instance the ExoPlayer logo as the app icon at the top left, the demo app uses a different icon)

Good point, I didn't realize it at the time.

It indicates that nothing is playing and the player is not prepared. In this situation system UI posts the playback resumption notification

I didn't know that also in this situation the system will display a playback resumption notification. As I described above, we have Callback.onPlaybackResumption() already implemented and from what I have tried so far, it has worked as expected.

I think this is working as intended. Can you let me know, what you are trying to achieve?

Audio player is just one of the functionalities in our application. What I'm trying to achieve is when the user really stops playing (not just pauses) or if the user logout. Right now in these situations I'm calling browser.stop(), browser.clearMediaItems() and MediaBrowser.releaseFuture(browserFuture).

So how should I behave in these situations if I don't want to display the playback resumption notification (moreover in these situations I have nothing to "resume" in onPlaybackResumption)?

marcbaechinger commented 10 months ago

Thanks for clarification. Very helpful.

Your use cases isn't well supported by Media3 yet. You can't opt-in and opt-out programmatically. There is only the way of declaring the receiver in the manifest. With this playback resumption is activated. Looks like a valid use case though, so I think we should aim to provide a bit more fine-grained support for opting-in and out.

Technically, Media3 could enable/disable resumption for media button event at runtim. So we could do something like session.setMediaButtonResumptionEnabled(boolean). However, I don't think this works with the System UI notification. System UI asks the library session whether to support playback resumption with a notification just after the session has been made active. I'm not aware that revisiting this decision is supported, besides releasing the session and restarting a new session to get into the service contract with System UI again which is an ugly hack with bad user experience.

long story short - looks like we should think about a way to separate media button resumption and the System UI notification. You could then at least choose to only support BT resumption which we then can make changeable at runtime.

I have marked this issue as an enhancement:

TomasValenta commented 10 months ago

Thank you very much Marc, very nice summary, I will look forward to it 🚀 👀

Flyktsodan commented 1 month ago

Any updates on this? I really don't like the idea of having a "dead" notification that doesn't do anything if the user would log out.

marcbaechinger commented 1 month ago

No updates I'm afraid.

having a "dead" notification that doesn't do anything

I don't think Media3 can solve this for the notification because this is provided by SystemUI and there isn't a way to opt-out of the resumption notification once it is opted-in.

As stated above, an option would be to separate media button event and notification resumption. This would allow apps to only use media button event resumption for which an opt-out at runtime would be possible. To opt-out at runtime from the notification, it would require a framework change from System UI which would be available starting from the API level that would include this change. On API levels before that won't be possible as it is restricted by the OS.

I'm not sure when we get around doing this, so I can't give you a timeline I'm afraid.

rnekicOD commented 1 month ago

This is an unfortunate issue and the reason we'll be leaving playback resumption disabled. Our content is time-limited and the inability to clear the notification ends up looking like an app issue. If System UI would at least query the app before moving an on-going notification into the resumption state, we could at least have some control over it. Instead it just abandons the notification, where it stays...forever? Until the device is restarted and System UI actually calls onPlaybackResumption where the app can properly respond with current content or no content?

I've disabled this feature on my own phone entirely because the media displayed there lingers so long and can't be swiped away.