diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2d64edf7e44..2257f82b80c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -77,6 +77,8 @@ ([#56](https://github.com/androidx/media/pull/56)). * Fix RTSP basic authorization header. ([#9544](https://github.com/google/ExoPlayer/issues/9544)). + * Stop checking mandatory SDP fields as ExoPlayer doesn't need them + ([#10049](https://github.com/google/ExoPlayer/issues/10049)). * Throw checked exception when parsing RTSP timing ([#10165](https://github.com/google/ExoPlayer/issues/10165)). * Session: diff --git a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescription.java b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescription.java index 797886fcf25..5ed534fa909 100644 --- a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescription.java +++ b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescription.java @@ -201,13 +201,8 @@ public Builder addMediaDescription(MediaDescription mediaDescription) { * Builds a new {@link SessionDescription} instance. * * @return The newly built {@link SessionDescription} instance. - * @throws IllegalStateException When one or more of {@link #sessionName}, {@link #timing} and - * {@link #origin} is not set. */ public SessionDescription build() { - if (sessionName == null || origin == null || timing == null) { - throw new IllegalStateException("One of more mandatory SDP fields are not set."); - } return new SessionDescription(this); } } @@ -239,11 +234,11 @@ public SessionDescription build() { */ public final ImmutableList mediaDescriptionList; /** The name of a session. */ - public final String sessionName; + @Nullable public final String sessionName; /** The origin sender info. */ - public final String origin; + @Nullable public final String origin; /** The timing info. */ - public final String timing; + @Nullable public final String timing; /** The estimated bitrate in bits per seconds. */ public final int bitrate; /** The uri of a linked content. */ @@ -287,9 +282,9 @@ public boolean equals(@Nullable Object o) { return bitrate == that.bitrate && attributes.equals(that.attributes) && mediaDescriptionList.equals(that.mediaDescriptionList) - && origin.equals(that.origin) - && sessionName.equals(that.sessionName) - && timing.equals(that.timing) + && Util.areEqual(origin, that.origin) + && Util.areEqual(sessionName, that.sessionName) + && Util.areEqual(timing, that.timing) && Util.areEqual(sessionInfo, that.sessionInfo) && Util.areEqual(uri, that.uri) && Util.areEqual(emailAddress, that.emailAddress) @@ -303,9 +298,9 @@ public int hashCode() { int result = 7; result = 31 * result + attributes.hashCode(); result = 31 * result + mediaDescriptionList.hashCode(); - result = 31 * result + origin.hashCode(); - result = 31 * result + sessionName.hashCode(); - result = 31 * result + timing.hashCode(); + result = 31 * result + (origin == null ? 0 : origin.hashCode()); + result = 31 * result + (sessionName == null ? 0 : sessionName.hashCode()); + result = 31 * result + (timing == null ? 0 : timing.hashCode()); result = 31 * result + bitrate; result = 31 * result + (sessionInfo == null ? 0 : sessionInfo.hashCode()); result = 31 * result + (uri == null ? 0 : uri.hashCode()); diff --git a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java index e754c7863ca..4fdc1fc2740 100644 --- a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java +++ b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/RtspClientTest.java @@ -19,7 +19,6 @@ import android.net.Uri; import androidx.annotation.Nullable; -import androidx.media3.common.ParserException; import androidx.media3.common.util.Util; import androidx.media3.exoplayer.rtsp.RtspClient.PlaybackEventListener; import androidx.media3.exoplayer.rtsp.RtspClient.SessionInfoListener; @@ -345,7 +344,7 @@ public void onSessionTimelineRequestFailed( } @Test - public void connectServerAndClient_malformedSdpInDescribeResponse_doesNotUpdateTimeline() + public void connectServerAndClient_sdpInDescribeResponseHasNoTracks_doesNotUpdateTimeline() throws Exception { class ResponseProvider implements RtspServer.ResponseProvider { @Override @@ -357,14 +356,16 @@ public RtspResponse getOptionsResponse() { @Override public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) { - // This session description misses required the o, t and s tags. return RtspTestUtils.newDescribeResponseWithSdpMessage( - /* sessionDescription= */ "v=0\r\n", rtpPacketStreamDumps, requestedUri); + /* sessionDescription= */ "v=0\r\n", + // This session description has no tracks. + /* rtpPacketStreamDumps= */ ImmutableList.of(), + requestedUri); } } rtspServer = new RtspServer(new ResponseProvider()); - AtomicReference failureCause = new AtomicReference<>(); + AtomicBoolean timelineRequestFailed = new AtomicBoolean(); rtspClient = new RtspClient( new SessionInfoListener() { @@ -375,7 +376,7 @@ public void onSessionTimelineUpdated( @Override public void onSessionTimelineRequestFailed( String message, @Nullable Throwable cause) { - failureCause.set(cause); + timelineRequestFailed.set(true); } }, EMPTY_PLAYBACK_LISTENER, @@ -385,8 +386,7 @@ public void onSessionTimelineRequestFailed( /* debugLoggingEnabled= */ false); rtspClient.start(); - RobolectricUtil.runMainLooperUntil(() -> failureCause.get() != null); - assertThat(failureCause.get()).hasCauseThat().isInstanceOf(ParserException.class); + RobolectricUtil.runMainLooperUntil(timelineRequestFailed::get); assertThat(rtspClient.getState()).isEqualTo(RtspClient.RTSP_STATE_UNINITIALIZED); } } diff --git a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/SessionDescriptionTest.java b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/SessionDescriptionTest.java index 527b899a220..189fb5653ba 100644 --- a/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/SessionDescriptionTest.java +++ b/libraries/exoplayer_rtsp/src/test/java/androidx/media3/exoplayer/rtsp/SessionDescriptionTest.java @@ -85,6 +85,48 @@ public void parse_sdpString_succeeds() throws Exception { assertThat(sessionDescription).isEqualTo(expectedSession); } + @Test + public void parse_sdpStringWithoutMandatoryFields_succeeds() throws Exception { + // This SDP string is similar to the one in parse_sdpString_succeeds(), it doesn't include the + // mandatory SDP fields origin, session name, session info and timing. + String testMediaSdpInfo = + "v=0\r\n" + + "u=http://www.example.com/lectures/sdp.ps\r\n" + + "e=seminar@example.com (Seminar Management)\r\n" + + "c=IN IP4 0.0.0.0\r\n" + + "a=control:*\r\n" + + "m=audio 3456 RTP/AVP 0\r\n" + + "a=control:audio\r\n" + + "a=rtpmap:0 PCMU/8000\r\n" + + "a=3GPP-Adaption-Support:1\r\n" + + "m=video 2232 RTP/AVP 31\r\n" + + "a=control:video\r\n" + + "a=rtpmap:31 H261/90000\r\n"; + + SessionDescription sessionDescription = SessionDescriptionParser.parse(testMediaSdpInfo); + + SessionDescription expectedSession = + new SessionDescription.Builder() + .setUri(Uri.parse("http://www.example.com/lectures/sdp.ps")) + .setEmailAddress("seminar@example.com (Seminar Management)") + .setConnection("IN IP4 0.0.0.0") + .addAttribute(ATTR_CONTROL, "*") + .addMediaDescription( + new MediaDescription.Builder(MEDIA_TYPE_AUDIO, 3456, RTP_AVP_PROFILE, 0) + .addAttribute(ATTR_CONTROL, "audio") + .addAttribute(ATTR_RTPMAP, "0 PCMU/8000") + .addAttribute("3GPP-Adaption-Support", "1") + .build()) + .addMediaDescription( + new MediaDescription.Builder(MEDIA_TYPE_VIDEO, 2232, RTP_AVP_PROFILE, 31) + .addAttribute(ATTR_CONTROL, "video") + .addAttribute(ATTR_RTPMAP, "31 H261/90000") + .build()) + .build(); + + assertThat(sessionDescription).isEqualTo(expectedSession); + } + @Test public void parse_sdpString2_succeeds() throws Exception { String testMediaSdpInfo =