Play media in the background
It is often desirable to play media while an app is not in the foreground. For example, a music player generally keeps playing music when the user has locked their device or is using another app. Similarly, a video player may want to enable a picture-in-picture mode. This is playing in the background.
The Media3 library provides a series of interfaces that allow you to support background playback in Android more easily than ever.
Use a MediaSessionService
To enable background playback, you should contain the Player
and
MediaSession
inside a separate Service. This allows the device to
continue serving media even while your app is not in the foreground.

When hosting a player inside a Service, you should use a MediaSessionService
.
To do this, create a class that extends MediaSessionService and create your
media session inside of it.
Using MediaSessionService
makes it easy for companion devices like Assistant,
System media controls or companion devices like Wear OS to discover your
service, connect to it, and control playback, all without accessing your app's
UI activity at all. In fact, there can be multiple apps connected to the same
MediaSessionService
at the same time, each app with its own MediaController
.
Provide access to the media session
Override the onGetSession()
method to give other clients access to your media
session.
// Extend MediaSessionService
class PlaybackService : MediaSessionService() {
private var mediaSession: MediaSession? = null
// Create your Player and MediaSession in the onCreate lifecycle event
override fun onCreate() {
super.onCreate()
Player player = ExoPlayer.Builder(this).build()
mediaSession = MediaSession.Builder(this, player).build()
}
// Return a MediaSession to link with the MediaController that is making
// this request.
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession?
= mediaSession
}
An app requires permission to run a foreground service. Add the
FOREGROUND_SERVICE
permission to the manifest:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
You must also declare your Service
class in the manifest with an intent filter
of MediaSessionService
.
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
You must define a
foregroundServiceType
that includes mediaPlayback
when your app is running on a device with Android
10 onwards.
Be sure to release the media session (and player) in your service’s
onDestroy()
lifecycle callback:
override fun onDestroy() {
mediaSession?.run {
player.release()
release()
mediaSession = null
}
super.onDestroy()
}
Control playback in the media session
In the Activity or Fragment containing your player UI, you can establish a link
between the UI and your media session using a MediaController
. Your UI uses
the media controller to send commands from your UI to the player within the
session.
Obtain a MediaController
from your MediaSession
by creating a SessionToken
in the onStart()
method of your Activity or Fragment.
override fun onStart() {
val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java))
}
Use this SessionToken
to build a MediaController
. Doing so connects the
controller to the given session. This takes place asynchronously so you should
listen for the result and assign it when constructed. This example shows how you
can do this to connect the MediaController
to your player UI.
val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
controllerFuture.addListener(
{ playerView.player = controllerFuture.get() },
MoreExecutors.directExecutor()
)
Handle UI commands
The MediaSession
receives commands from the controller through its
SessionCallback
. Initializing a MediaSession
creates a default
implementation of SessionCallback
that automatically handles all commands that
your MediaController
sends to your player.
You should also release the controller in the onStop()
method of its hosting
Activity or Fragment by calling
MediaController.releaseFuture(controllerFuture)
.
Notification
A MediaSessionService
automatically creates a MediaNotification
for you that
should work in most cases. By default, the published notification is a
MediaStyle
notification that stays updated with the latest information
from your media session and displays playback controls. The MediaNotification
is aware of your session and can be used to control playback for any other apps
that are connected to the same session.
For example, a music streaming app using a MediaSessionService
would create a
MediaNotification
that displays the title, artist, and album art for the
current song playing alongside playback controls based on your MediaSession
configuration.
If you’d like to provide your own custom MediaNotification
, you can override
MediaSessionService.onUpdateNotification()
.