Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import com.theoplayer.android.api.timerange.TimeRanges
class MediaSessionCallback(private val connector: MediaSessionConnector) :
MediaSessionCompat.Callback() {

// region PlaybackPreparer actions

override fun onPrepare() {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPrepare")
Expand Down Expand Up @@ -48,14 +50,45 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
}
}

override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlayFromMediaId $mediaId")
}
if (shouldHandlePlaybackPreparerAction(ACTION_PREPARE_FROM_MEDIA_ID)) {
connector.playbackPreparer?.onPrepareFromMediaId(mediaId, true, extras)
}
}

override fun onPlayFromSearch(query: String?, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlayFromSearch $query")
}
if (shouldHandlePlaybackPreparerAction(ACTION_PREPARE_FROM_SEARCH)) {
connector.playbackPreparer?.onPrepareFromSearch(query, true, extras)
}
}

override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlayFromUri ${uri?.path}")
}
if (shouldHandlePlaybackPreparerAction(ACTION_PREPARE_FROM_URI)) {
connector.playbackPreparer?.onPrepareFromUri(uri, true, extras)
}
}

// endregion
// region Playback actions

override fun onPlay() {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlay")
}
connector.player?.let { player ->
if (shouldHandlePlaybackAction(ACTION_PLAY)) {
player.play()

connector.playbackCallback?.onPlay() ?: {
player.play()
}
// Make sure the session is currently active and ready to receive commands.
connector.setActive(true)
}
Expand All @@ -71,48 +104,25 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
}
connector.player?.let { player ->
if (shouldHandlePlaybackAction(ACTION_PAUSE)) {
player.pause()
connector.playbackCallback?.onPause() ?: {
player.pause()
}
}
connector.listeners.forEach { listener ->
listener.onPause()
}
}
}

override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlayFromMediaId $mediaId")
}
if (shouldHandlePlaybackPreparerAction(ACTION_PREPARE_FROM_MEDIA_ID)) {
connector.playbackPreparer?.onPrepareFromMediaId(mediaId, true, extras)
}
}

override fun onPlayFromSearch(query: String?, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlayFromSearch $query")
}
if (shouldHandlePlaybackPreparerAction(ACTION_PREPARE_FROM_SEARCH)) {
connector.playbackPreparer?.onPrepareFromSearch(query, true, extras)
}
}

override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onPlayFromUri ${uri?.path}")
}
if (shouldHandlePlaybackPreparerAction(ACTION_PREPARE_FROM_URI)) {
connector.playbackPreparer?.onPrepareFromUri(uri, true, extras)
}
}

override fun onStop() {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onStop")
}
connector.player?.let { player ->
if (shouldHandlePlaybackAction(ACTION_STOP)) {
player.stop()
connector.playbackCallback?.onStop() ?: {
player.stop()
}
connector.setActive(false)
}
connector.listeners.forEach { listener ->
Expand All @@ -126,7 +136,9 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
Log.d(TAG, "MediaSessionCallback::onFastForward")
}
if (shouldHandlePlaybackAction(ACTION_FAST_FORWARD)) {
skip(connector.skipForwardInterval)
connector.playbackCallback?.onFastForward() ?: {
skip(connector.skipForwardInterval)
}
}
connector.listeners.forEach { listener ->
listener.onFastForward()
Expand All @@ -138,41 +150,50 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
Log.d(TAG, "MediaSessionCallback::onRewind")
}
if (shouldHandlePlaybackAction(ACTION_REWIND)) {
skip(-connector.skipBackwardsInterval)
connector.playbackCallback?.onRewind() ?: {
skip(-connector.skipBackwardsInterval)
}
}
connector.listeners.forEach { listener ->
listener.onRewind()
}
}

override fun onSetShuffleMode(@ShuffleMode shuffleMode: Int) {
// Unsupported.
override fun onSetPlaybackSpeed(speed: Float) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSetShuffleMode $shuffleMode")
Log.d(TAG, "MediaSessionCallback::onSetPlaybackSpeed $speed")
}
}

override fun onSetRepeatMode(@RepeatMode mediaSessionRepeatMode: Int) {
// Unsupported.
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSetRepeatMode $mediaSessionRepeatMode")
connector.player?.let { player ->
if (shouldHandlePlaybackAction(ACTION_SET_PLAYBACK_SPEED)) {
connector.playbackCallback?.onSetPlaybackSpeed(speed) ?: {
player.playbackRate = speed.toDouble()
}
}
connector.listeners.forEach { listener ->
listener.onSetPlaybackSpeed(speed)
}
}
}

override fun onSetPlaybackSpeed(speed: Float) {
override fun onSeekTo(positionMs: Long) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSetPlaybackSpeed $speed")
Log.d(TAG, "MediaSessionCallback::onSeekTo $positionMs")
}
connector.player?.let { player ->
if (shouldHandlePlaybackAction(ACTION_SET_PLAYBACK_SPEED)) {
player.playbackRate = speed.toDouble()
if (shouldHandlePlaybackAction(ACTION_SEEK_TO)) {
connector.playbackCallback?.onSeekTo(positionMs) ?: {
player.currentTime = 1e-03 * positionMs
}
}
connector.listeners.forEach { listener ->
listener.onSetPlaybackSpeed(speed)
listener.onSeekTo(positionMs)
}
}
}

// endregion
// region QueueNavigator actions

override fun onSkipToNext() {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSkipToNext")
Expand Down Expand Up @@ -257,6 +278,9 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
}
}

// endregion
// region Custom actions

override fun onCustomAction(action: String, extras: Bundle?) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onCustomAction $action")
Expand All @@ -273,19 +297,8 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
}
}

override fun onSeekTo(positionMs: Long) {
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSeekTo $positionMs")
}
connector.player?.let { player ->
if (shouldHandlePlaybackAction(ACTION_SEEK_TO)) {
player.currentTime = 1e-03 * positionMs
}
connector.listeners.forEach { listener ->
listener.onSeekTo(positionMs)
}
}
}
// endregion
// region Rating actions

override fun onSetRating(rating: RatingCompat) {
if (connector.debug) {
Expand Down Expand Up @@ -315,6 +328,25 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :
}
}

// endregion
// region Unsupported actions

override fun onSetShuffleMode(@ShuffleMode shuffleMode: Int) {
// Unsupported.
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSetShuffleMode $shuffleMode")
}
}

override fun onSetRepeatMode(@RepeatMode mediaSessionRepeatMode: Int) {
// Unsupported.
if (connector.debug) {
Log.d(TAG, "MediaSessionCallback::onSetRepeatMode $mediaSessionRepeatMode")
}
}

// endregion

private fun skip(skipTime: Double) {
val player = connector.player ?: return

Expand Down Expand Up @@ -349,9 +381,9 @@ class MediaSessionCallback(private val connector: MediaSessionConnector) :

private fun shouldHandleQueueNavigatorAction(action: Long): Boolean {
return (connector.player != null && (
connector.queueNavigator != null &&
connector.queueNavigator!!.getSupportedQueueNavigatorActions(connector.player!!) and action != 0L ||
connector.shouldDispatchUnsupportedActions)
connector.queueNavigator != null &&
connector.queueNavigator!!.getSupportedQueueNavigatorActions(connector.player!!) and action != 0L ||
connector.shouldDispatchUnsupportedActions)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,33 @@ class MediaSessionConnector(val mediaSession: MediaSessionCompat) {
}
}

/**
* A callback for queue navigation actions. When set, the media session will receive queue
* navigation events.
*/
var queueNavigator: QueueNavigator? = null

/**
* A callback for rating actions. When set, the media session will receive rating events.
*/
var ratingCallback: RatingCallback? = null

/**
* A callback for playback preparation actions.
* When set, the media session will receive prepare events.
*/
var playbackPreparer: PlaybackPreparer? = null

/**
* A callback for playback actions. When set, the media session will receive playback events,
* otherwise the default behavior will be executed for supported actions.
*/
var playbackCallback: PlaybackCallback? = null

/**
* A callback for queue editing actions.
* When set, the media session will receive queue editing events.
*/
var queueEditor: QueueEditor? = null
set(value) {
field = value
Expand All @@ -91,6 +115,7 @@ class MediaSessionConnector(val mediaSession: MediaSessionCompat) {
)
}


var shouldDispatchUnsupportedActions: Boolean = false

/**
Expand All @@ -99,7 +124,13 @@ class MediaSessionConnector(val mediaSession: MediaSessionCompat) {
var shouldDispatchTimeUpdateEvents: Boolean = false

var debug: Boolean = BuildConfig.DEBUG

/**
* The playback actions that are enabled for the media session.
* By default, all actions supported by the player are enabled.
*/
var enabledPlaybackActions: Long = PlaybackStateProvider.DEFAULT_PLAYBACK_ACTIONS

var customActionProviders: Array<CustomActionProvider> = arrayOf()

/**
Expand Down Expand Up @@ -201,4 +232,4 @@ class MediaSessionConnector(val mediaSession: MediaSessionCompat) {
Log.d(TAG, "MediaSession released")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.theoplayer.android.connector.mediasession

/**
* PlaybackCallback allows handling playback actions when sent by a media controller.
* By default, the connector will execute default behavior for supported actions.
* Setting a PlaybackCallback will disable the default handling of these actions, and instead route
* them to the callback.
*/
interface PlaybackCallback {
/**
* Called when a media controller wants to play or pause the current media.
*/
fun onPlay()

/**
* Called when a media controller wants to pause the current media.
*/
fun onPause()

/**
* Called when a media controller wants to stop the current media.
*/
fun onStop()

/**
* Called when a media controller wants to fast forward the current media.
*/
fun onFastForward()

/**
* Called when a media controller wants to rewind the current media.
*/
fun onRewind()

/**
* Called when a media controller wants to change the playback speed of the current media.
*/
fun onSetPlaybackSpeed(speed: Float)

/**
* Called when a media controller wants to seek to a specific position in the current media.
*/
fun onSeekTo(positionMs: Long)
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class PlaybackStateProvider(private val connector: MediaSessionConnector) {
}

private fun buildPlaybackActions(): Long {
var playbackActions = DEFAULT_PLAYBACK_ACTIONS
var playbackActions = connector.enabledPlaybackActions

// Optionally add queueNavigator actions.
val queueNavigator = connector.queueNavigator
Expand Down
Loading