From 2f471511319b9716d0bcc2ad584bd32699e0937c Mon Sep 17 00:00:00 2001 From: michaelkatz Date: Tue, 20 Feb 2024 02:44:50 -0800 Subject: [PATCH] Allow empty information attributes in RTSP Session Description Issue: androidx/media#1087 PiperOrigin-RevId: 608534659 (cherry picked from commit 52c1d60d39f690b7f3231095fb193510c93fd1ec) --- RELEASENOTES.md | 3 ++ .../rtsp/SessionDescriptionParser.java | 8 +++++ .../rtsp/SessionDescriptionTest.java | 33 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3f74bd7298b..4221e2d6e5b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -11,6 +11,9 @@ * Fallback to include audio track language name if `Locale` cannot identify a display name ([#988](https://github.com/androidx/media/issues/988)). +* RTSP Extension: + * Skip empty session information values (i-tags) in SDP parsing + ([#1087](https://github.com/androidx/media/issues/1087)). ## 1.3 diff --git a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescriptionParser.java b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescriptionParser.java index cbbd844a1e7..0e28d66e69e 100644 --- a/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescriptionParser.java +++ b/libraries/exoplayer_rtsp/src/main/java/androidx/media3/exoplayer/rtsp/SessionDescriptionParser.java @@ -26,6 +26,7 @@ import androidx.media3.common.ParserException; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,6 +36,8 @@ // SDP line always starts with an one letter tag, followed by an equal sign. The information // under the given tag follows an optional space. private static final Pattern SDP_LINE_PATTERN = Pattern.compile("([a-z])=\\s?(.+)"); + // SDP line with a one letter tag, an equal sign, and an empty value. + private static final Pattern SDP_LINE_WITH_EMPTY_VALUE_PATTERN = Pattern.compile("^([a-z])=$"); // Matches an attribute line (with a= sdp tag removed. Example: range:npt=0-50.0). // Attribute can also be a flag, i.e. without a value, like recvonly. Reference RFC4566 Section 9 // Page 43, under "token-char". @@ -81,6 +84,11 @@ public static SessionDescription parse(String sdpString) throws ParserException Matcher matcher = SDP_LINE_PATTERN.matcher(line); if (!matcher.matches()) { + Matcher sdpTagMatcher = SDP_LINE_WITH_EMPTY_VALUE_PATTERN.matcher(line); + if (sdpTagMatcher.matches() && Objects.equals(sdpTagMatcher.group(1), INFORMATION_TYPE)) { + // Allow and skip empty Session Information (tag 'i') attributes + continue; + } throw ParserException.createForMalformedManifest( "Malformed SDP line: " + line, /* cause= */ null); } 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 189fb5653ba..060e5727006 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 @@ -29,6 +29,7 @@ import static org.junit.Assert.assertThrows; import android.net.Uri; +import androidx.media3.common.ParserException; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; @@ -270,6 +271,38 @@ public void parse_sdpStringWithExtraSpaceInRtpMapAttribute_succeeds() throws Exc assertThat(rtpMapAttribute.clockRate).isEqualTo(44100); } + @Test + public void parse_sdpStringWithEmptyInformationAttribute_succeeds() throws Exception { + String testMediaSdpInfo = + "v=0\r\n" + + "o=MNobody 2890844526 2890842807 IN IP4 192.0.2.46\r\n" + + "s=SDP Seminar\r\n" + + "i=\r\n" + + "t=0 0\r\n" + + "a=control:*\r\n" + + "m=audio 3456 RTP/AVP 0\r\n" + + "i=\r\n" + + "a=rtpmap:97 AC3/44100 \r\n"; + + SessionDescription sessionDescription = SessionDescriptionParser.parse(testMediaSdpInfo); + + assertThat(sessionDescription.sessionInfo).isNull(); + assertThat(sessionDescription.mediaDescriptionList.get(0).mediaTitle).isNull(); + } + + @Test + public void parse_sdpStringWithEmptySessionAttribute_throwsParserException() { + String testMediaSdpInfo = + "v=0\r\n" + + "o=MNobody 2890844526 2890842807 IN IP4 192.0.2.46\r\n" + + "s=\r\n" + + "a=control:*\r\n" + + "m=audio 3456 RTP/AVP 0\r\n" + + "a=rtpmap:97 AC3/44100 \r\n"; + + assertThrows(ParserException.class, () -> SessionDescriptionParser.parse(testMediaSdpInfo)); + } + @Test public void buildMediaDescription_withInvalidRtpmapAttribute_throwsIllegalStateException() { assertThrows(