From 74ff9f21f0f0631200c4da32003ad5341182186c Mon Sep 17 00:00:00 2001 From: claincly Date: Fri, 4 Jun 2021 11:15:37 +0100 Subject: [PATCH] Add factory method to for using TCP streaming. #minor-release PiperOrigin-RevId: 377476603 --- RELEASENOTES.md | 1 + .../source/rtsp/RtspMediaPeriod.java | 14 ++++++---- .../source/rtsp/RtspMediaSource.java | 28 +++++++++++++++++-- 3 files changed, 34 insertions(+), 9 deletions(-) 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 rtspMediaTracks; @Nullable private IOException sourcePrepareException; - private RtspMediaSource(MediaItem mediaItem) { + private RtspMediaSource(MediaItem mediaItem, RtpDataChannel.Factory rtpDataChannelFactory) { this.mediaItem = mediaItem; - rtpDataChannelFactory = new UdpDataSourceRtpDataChannelFactory(); + this.rtpDataChannelFactory = rtpDataChannelFactory; } @Override