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

1

12

I am currently working on a part of an app which has video and audio functionality, and started refactor the code base recently. The goal is to integrate MediaSession/ MediaController and MediaBrowserService/ MediaBrowser framework.

We use ExoPlayer and PlayerControlView more specific, the PlayerView for both video and audio components, and it requires the reference to the player instance for the 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) {...

However, under the 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, which makes passing the instance of the player to the PlayerControlView (or the other way around) not possible.

I have tried using the various callbacks such as the MediaSessionCompat.Callback, but neither of the SimpleExoPlayer or the PlayerControlView are Parcelable.

In the traditional service, we uses Binder to access the methods we declared within the service and do something like:

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

However, this seems no possible with the MediaBrowserService/ MediaBrowser framework. I checked the answer to this question, which indicates that using [sendCommand] is a way to call custom methods. But it also requires the parameters to be Parcelable.

To sum up, my question is, is there a way to have the PlayerControlView access to the instance of SimpleExoPlayer or the other way around under the MediaBrowserService framework.

Many thanks ahead for any answer or comments.

Gnosticism answered 3/4, 2020 at 18:5 Comment(2)
were you able to do so?Boneblack
@Boneblack No, We wasn't able to. We ended it up go with two different approaches for Audio and for Video. For Audio, we decoupled the client site from the MediaBrowserService, to be more specific, we gave up the benefit of using the PlayerControlView with the ExoPlayer. Which means we had to do a lot of heavy lifting work on our own. For Video, we removed the usage of MediaBrowserService and MediaBrowser, since it seems unnecessary and the use of MediaSession / MediaController is enough.Gnosticism
O
2

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.

According to my understanding, this is not correct. You can always bind to MediaBrowserService in a traditional way i.e using IBinder to access Service. (Though I am not sure if this is the correct approach or not, otherwise I have to create a static MediaPlayer instance in Service).

I have faced a similar issue with Video Playback using MediaPlayer. I have bound to MediaBrowserService using IBinder and then fetched the MediaPlayer instance. In your service provide a method that returns a reference to MediaPlayer. Something like this:

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;
}

In your Activity/Fragment then bind to MediaBrowserService using IBinder. In my implementation, I have used MediaPlayer, but I think in similar ways it can be used for 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);
}

}

Overstock answered 17/10, 2020 at 15:19 Comment(2)
Thank you very much Arun! You are 100% correct, the MediaBrowserService is still a service, and could be bound and retrieve the IBinder. Just wondering in your implementation, did you treat it as a normal service or were you still able to utilize the functionalities provided by MediaBrowser?Gnosticism
Does not MediaBrowserServiceCompat is already a bound service? you cannot and should not override onBind(). Can you please explain? refer to this answer: https://mcmap.net/q/1012545/-how-to-access-instance-of-mediabrowserservicecompat-serviceExedra

© 2022 - 2024 — McMap. All rights reserved.