Add factory method to for using TCP streaming.

#minor-release

PiperOrigin-RevId: 377476603
This commit is contained in:
claincly 2021-06-04 11:15:37 +01:00 committed by Oliver Woodman
parent c15acdf0db
commit 74ff9f21f0
3 changed files with 34 additions and 9 deletions

View File

@ -46,6 +46,7 @@
* GL demo app: * GL demo app:
* Fix texture transformation to avoid green bars shown on some videos * Fix texture transformation to avoid green bars shown on some videos
([#8992](https://github.com/google/ExoPlayer/issues/8992)). ([#8992](https://github.com/google/ExoPlayer/issues/8992)).
* Add `RtspMediaSource.Factory` option to force using TCP for streaming.
### 2.14.0 (2021-05-13) ### 2.14.0 (2021-05-13)

View File

@ -84,7 +84,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private boolean prepared; private boolean prepared;
private boolean trackSelected; private boolean trackSelected;
private int portBindingRetryCount; private int portBindingRetryCount;
private boolean hasRetriedWithRtpTcp; private boolean isUsingRtpTcp;
/** /**
* Creates an RTSP media period. * Creates an RTSP media period.
@ -514,12 +514,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private LoadErrorAction handleSocketTimeout(RtpDataLoadable loadable) { private LoadErrorAction handleSocketTimeout(RtpDataLoadable loadable) {
// TODO(b/172331505) Allow for retry when loading is not ending. // TODO(b/172331505) Allow for retry when loading is not ending.
if (getBufferedPositionUs() == Long.MIN_VALUE) { if (getBufferedPositionUs() == Long.MIN_VALUE) {
// Retry playback with TCP if no sample has been received so far. if (!isUsingRtpTcp) {
if (!hasRetriedWithRtpTcp) { // 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(); retryWithRtpTcp();
hasRetriedWithRtpTcp = true; isUsingRtpTcp = true;
} }
// Don't retry with the current UDP backed loadables.
return Loader.DONT_RETRY; return Loader.DONT_RETRY;
} }
@ -685,6 +686,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
RtspMediaTrack mediaTrack, int trackId, RtpDataChannel.Factory rtpDataChannelFactory) { RtspMediaTrack mediaTrack, int trackId, RtpDataChannel.Factory rtpDataChannelFactory) {
this.mediaTrack = mediaTrack; this.mediaTrack = mediaTrack;
// This listener runs on the playback thread, posted by the Loader thread.
RtpDataLoadable.EventListener transportEventListener = RtpDataLoadable.EventListener transportEventListener =
(transport, rtpDataChannel) -> { (transport, rtpDataChannel) -> {
RtpLoadInfo.this.transport = transport; RtpLoadInfo.this.transport = transport;
@ -695,8 +697,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (interleavedBinaryDataListener != null) { if (interleavedBinaryDataListener != null) {
rtspClient.registerInterleavedDataChannel( rtspClient.registerInterleavedDataChannel(
rtpDataChannel.getLocalPort(), interleavedBinaryDataListener); rtpDataChannel.getLocalPort(), interleavedBinaryDataListener);
isUsingRtpTcp = true;
} }
maybeSetupTracks(); maybeSetupTracks();
}; };

View File

@ -58,6 +58,24 @@ public final class RtspMediaSource extends BaseMediaSource {
*/ */
public static final class Factory implements MediaSourceFactory { public static final class Factory implements MediaSourceFactory {
private boolean forceUseRtpTcp;
/**
* Sets whether to force using TCP as the default RTP transport.
*
* <p>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. */ /** Does nothing. {@link RtspMediaSource} does not support DRM. */
@Override @Override
public Factory setDrmSessionManagerProvider( public Factory setDrmSessionManagerProvider(
@ -122,7 +140,11 @@ public final class RtspMediaSource extends BaseMediaSource {
@Override @Override
public RtspMediaSource createMediaSource(MediaItem mediaItem) { public RtspMediaSource createMediaSource(MediaItem mediaItem) {
checkNotNull(mediaItem.playbackProperties); 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<RtspMediaTrack> rtspMediaTracks; @Nullable private ImmutableList<RtspMediaTrack> rtspMediaTracks;
@Nullable private IOException sourcePrepareException; @Nullable private IOException sourcePrepareException;
private RtspMediaSource(MediaItem mediaItem) { private RtspMediaSource(MediaItem mediaItem, RtpDataChannel.Factory rtpDataChannelFactory) {
this.mediaItem = mediaItem; this.mediaItem = mediaItem;
rtpDataChannelFactory = new UdpDataSourceRtpDataChannelFactory(); this.rtpDataChannelFactory = rtpDataChannelFactory;
} }
@Override @Override