mirror of
https://github.com/samsonjs/media.git
synced 2026-04-20 13:45:47 +00:00
Pass player ID to methods of LoadControl
The old methods are deprecated and are called from the new method for backwards compatibility of custom implementations. 'DefaultLoadControl' is unchanged, but `ExoPlayerImplInternal` already calls the new methods passing in the `PlayerId`, PiperOrigin-RevId: 613197190
This commit is contained in:
parent
a90a7049e8
commit
a0a40871b5
10 changed files with 322 additions and 78 deletions
|
|
@ -14,6 +14,8 @@
|
|||
`DefaultPreloadManager` which uses `PreloadMediaSource` to preload media
|
||||
samples of the sources into memory, and uses an integer `rankingData`
|
||||
that indicates the index of an item on the UI.
|
||||
* Add `PlayerId` to most methods of `LoadControl` to enable `LoadControl`
|
||||
implementations to support multiple players.
|
||||
* Transformer:
|
||||
* Add `audioConversionProcess` and `videoConversionProcess` to
|
||||
`ExportResult` indicating how the respective track in the output file
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import androidx.media3.datasource.DataSource;
|
|||
import androidx.media3.exoplayer.analytics.AnalyticsCollector;
|
||||
import androidx.media3.exoplayer.analytics.AnalyticsListener;
|
||||
import androidx.media3.exoplayer.analytics.DefaultAnalyticsCollector;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.audio.AudioSink;
|
||||
import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer;
|
||||
import androidx.media3.exoplayer.image.ImageOutput;
|
||||
|
|
@ -478,6 +479,7 @@ public interface ExoPlayer extends Player {
|
|||
@Nullable /* package */ Looper playbackLooper;
|
||||
/* package */ boolean buildCalled;
|
||||
/* package */ boolean suppressPlaybackOnUnsuitableOutput;
|
||||
/* package */ String playerName;
|
||||
|
||||
/**
|
||||
* Creates a builder.
|
||||
|
|
@ -678,6 +680,7 @@ public interface ExoPlayer extends Player {
|
|||
releaseTimeoutMs = DEFAULT_RELEASE_TIMEOUT_MS;
|
||||
detachSurfaceTimeoutMs = DEFAULT_DETACH_SURFACE_TIMEOUT_MS;
|
||||
usePlatformDiagnostics = true;
|
||||
playerName = "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1187,6 +1190,24 @@ public interface ExoPlayer extends Player {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player name that is included in the {@link PlayerId} for informational purpose to
|
||||
* recognize the player by its {@link PlayerId}.
|
||||
*
|
||||
* <p>The default is an empty string.
|
||||
*
|
||||
* @param playerName A name for the player in the {@link PlayerId}.
|
||||
* @return This builder.
|
||||
* @throws IllegalStateException If {@link #build()} has already been called.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
@UnstableApi
|
||||
public Builder setName(String playerName) {
|
||||
checkState(!buildCalled);
|
||||
this.playerName = playerName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an {@link ExoPlayer} instance.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -347,9 +347,12 @@ import java.util.concurrent.TimeoutException;
|
|||
analyticsCollector.setPlayer(this.wrappingPlayer, applicationLooper);
|
||||
PlayerId playerId =
|
||||
Util.SDK_INT < 31
|
||||
? new PlayerId()
|
||||
? new PlayerId(builder.playerName)
|
||||
: Api31.registerMediaMetricsListener(
|
||||
applicationContext, /* player= */ this, builder.usePlatformDiagnostics);
|
||||
applicationContext,
|
||||
/* player= */ this,
|
||||
builder.usePlatformDiagnostics,
|
||||
builder.playerName);
|
||||
internalPlayer =
|
||||
new ExoPlayerImplInternal(
|
||||
renderers,
|
||||
|
|
@ -3386,16 +3389,16 @@ import java.util.concurrent.TimeoutException;
|
|||
|
||||
@DoNotInline
|
||||
public static PlayerId registerMediaMetricsListener(
|
||||
Context context, ExoPlayerImpl player, boolean usePlatformDiagnostics) {
|
||||
Context context, ExoPlayerImpl player, boolean usePlatformDiagnostics, String playerName) {
|
||||
@Nullable MediaMetricsListener listener = MediaMetricsListener.create(context);
|
||||
if (listener == null) {
|
||||
Log.w(TAG, "MediaMetricsService unavailable.");
|
||||
return new PlayerId(LogSessionId.LOG_SESSION_ID_NONE);
|
||||
return new PlayerId(LogSessionId.LOG_SESSION_ID_NONE, playerName);
|
||||
}
|
||||
if (usePlatformDiagnostics) {
|
||||
player.addAnalyticsListener(listener);
|
||||
}
|
||||
return new PlayerId(listener.getLogSessionId());
|
||||
return new PlayerId(listener.getLogSessionId(), playerName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
private final MediaSourceList mediaSourceList;
|
||||
private final LivePlaybackSpeedControl livePlaybackSpeedControl;
|
||||
private final long releaseTimeoutMs;
|
||||
private final PlayerId playerId;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private SeekParameters seekParameters;
|
||||
|
|
@ -266,11 +267,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
this.setForegroundModeTimeoutMs = releaseTimeoutMs;
|
||||
this.pauseAtEndOfWindow = pauseAtEndOfWindow;
|
||||
this.clock = clock;
|
||||
this.playerId = playerId;
|
||||
|
||||
playbackMaybeBecameStuckAtMs = C.TIME_UNSET;
|
||||
lastRebufferRealtimeMs = C.TIME_UNSET;
|
||||
backBufferDurationUs = loadControl.getBackBufferDurationUs();
|
||||
retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe();
|
||||
backBufferDurationUs = loadControl.getBackBufferDurationUs(playerId);
|
||||
retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe(playerId);
|
||||
|
||||
playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult);
|
||||
playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo);
|
||||
|
|
@ -772,7 +774,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
/* resetPosition= */ false,
|
||||
/* releaseMediaSourceList= */ false,
|
||||
/* resetError= */ true);
|
||||
loadControl.onPrepared();
|
||||
loadControl.onPrepared(playerId);
|
||||
setState(playbackInfo.timeline.isEmpty() ? Player.STATE_ENDED : Player.STATE_BUFFERING);
|
||||
mediaSourceList.prepare(bandwidthMeter.getTransferListener());
|
||||
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
|
||||
|
|
@ -1473,7 +1475,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
/* releaseMediaSourceList= */ true,
|
||||
/* resetError= */ false);
|
||||
playbackInfoUpdate.incrementPendingOperationAcks(acknowledgeStop ? 1 : 0);
|
||||
loadControl.onStopped();
|
||||
loadControl.onStopped(playerId);
|
||||
setState(Player.STATE_IDLE);
|
||||
}
|
||||
|
||||
|
|
@ -1485,7 +1487,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
/* releaseMediaSourceList= */ true,
|
||||
/* resetError= */ false);
|
||||
releaseRenderers();
|
||||
loadControl.onReleased();
|
||||
loadControl.onReleased(playerId);
|
||||
setState(Player.STATE_IDLE);
|
||||
} finally {
|
||||
if (internalPlaybackThread != null) {
|
||||
|
|
@ -1938,6 +1940,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
return isBufferedToEnd
|
||||
|| isAdPendingPreparation
|
||||
|| loadControl.shouldStartPlayback(
|
||||
playerId,
|
||||
playbackInfo.timeline,
|
||||
playingPeriodHolder.info.id,
|
||||
getTotalBufferedDurationUs(),
|
||||
|
|
@ -2522,7 +2525,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
- loadingPeriodHolder.info.startPositionUs;
|
||||
boolean shouldContinueLoading =
|
||||
loadControl.shouldContinueLoading(
|
||||
playbackPositionUs, bufferedDurationUs, mediaClock.getPlaybackParameters().speed);
|
||||
playerId,
|
||||
playbackInfo.timeline,
|
||||
loadingPeriodHolder.info.id,
|
||||
playbackPositionUs,
|
||||
bufferedDurationUs,
|
||||
mediaClock.getPlaybackParameters().speed);
|
||||
if (!shouldContinueLoading
|
||||
&& bufferedDurationUs < PLAYBACK_BUFFER_EMPTY_THRESHOLD_US
|
||||
&& (backBufferDurationUs > 0 || retainBackBufferFromKeyframe)) {
|
||||
|
|
@ -2534,7 +2542,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
.discardBuffer(playbackInfo.positionUs, /* toKeyframe= */ false);
|
||||
shouldContinueLoading =
|
||||
loadControl.shouldContinueLoading(
|
||||
playbackPositionUs, bufferedDurationUs, mediaClock.getPlaybackParameters().speed);
|
||||
playerId,
|
||||
playbackInfo.timeline,
|
||||
loadingPeriodHolder.info.id,
|
||||
playbackPositionUs,
|
||||
bufferedDurationUs,
|
||||
mediaClock.getPlaybackParameters().speed);
|
||||
}
|
||||
return shouldContinueLoading;
|
||||
}
|
||||
|
|
@ -2759,6 +2772,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
TrackGroupArray trackGroups,
|
||||
TrackSelectorResult trackSelectorResult) {
|
||||
loadControl.onTracksSelected(
|
||||
playerId,
|
||||
playbackInfo.timeline,
|
||||
mediaPeriodId,
|
||||
renderers,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import androidx.media3.common.C;
|
|||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.TrackGroup;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
|
||||
import androidx.media3.exoplayer.source.TrackGroupArray;
|
||||
|
|
@ -37,15 +38,31 @@ public interface LoadControl {
|
|||
@Deprecated
|
||||
MediaPeriodId EMPTY_MEDIA_PERIOD_ID = new MediaPeriodId(/* periodUid= */ new Object());
|
||||
|
||||
/** Called by the player when prepared with a new source. */
|
||||
void onPrepared();
|
||||
/**
|
||||
* Called by the player when prepared with a new source.
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that prepared a new source.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default void onPrepared(PlayerId playerId) {
|
||||
onPrepared();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onPrepared(PlayerId)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default void onPrepared() {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("onPrepared not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the player when a track selection occurs.
|
||||
*
|
||||
* @param timeline The current {@link Timeline} in ExoPlayer. Can be {@link Timeline#EMPTY} only
|
||||
* when the deprecated {@link #onTracksSelected(Renderer[], TrackGroupArray,
|
||||
* ExoTrackSelection[])} was called.
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that selected tracks.
|
||||
* @param timeline The current {@link Timeline} in ExoPlayer.
|
||||
* @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} for which the
|
||||
* selection was made. Will be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty.
|
||||
* @param renderers The renderers.
|
||||
|
|
@ -53,6 +70,22 @@ public interface LoadControl {
|
|||
* @param trackSelections The track selections that were made.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default void onTracksSelected(
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodId,
|
||||
Renderer[] renderers,
|
||||
TrackGroupArray trackGroups,
|
||||
ExoTrackSelection[] trackSelections) {
|
||||
onTracksSelected(timeline, mediaPeriodId, renderers, trackGroups, trackSelections);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #onTracksSelected(PlayerId, Timeline, MediaPeriodId, Renderer[],
|
||||
* TrackGroupArray, ExoTrackSelection[])} instead.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
@Deprecated
|
||||
default void onTracksSelected(
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodId,
|
||||
|
|
@ -63,22 +96,57 @@ public interface LoadControl {
|
|||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #onTracksSelected(Timeline, MediaPeriodId, Renderer[],
|
||||
* @deprecated Implement {@link #onTracksSelected(PlayerId, Timeline, MediaPeriodId, Renderer[],
|
||||
* TrackGroupArray, ExoTrackSelection[])} instead.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Intentionally referencing deprecated constant
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
@Deprecated
|
||||
default void onTracksSelected(
|
||||
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections) {
|
||||
onTracksSelected(
|
||||
Timeline.EMPTY, EMPTY_MEDIA_PERIOD_ID, renderers, trackGroups, trackSelections);
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("onTracksSelected not implemented");
|
||||
}
|
||||
|
||||
/** Called by the player when stopped. */
|
||||
void onStopped();
|
||||
/**
|
||||
* Called by the player when stopped.
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that was stopped.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default void onStopped(PlayerId playerId) {
|
||||
onStopped();
|
||||
}
|
||||
|
||||
/** Called by the player when released. */
|
||||
void onReleased();
|
||||
/**
|
||||
* @deprecated Implement {@link #onStopped(PlayerId)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default void onStopped() {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("onStopped not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the player when released.
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that was released.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default void onReleased(PlayerId playerId) {
|
||||
onReleased();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #onReleased(PlayerId)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default void onReleased() {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("onReleased not implemented");
|
||||
}
|
||||
|
||||
/** Returns the {@link Allocator} that should be used to obtain media buffer allocations. */
|
||||
Allocator getAllocator();
|
||||
|
|
@ -93,10 +161,25 @@ public interface LoadControl {
|
|||
* <p>Note: Implementations should return a single value. Dynamic changes to the back-buffer are
|
||||
* not currently supported.
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that requests the back buffer
|
||||
* duration.
|
||||
* @return The duration of media to retain in the buffer prior to the current playback position,
|
||||
* in microseconds.
|
||||
*/
|
||||
long getBackBufferDurationUs();
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default long getBackBufferDurationUs(PlayerId playerId) {
|
||||
return getBackBufferDurationUs();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implements {@link #getBackBufferDurationUs(PlayerId)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default long getBackBufferDurationUs() {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("getBackBufferDurationUs not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether media should be retained from the keyframe before the current playback position
|
||||
|
|
@ -111,17 +194,36 @@ public interface LoadControl {
|
|||
* <p>Note: Implementations should return a single value. Dynamic changes to the back-buffer are
|
||||
* not currently supported.
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that requests whether to retain the
|
||||
* back buffer from key frame.
|
||||
* @return Whether media should be retained from the keyframe before the current playback position
|
||||
* minus {@link #getBackBufferDurationUs()}, rather than any sample before or at that
|
||||
* position.
|
||||
*/
|
||||
boolean retainBackBufferFromKeyframe();
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default boolean retainBackBufferFromKeyframe(PlayerId playerId) {
|
||||
return retainBackBufferFromKeyframe();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implements {@link #retainBackBufferFromKeyframe(PlayerId)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean retainBackBufferFromKeyframe() {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("retainBackBufferFromKeyframe not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the player to determine whether it should continue to load the source. If this method
|
||||
* returns true, the {@link MediaPeriod} identified in the most recent {@link #onTracksSelected}
|
||||
* call will continue being loaded.
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that wants to continue loading.
|
||||
* @param timeline The current {@link Timeline} in ExoPlayer.
|
||||
* @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} that is
|
||||
* currently loading.
|
||||
* @param playbackPositionUs The current playback position in microseconds, relative to the start
|
||||
* of the {@link Timeline.Period period} that will continue to be loaded if this method
|
||||
* returns {@code true}. If playback of this period has not yet started, the value will be
|
||||
|
|
@ -131,8 +233,28 @@ public interface LoadControl {
|
|||
* @param playbackSpeed The current factor by which playback is sped up.
|
||||
* @return Whether the loading should continue.
|
||||
*/
|
||||
boolean shouldContinueLoading(
|
||||
long playbackPositionUs, long bufferedDurationUs, float playbackSpeed);
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default boolean shouldContinueLoading(
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodId,
|
||||
long playbackPositionUs,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed) {
|
||||
return shouldContinueLoading(playbackPositionUs, bufferedDurationUs, playbackSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #shouldContinueLoading(PlayerId, Timeline, MediaPeriodId, long,
|
||||
* long, float)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean shouldContinueLoading(
|
||||
long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("shouldContinueLoading not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called repeatedly by the player when it's loading the source, has yet to start playback, and
|
||||
|
|
@ -140,6 +262,7 @@ public interface LoadControl {
|
|||
* determines whether playback is actually started. The load control may opt to return {@code
|
||||
* false} until some condition has been met (e.g. a certain amount of media is buffered).
|
||||
*
|
||||
* @param playerId The {@linkplain PlayerId ID of the player} that wants to start playback.
|
||||
* @param timeline The current {@link Timeline} in ExoPlayer. Can be {@link Timeline#EMPTY} only
|
||||
* when the deprecated {@link #shouldStartPlayback(long, float, boolean, long)} was called.
|
||||
* @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} for which
|
||||
|
|
@ -156,29 +279,48 @@ public interface LoadControl {
|
|||
*/
|
||||
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
|
||||
default boolean shouldStartPlayback(
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodId,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed,
|
||||
boolean rebuffering,
|
||||
long targetLiveOffsetUs) {
|
||||
return shouldStartPlayback(bufferedDurationUs, playbackSpeed, rebuffering, targetLiveOffsetUs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #shouldStartPlayback(Timeline, MediaPeriodId, long, float,
|
||||
* boolean, long)} instead.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Intentionally referencing deprecated constant
|
||||
@Deprecated
|
||||
default boolean shouldStartPlayback(
|
||||
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
|
||||
return shouldStartPlayback(
|
||||
Timeline.EMPTY,
|
||||
EMPTY_MEDIA_PERIOD_ID,
|
||||
timeline,
|
||||
mediaPeriodId,
|
||||
bufferedDurationUs,
|
||||
playbackSpeed,
|
||||
rebuffering,
|
||||
targetLiveOffsetUs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #shouldStartPlayback(PlayerId, Timeline, MediaPeriodId, long,
|
||||
* float, boolean, long)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean shouldStartPlayback(
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodId,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed,
|
||||
boolean rebuffering,
|
||||
long targetLiveOffsetUs) {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("shouldStartPlayback not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Implement {@link #shouldStartPlayback(PlayerId, Timeline, MediaPeriodId, long,
|
||||
* float, boolean, long)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean shouldStartPlayback(
|
||||
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
|
||||
// Media3 ExoPlayer will never call this method. This default implementation provides an
|
||||
// implementation to please the compiler only.
|
||||
throw new IllegalStateException("shouldStartPlayback not implemented");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.exoplayer.ExoPlayer.Builder;
|
||||
import java.util.Objects;
|
||||
|
||||
/** Identifier for a player instance. */
|
||||
@UnstableApi
|
||||
|
|
@ -32,28 +34,69 @@ public final class PlayerId {
|
|||
* A player identifier with unset default values that can be used as a placeholder or for testing.
|
||||
*/
|
||||
public static final PlayerId UNSET =
|
||||
Util.SDK_INT < 31 ? new PlayerId() : new PlayerId(LogSessionIdApi31.UNSET);
|
||||
Util.SDK_INT < 31
|
||||
? new PlayerId(/* playerName= */ "")
|
||||
: new PlayerId(LogSessionIdApi31.UNSET, /* playerName= */ "");
|
||||
|
||||
/**
|
||||
* A name to identify the player. Use {@link Builder#setName(String)} to set the name, otherwise
|
||||
* an empty string is used as the default.
|
||||
*/
|
||||
public final String name;
|
||||
|
||||
@Nullable private final LogSessionIdApi31 logSessionIdApi31;
|
||||
|
||||
/** Creates an instance for API < 31. */
|
||||
public PlayerId() {
|
||||
/**
|
||||
* An object used for equals/hashCode below API 31 or when the MediaMetricsService is unavailable.
|
||||
*/
|
||||
@Nullable private final Object equalityToken;
|
||||
|
||||
/**
|
||||
* Creates an instance for API < 31.
|
||||
*
|
||||
* @param playerName The name of the player, for informational purpose only.
|
||||
*/
|
||||
public PlayerId(String playerName) {
|
||||
checkState(Util.SDK_INT < 31);
|
||||
this.name = playerName;
|
||||
this.logSessionIdApi31 = null;
|
||||
equalityToken = new Object();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for API ≥ 31.
|
||||
*
|
||||
* @param logSessionId The {@link LogSessionId} used for this player.
|
||||
* @param playerName The name of the player, for informational purpose only.
|
||||
*/
|
||||
@RequiresApi(31)
|
||||
public PlayerId(LogSessionId logSessionId) {
|
||||
this(new LogSessionIdApi31(logSessionId));
|
||||
public PlayerId(LogSessionId logSessionId, String playerName) {
|
||||
this(new LogSessionIdApi31(logSessionId), playerName);
|
||||
}
|
||||
|
||||
private PlayerId(LogSessionIdApi31 logSessionIdApi31) {
|
||||
private PlayerId(LogSessionIdApi31 logSessionIdApi31, String playerName) {
|
||||
this.logSessionIdApi31 = logSessionIdApi31;
|
||||
this.name = playerName;
|
||||
equalityToken = new Object();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof PlayerId)) {
|
||||
return false;
|
||||
}
|
||||
PlayerId playerId = (PlayerId) o;
|
||||
return Objects.equals(name, playerId.name)
|
||||
&& Objects.equals(logSessionIdApi31, playerId.logSessionIdApi31)
|
||||
&& Objects.equals(equalityToken, playerId.equalityToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, logSessionIdApi31, equalityToken);
|
||||
}
|
||||
|
||||
/** Returns the {@link LogSessionId} for this player instance. */
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ import androidx.media3.common.util.Util;
|
|||
import androidx.media3.datasource.TransferListener;
|
||||
import androidx.media3.decoder.DecoderInputBuffer;
|
||||
import androidx.media3.exoplayer.analytics.AnalyticsListener;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
|
|
@ -5931,12 +5932,20 @@ public final class ExoPlayerTest {
|
|||
new DefaultLoadControl() {
|
||||
@Override
|
||||
public boolean shouldContinueLoading(
|
||||
long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) {
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodid,
|
||||
long playbackPositionUs,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartPlayback(
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodid,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed,
|
||||
boolean rebuffering,
|
||||
|
|
@ -5978,12 +5987,20 @@ public final class ExoPlayerTest {
|
|||
new DefaultLoadControl() {
|
||||
@Override
|
||||
public boolean shouldContinueLoading(
|
||||
long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) {
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodid,
|
||||
long playbackPositionUs,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed) {
|
||||
return bufferedDurationUs < maxBufferUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartPlayback(
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodid,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed,
|
||||
boolean rebuffering,
|
||||
|
|
@ -6058,12 +6075,20 @@ public final class ExoPlayerTest {
|
|||
new DefaultLoadControl() {
|
||||
@Override
|
||||
public boolean shouldContinueLoading(
|
||||
long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) {
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodid,
|
||||
long playbackPositionUs,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartPlayback(
|
||||
PlayerId playerId,
|
||||
Timeline timeline,
|
||||
MediaPeriodId mediaPeriodid,
|
||||
long bufferedDurationUs,
|
||||
float playbackSpeed,
|
||||
boolean rebuffering,
|
||||
|
|
@ -12947,7 +12972,7 @@ public final class ExoPlayerTest {
|
|||
spy(
|
||||
new DefaultLoadControl() {
|
||||
@Override
|
||||
public void onReleased() {
|
||||
public void onReleased(PlayerId playerId) {
|
||||
// Emulate a failure during player release.
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
|
@ -12958,13 +12983,13 @@ public final class ExoPlayerTest {
|
|||
.build();
|
||||
player.addListener(listener);
|
||||
// Ensure load control has not thrown the exception yet.
|
||||
verify(loadControl, never()).onReleased();
|
||||
verify(loadControl, never()).onReleased(any());
|
||||
|
||||
player.release();
|
||||
ShadowLooper.idleMainLooper();
|
||||
|
||||
// Verify load control threw the exception.
|
||||
verify(loadControl).onReleased();
|
||||
verify(loadControl).onReleased(any());
|
||||
verify(listener, never()).onPlayerError(any());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ import org.mockito.Mock;
|
|||
@RunWith(AndroidJUnit4.class)
|
||||
public class DefaultPreloadManagerTest {
|
||||
@Mock private TargetPreloadStatusControl<Integer> mockTargetPreloadStatusControl;
|
||||
private PlayerId playerId;
|
||||
private TrackSelector trackSelector;
|
||||
private Allocator allocator;
|
||||
private BandwidthMeter bandwidthMeter;
|
||||
|
|
@ -70,7 +69,6 @@ public class DefaultPreloadManagerTest {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
playerId = new PlayerId();
|
||||
trackSelector = new DefaultTrackSelector(ApplicationProvider.getApplicationContext());
|
||||
allocator = new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
||||
bandwidthMeter =
|
||||
|
|
@ -252,7 +250,7 @@ public class DefaultPreloadManagerTest {
|
|||
PreloadMediaSource preloadMediaSource2 =
|
||||
(PreloadMediaSource) preloadManager.getMediaSource(mediaItem2);
|
||||
preloadMediaSource2.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadManager.setCurrentPlayingIndex(2);
|
||||
preloadManager.invalidate();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
|
@ -303,7 +301,7 @@ public class DefaultPreloadManagerTest {
|
|||
PreloadMediaSource preloadMediaSource0 =
|
||||
(PreloadMediaSource) preloadManager.getMediaSource(mediaItem0);
|
||||
preloadMediaSource0.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadManager.setCurrentPlayingIndex(0);
|
||||
preloadManager.invalidate();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
|
@ -314,7 +312,7 @@ public class DefaultPreloadManagerTest {
|
|||
PreloadMediaSource preloadMediaSource2 =
|
||||
(PreloadMediaSource) preloadManager.getMediaSource(mediaItem2);
|
||||
preloadMediaSource2.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadManager.setCurrentPlayingIndex(2);
|
||||
preloadManager.invalidate();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ import org.robolectric.shadows.ShadowLooper;
|
|||
@RunWith(AndroidJUnit4.class)
|
||||
public class PreloadAndPlaybackCoordinationTest {
|
||||
|
||||
private final PlayerId playerId;
|
||||
private final BandwidthMeter bandwidthMeter;
|
||||
private final PreloadMediaSource preloadMediaSource;
|
||||
private final FakeMediaSource wrappedMediaSource;
|
||||
|
|
@ -76,7 +75,6 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
private final AtomicReference<MediaPeriod> preloadMediaPeriodReference;
|
||||
|
||||
public PreloadAndPlaybackCoordinationTest() {
|
||||
playerId = new PlayerId();
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
|
||||
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
||||
|
|
@ -165,7 +163,7 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
@Test
|
||||
public void playbackWithoutPreload_reusableForPreloadAfterRelease() {
|
||||
preloadMediaSource.prepareSource(
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
ShadowLooper.idleMainLooper();
|
||||
|
||||
assertThat(preloadControlOnSourceInfoRefreshedCalledCounter.get()).isEqualTo(0);
|
||||
|
|
@ -188,7 +186,7 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
@Test
|
||||
public void playbackBeforePreload_reusableForPreloadAfterRelease() {
|
||||
preloadMediaSource.prepareSource(
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
ShadowLooper.idleMainLooper();
|
||||
|
||||
|
|
@ -216,7 +214,7 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
ShadowLooper.idleMainLooper();
|
||||
preloadMediaSource.prepareSource(
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
wrappedMediaSource.setAllowPreparation(true);
|
||||
ShadowLooper.idleMainLooper();
|
||||
|
||||
|
|
@ -245,7 +243,7 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
ShadowLooper.idleMainLooper();
|
||||
preloadMediaSource.prepareSource(
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
FakeMediaPeriod lastCreatedActiveMediaPeriod =
|
||||
(FakeMediaPeriod) wrappedMediaSource.getLastCreatedActiveMediaPeriod();
|
||||
lastCreatedActiveMediaPeriod.setPreparationComplete();
|
||||
|
|
@ -274,7 +272,7 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
ShadowLooper.idleMainLooper();
|
||||
preloadMediaSource.prepareSource(
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
playbackMediaSourceCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
ShadowLooper.idleMainLooper();
|
||||
|
||||
assertThat(preloadControlOnSourceInfoRefreshedCalledCounter.get()).isEqualTo(1);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ public final class PreloadMediaSourceTest {
|
|||
private Allocator allocator;
|
||||
private BandwidthMeter bandwidthMeter;
|
||||
private RenderersFactory renderersFactory;
|
||||
private PlayerId playerId;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
|
@ -97,7 +96,6 @@ public final class PreloadMediaSourceTest {
|
|||
SystemClock.DEFAULT.createHandler(handler.getLooper(), /* callback= */ null),
|
||||
audioListener)
|
||||
};
|
||||
playerId = new PlayerId();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -326,7 +324,7 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
|
@ -391,7 +389,7 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
wrappedMediaSource.setAllowPreparation(true);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
|
|
@ -453,7 +451,7 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
|
||||
assertThat(onTimelineRefreshedCalled.get()).isTrue();
|
||||
assertThat(onPreparedCalled.get()).isTrue();
|
||||
|
|
@ -551,7 +549,7 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
Pair<Object, Long> periodPosition =
|
||||
externalCallerSourceInfoTimelineReference
|
||||
.get()
|
||||
|
|
@ -658,7 +656,7 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
// Create a period from different position.
|
||||
Pair<Object, Long> periodPosition =
|
||||
externalCallerSourceInfoTimelineReference
|
||||
|
|
@ -740,7 +738,7 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
preloadMediaSource.releaseSource(externalCaller);
|
||||
|
||||
|
|
@ -819,7 +817,7 @@ public final class PreloadMediaSourceTest {
|
|||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadMediaSource.releaseSource(externalCaller);
|
||||
|
||||
assertThat(onTimelineRefreshedCalled.get()).isTrue();
|
||||
|
|
@ -903,9 +901,9 @@ public final class PreloadMediaSourceTest {
|
|||
}
|
||||
};
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller1, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller1, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller2, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller2, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
// Only releaseSource by externalCaller1.
|
||||
preloadMediaSource.releaseSource(externalCaller1);
|
||||
|
||||
|
|
@ -1054,7 +1052,7 @@ public final class PreloadMediaSourceTest {
|
|||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), playerId);
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
preloadMediaSource.releasePreloadMediaSource();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
|
|
|||
Loading…
Reference in a new issue