带有 ExoPlayer 和 PlayerControlView 的 MediaBrowserService - 如何从 UI (PlayerControlView) 访问播放器实例?

MediaBrowserService with ExoPlayer and PlayerControlView - How to access to the player instance from the UI (PlayerControlView)?

我目前正在开发一个具有视频和音频功能的应用程序的一部分,最近开始重构代码库。目标是整合 MediaSession/ MediaControllerMediaBrowserService/ MediaBrowser 框架。

我们使用 ExoPlayerPlayerControlView 更具体地说,PlayerView 用于视频和音频组件,它需要引用 PlayerControlView 的播放器实例:

/**
   * Sets the {@link Player} to control.
   *
   * @param player The {@link Player} to control, or {@code null} to detach the current player. Only
   *     players which are accessed on the main thread are supported ({@code
   *     player.getApplicationLooper() == Looper.getMainLooper()}).
   */
  public void setPlayer(@Nullable Player player) {...

但是,在 android developers post and the documentation of MediaBrowserService, the player instance should be contained under the service. In addition, the only way for the client site (MediaBrowser and MediaController) to talk to service it through the connect() method and MediaBrowserConnectionCallback 下,这使得无法将播放器的实例传递给 PlayerControlView(或相反)。

我尝试使用各种回调,例如 MediaSessionCompat.Callback, but neither of the SimpleExoPlayer or the PlayerControlView 是 Parcelable。

在传统服务中,我们使用Binder来访问我们在服务中声明的方法,并执行如下操作:

boolean attachPlayerControlView(PlayerControlView playerControlView) {
            if (player != null) {
                playerControlView.setPlayer(player);
                return true;
            }
            return false;
        }

但是,MediaBrowserService/ MediaBrowser 框架似乎无法做到这一点。我检查了这个 的答案,这表明使用 [sendCommand] 是一种调用自定义方法的方法。但它也要求参数是Parcelable。

综上所述,我的问题是,有没有办法让 PlayerControlView 访问 SimpleExoPlayer 的实例,或者在 MediaBrowserService 框架下反过来。

非常感谢您的回答或评论。

In addition, the only way for the client site (MediaBrowser and MediaController) to talk to service it through the connect() method and MediaBrowserConnectionCallback, which makes passing the instance of the player to the PlayerControlView (or the other way around) not possible.

根据我的理解,这是不正确的。你总是可以绑定到 MediaBrowserService 以传统方式,即使用 IBinder 访问服务。 (虽然我不确定这是否是正确的方法,否则我必须在服务中创建一个静态 MediaPlayer 实例)。

我在使用 MediaPlayer 播放视频时遇到了类似的问题。我已经使用 IBinder 绑定到 MediaBrowserService,然后获取了 MediaPlayer 实例。在您的服务中提供一种 returns 对 MediaPlayer 的引用的方法。像这样:

private MediaPlayer mediaPlayer;

@Override
public IBinder onBind(Intent intent) {
    if (intent.getAction().equals("YOUR_INTENT")) {
        return new LocalBinder();
    }
    return super.onBind(intent);
}

public class LocalBinder extends Binder{
    public AudioService getService(){
        return AudioService.this;
    }
}

public MediaPlayer getMediaPlayer() {
    return mediaPlayer;
}

然后在您的 Activity/Fragment 中使用 IBinder 绑定到 MediaBrowserService。在我的实现中,我使用了 MediaPlayer,但我认为它可以以类似的方式用于 Exoplayer。

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{

private MediaPlayer mediaPlayer;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private boolean isServiceBounded;
private boolean isSurfaceReady;

private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        isServiceBounded = true;
        mediaPlayer = ((AudioService)service).getMediaPlayer();
        if (isSurfaceReady) {
            mediaPlayer.setDisplay(surfaceHolder);
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        isServiceBounded = false;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    surfaceView = findViewById(R.id.surfaceView);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    bindService(new Intent("YOUR_INTENT"), serviceConnection, BIND_AUTO_CREATE);
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    surfaceHolder = holder;
    isSurfaceReady = true;
    if (mediaPlayer != null) {
        mediaPlayer.setDisplay(holder);
    }
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    isSurfaceReady = false;
    if (mediaPlayer != null) {
        mediaPlayer.setDisplay(null);
    }
    surfaceHolder = null;
}

@Override
protected void onDestroy() {
    super.onDestroy();
    unbindService(serviceConnection);
}

}