Media Session Integration
This guide shows how to set up the media session integration with the Bitmovin Player Android SDK. Media sessions provide a universal way of interacting with an audio or video player. Integrating with the media session allows an app to advertise media playback externally, e.g. on the lock screen or in the notification area.
Prerequisites
- Basic understanding of Android development with Kotlin
- Bitmovin Player Android SDK added to your project (see Getting Started guide)
Add Required Permissions in the AndroidManifest.xml
AndroidManifest.xml
Add the necessary permissions FOREGROUND_SERVICE
and FOREGROUND_SERVICE_MEDIA_PLAYBACK
to the manifest. The INTERNET
permission should be already present, after following the Getting Started guide.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
...
</manifest>
Create a MediaSessionPlaybackService
MediaSessionPlaybackService
The MediaSessionPlaybackService
is responsible for managing the player instance and creating a MediaSession
instance that is populated to the Android system. Through the MediaSession
, the system can interact with the Bitmovin Player instance managed by this service. The service also automatically takes care of showing a playback notification in the notification area and on the lock screen.
class MediaSessionPlaybackService : MediaSessionService() {
inner class ServiceBinder : Binder() {
val player get() = [email protected]
fun connectSession() = addSession(mediaSession)
fun disconnectSession() = removeSession(mediaSession)
}
private val binder = ServiceBinder()
private lateinit var player: Player
private lateinit var mediaSession: MediaSession
override fun onGetSession(controllerInfo: ControllerInfo) = mediaSession
override fun onCreate() {
super.onCreate()
player = Player(
this, PlayerConfig(
playbackConfig = PlaybackConfig(
handleAudioFocus = true
)
)
)
mediaSession = MediaSession(
this,
mainLooper,
player,
)
}
override fun onDestroy() {
mediaSession.release()
player.destroy()
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder {
super.onBind(intent)
return binder
}
}
Register MediaSessionPlaybackService
in AndroidManifest.xml
MediaSessionPlaybackService
in AndroidManifest.xml
Declare the MediaSessionPlaybackService
in the manifest, inside the <application>
tag:
<service
android:name=".MediaSessionPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
Use the Service in Your Apps Playback Activity
The final step is to bind to the service in your playback activity. You can find a complete implementation of this in our MediaSessionKotlin sample application. The important parts are:
1. Bind to the MediaSessionPlaybackService
MediaSessionPlaybackService
The intent actions to start the service needs to be Intent.ACTION_MEDIA_BUTTON
. Once a connection to the service is established, the player
instance that is managed by the service can be accessed through the MediaSessionPlaybackService.ServiceBinder
.
override fun onStart() {
super.onStart()
bindService()
}
private fun bindService() {
val intent = Intent(this, MediaSessionPlaybackService::class.java)
intent.setAction(Intent.ACTION_MEDIA_BUTTON)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
startService(intent)
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
// We've bound to the Service, cast the IBinder and get the Player instance
val binder = service as MediaSessionPlaybackService.ServiceBinder
val player = binder.player ?: throw IllegalStateException("Player is null")
// Add the player to the player view
playerView.player = player
if (player.source == null) {
// Load a source into the player if there is the need
}
}
}
2. Detach the Player
From the PlayerView
When Going Into Background
Player
From the PlayerView
When Going Into BackgroundIn order to prevent the player from being paused when the app is minimized, the player instance needs to be detached from the player view when this happens. The player itself is managed by the service, so playback continues and can be controlled through the media controls on the lock screen or in the notification area.
override fun onPause() {
// Detach the Player to decouple it from the PlayerView lifecycle
playerView.player = null
playerView.onPause()
super.onPause()
}
override fun onResume() {
super.onResume()
// Attach the Player to allow the PlayerView to control the player.
playerView.player = player
playerView.onResume()
}
Test Your Media Session Integration
Your app should now be correctly set up to populate a MediaSession
. When a source is loaded and played back in the player, a notification should showing up that allows to control playback through the MediaSession
. Also the lock screen should be presented with media controls.
Keep in mind that this guide only outlines key parts of the implementation. A full implementation can be found in our MediaSessionKotlin sample application.
Updated 4 days ago