mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add setPlaybackLooper ExoPlayer builder method
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 (cherry picked from commit e1fe3120e29a66ac2dcde6e9960756197bac6444)
This commit is contained in:
parent
c11b5cf91c
commit
9ba059f73f
@ -34,6 +34,8 @@ This release corresponds to the
|
|||||||
* Fix bug where removing listeners during the player release can cause an
|
* Fix bug where removing listeners during the player release can cause an
|
||||||
`IllegalStateException`
|
`IllegalStateException`
|
||||||
([#10758](https://github.com/google/ExoPlayer/issues/10758)).
|
([#10758](https://github.com/google/ExoPlayer/issues/10758)).
|
||||||
|
* Add `ExoPlayer.Builder.setPlaybackLooper` that sets a pre-existing
|
||||||
|
playback thread for a new ExoPlayer instance.
|
||||||
* Build:
|
* Build:
|
||||||
* Enforce minimum `compileSdkVersion` to avoid compilation errors
|
* Enforce minimum `compileSdkVersion` to avoid compilation errors
|
||||||
([#10684](https://github.com/google/ExoPlayer/issues/10684)).
|
([#10684](https://github.com/google/ExoPlayer/issues/10684)).
|
||||||
|
@ -24,6 +24,7 @@ import android.media.AudioDeviceInfo;
|
|||||||
import android.media.AudioTrack;
|
import android.media.AudioTrack;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.Process;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
@ -485,6 +486,7 @@ public interface ExoPlayer extends Player {
|
|||||||
/* package */ long detachSurfaceTimeoutMs;
|
/* package */ long detachSurfaceTimeoutMs;
|
||||||
/* package */ boolean pauseAtEndOfMediaItems;
|
/* package */ boolean pauseAtEndOfMediaItems;
|
||||||
/* package */ boolean usePlatformDiagnostics;
|
/* package */ boolean usePlatformDiagnostics;
|
||||||
|
@Nullable /* package */ Looper playbackLooper;
|
||||||
/* package */ boolean buildCalled;
|
/* package */ boolean buildCalled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -527,6 +529,7 @@ public interface ExoPlayer extends Player {
|
|||||||
* <li>{@code pauseAtEndOfMediaItems}: {@code false}
|
* <li>{@code pauseAtEndOfMediaItems}: {@code false}
|
||||||
* <li>{@code usePlatformDiagnostics}: {@code true}
|
* <li>{@code usePlatformDiagnostics}: {@code true}
|
||||||
* <li>{@link Clock}: {@link Clock#DEFAULT}
|
* <li>{@link Clock}: {@link Clock#DEFAULT}
|
||||||
|
* <li>{@code playbackLooper}: {@code null} (create new thread)
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param context A {@link Context}.
|
* @param context A {@link Context}.
|
||||||
@ -1134,6 +1137,24 @@ public interface ExoPlayer extends Player {
|
|||||||
return this;
|
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
|
||||||
|
@UnstableApi
|
||||||
|
public Builder setPlaybackLooper(Looper playbackLooper) {
|
||||||
|
checkState(!buildCalled);
|
||||||
|
this.playbackLooper = playbackLooper;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an {@link ExoPlayer} instance.
|
* Builds an {@link ExoPlayer} instance.
|
||||||
*
|
*
|
||||||
|
@ -345,7 +345,8 @@ import java.util.concurrent.TimeoutException;
|
|||||||
applicationLooper,
|
applicationLooper,
|
||||||
clock,
|
clock,
|
||||||
playbackInfoUpdateListener,
|
playbackInfoUpdateListener,
|
||||||
playerId);
|
playerId,
|
||||||
|
builder.playbackLooper);
|
||||||
|
|
||||||
volume = 1;
|
volume = 1;
|
||||||
repeatMode = Player.REPEAT_MODE_OFF;
|
repeatMode = Player.REPEAT_MODE_OFF;
|
||||||
|
@ -189,7 +189,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
private final BandwidthMeter bandwidthMeter;
|
private final BandwidthMeter bandwidthMeter;
|
||||||
private final HandlerWrapper handler;
|
private final HandlerWrapper handler;
|
||||||
private final HandlerThread internalPlaybackThread;
|
@Nullable private final HandlerThread internalPlaybackThread;
|
||||||
private final Looper playbackLooper;
|
private final Looper playbackLooper;
|
||||||
private final Timeline.Window window;
|
private final Timeline.Window window;
|
||||||
private final Timeline.Period period;
|
private final Timeline.Period period;
|
||||||
@ -244,7 +244,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
Looper applicationLooper,
|
Looper applicationLooper,
|
||||||
Clock clock,
|
Clock clock,
|
||||||
PlaybackInfoUpdateListener playbackInfoUpdateListener,
|
PlaybackInfoUpdateListener playbackInfoUpdateListener,
|
||||||
PlayerId playerId) {
|
PlayerId playerId,
|
||||||
|
Looper playbackLooper) {
|
||||||
this.playbackInfoUpdateListener = playbackInfoUpdateListener;
|
this.playbackInfoUpdateListener = playbackInfoUpdateListener;
|
||||||
this.renderers = renderers;
|
this.renderers = renderers;
|
||||||
this.trackSelector = trackSelector;
|
this.trackSelector = trackSelector;
|
||||||
@ -285,12 +286,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
mediaSourceList =
|
mediaSourceList =
|
||||||
new MediaSourceList(/* listener= */ this, analyticsCollector, eventHandler, playerId);
|
new MediaSourceList(/* listener= */ this, analyticsCollector, eventHandler, playerId);
|
||||||
|
|
||||||
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
|
if (playbackLooper != null) {
|
||||||
// not normally change to this priority" is incorrect.
|
internalPlaybackThread = null;
|
||||||
internalPlaybackThread = new HandlerThread("ExoPlayer:Playback", Process.THREAD_PRIORITY_AUDIO);
|
this.playbackLooper = playbackLooper;
|
||||||
internalPlaybackThread.start();
|
} else {
|
||||||
playbackLooper = internalPlaybackThread.getLooper();
|
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
|
||||||
handler = clock.createHandler(playbackLooper, this);
|
// 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) {
|
public void experimentalSetForegroundModeTimeoutMs(long setForegroundModeTimeoutMs) {
|
||||||
@ -393,7 +400,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void sendMessage(PlayerMessage message) {
|
public synchronized void sendMessage(PlayerMessage message) {
|
||||||
if (released || !internalPlaybackThread.isAlive()) {
|
if (released || !playbackLooper.getThread().isAlive()) {
|
||||||
Log.w(TAG, "Ignoring messages sent after release.");
|
Log.w(TAG, "Ignoring messages sent after release.");
|
||||||
message.markAsProcessed(/* isDelivered= */ false);
|
message.markAsProcessed(/* isDelivered= */ false);
|
||||||
return;
|
return;
|
||||||
@ -408,7 +415,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* @return Whether the operations succeeded. If false, the operation timed out.
|
* @return Whether the operations succeeded. If false, the operation timed out.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean setForegroundMode(boolean foregroundMode) {
|
public synchronized boolean setForegroundMode(boolean foregroundMode) {
|
||||||
if (released || !internalPlaybackThread.isAlive()) {
|
if (released || !playbackLooper.getThread().isAlive()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (foregroundMode) {
|
if (foregroundMode) {
|
||||||
@ -430,7 +437,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* @return Whether the release succeeded. If false, the release timed out.
|
* @return Whether the release succeeded. If false, the release timed out.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean release() {
|
public synchronized boolean release() {
|
||||||
if (released || !internalPlaybackThread.isAlive()) {
|
if (released || !playbackLooper.getThread().isAlive()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
handler.sendEmptyMessage(MSG_RELEASE);
|
handler.sendEmptyMessage(MSG_RELEASE);
|
||||||
@ -1382,7 +1389,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
/* resetError= */ false);
|
/* resetError= */ false);
|
||||||
loadControl.onReleased();
|
loadControl.onReleased();
|
||||||
setState(Player.STATE_IDLE);
|
setState(Player.STATE_IDLE);
|
||||||
internalPlaybackThread.quit();
|
if (internalPlaybackThread != null) {
|
||||||
|
internalPlaybackThread.quit();
|
||||||
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
released = true;
|
released = true;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user