如何使用media3(配合Exoplayer + MediaSessionService)

max*_*max 4 audio android android-mediaplayer kotlin android-mediasession

如何实现 MediaSessionService 并使用 media3 构建一个非常简单的音频播放应用程序?我尝试过,但没有成功。我也找不到简单的文档...

Yur*_*itz 7

该库缺乏文档(在稳定版本发布之前可能会出现这种情况)。

对于音频播放的简单实现,也支持后台播放,我们需要将播放器与我们的 Activity 分开,而是生活在与其隔离但仍然可以作为我们应用程序的一部分的东西中,答案是 a ,并且服务Service可以自由使用应用程序上下文,并且可以在后台运行。

因此,假设您想要创建一个播放音乐的应用程序,您将需要:

  • 一项活动(我们称之为MainActivity
  • 服务(我们称之为服务MusicPlayerService

1-首先,我们在清单中声明我们的活动(相信每个人都熟悉这一步)。

2- 其次,我们在清单中声明我们的服务:

    <service
        android:name=".MusicPlayerService"
        android:enabled="true"
        android:exported="true"
        android:foregroundServiceType="mediaPlayback"
        tools:ignore="ExportedService">

        <intent-filter>
            <action android:name="androidx.media3.session.MediaLibraryService"/>
            <action android:name="android.media.browse.MediaBrowserService" />
        </intent-filter>
    </service>
Run Code Online (Sandbox Code Playgroud)

3- 现在,重要的步骤是,我们为 Media3 库构建必要的架构。UI(MainActivity)有一个叫做“MediaController”的东西,它基本上是与服务中的播放器的接口。

至于服务,里面有一个叫做 MediaSession 的东西,还有播放器本身(exoplayer)。有一个特殊版本的媒体会话,它还控制媒体项目(播放列表及其信息)并将其公开给其他客户端(例如 Android Auto、WearOS 等)。它叫做 MediaLibraryService,我们今天要尝试一下这个(但实现过程几乎是一样的)。

所以,在我们的 MainActivity 中:

    <service
        android:name=".MusicPlayerService"
        android:enabled="true"
        android:exported="true"
        android:foregroundServiceType="mediaPlayback"
        tools:ignore="ExportedService">

        <intent-filter>
            <action android:name="androidx.media3.session.MediaLibraryService"/>
            <action android:name="android.media.browse.MediaBrowserService" />
        </intent-filter>
    </service>
Run Code Online (Sandbox Code Playgroud)

现在最有趣的部分是,我们创建一个名为MusicPlayerServicewhich extends 的MediaLibraryService(或 MediaSessionService,取决于您的应用程序需求),如下所示:

@UnstableApi class MusicActivity : ComponentActivity() {

    /* This is the global variable of the player
       (which is basically a media controller) 
       you're going to use to control playback,
       you're not gonna need anything else other than this,
       which is created from the media controller */
    lateinit var player: Player

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        /* Creating session token (links our UI with service and starts it) */
        val sessionToken = SessionToken(applicationContext, ComponentName(this, MusicPlayerService::class.java))

        /* Instantiating our MediaController and linking it to the service using the session token */
        val mediacontrollerFuture = MediaController.Builder(this, sessionToken).buildAsync()

        mediacontrollerFuture.addListener({


            player = mediacontrollerFuture.get()


        }, MoreExecutors.directExecutor())
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一件事,如果您想在活动中加载媒体项目,请使用以下命令:


@UnstableApi class MusicPlayerService: MediaLibraryService() {

    /* This is the service side player, the media controller in the activity will control this one, so don't worry about it */
    lateinit var player: Player

    /* This is the session which will delegate everything you need about audio playback such as notifications, pausing player, resuming player, listening to states, etc */
    lateinit var session: MediaLibrarySession
    
    override fun  onCreate() {
        super.onCreate()
        
        /* Step 1 out of 2: Instantiate the player (ExoPlayer) */
        player = ExoPlayer.Builder(applicationContext)
            .setRenderersFactory(
                DefaultRenderersFactory(this).setExtensionRendererMode(
                    DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER /* We prefer extensions, such as FFmpeg */
                )
            ).build()


        /* Step 2 out of 2: Instantiate the session (most important part) */
        session = MediaLibrarySession.Builder(this, player,
            object: MediaLibrarySession.Callback {
                override fun onAddMediaItems(
                    mediaSession: MediaSession,
                    controller: MediaSession.ControllerInfo,
                    mediaItems: MutableList<MediaItem>
                ): ListenableFuture<MutableList<MediaItem>> {

                /* This is the trickiest part, if you don't do this here, nothing will play */
                    val updatedMediaItems = mediaItems.map { it.buildUpon().setUri(it.mediaId).build() }.toMutableList()
                    return Futures.immediateFuture(updatedMediaItems)
                }
            }).build()
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这能为您提供更好的 Media3 方法。