使用MediaSessionCompat连接exoplayer

时间:2018-01-01 02:49:59

标签: android exoplayer android-mediasession

我想将我的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中显示的按钮以触发媒体会话回调?

1 个答案:

答案 0 :(得分:6)

简而言之:

从(包括)

开始删除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);

使用此媒体控制器现在可以读取会话的元数据和队列。队列表示播放器的当前时间轴,会话的元数据描述当前正在播放的时间轴中的窗口。 (more about playlists)。

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

生命周期集成

请注意,您必须在onStart / onResume上创建播放器实例并在onPause / onStop上将其释放。这可以确保您在后台时可以释放与其他应用程序共享的编解码器资源。您的代码示例仅在onCreate上执行一次,这不是良好的公民身份:)。 See how the ExoPlayer demo app does it

请同时考虑Medium blog about the MediaSessionConnector