Reputation: 1257
How can I manually handle media button actions with Media3 in a peaceful and compatible way without using MediaSessionConnector?
Previously, I used to handle media button commands using MediaSessionConnector and MediaSessionCompat, but due to Android 13 changes, I migrated to Media3 and removed the MediaSessionConnector, here is what I had before:
mediaSessionConnector.setMediaButtonEventHandler { player, mediaButtonEvent ->
val event: KeyEvent? = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)
when (event?.keyCode) {
KeyEvent.KEYCODE_MEDIA_NEXT -> {
if (event.action == KeyEvent.ACTION_UP) {
nextSegment()
}
true
}
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> {
if (event.action == KeyEvent.ACTION_UP) {
previousSegment()
}
true
}
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
if (event.action == KeyEvent.ACTION_UP) {
onPlayPause()
}
true
}
else -> false
}
}
as you see I have some custom behaviors for backward and forward action to handle back and forth segments in our application. but recently due to android 13 changes I went through the migration guide (from exo to media3) and removed the media session connector but I can no longer handle the media button receiver manually.
Even I tried to register my own button receiver with android.intent.action.MEDIA_BUTTON
action but still is not triggering that. then I checked the MediaSession (from media3) implementation and found out it register a
MediaButtonReceive itself with the same action with below implementation which overrides mine and it only works for play/pause, (what I am looking for is double tap for fast-forward action while I need my customize functioning to go to next segment), :
here is google MediaButtonReceive:
private final class MediaButtonReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!Util.areEqual(intent.getAction(), Intent.ACTION_MEDIA_BUTTON)) {
return;
}
Uri sessionUri = intent.getData();
if (!Util.areEqual(sessionUri, sessionUri)) {
return;
}
KeyEvent keyEvent = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (keyEvent == null) {
return;
}
getSessionCompat().getController().dispatchMediaButtonEvent(keyEvent);
}
}
what I understand so far the MediaSession has an internal package private mediaSessionCompat which is used for some part of logic like dispatchMediaEvent.
------ a workaround which didn't work-----
I also attempted a workaround by defining MediaSessionCompat again alongside the actual MediaSession and setting a callback for it and override onMediaButtonEvent
but it's not triggering that callback.
here is how I defined that:
mediaSessionCompat = MediaSessionCompat(applicationContext, MEDIA_SESSION_TAG)
mediaSessionCompat?.setSessionActivity(mediaSession?.sessionActivity)
mediaSessionCompat?.setCallback{
override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {..}
}
Is there any other peaceful and compatible way to handle media button actions manually in media3? Any insights or alternative approaches would be appreciated.
Upvotes: 1
Views: 1446
Reputation: 21
class PlaybackService : MediaSessionService(){
private var mediaSession: MediaSession? = null
...
private fun thisIsWhereWeCreateMedia3Session(){
mediaSession = MediaSession.Builder(this, player).setCallback(MyMediaSessionCallback()).build()
}
}
class MyMediaSessionCallback : MediaSession.Callback {
@UnstableApi
override fun onMediaButtonEvent(
session: MediaSession,
controllerInfo: ControllerInfo,
intent: Intent
): Boolean {
val ke =
intent.extras!!.getParcelable(EXTRA_KEY_EVENT, KeyEvent::class.java) ?: return false
when (ke.keyCode) {
KEYCODE_MEDIA_PLAY_PAUSE -> {
//do whatever you want
return true
}
KEYCODE_MEDIA_PLAY -> {
//do whatever you want
return true
}
KEYCODE_MEDIA_PAUSE -> {
//do nothing, just reutrn false
return false
}
KEYCODE_MEDIA_STOP -> {
//do whatever you want
return true
}
KEYCODE_MEDIA_NEXT -> {
//do whatever you want
return true
}
KEYCODE_MEDIA_PREVIOUS -> {
//do whatever you want
return true
}
KEYCODE_MEDIA_REWIND -> {
//do whatever you want
return true
}
}
return super.onMediaButtonEvent(session, controllerInfo, intent)
}
}
<service
android:name=".service.PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
Upvotes: -1