Skip to content

Commit

Permalink
Add setPlaybackLooper ExoPlayer builder method
Browse files Browse the repository at this point in the history
The method allows clients to specify a pre-existing thread
to use for playback. This can be used to run multiple ExoPlayer
instances on the same playback thread.

PiperOrigin-RevId: 488980749
  • Loading branch information
Googler authored and microkatz committed Nov 21, 2022
1 parent f52bb27 commit 79b809b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.os.Looper;
import android.os.Process;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
Expand Down Expand Up @@ -473,6 +474,7 @@ final class Builder {
/* package */ long detachSurfaceTimeoutMs;
/* package */ boolean pauseAtEndOfMediaItems;
/* package */ boolean usePlatformDiagnostics;
@Nullable /* package */ Looper playbackLooper;
/* package */ boolean buildCalled;

/**
Expand Down Expand Up @@ -515,6 +517,7 @@ final class Builder {
* <li>{@code pauseAtEndOfMediaItems}: {@code false}
* <li>{@code usePlatformDiagnostics}: {@code true}
* <li>{@link Clock}: {@link Clock#DEFAULT}
* <li>{@code playbackLooper}: {@code null} (create new thread)
* </ul>
*
* @param context A {@link Context}.
Expand Down Expand Up @@ -1097,6 +1100,23 @@ public Builder setClock(Clock clock) {
return this;
}

/**
* Sets the {@link Looper} that will be used for playback.
*
* <p>The backing thread should run with priority {@link Process#THREAD_PRIORITY_AUDIO} and
* should handle messages within 10ms.
*
* @param playbackLooper A {@link looper}.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
@CanIgnoreReturnValue
public Builder setPlaybackLooper(Looper playbackLooper) {
checkState(!buildCalled);
this.playbackLooper = playbackLooper;
return this;
}

/**
* Builds an {@link ExoPlayer} instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ public ExoPlayerImpl(ExoPlayer.Builder builder, @Nullable Player wrappingPlayer)
applicationLooper,
clock,
playbackInfoUpdateListener,
playerId);
playerId,
builder.playbackLooper);

volume = 1;
repeatMode = Player.REPEAT_MODE_OFF;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public interface PlaybackInfoUpdateListener {
private final LoadControl loadControl;
private final BandwidthMeter bandwidthMeter;
private final HandlerWrapper handler;
private final HandlerThread internalPlaybackThread;
@Nullable private final HandlerThread internalPlaybackThread;
private final Looper playbackLooper;
private final Timeline.Window window;
private final Timeline.Period period;
Expand Down Expand Up @@ -236,7 +236,8 @@ public ExoPlayerImplInternal(
Looper applicationLooper,
Clock clock,
PlaybackInfoUpdateListener playbackInfoUpdateListener,
PlayerId playerId) {
PlayerId playerId,
Looper playbackLooper) {
this.playbackInfoUpdateListener = playbackInfoUpdateListener;
this.renderers = renderers;
this.trackSelector = trackSelector;
Expand Down Expand Up @@ -277,12 +278,18 @@ public ExoPlayerImplInternal(
mediaSourceList =
new MediaSourceList(/* listener= */ this, analyticsCollector, eventHandler, playerId);

// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
// not normally change to this priority" is incorrect.
internalPlaybackThread = new HandlerThread("ExoPlayer:Playback", Process.THREAD_PRIORITY_AUDIO);
internalPlaybackThread.start();
playbackLooper = internalPlaybackThread.getLooper();
handler = clock.createHandler(playbackLooper, this);
if (playbackLooper != null) {
internalPlaybackThread = null;
this.playbackLooper = playbackLooper;
} else {
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
// not normally change to this priority" is incorrect.
internalPlaybackThread =
new HandlerThread("ExoPlayer:Playback", Process.THREAD_PRIORITY_AUDIO);
internalPlaybackThread.start();
this.playbackLooper = internalPlaybackThread.getLooper();
}
handler = clock.createHandler(this.playbackLooper, this);
}

public void experimentalSetForegroundModeTimeoutMs(long setForegroundModeTimeoutMs) {
Expand Down Expand Up @@ -385,7 +392,7 @@ public void setShuffleOrder(ShuffleOrder shuffleOrder) {

@Override
public synchronized void sendMessage(PlayerMessage message) {
if (released || !internalPlaybackThread.isAlive()) {
if (released || !playbackLooper.getThread().isAlive()) {
Log.w(TAG, "Ignoring messages sent after release.");
message.markAsProcessed(/* isDelivered= */ false);
return;
Expand All @@ -400,7 +407,7 @@ public synchronized void sendMessage(PlayerMessage message) {
* @return Whether the operations succeeded. If false, the operation timed out.
*/
public synchronized boolean setForegroundMode(boolean foregroundMode) {
if (released || !internalPlaybackThread.isAlive()) {
if (released || !playbackLooper.getThread().isAlive()) {
return true;
}
if (foregroundMode) {
Expand All @@ -422,7 +429,7 @@ public synchronized boolean setForegroundMode(boolean foregroundMode) {
* @return Whether the release succeeded. If false, the release timed out.
*/
public synchronized boolean release() {
if (released || !internalPlaybackThread.isAlive()) {
if (released || !playbackLooper.getThread().isAlive()) {
return true;
}
handler.sendEmptyMessage(MSG_RELEASE);
Expand Down Expand Up @@ -1374,7 +1381,9 @@ private void releaseInternal() {
/* resetError= */ false);
loadControl.onReleased();
setState(Player.STATE_IDLE);
internalPlaybackThread.quit();
if (internalPlaybackThread != null) {
internalPlaybackThread.quit();
}
synchronized (this) {
released = true;
notifyAll();
Expand Down

0 comments on commit 79b809b

Please sign in to comment.