Open baruckis opened 1 year ago
I think this is difficult to achieve indeed.
When I test with two different BT headsets I see that the skip to next and skip to previous user interactions (like double and triple press the play button) emits a KEYCODE_MEDIA_NEXT
or KEYCODE_MEDIA_PREVIOUS
. These have the values 87 or 88 respectively.
I then see that your analysis is correct: Media3 in aware of this MediaButtonEvent
in MediaSessionLegacyStub.onMediaButtonEvent(...)
, but it is not handled there but instead left to the system to be handled (the callback method returns false
to indicate to the system the event isn't handled).
The system then checks the actions of the platform media session, sees the action [ACTION_SKIP_TO_NEXT
](https://developer.android.com/reference/android/support/v4/media/session/PlaybackStateCompat#ACTION_SKIP_TO_NEXT()) is not available and then drops the command, meaning the corresponding MediaSession.Callback
method is not called by the system.
Changing this behaviour in the Media3 library is technically possible, but I'm not sure how sensible that would be. We had to handle the key event in MediaSessionLegacyStub.onMediaButtonEvent
ouself and then process some specific logic. But then we would break the vailable commands
design ourself.
You could use a ForwardingPlayer
that wraps the actual player, overrides getAvailableCommands()
, and intercepts the listeners to customize onAvailableCommands
and then tells the session that the COMMAND_SEEK_TO_NEXT
is always available. However, this would change the available actions in the platform session (see adb shell dumpsys media_session
) are shared across all users of the legacy session. So you would change this behaviour for all clients which includes for instance SystemUI (the media notification), Bluetooth clients, Android Auto and any third party app that is connecting with your platform session. All these potential clients setup their UI (like the next button) according to these actions. They could also look at the queue and notice that we are already on the last item. But I wouldn't rely on this behaviour specifically, because you had to test this on various OS versions and API levels.
So even if this is probably not a very helpful answer, I think that unless the BT headset is actually sending a KEYCODE_MEDIA_FAST_FORWARD
, I don't know how this could be achieved.
Have you been able to do that with the legacy API?
Hey thank you for your reply and that overviewed possible scenarios. That is useful. I was trying to implement a workaround with Player.REPEAT_MODE_ALL after your reply but in general it does not work well for us. I have not tried to do this on legacy API, we have full focus now just on media3 as our main service. However, our users are requesting this functionality by leaving negative app reviews. When they are listening to podcasts on headphones, they expect to just seek forward or backward by a few seconds. This behavior is on the Google podcasts app or Spotify podcasts, so it is what they expect.
Hi @marcbaechinger
You could use a
ForwardingPlayer
that wraps the actual player, overridesgetAvailableCommands()
, and intercepts the listeners to customizeonAvailableCommands
and then tells the session that theCOMMAND_SEEK_TO_NEXT
is always available.
This how I tried to solve the same issue: Intercepting the headphone issued skip commands for a podcast player app.
The thing is: this method used to work in 1.0.0-beta03 and stopped working in 1.0.0-rc01.
Can you expand on what is not working anymore? Best would be to file a new issue.
Sorry. I meant, I was doing the exact thing, that you described as a workaround:
I was using a ForwardingPlayer
to override getAvailableCommands()
to ensure that COMMAND_SEEK_TO_NEXT
is always available.
Best would be to file a new issue.
Sure. I will do that. I just suspected it was an deliberate change not a bug.
Same issue here with Media3 v1.1.0
I don't want to use Player.REPEAT_MODE_ALL
since that will add skip next/previous buttons to my notification/android auto. My app only plays 1 audio file at a time (so no need for queue).
I have 2 custom actions for fast-forward/rewind.
Is there a way to have the skip commands active in the session without displaying them in the notification? Or is there a way to inject my own MediaButtonReceiver to handle the skip events from the headset?
Is there a way to have the skip commands active in the session without displaying them in the notification?
I understand with skip commands active in the session
you mean to keep them in PlaybackStateCompat.getActions()
but not showing them in the notification.
Technically you can provide your own MediaNotificationProvider
or override DefaultMediaNotificationManager.getMediaButtons
. There you can define what buttons to show in the notification and keep the commands available with the ForwardingPlayer
and hence for the platform session.
This can probably solve your problem with API 32 and below. However, with API 33 and later, the actions in the notification are not relevant, instead System UI uses the actions in the PlaybackStateCompat
, so I think the buttons would still show up on API 33.
That doesn't feel like an optimal solution then.
I can see from the logs that my headset is sending Sending KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_MEDIA_NEXT
and Sending KeyEvent { action=ACTION_UP, keyCode=KEYCODE_MEDIA_NEXT,
to androidx.media3.session.id.
And from the androidx.media3.session.MediaSession
docs:
Media Key Events Mapping When the session receives media key events they are mapped to a method call on the underlying player. KeyEvent.KEYCODE_MEDIA_NEXT -> Player.seekToNext()
But my ForwardingPlayer´s seekToNext() is not called unless I add COMMAND_SEEK_TO_PREVIOUS
and COMMAND_SEEK_TO_NEXT
or use Player.REPEAT_MODE_ALL
. Both which will make the notification display skip buttons in addition to my Custom seek actions.
unless I add COMMAND_SEEK_TO_PREVIOUS and COMMAND_SEEK_TO_NEXT
When a player is saying to not support for instance COMMAND_SEEK_TO_PREVIOUS
then it looks correct to me to not deliver these messages even when a source send such events. The player says it is not supported by not providing the available command for it.
A session can have arbitrary implementation of the Player
interface. If such a player implementation tells the session to not support COMMAND_SEEK_TO_PREVIOUS
, then your statement 'my ForwardingPlayer´s seekToNext() is not called unless I add COMMAND_SEEK_TO_PREVIOUS and COMMAND_SEEK_TO_NEXT' seems to confirm that this is implemented as intended.
Understood. It sounds like it is working as intended. But that is not how Google Podcasts app works. I've checked (in Media Controller Tester) that their MediaSession has COMMAND_SEEK_TO_PREVIOUS and COMMAND_SEEK_TO_NEXT inactivated. Yet they support seek next/previous media buttons and handle them as ffw/rewind.
If you have any insights on wether this is doable with media3 would be appreciated.
One possibility is to intercept the key intent in onStartCommand
in MediaSessionService
and handle NEXT/PREVIOUS there.
Hi, I would like to handle Bluetooth headset commands COMMAND_SEEK_TO_PREVIOUS and COMMAND_SEEK_TO_NEXT differently. Instead of jumping back to the previous item or next item from the playlist, I want to only seek back and seek forward in the current item by a specific number of seconds (common behaviour in podcasts apps). I have followed your documentation note on how to do that https://developer.android.com/guide/topics/media/media3/getting-started/playing-in-background?authuser=3#handling-ui
The problem is if I have only one item in my playlist or my item is last in the playlist. Then COMMAND_SEEK_TO_NEXT is not available because there is no next item. So I can not catch this command and re-map action. I could set
player.repeatMode = Player.REPEAT_MODE_ALL
to have button next enabled but that is also not acceptable to repeat content always. Any ideas what else I can try to do? Or is this missing funcionallity?