@DoNotMock
class MediaSession


A session that allows a media app to expose its player functionality, information of the playlist and the media item currently being played to other processes including the Android framework and other apps. The common use cases are as follows:

  • Receiving and dispatching media key events (for instance Bluetooth/wired headset and remote control devices).
  • Publish media playback information and player commands to SystemUI (media notification) and Android Auto/Wear OS.
  • Separating UI process and playback process.

A session should be created when an app wants to publish media playback information or handle media key events. In general, an app only needs one session for all playback, though multiple sessions can be created to provide finer grain controls of media. See Supporting Multiple Sessions for details.

If an app wants to support playback when in the background, using a is the preferred approach. See MediaSessionService for details.

Topics covered here:

  1. Session Lifecycle
  2. Threading Model
  3. Media Key Events Mapping
  4. Supporting Multiple Sessions
  5. Backward Compatibility with Legacy Session APIs
  6. Backward Compatibility with Legacy Controller APIs

Session Lifecycle

A session can be created by Builder. The owner of the session may pass its session token to other processes to allow them to create a MediaController to interact with the session.

When a session receives playback commands, the session calls corresponding methods directly on the underlying player set by Builder or setPlayer.

When an app is finished performing playback it must call release to clean up the session and notify any controllers. The app is responsible for releasing the underlying player after releasing the session.

Threading Model

The instances are thread safe, but must be used on a thread with a looper.

Callback methods will be called on the application thread associated with the application looper of the underlying player. When a new player is set by setPlayer, the player must use the same application looper as the previous one.

The session listens to player events via Player.Listener and expects the callback methods to be called on the application thread. If the player violates the threading contract, an IllegalStateException will be thrown.

Media Key Events Mapping

When the session receives media key events they are mapped to a method call on the underlying player. The following table shows the mapping between the event key code and the Player method which is called.

Key code and corresponding Player API
Key code Player API
KEYCODE_MEDIA_PLAY play
KEYCODE_MEDIA_PAUSE pause
  • For a single tap,
  • In case the media key events are coming from another package ID than the package ID of the media app (events coming for instance from Bluetooth), a double tap generating two key events within a brief amount of time, is converted to seekToNext
KEYCODE_MEDIA_NEXT seekToNext
KEYCODE_MEDIA_PREVIOUS seekToPrevious
KEYCODE_MEDIA_STOP stop
KEYCODE_MEDIA_FAST_FORWARD seekForward
KEYCODE_MEDIA_REWIND seekBack

Supporting Multiple Sessions

Generally, multiple sessions aren't necessary for most media apps. One exception is if your app can play multiple media content at the same time, but only for the playback of video-only media or remote playback, since the audio focus policy recommends not playing multiple audio content at the same time. Also, keep in mind that multiple media sessions would make Android Auto and Bluetooth devices with display to show your app multiple times, because they list up media sessions, not media apps.

Backward Compatibility with Legacy Session APIs

An active MediaSessionCompat is internally created with the session for backwards compatibility. It's used to handle incoming connections and commands from instances, and helps to utilize existing APIs that are built with legacy media session APIs.

Backward Compatibility with Legacy Controller APIs

In addition to MediaController, the session also supports connections from the legacy controller APIs - framework controller and AndroidX controller compat. However, ControllerInfo may not be precise for legacy controllers. See ControllerInfo for the details.

Neither an unknown package name nor an unknown UID mean that you should disallow a connection or commands per se. For SDK levels where such issues happen, session tokens can only be obtained by trusted controllers (e.g. Bluetooth, Auto, ...). This means only trusted controllers can connect and an app can accept such controllers in the same way as with legacy sessions.

Summary

Nested types

A builder for MediaSession.

A callback to handle incoming commands from MediaController.

A result for onConnect to denote the set of available commands and the custom layout for a controller.

A builder for ConnectionResult instances to accept a connection.

Information of a MediaController or a MediaBrowser.

Representation of a list of media items and where to start playing.

Public functions

Unit

Broadcasts a custom command to all connected controllers.

BitmapLoader!

Returns the BitmapLoader.

(Mutable)List<MediaSession.ControllerInfo!>!

Returns the list of connected controllers.

MediaSession.ControllerInfo?

Returns the ControllerInfo for the controller that sent the current request for a Player method.

ImmutableList<CommandButton!>!

Returns the custom layout of the session.

String!

Returns the session ID.

MediaSession.ControllerInfo?

Returns the ControllerInfo of the media notification controller.

Player!

Returns the underlying Player.

PendingIntent?

Returns the PendingIntent to launch the session activity or null if not set.

MediaSessionCompat.Token!

Returns the MediaSessionCompat.Token of the MediaSessionCompat created internally by this session.

Bundle!

Returns the session extras.

Boolean

Returns whether a play button is shown if playback is suppressed.

SessionToken!

Returns the SessionToken for creating MediaController.

Boolean

Returns whether the given ControllerInfo belongs to an Android Auto companion app controller.

Boolean

Returns whether the given ControllerInfo belongs to an Automotive OS controller.

Boolean

Returns whether the given media controller info belongs to the media notification controller.

Unit

Releases the session and disconnects all connected controllers.

ListenableFuture<SessionResult!>!
sendCustomCommand(
    controller: MediaSession.ControllerInfo!,
    command: SessionCommand!,
    args: Bundle!
)

Sends a custom command to a specific controller.

Unit
setAvailableCommands(
    controller: MediaSession.ControllerInfo!,
    sessionCommands: SessionCommands!,
    playerCommands: Player.Commands!
)

Sets the new available commands for the controller.

Unit

Sets the custom layout that can initially be set when building the session.

ListenableFuture<SessionResult!>!

Sets the custom layout for the given Media3 controller.

Unit
setPlayer(player: Player!)

Sets the underlying Player for this session to dispatch incoming events to.

Unit
@UnstableApi
setSessionActivity(activityPendingIntent: PendingIntent!)

Updates the session activity that was set when building the session.

Unit
setSessionExtras(sessionExtras: Bundle!)

Sets the session extras and sends them to connected controllers.

Unit
setSessionExtras(
    controller: MediaSession.ControllerInfo!,
    sessionExtras: Bundle!
)

Sends the session extras to the connected controller.

Public functions

broadcastCustomCommand

fun broadcastCustomCommand(command: SessionCommand!, args: Bundle!): Unit

Broadcasts a custom command to all connected controllers.

This is a synchronous call and doesn't wait for results from the controllers.

A command is not accepted if it is not a custom command.

Parameters
command: SessionCommand!

A custom command.

args: Bundle!

A Bundle for additional arguments. May be empty.

getBitmapLoader

@UnstableApi
fun getBitmapLoader(): BitmapLoader!

Returns the BitmapLoader.

getConnectedControllers

fun getConnectedControllers(): (Mutable)List<MediaSession.ControllerInfo!>!

Returns the list of connected controllers.

getControllerForCurrentRequest

fun getControllerForCurrentRequest(): MediaSession.ControllerInfo?

Returns the ControllerInfo for the controller that sent the current request for a Player method.

This method will return a non-null value while Player methods triggered by a controller are executed.

Note: If you want to prevent a controller from calling a method, specify the available commands in onConnect or set them via setAvailableCommands.

This method must be called on the application thread of the underlying player.

Returns
MediaSession.ControllerInfo?

The ControllerInfo of the controller that sent the current request, or null if not applicable.

getCustomLayout

@UnstableApi
fun getCustomLayout(): ImmutableList<CommandButton!>!

Returns the custom layout of the session.

For informational purpose only. Mutations on the Bundle of either a or a SessionCommand do not have effect. To change the custom layout use setCustomLayout or setCustomLayout.

getId

fun getId(): String!

Returns the session ID.

getMediaNotificationControllerInfo

@UnstableApi
fun getMediaNotificationControllerInfo(): MediaSession.ControllerInfo?

Returns the ControllerInfo of the media notification controller.

Use this controller info to set available commands and custom layout that are consistently applied to the media notification on all API levels.

Available session commands of the media notification controller are used to enable or disable buttons of the custom layout before it is passed to the notification provider. Disabled command buttons are not converted to notification actions when using . This affects the media notification displayed by System UI below API 33.

The available session commands of the media notification controller are used to maintain custom actions of the platform session (see PlaybackStateCompat.getCustomActions()). Command buttons of the custom layout are disabled or enabled according to the available session commands. Disabled command buttons are not converted to custom actions of the platform session. This affects the media notification displayed by System UI starting with API 33.

The available player commands are intersected with the actual available commands of the underlying player to determine the playback actions of the platform session (see PlaybackStateCompat.getActions()).

getPlayer

fun getPlayer(): Player!

Returns the underlying Player.

getSessionActivity

fun getSessionActivity(): PendingIntent?

Returns the PendingIntent to launch the session activity or null if not set.

Returns
PendingIntent?

The PendingIntent to launch an activity belonging to the session.

getSessionCompatToken

@UnstableApi
fun getSessionCompatToken(): MediaSessionCompat.Token!

Returns the MediaSessionCompat.Token of the MediaSessionCompat created internally by this session.

getSessionExtras

@UnstableApi
fun getSessionExtras(): Bundle!

Returns the session extras.

For informational purpose only. Mutations on the Bundle do not have immediate effect. To change the session extras use setSessionExtras or setSessionExtras.

getShowPlayButtonIfPlaybackIsSuppressed

@UnstableApi
fun getShowPlayButtonIfPlaybackIsSuppressed(): Boolean

Returns whether a play button is shown if playback is suppressed.

getToken

fun getToken(): SessionToken!

Returns the SessionToken for creating MediaController.

isAutoCompanionController

@UnstableApi
fun isAutoCompanionController(controllerInfo: MediaSession.ControllerInfo!): Boolean

Returns whether the given ControllerInfo belongs to an Android Auto companion app controller.

Note: This is not a security validation.

Parameters
controllerInfo: MediaSession.ControllerInfo!

The controller info of the connected controller.

Returns
Boolean

True if the controller into belongs to a connected Auto companion client app.

isAutomotiveController

@UnstableApi
fun isAutomotiveController(controllerInfo: MediaSession.ControllerInfo!): Boolean

Returns whether the given ControllerInfo belongs to an Automotive OS controller.

Note: This is not a security validation.

Parameters
controllerInfo: MediaSession.ControllerInfo!

The controller info of the connected controller.

Returns
Boolean

True if the controller into belongs to a connected Automotive OS controller.

isMediaNotificationController

@UnstableApi
fun isMediaNotificationController(
    controllerInfo: MediaSession.ControllerInfo!
): Boolean

Returns whether the given media controller info belongs to the media notification controller.

See getMediaNotificationControllerInfo.

Parameters
controllerInfo: MediaSession.ControllerInfo!

The controller info.

Returns
Boolean

Whether the controller info belongs to the media notification controller.

release

fun release(): Unit

Releases the session and disconnects all connected controllers.

The session must not be used after calling this method.

Releasing the session removes the session's listeners from the player but does not stop or release the player. An app can further use the player after the session is released and needs to make sure to eventually release the player.

sendCustomCommand

fun sendCustomCommand(
    controller: MediaSession.ControllerInfo!,
    command: SessionCommand!,
    args: Bundle!
): ListenableFuture<SessionResult!>!

Sends a custom command to a specific controller.

The result from onCustomCommand will be returned.

A command is not accepted if it is not a custom command.

Interoperability: This call has no effect when called for a legacy controller.

Parameters
controller: MediaSession.ControllerInfo!

The controller to send the custom command to.

command: SessionCommand!

A custom command.

args: Bundle!

A Bundle for additional arguments. May be empty.

Returns
ListenableFuture<SessionResult!>!

A ListenableFuture of SessionResult from the controller.

setAvailableCommands

fun setAvailableCommands(
    controller: MediaSession.ControllerInfo!,
    sessionCommands: SessionCommands!,
    playerCommands: Player.Commands!
): Unit

Sets the new available commands for the controller.

This is a synchronous call. Changes in the available commands take effect immediately regardless of the controller notified about the change through onAvailableCommandsChanged and onAvailableSessionCommandsChanged.

Note that playerCommands will be intersected with the available commands of the underlying Player and the controller will only be able to call the commonly available commands.

Parameters
controller: MediaSession.ControllerInfo!

The controller to change allowed commands.

sessionCommands: SessionCommands!

The new available session commands.

playerCommands: Player.Commands!

The new available player commands.

setCustomLayout

fun setCustomLayout(layout: (Mutable)List<CommandButton!>!): Unit

Sets the custom layout that can initially be set when building the session.

Calling this method broadcasts the custom layout to all connected Media3 controllers, including the media notification controller.

On the controller side, the enabled flag is set according to the available commands of the controller which overrides a value that has been set by the session.

onCustomLayoutChanged is only called if the new custom layout is different to the custom layout the controller already has available. Note that extras are ignored when comparing command buttons.

Controllers that connect after calling this method will have the new custom layout available with the initial connection result. A custom layout specific to a controller can be set when the controller connects by using an .

Parameters
layout: (Mutable)List<CommandButton!>!

The ordered list of CommandButton.

setCustomLayout

@CanIgnoreReturnValue
fun setCustomLayout(
    controller: MediaSession.ControllerInfo!,
    layout: (Mutable)List<CommandButton!>!
): ListenableFuture<SessionResult!>!

Sets the custom layout for the given Media3 controller.

Make sure to have the session commands of all command buttons of the custom layout available for controllers. Include the custom session commands a controller should be able to send in the available commands of the connection result that your app returns when the controller connects. The isEnabled flag is set according to the available commands of the controller and overrides a value that may have been set by the app.

On the controller side, onCustomLayoutChanged is only called if the new custom layout is different to the custom layout the controller already has available. Note that this comparison uses equals and therefore ignores extras.

It's up to controller's decision how to represent the layout in its own UI.

Interoperability: This call has no effect when called for a legacy controller.

Parameters
controller: MediaSession.ControllerInfo!

The controller for which to set the custom layout.

layout: (Mutable)List<CommandButton!>!

The ordered list of command buttons.

setPlayer

fun setPlayer(player: Player!): Unit

Sets the underlying Player for this session to dispatch incoming events to.

Parameters
player: Player!

A player that handles actual media playback in your app.

Throws
java.lang.IllegalArgumentException

if the new player's application looper differs from the current player's looper, or canAdvertiseSession returns false.

java.lang.IllegalStateException

if the new player's application looper differs from the current looper.

setSessionActivity

@UnstableApi
fun setSessionActivity(activityPendingIntent: PendingIntent!): Unit

Updates the session activity that was set when building the session.

Parameters
activityPendingIntent: PendingIntent!

The pending intent to start the session activity.

setSessionExtras

fun setSessionExtras(sessionExtras: Bundle!): Unit

Sets the session extras and sends them to connected controllers.

The initial extras can be set when building the session.

This is a synchronous call and doesn't wait for results from the controllers.

Parameters
sessionExtras: Bundle!

The session extras.

setSessionExtras

fun setSessionExtras(
    controller: MediaSession.ControllerInfo!,
    sessionExtras: Bundle!
): Unit

Sends the session extras to the connected controller.

The initial extras for a specific controller can be set in onConnect when building the connection result.

This is a synchronous call and doesn't wait for results from the controller.

Interoperability: This call has no effect when called for a legacy controller.

Parameters
controller: MediaSession.ControllerInfo!

The controller to send the extras to.

sessionExtras: Bundle!

The session extras.