open class MediaController : Closeable
Allows an app to interact with an active or a
MediaSessionService which would provide . Media buttons and other commands can be sent to the session.
MediaController objects are thread-safe.
Topics covered here:
When a controller is created with the
SessionToken for a
MediaSessionService (i.e. session token type is
SessionToken#TYPE_LIBRARY_SERVICE), the controller binds to the service for connecting to a
MediaSession in it.
MediaSessionService will provide a session to connect.
When a controller connects to a session,
MediaSession.SessionCallback#onConnect(MediaSession, MediaSession.ControllerInfo) will be called to either accept or reject the connection. Wait
ControllerCallback#onConnected(MediaController, SessionCommandGroup) or
ControllerCallback#onDisconnected(MediaController) for the result.
When the connected session is closed, the controller will receive
When you're done, use #close() to clean up resources. This also helps session service to be destroyed when there's no controller associated with it.
Controlling the MediaSession in the same processWhen you control the
SessionPlayer, it's recommended to use them directly rather than creating
MediaController. However, if you need to use
MediaControllerin the same process, be careful not to block session callback executor's thread. Here's an example code that would never return due to the thread issue.
<code>// Code runs on the main thread. MediaSession session = new MediaSession.Builder(context, player) .setSessionCallback(sessionCallback, Context.getMainExecutor(context)).build(); MediaController controller = new MediaController.Builder(context) .setSessionToken(session.getToken()) .setControllerCallback(Context.getMainExecutor(context), controllerCallback) .build(); // This will hang and never return. controller.play().get();</code>When a session gets a command from a controller, the session's
MediaSession.SessionCallback#onCommandRequestwould be executed on the session's callback executor to decide whether to ignore or handle the incoming command. To do so, the session's callback executor shouldn't be blocked to handle the incoming calls. However, if you call ListenableFuture#get on the thread for the session callback executor, then your call wouldn't be executed and never return.
To avoid such issue, don't block the session callback executor's thread. Creating a dedicated thread for the session callback executor would be helpful. See Executors#newSingleThreadExecutor for creating a new thread.
Interface for listening to change in activeness of the
Holds information about the way volume is handled for this session.
@NonNull open fun addPlaylistItem(
@IntRange(0) index: Int,
@NonNull mediaId: String
Requests that the
SessionPlayer associated with the connected
MediaSession adds the media item to the playlist at the index with the media ID. Index equals to or greater than the current playlist size (e.g.
Integer#MAX_VALUE) will add the item at the end of the playlist.
If index is less than or equal to the current index of the playlist, the current index of the playlist will be increased correspondingly.
On success, a
SessionResult would be returned with
||Int: the index you want to add|
||String: the non-empty media id of the new item|
@NonNull open fun adjustVolume(
Requests that the connected
MediaSession adjusts the volume of the output that is playing on. The direction must be one of
If the session is local playback, this changes the device's volume with the stream that session's player is using. Flags will be specified for the
If the session is remote player (i.e. session has set volume provider), its volume provider will receive this request instead.
||Int: the direction to adjust the volume in|
||Int: flags from
open fun close(): Unit
Releases this object, and disconnects from the session. After this, callbacks wouldn't be received.
@NonNull open fun deselectTrack(@NonNull trackInfo: SessionPlayer.TrackInfo): ListenableFuture<SessionResult!>
Generally, a track should already be selected in order to be deselected and audio and video tracks should not be deselected.
The types of tracks supported may vary based on players.
getSelectedTrack(int) returns the currently selected track per track type that can be deselected, but the list may be invalidated when
ControllerCallback#onTracksChanged(MediaController, List) is called.
||SessionPlayer.TrackInfo: track to be deselected|
@NonNull open fun fastForward(): ListenableFuture<SessionResult!>
The implementation may be different depending on the players. For example, it can be implemented by seeking forward once, series of seeking forward, or increasing playback speed. If you need full control, then use
@Nullable open fun getAllowedCommands(): SessionCommandGroup?
Gets the cached allowed commands from
ControllerCallback#onAllowedCommandsChanged. If it is not connected yet, it returns
||the allowed commands|