Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do you intercept commands with a ForwardingPlayer? #1026

Closed
aljohnston112 opened this issue Jan 25, 2024 · 3 comments
Closed

How do you intercept commands with a ForwardingPlayer? #1026

aljohnston112 opened this issue Jan 25, 2024 · 3 comments
Assignees
Labels

Comments

@aljohnston112
Copy link

aljohnston112 commented Jan 25, 2024

It seemed pretty straightforward to me, but it is not working as expected.

I have a MediaBrowser that I am using as a MediaController for a MediaLibraryService.MediaLibrarySession

I set up the ForwardingPlayer like so

class MyPlayer(
    private var context: Context?,
    private val mediaItemCreator: MediaItemCreator
) : ForwardingPlayer(
    ExoPlayer.Builder(context!!)
        .setSkipSilenceEnabled(true)
        .setSeekParameters(SeekParameters.EXACT)
        .build()
) {

    private lateinit var _playlist: ProbabilityMap<MusicFile>

    fun setPlaylist(playlist: ProbabilityMap<MusicFile>) {
        _playlist = playlist
    }

    override fun getAvailableCommands(): Player.Commands {
        return super.getAvailableCommands()
            .buildUpon()
            .add(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
            .add(COMMAND_SEEK_TO_NEXT)
            .build()
    }

    override fun isCommandAvailable(command: Int): Boolean {
        return availableCommands.contains(command)
    }

    override fun setMediaItem(mediaItem: MediaItem) {
        val next = mediaItemCreator.getMediaItem(
            context!!,
            _playlist.sample().id
        )
        super.setMediaItems(listOf(mediaItem, next))
    }

    override fun seekToNextMediaItem() {
        if(::_playlist.isInitialized) {
            val next = mediaItemCreator.getMediaItem(
                context!!,
                _playlist.sample().id
            )
            replaceMediaItem(mediaItemCount - 1, next)
            seekTo(
                currentMediaItemIndex + 1,
                C.TIME_UNSET
            )
            val afterNext = mediaItemCreator.getMediaItem(
                context!!,
                _playlist.sample().id
            )
            addMediaItem(afterNext)
        }
    }

    override fun release() {
        super.release()
        context = null
    }

}

The command methods do get called, but COMMAND_SEEK_TO_NEXT_MEDIA_ITEM is not always available to the controller.

Then when the controller method setMediaItem is called, the MyPlayer.setMediaItem method is not called.

This issue I made earlier has more details:
#1021

@aljohnston112
Copy link
Author

aljohnston112 commented Jan 26, 2024

I did some more debugging and it turns out the mappings from controller calls to player calls are not one-to-one and there is no mapping in the docs: https://developer.android.com/reference/androidx/media3/session/MediaController#setMediaItem(androidx.media3.common.MediaItem)

In particular, setMediaItem from the controller calls setMediaItems in the player. I have verified with the debugger and this code in MyPlayer.

    override fun setMediaItems(mediaItems: MutableList<MediaItem>, resetPosition: Boolean) {
        super.setMediaItems(mediaItems, resetPosition)
    }

I think this is an issue because if I override what commands are available (which are overridden in some circumstances for some reason), I expect to be able to know which ForwardingPlayer overrides I will need to provide for said command for the custom behaviors of my app.

Are the mappings for this type of thing documented somewhere? Are they consistent? Are these subject to change?

@tonihei
Copy link
Collaborator

tonihei commented Jan 26, 2024

Are the mappings for this type of thing documented somewhere? Are they consistent? Are these subject to change?

We attempt to call the same Player method as far as possible, but sometimes need to change it slightly depending on the available commands and parameters we need to pass in. I think from your perspective, it's best to implement all the methods you declare as available via the commands without making assumptions which one is called exactly.

I expect to be able to know which ForwardingPlayer overrides I will need to provide for said command

All these command codes fully list the methods that need to be implemented for this code. Example: https://developer.android.com/reference/androidx/media3/common/Player#COMMAND_SET_SPEED_AND_PITCH() explains how COMMAND_SET_SPEED_AND_PITCH maps to setPlaybackParametersandsetPlaybackSpeed`.

@tonihei tonihei self-assigned this Jan 26, 2024
@aljohnston112
Copy link
Author

Thank you so much for the explanation! That page looks like a fantastic resource for this.

@androidx androidx locked and limited conversation to collaborators Mar 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants