diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java
index 216ecc1422..45f2b6fcfc 100644
--- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java
+++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java
@@ -1477,6 +1477,8 @@ public class DashManifestParser extends DefaultHandler
case "main":
return C.SELECTION_FLAG_DEFAULT;
case "forced_subtitle":
+ // Support both hyphen and underscore (https://github.com/google/ExoPlayer/issues/9727).
+ case "forced-subtitle":
return C.SELECTION_FLAG_FORCED;
default:
return 0;
@@ -1547,6 +1549,8 @@ public class DashManifestParser extends DefaultHandler
case "caption":
return C.ROLE_FLAG_CAPTION;
case "forced_subtitle":
+ // Support both hyphen and underscore (https://github.com/google/ExoPlayer/issues/9727).
+ case "forced-subtitle":
case "subtitle":
return C.ROLE_FLAG_SUBTITLE;
case "sign":
diff --git a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java
index 13e5fc7e01..d446ed0f7e 100644
--- a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java
+++ b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java
@@ -254,7 +254,13 @@ public class DashManifestParserTest {
assertThat(format.selectionFlags).isEqualTo(C.SELECTION_FLAG_FORCED);
assertThat(adaptationSets.get(1).type).isEqualTo(C.TRACK_TYPE_TEXT);
+ // Ensure that forced-subtitle and forced_subtitle are both parsed as a 'forced' text track.
+ // https://github.com/google/ExoPlayer/issues/9727
format = adaptationSets.get(2).representations.get(0).format;
+ assertThat(format.roleFlags).isEqualTo(C.ROLE_FLAG_SUBTITLE);
+ assertThat(format.selectionFlags).isEqualTo(C.SELECTION_FLAG_FORCED);
+
+ format = adaptationSets.get(3).representations.get(0).format;
assertThat(format.containerMimeType).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(format.sampleMimeType).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(format.codecs).isNull();
@@ -586,10 +592,11 @@ public class DashManifestParserTest {
assertThat(manifest.getPeriodCount()).isEqualTo(1);
List adaptationSets = manifest.getPeriod(0).adaptationSets;
- assertThat(adaptationSets).hasSize(3);
+ assertThat(adaptationSets).hasSize(4);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(0))).isEqualTo(C.TIME_UNSET);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(1))).isEqualTo(C.TIME_UNSET);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(2))).isEqualTo(C.TIME_UNSET);
+ assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(3))).isEqualTo(C.TIME_UNSET);
}
@Test
diff --git a/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text
index f940527037..4220f5b2f2 100644
--- a/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text
+++ b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text
@@ -13,11 +13,17 @@
-
+
https://test.com/0
+
+
+
+ https://test.com/0
+
+
https://test.com/0