Handle RTSP 301/302 redirection.

PiperOrigin-RevId: 396303242
This commit is contained in:
claincly 2021-09-13 09:34:57 +01:00 committed by Christos Tsilopoulos
parent 76014cf0e9
commit ff7dcbd6f2
4 changed files with 82 additions and 9 deletions

View file

@ -101,8 +101,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final SessionInfoListener sessionInfoListener;
private final PlaybackEventListener playbackEventListener;
private final Uri uri;
@Nullable private final RtspAuthUserInfo rtspAuthUserInfo;
private final String userAgent;
private final boolean debugLoggingEnabled;
private final ArrayDeque<RtpLoadInfo> pendingSetupRtpLoadInfos;
@ -110,7 +108,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final SparseArray<RtspRequest> pendingRequests;
private final MessageSender messageSender;
/** RTSP session URI. */
private Uri uri;
private RtspMessageChannel messageChannel;
@Nullable private RtspAuthUserInfo rtspAuthUserInfo;
@Nullable private String sessionId;
@Nullable private KeepAliveMonitor keepAliveMonitor;
@Nullable private RtspAuthenticationInfo rtspAuthenticationInfo;
@ -140,15 +142,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
boolean debugLoggingEnabled) {
this.sessionInfoListener = sessionInfoListener;
this.playbackEventListener = playbackEventListener;
this.uri = RtspMessageUtil.removeUserInfo(uri);
this.rtspAuthUserInfo = RtspMessageUtil.parseUserInfo(uri);
this.userAgent = userAgent;
this.debugLoggingEnabled = debugLoggingEnabled;
pendingSetupRtpLoadInfos = new ArrayDeque<>();
pendingRequests = new SparseArray<>();
messageSender = new MessageSender();
pendingSeekPositionUs = C.TIME_UNSET;
messageChannel = new RtspMessageChannel(new MessageListener());
this.pendingSetupRtpLoadInfos = new ArrayDeque<>();
this.pendingRequests = new SparseArray<>();
this.messageSender = new MessageSender();
this.uri = RtspMessageUtil.removeUserInfo(uri);
this.messageChannel = new RtspMessageChannel(new MessageListener());
this.rtspAuthUserInfo = RtspMessageUtil.parseUserInfo(uri);
this.pendingSeekPositionUs = C.TIME_UNSET;
}
/**
@ -482,6 +484,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
switch (response.status) {
case 200:
break;
case 301:
case 302:
// Redirection request.
@Nullable String redirectionUriString = response.headers.get(RtspHeaders.LOCATION);
if (redirectionUriString == null) {
sessionInfoListener.onSessionTimelineRequestFailed(
"Redirection without new location.", /* cause= */ null);
} else {
Uri redirectionUri = Uri.parse(redirectionUriString);
RtspClient.this.uri = RtspMessageUtil.removeUserInfo(redirectionUri);
RtspClient.this.rtspAuthUserInfo = RtspMessageUtil.parseUserInfo(redirectionUri);
messageSender.sendDescribeRequest(RtspClient.this.uri, RtspClient.this.sessionId);
}
return;
case 401:
if (rtspAuthUserInfo != null && !receivedAuthorizationRequest) {
// Unauthorized.

View file

@ -50,6 +50,7 @@ import java.util.Map;
public static final String CSEQ = "CSeq";
public static final String DATE = "Date";
public static final String EXPIRES = "Expires";
public static final String LOCATION = "Location";
public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
public static final String PROXY_REQUIRE = "Proxy-Require";
public static final String PUBLIC = "Public";
@ -251,6 +252,8 @@ import java.util.Map;
return DATE;
} else if (Ascii.equalsIgnoreCase(messageHeaderName, EXPIRES)) {
return EXPIRES;
} else if (Ascii.equalsIgnoreCase(messageHeaderName, LOCATION)) {
return LOCATION;
} else if (Ascii.equalsIgnoreCase(messageHeaderName, PROXY_AUTHENTICATE)) {
return PROXY_AUTHENTICATE;
} else if (Ascii.equalsIgnoreCase(messageHeaderName, PROXY_REQUIRE)) {

View file

@ -462,6 +462,10 @@ import java.util.regex.Pattern;
switch (statusCode) {
case 200:
return "OK";
case 301:
return "Move Permanently";
case 302:
return "Move Temporarily";
case 400:
return "Bad Request";
case 401:

View file

@ -120,6 +120,56 @@ public final class RtspClientTest {
assertThat(tracksInSession.get()).hasSize(2);
}
@Test
public void connectServerAndClient_describeRedirects_updatesSessionTimeline() throws Exception {
class ResponseProvider implements RtspServer.ResponseProvider {
@Override
public RtspResponse getOptionsResponse() {
return new RtspResponse(/* status= */ 200, RtspHeaders.EMPTY);
}
@Override
public RtspResponse getDescribeResponse(Uri requestedUri) {
if (!requestedUri.getPath().contains("redirect")) {
return new RtspResponse(
301,
new RtspHeaders.Builder()
.add(
RtspHeaders.LOCATION,
requestedUri.buildUpon().appendEncodedPath("redirect").build().toString())
.build());
}
return RtspTestUtils.newDescribeResponseWithSdpMessage(
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
}
}
rtspServer = new RtspServer(new ResponseProvider());
AtomicReference<ImmutableList<RtspMediaTrack>> tracksInSession = new AtomicReference<>();
rtspClient =
new RtspClient(
new SessionInfoListener() {
@Override
public void onSessionTimelineUpdated(
RtspSessionTiming timing, ImmutableList<RtspMediaTrack> tracks) {
tracksInSession.set(tracks);
}
@Override
public void onSessionTimelineRequestFailed(
String message, @Nullable Throwable cause) {}
},
EMPTY_PLAYBACK_LISTENER,
/* userAgent= */ "ExoPlayer:RtspClientTest",
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
/* debugLoggingEnabled= */ false);
rtspClient.start();
RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null);
assertThat(tracksInSession.get()).hasSize(2);
}
@Test
public void
connectServerAndClient_serverSupportsDescribeNoHeaderInOptions_updatesSessionTimeline()