首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在使用MediaItem库时添加media3会导致错误

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

Stack Overflow用户
提问于 2021-11-24 13:11:34
回答 1查看 1.3K关注 0票数 8

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

我创建了一个MediaSessionService,,然后在活动中获得了MediaController,然后当我试图调用媒体控制器并添加一些MediaItems时,出现了一个错误:

代码语言:javascript
运行
复制
 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)

因此,我检查了createMediaSource函数DefaultMediaSourceFactory,发现它正在检查MediaItem的localConfiguration是否为null:

代码语言:javascript
运行
复制
  @Override
  public MediaSource createMediaSource(MediaItem mediaItem) {
    checkNotNull(mediaItem.localConfiguration);
    ...
  }

这是localConfiguration:

代码语言:javascript
运行
复制
/**
   * Optional configuration for local playback. May be {@code null} if shared over process
   * boundaries.
   */
  @Nullable public final LocalConfiguration localConfiguration;

我非常肯定我创建MediaItem的方式没有问题,而且它在服务中运行良好,但是当我试图在活动中插入MediaItem时,会发生错误。根据评论,我想这可能是一个跨进程的沟通问题,但我对此一无所知。有人有使用Media3的经验吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-24 22:00:59

当您从控制器中添加/设置MediaItems时,MediaItem的localConfiguration (uri、mimeType、drm等)将被移除为安全/隐私理由。没有localConfiguration,播放器就不能播放媒体项目。我们需要将丢失的信息添加回MediaItem。

更新的答案(media3 1.0.0-beta01或更高)

打开在服务中创建MediaLibrarySession时定义的回调。

代码语言:javascript
运行
复制
// 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将被调用和返回的MediaItems。

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
// 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。这个MediaItemFiller有一个fillInLocalConfiguration方法,它将是“从控制器调用来填写媒体项目的MediaItem.localConfiguration。”

知道了这一点,你就需要:

在服务中向MediaItemFiller构建器添加一个MediaLibrarySession。

代码语言:javascript
运行
复制
// My MediaLibraryService
// onCreate()
mediaLibrarySession = MediaLibrarySession.Builder(this, player, librarySessionCallback)
    .setMediaItemFiller(CustomMediaItemFiller()) // <--
    .setSessionActivity(pendingIntent)
    .build()

创建一个自定义MediaSession.MediaItemFiller。每当您使用来自控制器的setMediaItem/addMediaItem时,都会调用它,这里返回的MediaItem将被播放。

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
// 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,您会发现他们使用mediaItem.mediaId从媒体目录中获取有效的MediaItem。这就是为什么当他们使用来自活动的setMediaItem时,他们的演示可以工作的原因。

而且,据我所知,fillInLocalConfiguration内部的任何操作都必须阻塞主线程(我认为必须从main调用setMediaItem ),因此,如果可以的话,尝试将任何繁重的工作(即从数据库获取媒体信息)转移到有更多控件的Activity/ViewModel,填充所需的所有元数据,并使用MediaSession.MediaItemFiller进行简单的转换。或者把一切都转移到你的服务上,忘记一切。

我希望你能理解我的心声。我对media3没有太多的经验,也许我遗漏了一些东西,但是由于MediaItemFiller的局限性,我发现它有点没用,我真的很想知道它的目的。

票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70096715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档