Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e288f94

Browse filesBrowse files
committed
Merge pull request #9606 from ened:rtsp-socket-factory
PiperOrigin-RevId: 413751821
2 parents fc99237 + e158f9a commit e288f94
Copy full SHA for e288f94

File tree

Expand file treeCollapse file tree

8 files changed

+143
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

8 files changed

+143
-2
lines changed
Open diff view settings
Collapse file

‎RELEASENOTES.md‎

Copy file name to clipboardExpand all lines: RELEASENOTES.md
+3Lines changed: 3 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
* MediaSession extension
3939
* Remove deprecated call to `onStop(/* reset= */ true)` and provide an
4040
opt-out flag for apps that don't want to clear the playlist on stop.
41+
* RTSP
42+
* Provide a client API to override the `SocketFactory` used for any server
43+
connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)).
4144

4245
### 2.16.1 (2021-11-18)
4346

Collapse file

‎docs/rtsp.md‎

Copy file name to clipboardExpand all lines: docs/rtsp.md
+21Lines changed: 21 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,24 @@ end-of-stream signal under poor network conditions.
7575
RTP/TCP offers better compatibility under some network setups. You can configure
7676
ExoPlayer to use RTP/TCP by default with
7777
`RtspMediaSource.Factory.setForceUseRtpTcp()`.
78+
79+
### Passing a custom SocketFactory
80+
Custom `SocketFactory` instances can be useful when particular routing is
81+
required (e.g. when RTSP traffic needs to pass a specific interface, or the
82+
socket needs additional connectivity flags).
83+
84+
By default, `RtspMediaSource` will use Java's standard socket factory
85+
(`SocketFactory.getDefault()`) to create connections to the remote endpoints.
86+
This behavior can be overridden using
87+
`RtspMediaSource.Factory.setSocketFactory()`.
88+
89+
~~~
90+
// Create an RTSP media source pointing to an RTSP uri and override the socket
91+
// factory.
92+
MediaSource mediaSource =
93+
new RtspMediaSource.Factory()
94+
.setSocketFactory(...)
95+
.createMediaSource(MediaItem.fromUri(rtspUri));
96+
~~~
97+
{: .language-java}
98+
Collapse file

‎library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java‎

Copy file name to clipboardExpand all lines: library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java
+7-2Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ public interface PlaybackEventListener {
123123
private final SessionInfoListener sessionInfoListener;
124124
private final PlaybackEventListener playbackEventListener;
125125
private final String userAgent;
126+
private final SocketFactory socketFactory;
126127
private final boolean debugLoggingEnabled;
127128
private final ArrayDeque<RtpLoadInfo> pendingSetupRtpLoadInfos;
128129
// TODO(b/172331505) Add a timeout monitor for pending requests.
@@ -155,16 +156,20 @@ public interface PlaybackEventListener {
155156
* @param playbackEventListener The {@link PlaybackEventListener}.
156157
* @param userAgent The user agent.
157158
* @param uri The RTSP playback URI.
159+
* @param socketFactory A socket factory for the RTSP connection.
160+
* @param debugLoggingEnabled Whether to log RTSP messages.
158161
*/
159162
public RtspClient(
160163
SessionInfoListener sessionInfoListener,
161164
PlaybackEventListener playbackEventListener,
162165
String userAgent,
163166
Uri uri,
167+
SocketFactory socketFactory,
164168
boolean debugLoggingEnabled) {
165169
this.sessionInfoListener = sessionInfoListener;
166170
this.playbackEventListener = playbackEventListener;
167171
this.userAgent = userAgent;
172+
this.socketFactory = socketFactory;
168173
this.debugLoggingEnabled = debugLoggingEnabled;
169174
this.pendingSetupRtpLoadInfos = new ArrayDeque<>();
170175
this.pendingRequests = new SparseArray<>();
@@ -286,10 +291,10 @@ private void maybeLogMessage(List<String> message) {
286291
}
287292

288293
/** Returns a {@link Socket} that is connected to the {@code uri}. */
289-
private static Socket getSocket(Uri uri) throws IOException {
294+
private Socket getSocket(Uri uri) throws IOException {
290295
checkArgument(uri.getHost() != null);
291296
int rtspPort = uri.getPort() > 0 ? uri.getPort() : DEFAULT_RTSP_PORT;
292-
return SocketFactory.getDefault().createSocket(checkNotNull(uri.getHost()), rtspPort);
297+
return socketFactory.createSocket(checkNotNull(uri.getHost()), rtspPort);
293298
}
294299

295300
private void dispatchRtspError(Throwable error) {
Collapse file

‎library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java‎

Copy file name to clipboardExpand all lines: library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import java.net.BindException;
5656
import java.util.ArrayList;
5757
import java.util.List;
58+
import javax.net.SocketFactory;
5859
import org.checkerframework.checker.nullness.compatqual.NullableType;
5960
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
6061

@@ -102,13 +103,16 @@ interface Listener {
102103
* @param uri The RTSP playback {@link Uri}.
103104
* @param listener A {@link Listener} to receive session information updates.
104105
* @param userAgent The user agent.
106+
* @param socketFactory A socket factory for {@link RtspClient}'s connection.
107+
* @param debugLoggingEnabled Whether to log RTSP messages.
105108
*/
106109
public RtspMediaPeriod(
107110
Allocator allocator,
108111
RtpDataChannel.Factory rtpDataChannelFactory,
109112
Uri uri,
110113
Listener listener,
111114
String userAgent,
115+
SocketFactory socketFactory,
112116
boolean debugLoggingEnabled) {
113117
this.allocator = allocator;
114118
this.rtpDataChannelFactory = rtpDataChannelFactory;
@@ -122,6 +126,7 @@ public RtspMediaPeriod(
122126
/* playbackEventListener= */ internalListener,
123127
/* userAgent= */ userAgent,
124128
/* uri= */ uri,
129+
socketFactory,
125130
debugLoggingEnabled);
126131
rtspLoaderWrappers = new ArrayList<>();
127132
selectedLoadInfos = new ArrayList<>();
Collapse file

‎library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java‎

Copy file name to clipboardExpand all lines: library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.google.android.exoplayer2.upstream.TransferListener;
4242
import com.google.android.exoplayer2.util.Util;
4343
import java.io.IOException;
44+
import javax.net.SocketFactory;
4445

4546
/** An Rtsp {@link MediaSource} */
4647
public final class RtspMediaSource extends BaseMediaSource {
@@ -69,12 +70,14 @@ public static final class Factory implements MediaSourceFactory {
6970

7071
private long timeoutMs;
7172
private String userAgent;
73+
private SocketFactory socketFactory;
7274
private boolean forceUseRtpTcp;
7375
private boolean debugLoggingEnabled;
7476

7577
public Factory() {
7678
timeoutMs = DEFAULT_TIMEOUT_MS;
7779
userAgent = ExoPlayerLibraryInfo.VERSION_SLASHY;
80+
socketFactory = SocketFactory.getDefault();
7881
}
7982

8083
/**
@@ -104,6 +107,18 @@ public Factory setUserAgent(String userAgent) {
104107
return this;
105108
}
106109

110+
/**
111+
* Sets a socket factory for {@link RtspClient}'s connection, the default value is {@link
112+
* SocketFactory#getDefault()}.
113+
*
114+
* @param socketFactory A socket factory.
115+
* @return This Factory, for convenience.
116+
*/
117+
public Factory setSocketFactory(SocketFactory socketFactory) {
118+
this.socketFactory = socketFactory;
119+
return this;
120+
}
121+
107122
/**
108123
* Sets whether to log RTSP messages, the default value is {@code false}.
109124
*
@@ -203,6 +218,7 @@ public RtspMediaSource createMediaSource(MediaItem mediaItem) {
203218
? new TransferRtpDataChannelFactory(timeoutMs)
204219
: new UdpDataSourceRtpDataChannelFactory(timeoutMs),
205220
userAgent,
221+
socketFactory,
206222
debugLoggingEnabled);
207223
}
208224
}
@@ -226,6 +242,7 @@ public RtspPlaybackException(String message, Throwable e) {
226242
private final RtpDataChannel.Factory rtpDataChannelFactory;
227243
private final String userAgent;
228244
private final Uri uri;
245+
private final SocketFactory socketFactory;
229246
private final boolean debugLoggingEnabled;
230247

231248
private long timelineDurationUs;
@@ -238,11 +255,13 @@ public RtspPlaybackException(String message, Throwable e) {
238255
MediaItem mediaItem,
239256
RtpDataChannel.Factory rtpDataChannelFactory,
240257
String userAgent,
258+
SocketFactory socketFactory,
241259
boolean debugLoggingEnabled) {
242260
this.mediaItem = mediaItem;
243261
this.rtpDataChannelFactory = rtpDataChannelFactory;
244262
this.userAgent = userAgent;
245263
this.uri = checkNotNull(this.mediaItem.localConfiguration).uri;
264+
this.socketFactory = socketFactory;
246265
this.debugLoggingEnabled = debugLoggingEnabled;
247266
this.timelineDurationUs = C.TIME_UNSET;
248267
this.timelineIsPlaceholder = true;
@@ -282,6 +301,7 @@ public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long star
282301
notifySourceInfoRefreshed();
283302
},
284303
userAgent,
304+
socketFactory,
285305
debugLoggingEnabled);
286306
}
287307

Collapse file

‎library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java‎

Copy file name to clipboardExpand all lines: library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java
+83Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
import com.google.android.exoplayer2.source.rtsp.RtspMediaSource.RtspPlaybackException;
2828
import com.google.android.exoplayer2.util.Util;
2929
import com.google.common.collect.ImmutableList;
30+
import java.io.IOException;
31+
import java.net.InetAddress;
32+
import java.net.Socket;
3033
import java.util.concurrent.atomic.AtomicBoolean;
3134
import java.util.concurrent.atomic.AtomicReference;
35+
import javax.net.SocketFactory;
3236
import org.junit.After;
3337
import org.junit.Before;
3438
import org.junit.Test;
@@ -77,6 +81,80 @@ public void tearDown() {
7781
Util.closeQuietly(rtspClient);
7882
}
7983

84+
@Test
85+
public void connectServerAndClient_usesCustomSocketFactory() throws Exception {
86+
class ResponseProvider implements RtspServer.ResponseProvider {
87+
@Override
88+
public RtspResponse getOptionsResponse() {
89+
return new RtspResponse(
90+
/* status= */ 200,
91+
new RtspHeaders.Builder().add(RtspHeaders.PUBLIC, "OPTIONS, DESCRIBE").build());
92+
}
93+
94+
@Override
95+
public RtspResponse getDescribeResponse(Uri requestedUri) {
96+
return RtspTestUtils.newDescribeResponseWithSdpMessage(
97+
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
98+
}
99+
}
100+
rtspServer = new RtspServer(new ResponseProvider());
101+
102+
AtomicBoolean didCallCreateSocket = new AtomicBoolean();
103+
SocketFactory socketFactory =
104+
new SocketFactory() {
105+
106+
@Override
107+
public Socket createSocket(String host, int port) throws IOException {
108+
didCallCreateSocket.set(true);
109+
return SocketFactory.getDefault().createSocket(host, port);
110+
}
111+
112+
@Override
113+
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1)
114+
throws IOException {
115+
didCallCreateSocket.set(true);
116+
return SocketFactory.getDefault().createSocket(s, i, inetAddress, i1);
117+
}
118+
119+
@Override
120+
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
121+
didCallCreateSocket.set(true);
122+
return SocketFactory.getDefault().createSocket(inetAddress, i);
123+
}
124+
125+
@Override
126+
public Socket createSocket(
127+
InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
128+
didCallCreateSocket.set(true);
129+
return SocketFactory.getDefault().createSocket(inetAddress, i, inetAddress1, i1);
130+
}
131+
};
132+
133+
AtomicReference<ImmutableList<RtspMediaTrack>> tracksInSession = new AtomicReference<>();
134+
rtspClient =
135+
new RtspClient(
136+
new SessionInfoListener() {
137+
@Override
138+
public void onSessionTimelineUpdated(
139+
RtspSessionTiming timing, ImmutableList<RtspMediaTrack> tracks) {
140+
tracksInSession.set(tracks);
141+
}
142+
143+
@Override
144+
public void onSessionTimelineRequestFailed(
145+
String message, @Nullable Throwable cause) {}
146+
},
147+
EMPTY_PLAYBACK_LISTENER,
148+
/* userAgent= */ "ExoPlayer:RtspClientTest",
149+
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
150+
socketFactory,
151+
/* debugLoggingEnabled= */ false);
152+
rtspClient.start();
153+
RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null);
154+
155+
assertThat(didCallCreateSocket.get()).isTrue();
156+
}
157+
80158
@Test
81159
public void connectServerAndClient_serverSupportsDescribe_updatesSessionTimeline()
82160
throws Exception {
@@ -113,6 +191,7 @@ public void onSessionTimelineRequestFailed(
113191
EMPTY_PLAYBACK_LISTENER,
114192
/* userAgent= */ "ExoPlayer:RtspClientTest",
115193
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
194+
SocketFactory.getDefault(),
116195
/* debugLoggingEnabled= */ false);
117196
rtspClient.start();
118197
RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null);
@@ -164,6 +243,7 @@ public void onSessionTimelineRequestFailed(
164243
EMPTY_PLAYBACK_LISTENER,
165244
/* userAgent= */ "ExoPlayer:RtspClientTest",
166245
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
246+
SocketFactory.getDefault(),
167247
/* debugLoggingEnabled= */ false);
168248
rtspClient.start();
169249
RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null);
@@ -207,6 +287,7 @@ public void onSessionTimelineRequestFailed(
207287
EMPTY_PLAYBACK_LISTENER,
208288
/* userAgent= */ "ExoPlayer:RtspClientTest",
209289
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
290+
SocketFactory.getDefault(),
210291
/* debugLoggingEnabled= */ false);
211292
rtspClient.start();
212293
RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null);
@@ -253,6 +334,7 @@ public void onSessionTimelineRequestFailed(
253334
EMPTY_PLAYBACK_LISTENER,
254335
/* userAgent= */ "ExoPlayer:RtspClientTest",
255336
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
337+
SocketFactory.getDefault(),
256338
/* debugLoggingEnabled= */ false);
257339
rtspClient.start();
258340
RobolectricUtil.runMainLooperUntil(() -> failureMessage.get() != null);
@@ -299,6 +381,7 @@ public void onSessionTimelineRequestFailed(
299381
EMPTY_PLAYBACK_LISTENER,
300382
/* userAgent= */ "ExoPlayer:RtspClientTest",
301383
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
384+
SocketFactory.getDefault(),
302385
/* debugLoggingEnabled= */ false);
303386
rtspClient.start();
304387

Collapse file

‎library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java‎

Copy file name to clipboardExpand all lines: library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.google.common.collect.ImmutableList;
2828
import java.util.concurrent.atomic.AtomicBoolean;
2929
import java.util.concurrent.atomic.AtomicLong;
30+
import javax.net.SocketFactory;
3031
import org.junit.After;
3132
import org.junit.Test;
3233
import org.junit.runner.RunWith;
@@ -84,6 +85,7 @@ public RtspResponse getDescribeResponse(Uri requestedUri) {
8485
RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()),
8586
/* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()),
8687
/* userAgent= */ "ExoPlayer:RtspPeriodTest",
88+
/* socketFactory= */ SocketFactory.getDefault(),
8789
/* debugLoggingEnabled= */ false);
8890

8991
mediaPeriod.prepare(
Collapse file

‎library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java‎

Copy file name to clipboardExpand all lines: library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.List;
4747
import java.util.concurrent.ConcurrentLinkedQueue;
4848
import java.util.concurrent.atomic.AtomicReference;
49+
import javax.net.SocketFactory;
4950
import org.junit.Before;
5051
import org.junit.Rule;
5152
import org.junit.Test;
@@ -156,6 +157,7 @@ private ExoPlayer createExoPlayer(
156157
MediaItem.fromUri(RtspTestUtils.getTestUri(serverRtspPortNumber)),
157158
rtpDataChannelFactory,
158159
"ExoPlayer:PlaybackTest",
160+
SocketFactory.getDefault(),
159161
/* debugLoggingEnabled= */ false),
160162
false);
161163
return player;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.