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

Allow MediaController to set local configuration (e.g. Uri) to start playback #282

Closed
1 task done
jakoss opened this issue Mar 24, 2023 · 8 comments
Closed
1 task done
Assignees

Comments

@jakoss
Copy link

jakoss commented Mar 24, 2023

Media3 Version

Media3 1.0.0

Devices that reproduce the issue

  • Samsung Galaxy S21 FE
  • Any emulator i tried it on

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Not tested

Reproduction steps

Reproduction project: repro.zip

I created PlaybackService by mirroring the example from website:

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this)
            .setMediaSourceFactory(
                DefaultMediaSourceFactory(this)
                    .setDataSourceFactory(
                        DefaultDataSource.Factory(
                            this,
                            OkHttpDataSource.Factory(OkHttpClient.Builder().build())
                        )
                    )
            )
            .build()
        player.addAnalyticsListener(EventLogger())
        mediaSession = MediaSession
            .Builder(this, player)
            .build()
    }

    override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = mediaSession

    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }
}

Then i setup MediaController in Activity like this:

override fun onStart() {
        super.onStart()
        val sessionToken = SessionToken(this@MainActivity, ComponentName(this@MainActivity, PlaybackService::class.java))
        val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
        controllerFuture.addListener(
            { mediaController = controllerFuture.get() },
            MoreExecutors.directExecutor()
        )
    }

Then i try to set new item to play like this:

mediaController?.let {
                                it.setMediaItem(
                                    MediaItem.Builder()
                                        .setUri("https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8")
                                        .setMediaId("id")
                                        .setMediaMetadata(
                                            MediaMetadata.Builder()
                                                .setTitle("Test title")
                                                .setArtist("Test artist")
                                                .setArtworkUri("https://images.unsplash.com/photo-1679663877752-c00ad7f1c5c5?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2940&q=80".toUri())
                                                .build()
                                        )
                                        .build()
                                )
                                it.prepare()
                                it.play()
                            }

In attached reproduction app you can click "Play by service" and literally nothing happens (logs are empty too, even with EventLogger setup. It's seems like the command passed through, but the playback never started.

Playing via local exoplayer works properly as presented in the "Play locally" button

Expected result

I should be able to set new media item with HLS content via MediaController

Actual result

Nothing happens, log is empty. Player have no error. It seems like after trying to play item player instantly goes to ENDED state without particular reason

Media

https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8

Bug Report

@AxonDragonScale
Copy link

I am facing the exact same issue. Not playing when using MediaController.
But able to play when i set the mediaSession instance in the service in its companion object and used it from activity.

@microkatz
Copy link
Contributor

@jakoss
Thank you for posting your issue! The behaviour is a result of that the URI information is stripped when it is sent from the controller to the session. This is by design for security. To fix this:

  1. You must set a RequestMetadata with your URI in your MediaItem.
  2. Implement onAddMediaItems in your Session callback. You can then take the Uri from the RequestMetadata object in your callback, buildUpon the provided mediaItems with setUri, and return that list.
    That should fix your issue!

@jakoss
Copy link
Author

jakoss commented Mar 29, 2023

@microkatz Thanks, that made it work. While i understand the reason behind that design - this definitely should be documented :)

@jakoss jakoss closed this as completed Mar 29, 2023
@microkatz
Copy link
Contributor

@jakoss
No problem! And understood. It is in a note on this page about MediaSession https://developer.android.com/guide/topics/media/media3/getting-started/mediasession that one would need to implement onAddMediaItems.

However, noted about the clarity and thank you for your input!

@tonihei
Copy link
Collaborator

tonihei commented Mar 29, 2023

this definitely should be documented

Besides the link @microkatz provided above, there is also currently still work being done to document various use cases on developer.android.com.

that made it work

More generally, we received multiple questions for this exact problem and we are thinking about ways to improve the default behavior. For example, the security concern is really only relevant for a session accidentally publishing their media uris to all other controller apps. But it seems legit to assume that a controller can create a MediaItem with local configuration properties like the URI set, and that the session is then able to use this to start playback without further customization.

I'll mark it as an enhancement to improve the default out-of-the-box logic. (Ideally, we would then not even need to document this issue as prominently as we should now).

@tonihei tonihei reopened this Mar 29, 2023
@tonihei tonihei changed the title Cannot use new MediaController to start playback Allow MediaController to set local configuration (e.g. Uri) to start playback Mar 29, 2023
tof-tof pushed a commit that referenced this issue Jun 7, 2023
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.

However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.

Issue: #282

#minor-release

PiperOrigin-RevId: 537993460
tof-tof pushed a commit to google/ExoPlayer that referenced this issue Jun 7, 2023
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.

However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.

Issue: androidx/media#282

#minor-release

PiperOrigin-RevId: 537993460
tof-tof pushed a commit that referenced this issue Jun 12, 2023
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.

However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.

Issue: #282

RELEASENOTES.md modified in cherrypick

PiperOrigin-RevId: 537993460
(cherry picked from commit d9764c1)
tof-tof pushed a commit to google/ExoPlayer that referenced this issue Jun 14, 2023
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.

However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.

Issue: androidx/media#282

#minor-release

PiperOrigin-RevId: 537993460
(cherry picked from commit bcddaf2)
@microkatz
Copy link
Contributor

Hello @jakoss. We added some default logic so that onAddMediaItems need not be implemented to pass the uri across from MediaController. The code was added in this commit, d9764c1

@jakoss
Copy link
Author

jakoss commented Jul 20, 2023

@microkatz awesome, thanks. So as far as i understand - i can now expect that my original code should work without implementing the onAddMediaItems?

@microkatz
Copy link
Contributor

It should. The original code should work without implementing onAddMediaItems

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

No branches or pull requests

4 participants