diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d5598903f8..b0f4686a66 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -46,6 +46,7 @@ * GL demo app: * Fix texture transformation to avoid green bars shown on some videos ([#8992](https://github.com/google/ExoPlayer/issues/8992)). + * Add `RtspMediaSource.Factory` option to force using TCP for streaming. ### 2.14.0 (2021-05-13) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java index 3ed4746d50..aa5038848a 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java @@ -84,7 +84,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private boolean prepared; private boolean trackSelected; private int portBindingRetryCount; - private boolean hasRetriedWithRtpTcp; + private boolean isUsingRtpTcp; /** * Creates an RTSP media period. @@ -514,12 +514,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private LoadErrorAction handleSocketTimeout(RtpDataLoadable loadable) { // TODO(b/172331505) Allow for retry when loading is not ending. if (getBufferedPositionUs() == Long.MIN_VALUE) { - // Retry playback with TCP if no sample has been received so far. - if (!hasRetriedWithRtpTcp) { + if (!isUsingRtpTcp) { + // Retry playback with TCP if no sample has been received so far, and we are not already + // using TCP. Retrying will setup new loadables, so will not retry with the current + // loadables. retryWithRtpTcp(); - hasRetriedWithRtpTcp = true; + isUsingRtpTcp = true; } - // Don't retry with the current UDP backed loadables. return Loader.DONT_RETRY; } @@ -685,6 +686,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; RtspMediaTrack mediaTrack, int trackId, RtpDataChannel.Factory rtpDataChannelFactory) { this.mediaTrack = mediaTrack; + // This listener runs on the playback thread, posted by the Loader thread. RtpDataLoadable.EventListener transportEventListener = (transport, rtpDataChannel) -> { RtpLoadInfo.this.transport = transport; @@ -695,8 +697,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; if (interleavedBinaryDataListener != null) { rtspClient.registerInterleavedDataChannel( rtpDataChannel.getLocalPort(), interleavedBinaryDataListener); + isUsingRtpTcp = true; } - maybeSetupTracks(); }; diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java index 9596be328f..625a4d775d 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java @@ -58,6 +58,24 @@ public final class RtspMediaSource extends BaseMediaSource { */ public static final class Factory implements MediaSourceFactory { + private boolean forceUseRtpTcp; + + /** + * Sets whether to force using TCP as the default RTP transport. + * + *
The default value is {@code false}, the source will first try streaming RTSP with UDP. If
+ * no data is received on the UDP channel (for instance, when streaming behind a NAT) for a
+ * while, the source will switch to streaming using TCP. If this value is set to {@code true},
+ * the source will always use TCP for streaming.
+ *
+ * @param forceUseRtpTcp Whether force to use TCP for streaming.
+ * @return This Factory, for convenience.
+ */
+ public Factory setForceUseRtpTcp(boolean forceUseRtpTcp) {
+ this.forceUseRtpTcp = forceUseRtpTcp;
+ return this;
+ }
+
/** Does nothing. {@link RtspMediaSource} does not support DRM. */
@Override
public Factory setDrmSessionManagerProvider(
@@ -122,7 +140,11 @@ public final class RtspMediaSource extends BaseMediaSource {
@Override
public RtspMediaSource createMediaSource(MediaItem mediaItem) {
checkNotNull(mediaItem.playbackProperties);
- return new RtspMediaSource(mediaItem);
+ return new RtspMediaSource(
+ mediaItem,
+ forceUseRtpTcp
+ ? new TransferRtpDataChannelFactory()
+ : new UdpDataSourceRtpDataChannelFactory());
}
}
@@ -148,9 +170,9 @@ public final class RtspMediaSource extends BaseMediaSource {
@Nullable private ImmutableList