mirror of
https://github.com/androidx/media.git
synced 2025-05-14 11:09:53 +08:00
Allow continuous seeking.
PiperOrigin-RevId: 419629912
This commit is contained in:
parent
34ed8e2b5f
commit
90912b0710
@ -141,6 +141,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@RtspState private int rtspState;
|
||||
private boolean hasUpdatedTimelineAndTracks;
|
||||
private boolean receivedAuthorizationRequest;
|
||||
private boolean hasPendingPauseRequest;
|
||||
private long pendingSeekPositionUs;
|
||||
|
||||
/**
|
||||
@ -235,7 +236,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
* @param positionUs The seek time measured in microseconds.
|
||||
*/
|
||||
public void seekToUs(long positionUs) {
|
||||
// RTSP state is PLAYING after sending out a PAUSE, before receiving the PAUSE response. Sends
|
||||
// out PAUSE only when state PLAYING and no PAUSE is sent.
|
||||
if (rtspState == RTSP_STATE_PLAYING && !hasPendingPauseRequest) {
|
||||
messageSender.sendPauseRequest(uri, checkNotNull(sessionId));
|
||||
}
|
||||
pendingSeekPositionUs = positionUs;
|
||||
}
|
||||
|
||||
@ -399,6 +404,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
sendRequest(
|
||||
getRequestWithCommonHeaders(
|
||||
METHOD_PAUSE, sessionId, /* additionalHeaders= */ ImmutableMap.of(), uri));
|
||||
hasPendingPauseRequest = true;
|
||||
}
|
||||
|
||||
public void retryLastRequest() {
|
||||
@ -690,15 +696,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
keepAliveMonitor.start();
|
||||
}
|
||||
|
||||
pendingSeekPositionUs = C.TIME_UNSET;
|
||||
// onPlaybackStarted could initiate another seek request, which will set
|
||||
// pendingSeekPositionUs.
|
||||
playbackEventListener.onPlaybackStarted(
|
||||
Util.msToUs(response.sessionTiming.startTimeMs), response.trackTimingList);
|
||||
pendingSeekPositionUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
private void onPauseResponseReceived() {
|
||||
checkState(rtspState == RTSP_STATE_PLAYING);
|
||||
|
||||
rtspState = RTSP_STATE_READY;
|
||||
hasPendingPauseRequest = false;
|
||||
if (pendingSeekPositionUs != C.TIME_UNSET) {
|
||||
startPlayback(Util.usToMs(pendingSeekPositionUs));
|
||||
}
|
||||
|
@ -86,8 +86,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Nullable private IOException preparationError;
|
||||
@Nullable private RtspPlaybackException playbackException;
|
||||
|
||||
private long lastSeekPositionUs;
|
||||
private long requestedSeekPositionUs;
|
||||
private long pendingSeekPositionUs;
|
||||
private long pendingSeekPositionUsForTcpRetry;
|
||||
private boolean loadingFinished;
|
||||
private boolean released;
|
||||
private boolean prepared;
|
||||
@ -132,6 +133,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
selectedLoadInfos = new ArrayList<>();
|
||||
|
||||
pendingSeekPositionUs = C.TIME_UNSET;
|
||||
requestedSeekPositionUs = C.TIME_UNSET;
|
||||
pendingSeekPositionUsForTcpRetry = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/** Releases the {@link RtspMediaPeriod}. */
|
||||
@ -245,17 +248,52 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
public long seekToUs(long positionUs) {
|
||||
// Handles all RTSP seeking cases:
|
||||
// 1. Seek before the first RTP/UDP packet is received. The seek position is cached to be used
|
||||
// after retrying playback with RTP/TCP.
|
||||
// 2a. Normal RTSP seek: if no additional seek is requested after the first seek. Request RTSP
|
||||
// PAUSE and then PLAY at the seek position.
|
||||
// 2b. If additional seek is requested after the first seek, records the new seek position,
|
||||
// 2b.1. If RTSP PLAY (for the first seek) is already sent, the new seek position is used to
|
||||
// initiate another seek upon receiving PLAY response by invoking this method again.
|
||||
// 2b.2. If RTSP PLAY (for the first seek) has not been sent, the new seek position will be
|
||||
// used in the following PLAY request.
|
||||
|
||||
// TODO(internal: b/198620566) Handle initial seek.
|
||||
// TODO(internal: b/213153670) Handle dropped seek position.
|
||||
if (getBufferedPositionUs() == 0 && !isUsingRtpTcp) {
|
||||
// Stores the seek position for later, if no RTP packet is received when using UDP.
|
||||
pendingSeekPositionUsForTcpRetry = positionUs;
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
discardBuffer(positionUs, /* toKeyframe= */ false);
|
||||
requestedSeekPositionUs = positionUs;
|
||||
|
||||
if (isSeekPending()) {
|
||||
// TODO(internal b/172331505) Allow seek when a seek is pending.
|
||||
// Does not allow another seek if a seek is pending.
|
||||
return pendingSeekPositionUs;
|
||||
switch (rtspClient.getState()) {
|
||||
case RtspClient.RTSP_STATE_READY:
|
||||
// PLAY request is sent, yet to receive the response. requestedSeekPositionUs stores the
|
||||
// new position to do another seek upon receiving the PLAY response.
|
||||
return positionUs;
|
||||
case RtspClient.RTSP_STATE_PLAYING:
|
||||
// Pending PAUSE response, updates client with the newest seek position for the following
|
||||
// PLAY request.
|
||||
pendingSeekPositionUs = positionUs;
|
||||
rtspClient.seekToUs(pendingSeekPositionUs);
|
||||
return positionUs;
|
||||
case RtspClient.RTSP_STATE_UNINITIALIZED:
|
||||
case RtspClient.RTSP_STATE_INIT:
|
||||
default:
|
||||
// Never happens.
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
if (seekInsideBufferUs(positionUs)) {
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
lastSeekPositionUs = positionUs;
|
||||
pendingSeekPositionUs = positionUs;
|
||||
rtspClient.seekToUs(positionUs);
|
||||
for (int i = 0; i < rtspLoaderWrappers.size(); i++) {
|
||||
@ -275,8 +313,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
return C.TIME_END_OF_SOURCE;
|
||||
}
|
||||
|
||||
if (isSeekPending()) {
|
||||
return pendingSeekPositionUs;
|
||||
if (requestedSeekPositionUs != C.TIME_UNSET) {
|
||||
return requestedSeekPositionUs;
|
||||
}
|
||||
|
||||
boolean allLoaderWrappersAreCanceled = true;
|
||||
@ -290,7 +328,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
return allLoaderWrappersAreCanceled || bufferedPositionUs == Long.MIN_VALUE
|
||||
? lastSeekPositionUs
|
||||
? 0
|
||||
: bufferedPositionUs;
|
||||
}
|
||||
|
||||
@ -441,7 +479,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
public void onLoadCompleted(
|
||||
RtpDataLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) {
|
||||
// TODO(b/172331505) Allow for retry when loading is not ending.
|
||||
if (getBufferedPositionUs() == 0) {
|
||||
if (!isUsingRtpTcp) {
|
||||
// Retry playback with TCP if no sample has been received so far, and we are not already
|
||||
@ -537,13 +574,26 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
dataLoadable.setTimestamp(trackTiming.rtpTimestamp);
|
||||
dataLoadable.setSequenceNumber(trackTiming.sequenceNumber);
|
||||
|
||||
if (isSeekPending()) {
|
||||
if (isSeekPending() && pendingSeekPositionUs == requestedSeekPositionUs) {
|
||||
// Seek loadable only when all pending seeks are processed, or SampleQueues will report
|
||||
// inconsistent bufferedPosition.
|
||||
dataLoadable.seekToUs(startPositionUs, trackTiming.rtpTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSeekPending()) {
|
||||
if (pendingSeekPositionUs == requestedSeekPositionUs) {
|
||||
// No seek request was made after the current pending seek.
|
||||
pendingSeekPositionUs = C.TIME_UNSET;
|
||||
requestedSeekPositionUs = C.TIME_UNSET;
|
||||
} else {
|
||||
// Resets pendingSeekPositionUs to perform a fresh RTSP seek.
|
||||
pendingSeekPositionUs = C.TIME_UNSET;
|
||||
seekToUs(requestedSeekPositionUs);
|
||||
}
|
||||
} else if (pendingSeekPositionUsForTcpRetry != C.TIME_UNSET) {
|
||||
seekToUs(pendingSeekPositionUsForTcpRetry);
|
||||
pendingSeekPositionUsForTcpRetry = C.TIME_UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user