/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.exoplayer;
import androidx.annotation.CheckResult;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Metadata;
import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.Player;
import androidx.media3.common.Player.PlaybackSuppressionReason;
import androidx.media3.common.Timeline;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
import androidx.media3.exoplayer.source.TrackGroupArray;
import androidx.media3.exoplayer.trackselection.TrackSelectorResult;
import com.google.common.collect.ImmutableList;
import java.util.List;
/** Information about an ongoing playback. */
/* package */ final class PlaybackInfo {
/**
* Placeholder media period id used while the timeline is empty and no period id is specified.
* This id is used when playback infos are created with {@link #createDummy(TrackSelectorResult)}.
*/
private static final MediaPeriodId PLACEHOLDER_MEDIA_PERIOD_ID =
new MediaPeriodId(/* periodUid= */ new Object());
/** The current {@link Timeline}. */
public final Timeline timeline;
/** The {@link MediaPeriodId} of the currently playing media period in the {@link #timeline}. */
public final MediaPeriodId periodId;
/**
* The requested next start position for the current period in the {@link #timeline}, in
* microseconds, or {@link C#TIME_UNSET} if the period was requested to start at its default
* position.
*
* <p>Note that if {@link #periodId} refers to an ad, this is the requested start position for the
* suspended content.
*/
public final long requestedContentPositionUs;
/** The start position after a reported position discontinuity, in microseconds. */
public final long discontinuityStartPositionUs;
/** The current playback state. One of the {@link Player}.STATE_ constants. */
public final @Player.State int playbackState;
/** The current playback error, or null if this is not an error state. */
@Nullable public final ExoPlaybackException playbackError;
/** Whether the player is currently loading. */
public final boolean isLoading;
/** The currently available track groups. */
public final TrackGroupArray trackGroups;
/** The result of the current track selection. */
public final TrackSelectorResult trackSelectorResult;
/** The current static metadata of the track selections. */
public final List<Metadata> staticMetadata;
/** The {@link MediaPeriodId} of the currently loading media period in the {@link #timeline}. */
public final MediaPeriodId loadingMediaPeriodId;
/** Whether playback should proceed when {@link #playbackState} == {@link Player#STATE_READY}. */
public final boolean playWhenReady;
/** Reason why playback is suppressed even though {@link #playWhenReady} is {@code true}. */
public final @PlaybackSuppressionReason int playbackSuppressionReason;
/** The playback parameters. */
public final PlaybackParameters playbackParameters;
/** Whether the main player loop is sleeping, while using offload scheduling. */
public final boolean sleepingForOffload;
/**
* Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start
* of the associated period in the {@link #timeline}, in microseconds.
*/
public volatile long bufferedPositionUs;
/**
* Total duration of buffered media from {@link #positionUs} to {@link #bufferedPositionUs}
* including all ads.
*/
public volatile long totalBufferedDurationUs;
/**
* Current playback position in {@link #periodId} relative to the start of the associated period
* in the {@link #timeline}, in microseconds.
*/
public volatile long positionUs;
/**
* Creates an empty placeholder playback info which can be used for masking as long as no real
* playback info is available.
*
* @param emptyTrackSelectorResult An empty track selector result with null entries for each
* renderer.
* @return A placeholder playback info.
*/
public static PlaybackInfo createDummy(TrackSelectorResult emptyTrackSelectorResult) {
return new PlaybackInfo(
Timeline.EMPTY,
PLACEHOLDER_MEDIA_PERIOD_ID,
/* requestedContentPositionUs= */ C.TIME_UNSET,
/* discontinuityStartPositionUs= */ 0,
Player.STATE_IDLE,
/* playbackError= */ null,
/* isLoading= */ false,
TrackGroupArray.EMPTY,
emptyTrackSelectorResult,
/* staticMetadata= */ ImmutableList.of(),
PLACEHOLDER_MEDIA_PERIOD_ID,
/* playWhenReady= */ false,
Player.PLAYBACK_SUPPRESSION_REASON_NONE,
PlaybackParameters.DEFAULT,
/* bufferedPositionUs= */ 0,
/* totalBufferedDurationUs= */ 0,
/* positionUs= */ 0,
/* sleepingForOffload= */ false);
}
/**
* Create playback info.
*
* @param timeline See {@link #timeline}.
* @param periodId See {@link #periodId}.
* @param requestedContentPositionUs See {@link #requestedContentPositionUs}.
* @param playbackState See {@link #playbackState}.
* @param playbackError See {@link #playbackError}.
* @param isLoading See {@link #isLoading}.
* @param trackGroups See {@link #trackGroups}.
* @param trackSelectorResult See {@link #trackSelectorResult}.
* @param staticMetadata See {@link #staticMetadata}.
* @param loadingMediaPeriodId See {@link #loadingMediaPeriodId}.
* @param playWhenReady See {@link #playWhenReady}.
* @param playbackSuppressionReason See {@link #playbackSuppressionReason}.
* @param playbackParameters See {@link #playbackParameters}.
* @param bufferedPositionUs See {@link #bufferedPositionUs}.
* @param totalBufferedDurationUs See {@link #totalBufferedDurationUs}.
* @param positionUs See {@link #positionUs}.
* @param sleepingForOffload See {@link #sleepingForOffload}.
*/
public PlaybackInfo(
Timeline timeline,
MediaPeriodId periodId,
long requestedContentPositionUs,
long discontinuityStartPositionUs,
@Player.State int playbackState,
@Nullable ExoPlaybackException playbackError,
boolean isLoading,
TrackGroupArray trackGroups,
TrackSelectorResult trackSelectorResult,
List<Metadata> staticMetadata,
MediaPeriodId loadingMediaPeriodId,
boolean playWhenReady,
@PlaybackSuppressionReason int playbackSuppressionReason,
PlaybackParameters playbackParameters,
long bufferedPositionUs,
long totalBufferedDurationUs,
long positionUs,
boolean sleepingForOffload) {
this.timeline = timeline;
this.periodId = periodId;
this.requestedContentPositionUs = requestedContentPositionUs;
this.discontinuityStartPositionUs = discontinuityStartPositionUs;
this.playbackState = playbackState;
this.playbackError = playbackError;
this.isLoading = isLoading;
this.trackGroups = trackGroups;
this.trackSelectorResult = trackSelectorResult;
this.staticMetadata = staticMetadata;
this.loadingMediaPeriodId = loadingMediaPeriodId;
this.playWhenReady = playWhenReady;
this.playbackSuppressionReason = playbackSuppressionReason;
this.playbackParameters = playbackParameters;
this.bufferedPositionUs = bufferedPositionUs;
this.totalBufferedDurationUs = totalBufferedDurationUs;
this.positionUs = positionUs;
this.sleepingForOffload = sleepingForOffload;
}
/** Returns a placeholder period id for an empty timeline. */
public static MediaPeriodId getDummyPeriodForEmptyTimeline() {
return PLACEHOLDER_MEDIA_PERIOD_ID;
}
/**
* Copies playback info with new playing position.
*
* @param periodId New playing media period. See {@link #periodId}.
* @param positionUs New position. See {@link #positionUs}.
* @param requestedContentPositionUs New requested content position. See {@link
* #requestedContentPositionUs}.
* @param totalBufferedDurationUs New buffered duration. See {@link #totalBufferedDurationUs}.
* @param trackGroups The track groups for the new position. See {@link #trackGroups}.
* @param trackSelectorResult The track selector result for the new position. See {@link
* #trackSelectorResult}.
* @param staticMetadata The static metadata for the track selections. See {@link
* #staticMetadata}.
* @return Copied playback info with new playing position.
*/
@CheckResult
public PlaybackInfo copyWithNewPosition(
MediaPeriodId periodId,
long positionUs,
long requestedContentPositionUs,
long discontinuityStartPositionUs,
long totalBufferedDurationUs,
TrackGroupArray trackGroups,
TrackSelectorResult trackSelectorResult,
List<Metadata> staticMetadata) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with the new timeline.
*
* @param timeline New timeline. See {@link #timeline}.
* @return Copied playback info with the new timeline.
*/
@CheckResult
public PlaybackInfo copyWithTimeline(Timeline timeline) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with new playback state.
*
* @param playbackState New playback state. See {@link #playbackState}.
* @return Copied playback info with new playback state.
*/
@CheckResult
public PlaybackInfo copyWithPlaybackState(int playbackState) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with a playback error.
*
* @param playbackError The error. See {@link #playbackError}.
* @return Copied playback info with the playback error.
*/
@CheckResult
public PlaybackInfo copyWithPlaybackError(@Nullable ExoPlaybackException playbackError) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with new loading state.
*
* @param isLoading New loading state. See {@link #isLoading}.
* @return Copied playback info with new loading state.
*/
@CheckResult
public PlaybackInfo copyWithIsLoading(boolean isLoading) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with new loading media period.
*
* @param loadingMediaPeriodId New loading media period id. See {@link #loadingMediaPeriodId}.
* @return Copied playback info with new loading media period.
*/
@CheckResult
public PlaybackInfo copyWithLoadingMediaPeriodId(MediaPeriodId loadingMediaPeriodId) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with new information about whether playback should proceed when ready.
*
* @param playWhenReady Whether playback should proceed when {@link #playbackState} == {@link
* Player#STATE_READY}.
* @param playbackSuppressionReason Reason why playback is suppressed even though {@link
* #playWhenReady} is {@code true}.
* @return Copied playback info with new information.
*/
@CheckResult
public PlaybackInfo copyWithPlayWhenReady(
boolean playWhenReady, @PlaybackSuppressionReason int playbackSuppressionReason) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with new playback parameters.
*
* @param playbackParameters New playback parameters. See {@link #playbackParameters}.
* @return Copied playback info with new playback parameters.
*/
@CheckResult
public PlaybackInfo copyWithPlaybackParameters(PlaybackParameters playbackParameters) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
/**
* Copies playback info with new sleepingForOffload.
*
* @param sleepingForOffload New main player loop sleeping state. See {@link #sleepingForOffload}.
* @return Copied playback info with new main player loop sleeping state.
*/
@CheckResult
public PlaybackInfo copyWithSleepingForOffload(boolean sleepingForOffload) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
discontinuityStartPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
staticMetadata,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackParameters,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs,
sleepingForOffload);
}
}