5

我想将我的 exoplayer 实现与媒体会话对象连接起来。我设置了一个 SimpleExoPlayerView 来显示视频。每次单击按钮时,我都希望触发媒体会话回调。我只能在使用耳机之类的东西时触发回调。应用程序中使用的代码如下所示

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void setUp(LifecycleOwner lifecycleOwner){
    // Create a MediaSessionCompat
    Log.i("Hoe8", "lco setup called");
    mMediaSession = new MediaSessionCompat(activity, "this");

    // Enable callbacks from MediaButtons and TransportControls
    mMediaSession.setFlags(
            MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                    MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

    // Do not let MediaButtons restart the player when the app is not visible
    mMediaSession.setMediaButtonReceiver(null);

    // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player
    mStateBuilder = new PlaybackStateCompat.Builder()
            .setActions(
                    PlaybackStateCompat.ACTION_PLAY |
                            PlaybackStateCompat.ACTION_PLAY_PAUSE);
    mMediaSession.setPlaybackState(mStateBuilder.build());

    // MySessionCallback has methods that handle callbacks from a media controller
    mMediaSession.setCallback(new MediaSessionCompat.Callback() {
        @Override
        public void onPlay() {
            super.onPlay();
            Log.i("Hoe8", "MediaSession callback play called");
            mMediaSession.setActive(true);
            ((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(true);
            ((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(true);

        }

        @Override
        public void onPause() {
            super.onPause();
            ((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
        }

        @Override
        public void onStop() {
            super.onStop();
            mMediaSession.setActive(false);
            ((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
            ((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(false);
        }
    });

    // Create a MediaControllerCompat
    MediaControllerCompat mediaController =
            new MediaControllerCompat(activity, mMediaSession);

    MediaControllerCompat.setMediaController(activity, mediaController);

    //Handler mainHandler = new Handler();
    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory =
            new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector =
            new DefaultTrackSelector(videoTrackSelectionFactory);




// 2. Create the player
        player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector);
        playerView.setPlayer(player);

    MediaSessionConnector mediaSessionConnector =
            new MediaSessionConnector(mMediaSession);
    mediaSessionConnector.setPlayer(player, null,null );


}

对代码做了一些改动

public class VideoLifeCyclerObserver implements LifecycleObserver {

MediaSessionCompat mMediaSession;
PlaybackStateCompat.Builder mStateBuilder;
AppCompatActivity activity;
SimpleExoPlayerView playerView;
SimpleExoPlayer player;
ExoPlayer.ExoPlayerComponent rv;
MediaSessionConnector mediaSessionConnector;

public VideoLifeCyclerObserver(AppCompatActivity activity, SimpleExoPlayerView playerView, ExoPlayer.ExoPlayerComponent rv){
    this.activity = activity;
    this.playerView = playerView;
    this.activity.getLifecycle().addObserver(this);
    this.rv = rv;
    Log.i("Hoe8","video lco created");
}


@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void setUp(LifecycleOwner lifecycleOwner){
    // Create a MediaSessionCompat
    Log.i("Hoe8", "lco setup called");
    mMediaSession = new MediaSessionCompat(activity, "this");

    // Create a MediaControllerCompat
    MediaControllerCompat mediaController =
            new MediaControllerCompat(activity, mMediaSession);

    MediaControllerCompat.setMediaController(activity, mediaController);

    mediaSessionConnector =
            new MediaSessionConnector(mMediaSession, new PlayBackController());
}

@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void startPlayer(LifecycleOwner lifecycleOwner){
    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory =
            new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector =
            new DefaultTrackSelector(videoTrackSelectionFactory);
    player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector);
    playerView.setPlayer(player);
    mediaSessionConnector.setPlayer(player, null,null );
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void tearDown(LifecycleOwner lifecycleOwner){
    player.stop();
    player.release();
    player.sendMessages(new ExoPlayer.ExoPlayerMessage(rv,1,player.getContentPosition()));
}

public class PlayBackController extends DefaultPlaybackController{
    @Override
    public void onPause(Player player) {
        Log.i("Hoe8", "onPause called");
        ((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
        super.onPause(player);
    }

    @Override
    public void onPlay(Player player) {
        Log.i("Hoe8", "MediaSession callback play called 2");
        mMediaSession.setActive(true);
        ((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(true);
        ((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(true);
        super.onPlay(player);
    }

    @Override
    public void onStop(Player player) {
        Log.i("Hoe8", "onStop called");
        mMediaSession.setActive(false);
        ((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
        ((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(false);
        super.onStop(player);
    }


}
}

如何获取 SimpleExoPlayerView 中显示的按钮来触发媒体会话回调?

4

1 回答 1

14

简而言之:

从(含)开始删除 onCreate 中的所有代码

// 启用来自 MediaButtons 和 TransportControls 的回调

至(独家)

// 创建一个 MediaControllerCompat

:)

更冗长:

我建议通过侦听播放器的状态转换而不是单击按钮来触发媒体会话回调。这使您不必为与播放器交互的每个 UI 元素执行此操作。这实际上就是 MediaSessionConnector 为您所做的。

使用 MediaSessionConnector,您无需自己操作 MediaSession。连接器在播放器实例和媒体会话之间进行调解。这意味着连接器监听播放器的状态转换并将播放器状态映射到媒体会话状态。连接器还侦听传输控件发送的媒体操作,并将它们委托给播放器或您的应用程序。注意:您的应用不需要提供 MediaSessionCompat.Callback,连接器会注册自己的(并覆盖您的,因为每个会话只能有一个)。

一般来说:您的应用程序只与 SimpleExoPlayer 实例交互,而连接器将播放器状态映射到会话。

让我们从将播放器状态映射到触发适当 MediaControllerCompat.Callback 方法的会话的基本方法开始:

// code running in a activity or service where (this instanceof Context)

mediaSession = new MediaSessionCompat(this, getPackageName());
mediaSessionConnector = new MediaSessionConnector(mediaSession)
mediaSessionConnector.setPlayer(player, null, null);
mediaSession.setActive(true);

您现在可以像以前一样准备和使用播放器,例如调用 setPlayWhenReady(true|false)、seekTo(t),并且连接器会维护 PlaybackStateCompat,它会广播到会话的控制器。

连接器确实在此级别接收并实现了几个媒体操作(不需要您自己的 MediaSession.Callback):

PlaybackStateCompat.ACTION_PLAY_PAUSE |
PlaybackStateCompat.ACTION_PLAY | 
PlaybackStateCompat.ACTION_PAUSE | 
PlaybackStateCompat.ACTION_STOP |
PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE |
PlaybackStateCompat.ACTION_SET_REPEAT_MODE;

PlayFromXYZ 动作

您可能希望支持其他媒体操作,例如 ACTION_PLAY_FROM_MEDIA_ID。您可以通过提供PlaybackPreparer来做到这一点:

playbackPreparer = new YourPlaybackPreparer(); 
mediaSessionConnector.setPlayer(player, playbackPreparer, null);

连接器现在将 ACTION_PLAY_FROM_MEDIA_ID 或 ACTION_PREPARE_FROM_MEDIA_ID 之类的操作委托给您的播放准备器,该播放准备器为给定的媒体 ID 创建一个 MediaSource 以准备播放器。

元数据和队列管理

同样有趣的是能够将播放器的时间线直接映射到媒体会话的队列和元数据。为此,您可以提供一个QueueNavigator。扩展提供了一个抽象的TimelineQueueNavigator :

QueueNavigator queueNavigator = new TimelineQueueNavigator(mediaSession) {
  @Override
  public MediaDescriptionCompat getMediaDescription(int windowIndex) {
    // implement this method and read from your backing data:
    getMediaDescriptionAtQueuePosition(windowIndex):
    return mediaDescription;
  }
}
mediaSessionConnector.setQueueNavigator(queueNavigator);

有了这个媒体控制器现在可以读取会话的元数据和队列。队列表示播放器的当前时间线,会话的元数据描述时间线中当前正在播放的窗口。(更多关于播放列表)。

提供 TimelineQueueNavigator,连接器侦听传输控件发送的 ACTION_SKIP_TO_NEXT、ACTION_SKIP_TO_PREVIOUS 和 ACTION_SKIP_TO_QUEUE_ITEM 并相应地沿时间线导航。

生命周期集成

请注意,您必须在 onStart/onResume 上创建播放器实例,并在 onPause/onStop 上释放它。这可确保您与其他应用程序共享的编解码器资源在您处于后台时被释放。您的代码示例仅在 onCreate 上执行一次,这不是良好的公民身份:)。看看 ExoPlayer 演示应用程序是如何做到的

还请考虑有关 MediaSessionConnector 的 Medium 博客

于 2018-01-02T19:08:42.147 回答