当您从控制器添加/设置 MediaItems 时,localConfiguration
MediaItem 的(uri、mimeType、drm 配置等)已删除安全/隐私原因 https://github.com/androidx/media/issues/43#issuecomment-1055836630。没有localConfiguration
播放器无法播放媒体项目。我们需要将缺失的信息添加回 MediaItem。
更新的答案(media3 1.0.0-beta01 或更高版本)
打开您在服务中创建 MediaLibrarySession 时定义的回调。
// My MediaLibraryService
// onCreate()
mediaLibrarySession = MediaLibrarySession.Builder(
this,
player,
librarySessionCallback // <--
).build()
// NOTE: If you are using MediaSessionService instead of MediaLibraryService,
// use `setCallback(librarySessionCallback)` from the MediaSession.Builder.
覆盖onAddMediaItems
在你的里面MediaLibrarySession.Callback
。每次使用时setMediaItem
/addMediaItem
从控制器,你的onAddMediaItems 将被调用 https://github.com/androidx/media/blob/1.0.0-beta01/libraries/session/src/main/java/androidx/media3/session/MediaSession.java#L972返回的 MediaItem 就是将要播放的 MediaItem。
class CustomMediaLibrarySessionCallback : MediaLibraryService.MediaLibrarySession.Callback {
// [...]
override fun onAddMediaItems(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo,
mediaItems: MutableList<MediaItem>
): ListenableFuture<List<MediaItem>> {
// NOTE: You can use the id from the mediaItems to look up missing
// information (e.g. get URI from a database) and return a Future with
// a list of playable MediaItems.
// If your use case is really simple and the security/privacy reasons
// mentioned earlier don't apply to you, you can add the URI to the
// MediaItem request metadata in your activity/fragment and use it
// to rebuild the playable MediaItem.
val updatedMediaItems = mediaItems.map { mediaItem ->
mediaItem.buildUpon()
.setUri(mediaItem.requestMetadata.mediaUri)
.build()
}
return Futures.immediateFuture(updatedMediaItems)
}
}
创建并播放您的MediaItem
来自活动/片段。
// My Activity
val mmd = MediaMetadata.Builder()
.setTitle("Example")
.setArtist("Artist name")
.build()
// Request metadata. New in (1.0.0-beta01)
// This is optional. I'm adding a RequestMetadata to the MediaItem so I
// can get the mediaUri from my `onAddMediaItems` simple use case (see
// onAddMediaItems for more info).
// If you are going to get the final URI from a database, you can move your
// query to your `MediaLibrarySession.Callback#onAddMediaItems` and skip this.
val rmd = RequestMetadata.Builder()
.setMediaUri("...".toUri())
.build()
val mediaItem = MediaItem.Builder()
.setMediaId("123")
.setMediaMetadata(mmd)
.setRequestMetadata(rmd)
.build()
browser.setMediaItem(mediaItem)
browser.prepare()
browser.play()
旧答案(media3 1.0.0-alpha)
当您创建MediaLibrarySession
在你的里面MediaLibraryService
,您可以添加一个MediaItemFiller
. This MediaItemFiller
has a fillInLocalConfiguration
方法将是“调用以填充控制器中媒体项的 MediaItem.localConfiguration。” https://github.com/androidx/media/blob/72a4fb082d9e68ecd7db3ff87b19f4232a5991d2/libraries/session/src/main/java/androidx/media3/session/MediaSession.java#L1001
知道这一点后,您需要:
将 MediaItemFiller 添加到服务内的 MediaLibrarySession 构建器。
// My MediaLibraryService
// onCreate()
mediaLibrarySession = MediaLibrarySession.Builder(this, player, librarySessionCallback)
.setMediaItemFiller(CustomMediaItemFiller()) // <--
.setSessionActivity(pendingIntent)
.build()
创建自定义MediaSession.MediaItemFiller
。任何时候你使用setMediaItem
/addMediaItem
这将从控制器中调用,并且此处返回的 MediaItem 将是播放的 MediaItem。
class CustomMediaItemFiller : MediaSession.MediaItemFiller {
override fun fillInLocalConfiguration(
session: MediaSession,
controller: MediaSession.ControllerInfo,
mediaItem: MediaItem
): MediaItem {
// Return the media item to be played
return mediaItem.buildUpon()
// Use the metadata values to fill our media item
.setUri(mediaItem.mediaMetadata.mediaUri)
.build()
}
}
最后,创建并播放您的MediaItem
从活动中。
// My Activity
// Fill some metadata that the MediaItemFiller
// will use to create the new MediaItem
val mmd = MediaMetadata.Builder()
.setTitle("Example")
.setArtist("Artist name")
.setMediaUri("...".toUri())
.build()
val mediaItem: MediaItem =
MediaItem.Builder()
.setMediaMetadata(mmd)
.build()
browser.setMediaItem(mediaItem)
browser.prepare()
browser.play()
我不知道为什么会这么尴尬,但如果你看看他们在官方仓库中使用的 CustomMediaItemFiller https://github.com/androidx/media/blob/039eef00bf9de7f03f65c481e41a1f0437a12d27/demos/session/src/main/java/androidx/media3/demo/session/PlaybackService.kt#L129,你会看到他们使用mediaItem.mediaId
从媒体目录中获取有效的 MediaItem。这就是为什么他们的演示在使用时有效从活动中设置MediaItem https://github.com/androidx/media/blob/039eef00bf9de7f03f65c481e41a1f0437a12d27/demos/session/src/main/java/androidx/media3/demo/session/PlayableFolderActivity.kt#L70.
另外,据我所知,你在里面做的任何事情fillInLocalConfiguration
必须阻塞主线程(我相信setMediaItem
必须从 main 调用)所以,如果可以的话,尝试将任何繁重的工作(即从数据库获取媒体信息)移动到您有更多控制权的 Activity/ViewModel 中,填充您需要的所有元数据,然后使用你的MediaSession.MediaItemFiller
做一个简单的转换。或者将所有内容移至您的服务中并忘记所有内容。
我希望流程能够被理解。我对 media3 没有太多经验,也许我错过了一些东西,但由于其局限性MediaItemFiller
我发现它有点没用,我真的很想更多地了解它的用途。