From 8e24d290405cd5c10e772eccbe0ed6b11ada1206 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 25 Oct 2021 13:13:08 +0100 Subject: [PATCH 1/9] Make the RTSP SocketFactory configurable --- .../exoplayer2/source/rtsp/RtspClient.java | 13 +++++++-- .../source/rtsp/RtspMediaPeriod.java | 12 +++++--- .../source/rtsp/RtspMediaSource.java | 28 +++++++++++++++++-- .../source/rtsp/RtspClientTest.java | 15 ++++++---- .../source/rtsp/RtspMediaPeriodTest.java | 3 +- .../source/rtsp/RtspPlaybackTest.java | 3 +- 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java index 715212d211d..c1b982634a3 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java @@ -124,6 +124,7 @@ public interface PlaybackEventListener { private final PlaybackEventListener playbackEventListener; private final String userAgent; private final boolean debugLoggingEnabled; + @Nullable private final SocketFactory socketFactory; private final ArrayDeque pendingSetupRtpLoadInfos; // TODO(b/172331505) Add a timeout monitor for pending requests. private final SparseArray pendingRequests; @@ -161,11 +162,13 @@ public RtspClient( PlaybackEventListener playbackEventListener, String userAgent, Uri uri, - boolean debugLoggingEnabled) { + boolean debugLoggingEnabled, + @Nullable SocketFactory socketFactory) { this.sessionInfoListener = sessionInfoListener; this.playbackEventListener = playbackEventListener; this.userAgent = userAgent; this.debugLoggingEnabled = debugLoggingEnabled; + this.socketFactory = socketFactory; this.pendingSetupRtpLoadInfos = new ArrayDeque<>(); this.pendingRequests = new SparseArray<>(); this.messageSender = new MessageSender(); @@ -286,10 +289,14 @@ private void maybeLogMessage(List message) { } /** Returns a {@link Socket} that is connected to the {@code uri}. */ - private static Socket getSocket(Uri uri) throws IOException { + private Socket getSocket(Uri uri) throws IOException { checkArgument(uri.getHost() != null); int rtspPort = uri.getPort() > 0 ? uri.getPort() : DEFAULT_RTSP_PORT; - return SocketFactory.getDefault().createSocket(checkNotNull(uri.getHost()), rtspPort); + + SocketFactory socketFactory = + this.socketFactory != null ? this.socketFactory : SocketFactory.getDefault(); + + return socketFactory.createSocket(checkNotNull(uri.getHost()), rtspPort); } private void dispatchRtspError(Throwable error) { 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 435bb59a30e..e71f4d72a3a 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 @@ -55,6 +55,7 @@ import java.net.BindException; import java.util.ArrayList; import java.util.List; +import javax.net.SocketFactory; import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -96,12 +97,13 @@ interface Listener { /** * Creates an RTSP media period. - * - * @param allocator An {@link Allocator} from which to obtain media buffer allocations. + * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param rtpDataChannelFactory A {@link RtpDataChannel.Factory} for {@link RtpDataChannel}. * @param uri The RTSP playback {@link Uri}. * @param listener A {@link Listener} to receive session information updates. * @param userAgent The user agent. + * @param debugLoggingEnabled Whether to log RTSP messages. + * @param socketFactory A socket factory. */ public RtspMediaPeriod( Allocator allocator, @@ -109,7 +111,8 @@ public RtspMediaPeriod( Uri uri, Listener listener, String userAgent, - boolean debugLoggingEnabled) { + boolean debugLoggingEnabled, + @Nullable SocketFactory socketFactory) { this.allocator = allocator; this.rtpDataChannelFactory = rtpDataChannelFactory; this.listener = listener; @@ -122,7 +125,8 @@ public RtspMediaPeriod( /* playbackEventListener= */ internalListener, /* userAgent= */ userAgent, /* uri= */ uri, - debugLoggingEnabled); + debugLoggingEnabled, + socketFactory); rtspLoaderWrappers = new ArrayList<>(); selectedLoadInfos = new ArrayList<>(); 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 63bbeed35c6..54145cad9b6 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 @@ -40,6 +40,7 @@ import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; +import javax.net.SocketFactory; /** An Rtsp {@link MediaSource} */ public final class RtspMediaSource extends BaseMediaSource { @@ -70,6 +71,7 @@ public static final class Factory implements MediaSourceFactory { private String userAgent; private boolean forceUseRtpTcp; private boolean debugLoggingEnabled; + private SocketFactory socketFactory; public Factory() { timeoutMs = DEFAULT_TIMEOUT_MS; @@ -117,6 +119,19 @@ public Factory setDebugLoggingEnabled(boolean debugLoggingEnabled) { return this; } + /** + * Configures a socket factory to be used for client connections. + * + * When unspecified, {@link SocketFactory#getDefault()} is used. + * + * @param socketFactory A socket factory. + * @return This Factory, for convenience. + */ + public Factory setSocketFactory(SocketFactory socketFactory) { + this.socketFactory = socketFactory; + return this; + } + /** * Sets the timeout in milliseconds, the default value is {@link #DEFAULT_TIMEOUT_MS}. * @@ -202,7 +217,8 @@ public RtspMediaSource createMediaSource(MediaItem mediaItem) { ? new TransferRtpDataChannelFactory(timeoutMs) : new UdpDataSourceRtpDataChannelFactory(timeoutMs), userAgent, - debugLoggingEnabled); + debugLoggingEnabled, + socketFactory); } } @@ -227,6 +243,9 @@ public RtspPlaybackException(String message, Throwable e) { private final Uri uri; private final boolean debugLoggingEnabled; + @Nullable + private final SocketFactory socketFactory; + private long timelineDurationUs; private boolean timelineIsSeekable; private boolean timelineIsLive; @@ -237,12 +256,14 @@ public RtspPlaybackException(String message, Throwable e) { MediaItem mediaItem, RtpDataChannel.Factory rtpDataChannelFactory, String userAgent, - boolean debugLoggingEnabled) { + boolean debugLoggingEnabled, + @Nullable SocketFactory socketFactory) { this.mediaItem = mediaItem; this.rtpDataChannelFactory = rtpDataChannelFactory; this.userAgent = userAgent; this.uri = checkNotNull(this.mediaItem.localConfiguration).uri; this.debugLoggingEnabled = debugLoggingEnabled; + this.socketFactory = socketFactory; this.timelineDurationUs = C.TIME_UNSET; this.timelineIsPlaceholder = true; } @@ -281,7 +302,8 @@ public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long star notifySourceInfoRefreshed(); }, userAgent, - debugLoggingEnabled); + debugLoggingEnabled, + socketFactory); } @Override diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index 0018c8a9e43..ca239695ad6 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -113,7 +113,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -164,7 +165,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -207,7 +209,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -253,7 +256,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureMessage.get() != null); @@ -299,7 +303,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureCause.get() != null); diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java index da7da55d8eb..90594f6ca18 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java @@ -84,7 +84,8 @@ public RtspResponse getDescribeResponse(Uri requestedUri) { RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), /* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */ "ExoPlayer:RtspPeriodTest", - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + null); mediaPeriod.prepare( new MediaPeriod.Callback() { diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java index c82f68c0a3b..8ebcbbe36dd 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java @@ -156,7 +156,8 @@ private ExoPlayer createExoPlayer( MediaItem.fromUri(RtspTestUtils.getTestUri(serverRtspPortNumber)), rtpDataChannelFactory, "ExoPlayer:PlaybackTest", - /* debugLoggingEnabled= */ false), + /* debugLoggingEnabled= */ false, + null), false); return player; } From c14a9c09b324caa819386690e582f16a640b15c9 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 25 Oct 2021 16:11:38 +0100 Subject: [PATCH 2/9] docs --- .../google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java | 2 +- .../android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java | 2 +- .../google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 e71f4d72a3a..8d0347138b2 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 @@ -97,7 +97,7 @@ interface Listener { /** * Creates an RTSP media period. - * @param allocator An {@link Allocator} from which to obtain media buffer allocations. + * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param rtpDataChannelFactory A {@link RtpDataChannel.Factory} for {@link RtpDataChannel}. * @param uri The RTSP playback {@link Uri}. * @param listener A {@link Listener} to receive session information updates. diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java index 90594f6ca18..9c77d5406e2 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java @@ -85,7 +85,7 @@ public RtspResponse getDescribeResponse(Uri requestedUri) { /* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */ "ExoPlayer:RtspPeriodTest", /* debugLoggingEnabled= */ false, - null); + /* socketFactory */ null); mediaPeriod.prepare( new MediaPeriod.Callback() { diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java index 8ebcbbe36dd..625f310387d 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java @@ -157,7 +157,7 @@ private ExoPlayer createExoPlayer( rtpDataChannelFactory, "ExoPlayer:PlaybackTest", /* debugLoggingEnabled= */ false, - null), + /* socketFactory */ null), false); return player; } From 4001592c93b411aca2a47f84091b85493bf16095 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 26 Oct 2021 12:58:03 +0100 Subject: [PATCH 3/9] Add a test --- .../source/rtsp/RtspClientTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index ca239695ad6..2ffb507de2b 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -27,8 +27,12 @@ import com.google.android.exoplayer2.source.rtsp.RtspMediaSource.RtspPlaybackException; import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableList; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import javax.net.SocketFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,6 +81,79 @@ public void tearDown() { Util.closeQuietly(rtspClient); } + @Test + public void connectServerAndClient_usesCustomSocketFactory() throws Exception { + class ResponseProvider implements RtspServer.ResponseProvider { + @Override + public RtspResponse getOptionsResponse() { + return new RtspResponse( + /* status= */ 200, + new RtspHeaders.Builder().add(RtspHeaders.PUBLIC, "OPTIONS, DESCRIBE").build()); + } + + @Override + public RtspResponse getDescribeResponse(Uri requestedUri) { + return RtspTestUtils.newDescribeResponseWithSdpMessage( + SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri); + } + } + rtspServer = new RtspServer(new ResponseProvider()); + + final AtomicReference didCallCreateSocket = new AtomicReference<>(); + + final SocketFactory socketFactory = + new SocketFactory() { + + @Override + public Socket createSocket(String host, int port) throws IOException { + didCallCreateSocket.set(true); + + return SocketFactory.getDefault().createSocket(host, port); + } + + @Override + public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) + throws IOException { + return SocketFactory.getDefault().createSocket(s, i, inetAddress, i1); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + return SocketFactory.getDefault().createSocket(inetAddress, i); + } + + @Override + public Socket createSocket( + InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { + return SocketFactory.getDefault().createSocket(inetAddress, i, inetAddress1, i1); + } + }; + + AtomicReference> tracksInSession = new AtomicReference<>(); + rtspClient = + new RtspClient( + new SessionInfoListener() { + @Override + public void onSessionTimelineUpdated( + RtspSessionTiming timing, ImmutableList 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, + socketFactory); + rtspClient.start(); + RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); + + assertThat(didCallCreateSocket.get()).isTrue(); + } + @Test public void connectServerAndClient_serverSupportsDescribe_updatesSessionTimeline() throws Exception { From 6dd2177a85cbef092502608a7b45c16e9ff963b9 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 26 Oct 2021 12:58:08 +0100 Subject: [PATCH 4/9] Add release notes --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2ace17dc48a..5e3a4aa6751 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -73,6 +73,8 @@ * RTSP: * Support RFC4566 SDP attribute field grammar ([#9430](https://github.com/google/ExoPlayer/issues/9430)). + * Provide a client API to override the `SocketFactory` used for any server + connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). * DASH: * Populate `Format.sampleMimeType`, `width` and `height` for image `AdaptationSet` elements From 1ecbdb8d9ceade788930da73bc0cb4d292b1047f Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 26 Oct 2021 12:58:49 +0100 Subject: [PATCH 5/9] formatting --- RELEASENOTES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5e3a4aa6751..17a41a06184 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -73,8 +73,8 @@ * RTSP: * Support RFC4566 SDP attribute field grammar ([#9430](https://github.com/google/ExoPlayer/issues/9430)). - * Provide a client API to override the `SocketFactory` used for any server - connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). + * Provide a client API to override the `SocketFactory` used for any server + connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). * DASH: * Populate `Format.sampleMimeType`, `width` and `height` for image `AdaptationSet` elements From 0830c06cd7e72695543978484446180512fad842 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 2 Nov 2021 14:58:15 +0000 Subject: [PATCH 6/9] PR feedback --- .../exoplayer2/source/rtsp/RtspClient.java | 11 ++++----- .../source/rtsp/RtspMediaPeriod.java | 10 ++++---- .../source/rtsp/RtspMediaSource.java | 23 ++++++++---------- .../source/rtsp/RtspClientTest.java | 24 +++++++++---------- .../source/rtsp/RtspMediaPeriodTest.java | 5 ++-- .../source/rtsp/RtspPlaybackTest.java | 5 ++-- 6 files changed, 38 insertions(+), 40 deletions(-) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java index c1b982634a3..e4f94403e6c 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java @@ -123,8 +123,8 @@ public interface PlaybackEventListener { private final SessionInfoListener sessionInfoListener; private final PlaybackEventListener playbackEventListener; private final String userAgent; + private final SocketFactory socketFactory; private final boolean debugLoggingEnabled; - @Nullable private final SocketFactory socketFactory; private final ArrayDeque pendingSetupRtpLoadInfos; // TODO(b/172331505) Add a timeout monitor for pending requests. private final SparseArray pendingRequests; @@ -156,14 +156,16 @@ public interface PlaybackEventListener { * @param playbackEventListener The {@link PlaybackEventListener}. * @param userAgent The user agent. * @param uri The RTSP playback URI. + * @param socketFactory The {@link SocketFactory} for the client connection. + * @param debugLoggingEnabled Whether to print RTSP messages. */ public RtspClient( SessionInfoListener sessionInfoListener, PlaybackEventListener playbackEventListener, String userAgent, Uri uri, - boolean debugLoggingEnabled, - @Nullable SocketFactory socketFactory) { + SocketFactory socketFactory, + boolean debugLoggingEnabled) { this.sessionInfoListener = sessionInfoListener; this.playbackEventListener = playbackEventListener; this.userAgent = userAgent; @@ -293,9 +295,6 @@ private Socket getSocket(Uri uri) throws IOException { checkArgument(uri.getHost() != null); int rtspPort = uri.getPort() > 0 ? uri.getPort() : DEFAULT_RTSP_PORT; - SocketFactory socketFactory = - this.socketFactory != null ? this.socketFactory : SocketFactory.getDefault(); - return socketFactory.createSocket(checkNotNull(uri.getHost()), rtspPort); } 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 8d0347138b2..cea3c4e85d5 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 @@ -103,7 +103,7 @@ interface Listener { * @param listener A {@link Listener} to receive session information updates. * @param userAgent The user agent. * @param debugLoggingEnabled Whether to log RTSP messages. - * @param socketFactory A socket factory. + * @param socketFactory A socket factory for {@link RtspClient}'s connection. */ public RtspMediaPeriod( Allocator allocator, @@ -111,8 +111,8 @@ public RtspMediaPeriod( Uri uri, Listener listener, String userAgent, - boolean debugLoggingEnabled, - @Nullable SocketFactory socketFactory) { + SocketFactory socketFactory, + boolean debugLoggingEnabled) { this.allocator = allocator; this.rtpDataChannelFactory = rtpDataChannelFactory; this.listener = listener; @@ -125,8 +125,8 @@ public RtspMediaPeriod( /* playbackEventListener= */ internalListener, /* userAgent= */ userAgent, /* uri= */ uri, - debugLoggingEnabled, - socketFactory); + socketFactory, + debugLoggingEnabled); rtspLoaderWrappers = new ArrayList<>(); selectedLoadInfos = new ArrayList<>(); 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 54145cad9b6..9fb0912f9d8 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 @@ -69,9 +69,9 @@ public static final class Factory implements MediaSourceFactory { private long timeoutMs; private String userAgent; + @Nullable private SocketFactory socketFactory; private boolean forceUseRtpTcp; private boolean debugLoggingEnabled; - private SocketFactory socketFactory; public Factory() { timeoutMs = DEFAULT_TIMEOUT_MS; @@ -120,9 +120,8 @@ public Factory setDebugLoggingEnabled(boolean debugLoggingEnabled) { } /** - * Configures a socket factory to be used for client connections. - * - * When unspecified, {@link SocketFactory#getDefault()} is used. + * Sets a socket factory for {@link RtspClient}'s connection, the default value is {@link + * SocketFactory#getDefault()}. * * @param socketFactory A socket factory. * @return This Factory, for convenience. @@ -217,8 +216,8 @@ public RtspMediaSource createMediaSource(MediaItem mediaItem) { ? new TransferRtpDataChannelFactory(timeoutMs) : new UdpDataSourceRtpDataChannelFactory(timeoutMs), userAgent, - debugLoggingEnabled, - socketFactory); + socketFactory == null ? SocketFactory.getDefault() : socketFactory, + debugLoggingEnabled); } } @@ -241,10 +240,8 @@ public RtspPlaybackException(String message, Throwable e) { private final RtpDataChannel.Factory rtpDataChannelFactory; private final String userAgent; private final Uri uri; - private final boolean debugLoggingEnabled; - - @Nullable private final SocketFactory socketFactory; + private final boolean debugLoggingEnabled; private long timelineDurationUs; private boolean timelineIsSeekable; @@ -256,8 +253,8 @@ public RtspPlaybackException(String message, Throwable e) { MediaItem mediaItem, RtpDataChannel.Factory rtpDataChannelFactory, String userAgent, - boolean debugLoggingEnabled, - @Nullable SocketFactory socketFactory) { + SocketFactory socketFactory, + boolean debugLoggingEnabled) { this.mediaItem = mediaItem; this.rtpDataChannelFactory = rtpDataChannelFactory; this.userAgent = userAgent; @@ -302,8 +299,8 @@ public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long star notifySourceInfoRefreshed(); }, userAgent, - debugLoggingEnabled, - socketFactory); + socketFactory, + debugLoggingEnabled); } @Override diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index 2ffb507de2b..89a0b242873 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -146,8 +146,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - socketFactory); + socketFactory, + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -190,8 +190,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ null, + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -242,8 +242,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -286,8 +286,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -333,8 +333,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureMessage.get() != null); @@ -380,8 +380,8 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureCause.get() != null); diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java index 9c77d5406e2..45da1a3785c 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java @@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import javax.net.SocketFactory; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -84,8 +85,8 @@ public RtspResponse getDescribeResponse(Uri requestedUri) { RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), /* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */ "ExoPlayer:RtspPeriodTest", - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); mediaPeriod.prepare( new MediaPeriod.Callback() { diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java index 625f310387d..9f464ee5c37 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java @@ -46,6 +46,7 @@ import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicReference; +import javax.net.SocketFactory; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -156,8 +157,8 @@ private ExoPlayer createExoPlayer( MediaItem.fromUri(RtspTestUtils.getTestUri(serverRtspPortNumber)), rtpDataChannelFactory, "ExoPlayer:PlaybackTest", - /* debugLoggingEnabled= */ false, - /* socketFactory */ null), + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false), false); return player; } From b7b490326268a4a097a2c276e42474a5df52cdd4 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 2 Nov 2021 15:07:46 +0000 Subject: [PATCH 7/9] some RTSP docs --- docs/rtsp.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/rtsp.md b/docs/rtsp.md index 9c4cd38753d..674f100efda 100644 --- a/docs/rtsp.md +++ b/docs/rtsp.md @@ -51,6 +51,30 @@ player.prepare(); ~~~ {: .language-java} +### Passing a custom SocketFactory + +By default, `RtspMediaSource` will use Java's standard socket factory (`SocketFactory.getDefault()`) +to create connections to the remote endpoints. This behavior can be overridden using +`.setSocketFactory()`. + +~~~ +// Create an RTSP media source pointing to an RTSP uri and override the socket factory. +MediaSource mediaSource = + new RtspMediaSource.Factory() + .setSocketFactory(...) + .createMediaSource(MediaItem.fromUri(rtspUri)); +// Create a player instance. +ExoPlayer player = new ExoPlayer.Builder(context).build(); +// Set the media source to be played. +player.setMediaSource(mediaSource); +// Prepare the player. +player.prepare(); +~~~ +{: .language-java} + +Custom `SocketFactory` instances can be useful when particular routing is required (e.g. when RTSP +traffic needs to pass a specific interface, or the socket needs additional connectivity flags). + ## Using RTSP behind a NAT (RTP/TCP support) ## ExoPlayer uses UDP as the default protocol for RTP transport. From ab397e408a7a34a3b9e914559644f7e2b6720fdc Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 5 Nov 2021 11:10:29 +0000 Subject: [PATCH 8/9] move release notes entry --- RELEASENOTES.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 093665e6473..8adfa66e6bf 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -8,6 +8,9 @@ `buildVideoRenderers()` or `buildAudioRenderers()` can access the codec adapter factory and pass it to `MediaCodecRenderer` instances they create. +* RTSP + * Provide a client API to override the `SocketFactory` used for any server + connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). ### 2.16.0 (2021-11-04) @@ -90,8 +93,6 @@ * RTSP: * Support RFC4566 SDP attribute field grammar ([#9430](https://github.com/google/ExoPlayer/issues/9430)). - * Provide a client API to override the `SocketFactory` used for any server - connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). * DASH: * Populate `Format.sampleMimeType`, `width` and `height` for image `AdaptationSet` elements From c09fa7560d5c7158fa51f0254d47d1f2a536af2b Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Wed, 10 Nov 2021 16:41:48 +0000 Subject: [PATCH 9/9] PR feedback --- .../google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java | 2 +- .../google/android/exoplayer2/source/rtsp/RtspClientTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 cea3c4e85d5..3a60ea7d003 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 @@ -102,8 +102,8 @@ interface Listener { * @param uri The RTSP playback {@link Uri}. * @param listener A {@link Listener} to receive session information updates. * @param userAgent The user agent. - * @param debugLoggingEnabled Whether to log RTSP messages. * @param socketFactory A socket factory for {@link RtspClient}'s connection. + * @param debugLoggingEnabled Whether to log RTSP messages. */ public RtspMediaPeriod( Allocator allocator, diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index 89a0b242873..55d2366f406 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -190,7 +190,7 @@ public void onSessionTimelineRequestFailed( EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* socketFactory */ null, + /* socketFactory */ SocketFactory.getDefault(), /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null);