使用media3库时添加MediaItem导致错误

2024-04-06

我正在使用最新的Android Media3库,但是我在使用它时发现了一个问题......

我创建了一个媒体会话服务,然后得到MediaController中的Activity,然后当我尝试调用媒体控制器并添加一些 MediaItem 时,发生错误:

 java.lang.NullPointerException
        at androidx.media3.common.util.Assertions.checkNotNull(Assertions.java:155)
        at androidx.media3.exoplayer.source.DefaultMediaSourceFactory.createMediaSource(DefaultMediaSourceFactory.java:338)
        at androidx.media3.exoplayer.ExoPlayerImpl.createMediaSources(ExoPlayerImpl.java:1164)
        at androidx.media3.exoplayer.ExoPlayerImpl.addMediaItems(ExoPlayerImpl.java:463)
        at androidx.media3.exoplayer.SimpleExoPlayer.addMediaItems(SimpleExoPlayer.java:1146)
        at androidx.media3.common.BasePlayer.addMediaItems(BasePlayer.java:69)
        at androidx.media3.common.BasePlayer.addMediaItem(BasePlayer.java:64)
        at androidx.media3.common.ForwardingPlayer.addMediaItem(ForwardingPlayer.java:90)
        at androidx.media3.session.PlayerWrapper.addMediaItem(PlayerWrapper.java:346)
        at androidx.media3.session.MediaSessionStub.lambda$addMediaItem$28(MediaSessionStub.java:1052)
        at androidx.media3.session.MediaSessionStub$$ExternalSyntheticLambda8.run(Unknown Source:2)
        at androidx.media3.session.MediaSessionStub.lambda$getSessionTaskWithPlayerCommandRunnable$2$androidx-media3-session-MediaSessionStub(MediaSessionStub.java:234)
        at androidx.media3.session.MediaSessionStub$$ExternalSyntheticLambda52.run(Unknown Source:14)
        at androidx.media3.session.MediaSessionStub.lambda$flushCommandQueue$50(MediaSessionStub.java:1479)
        at androidx.media3.session.MediaSessionStub$$ExternalSyntheticLambda58.run(Unknown Source:2)
        at androidx.media3.common.util.Util.postOrRun(Util.java:517)
        at androidx.media3.session.MediaSessionStub.flushCommandQueue(MediaSessionStub.java:1473)
        at androidx.media3.session.MediaControllerImplBase$FlushCommandQueueHandler.handleMessage(MediaControllerImplBase.java:3035)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7813)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

于是我检查了DefaultMediaSourceFactory的createMediaSource函数,发现它是在检查是否localConfigurationMediaItem 为空:

  @Override
  public MediaSource createMediaSource(MediaItem mediaItem) {
    checkNotNull(mediaItem.localConfiguration);
    ...
  }

这是本地配置:

/**
   * Optional configuration for local playback. May be {@code null} if shared over process
   * boundaries.
   */
  @Nullable public final LocalConfiguration localConfiguration;

我非常确定我创建 MediaItem 的方式没有问题,并且它在 Service 中运行良好,但是当我尝试在 Activity 中插入 MediaItem 时,会发生错误。根据评论,我猜这可能是跨进程通信问题,但我对此没有任何线索。有人有 Media3 的经验吗?


当您从控制器添加/设置 MediaItems 时,localConfigurationMediaItem 的(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我发现它有点没用,我真的很想更多地了解它的用途。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用media3库时添加MediaItem导致错误 的相关文章

随机推荐

  • 如何包含与其中的 OBJECT 文件同名的静态库?

    我正在开发一个 iPad 应用程序 其中包含 2 个第三方静态库 这两个库中的目标文件的名称相同 在构建应用程序时我得到 Apple Mach O id 错误 因为这两个库中的目标文件名称相同 如何解决这个问题呢 错误看起来像 ld dup
  • 在android中使用SMTP无意图发送邮件

    您好 我正在开发一个 Android 应用程序 只需单击按钮即可发送邮件 代码最初可以工作 但由于某种原因现在无法工作 有人可以帮我解决这个问题吗 电子邮件受保护 cdn cgi l email protection是收件人 电子邮件受保护
  • 在 selenium 上使用 BeautifulSoup 和 Geckodriver 有什么区别?

    我目前对使用 selenium 3 的 beautiful soup 和 geckodriver 都是新手 我正在开发一个项目 我必须从网页中抓取 URL 我发现它们都用于网页抓取 但无法区分两者之间的区别 BeautifulSoup 和
  • 为什么需要用 pyqtSlot 装饰连接的槽?

    我正在使用 pyqt5 并且使用类似于以下的代码连接了几种方法 self progress canceled connect self cancel 例如 其中self cancel is def cancel self self time
  • iOS:条形样式外观缺少 Monotouch 绑定?

    我正在尝试将其转换为 Monotouch C UINavigationBar appearance setBarStyle UIBarStyleBlackOpaque 但在外观对象上似乎没有条形样式 是否有解决方法或替代接入点 此房源没有装
  • Angular ngRoute 突然将 URL 转换为编码字符 #!/#%2F

    我的应用程序中的所有内容都工作正常 直到我尝试添加 ngAnimate ngMaterial 和 ng image gallery 我不知道添加这些模块是否是问题的根源 但在问题发生之前我没有更改任何其他内容 从那时起 即使在我从 app
  • Android——在 OnDrawFrame 方法之外将 GLSurfaceView.Renderer 置于睡眠状态(如 Thread.sleep(20))

    我想控制 GLSurfaceView Renderer 的渲染速率 我在扩展 GLSurfaceView 的类中实现了一个线程 并在 while true 循环中定期将其置于睡眠状态 这不会减慢渲染器的速度 有一个很好的答案here htt
  • 自旋锁与信号量

    信号量和自旋锁之间的基本区别是什么 我们什么时候会使用信号量而不是自旋锁 自旋锁和信号量主要有四个不同点 1 它们是什么 A spinlock是锁的一种可能实现 即通过忙等待 旋转 实现的锁 信号量是锁的概括 或者 相反 锁是信号量的特例
  • 带有节标题的列表视图android

    在 android listview gt Headerbar section 中是否有可能不滚动 直到该部分的列表不滚动 就像 iPhone 的桌面视图一样 我使用了部分列表视图 但我想要像这个 iphone 表格视图 有没有可能 谢谢
  • Jenkins 在 ClearCase 中创建视图

    我正在使用 Jenkins 和 ClearCase 进行自动构建 但遇到了问题 我编写了一个批处理脚本 使用cleartool命令mkview在ClearCase中创建视图 当我通过单击脚本来执行该脚本时 一切正常 视图是在 ClearCa
  • 解析在tinyxml中

    如何在 TinyXML 中解析以下内容
  • netstandard 1.5 中的 BinaryFormatter

    根据 NET CoreFx API 及其关联的 NET 平台标准版本列表 https github com dotnet corefx blob master Documentation architecture net platform
  • 在 .Net 中使用私有集初始化属性

    public class Foo public string Name get private set lt Because set is private void Main var bar new Foo Name baz lt This
  • 二维数组作为函数的参数

    为什么不能像处理普通数组一样在函数中声明二维数组参数 void F int bar Ok void Fo int bar Not ok void Foo int bar SIZE Ok 为什么需要声明列的大小 静态数组 你似乎没有完全明白这
  • 如何在yii2高级模板中上传web文件夹中的文件?

    我尝试在后端上传文件 每次上传文件时 它都会成功上传并成功保存在数据库中 但它没有保存到我指定的目录中 因此我的应用程序找不到该文件 并且我已经给出了 777对 web 目录中的 uploads 文件夹的权限 下面是我的代码 处理和保存文件
  • 如何使用 Compact Framework 在 C# 中验证 X.509 证书

    我正在尝试使用 C 和 NetCF 验证 X 509 证书 我有 CA 证书 如果我理解正确的话 我需要使用该 CA 证书中的公钥来解密不受信任的证书的签名 这应该给我不可信证书的计算哈希值 然后我应该自己计算证书的哈希值并确保两个值匹配
  • Swift组合:使用其他发布者(使用CombineLatest)的后续发布者不会“触发”

    我正在尝试复制 WWDC 2019 会议 实践中组合 中给出的 向导学校注册 示例https developer apple com videos play wwdc2019 721 https developer apple com vi
  • 属性的访问器实现

    是否有一些文档说明编译器如何自动生成属性的访问器 当编写自定义访问器 覆盖合成的访问器 时 最好了解原始实现 特别是要查看具有不同 弱 强 保留 复制等 属性的属性的访问器的不同实现 是否有一些文档说明编译器如何自动生成属性的访问器 编译器
  • 从 openstreetmap 获取城市边界

    我正在开发一个网站 我需要根据用户输入获取某个区域的所有边界 例如 用户想知道名为 x 的城市的边界 我应该如何从 openstreetmap 获取它 我听说过 xapi 和 osmosis 但在任何地方都找不到任何例子 谢谢 我在这里尝试
  • 使用media3库时添加MediaItem导致错误

    我正在使用最新的Android Media3库 但是我在使用它时发现了一个问题 我创建了一个媒体会话服务 然后得到MediaController中的Activity 然后当我尝试调用媒体控制器并添加一些 MediaItem 时 发生错误 j