diff --git a/packager/hls/base/master_playlist.cc b/packager/hls/base/master_playlist.cc index e1c336cc80..b35ef4757e 100644 --- a/packager/hls/base/master_playlist.cc +++ b/packager/hls/base/master_playlist.cc @@ -366,12 +366,20 @@ void BuildMediaTags( bool is_default = false; bool is_autoselect = false; - const std::string language = playlist->language(); - if (languages.find(language) == languages.end()) { - is_default = !language.empty() && language == default_language; + if (playlist->is_dvs()) { + // According to HLS Authoring Specification for Apple Devices + // https://developer.apple.com/documentation/http_live_streaming/hls_authoring_specification_for_apple_devices#overview + // section 2.13 If you provide DVS, the AUTOSELECT attribute MUST have + // a value of "YES". is_autoselect = true; + } else { + const std::string language = playlist->language(); + if (languages.find(language) == languages.end()) { + is_default = !language.empty() && language == default_language; + is_autoselect = true; - languages.insert(language); + languages.insert(language); + } } BuildMediaTag(*playlist, group_id, is_default, is_autoselect, base_url, diff --git a/packager/hls/base/master_playlist_unittest.cc b/packager/hls/base/master_playlist_unittest.cc index 9f0f0cf741..60fac6131f 100644 --- a/packager/hls/base/master_playlist_unittest.cc +++ b/packager/hls/base/master_playlist_unittest.cc @@ -523,6 +523,51 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextWithCharacteritics) { ASSERT_EQ(expected, actual); } +TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndDvsAudio) { + // Video, sd.m3u8. + std::unique_ptr video = + CreateVideoPlaylist("sd.m3u8", "sdvideocodec", 300000, 200000); + + // DVS Audio, dvs_eng.m3u8. + std::unique_ptr dvs_audio = CreateAudioPlaylist( + "dvs_eng.m3u8", "DVS english", "audiogroup", "audiocodec", "en", 2, 50000, + 30000, kEC3JocComplexityZero, !kAC4IMSFlagEnabled, !kAC4CBIFlagEnabled); + dvs_audio->SetCharacteristicsForTesting( + std::vector{"public.accessibility.describes-video"}); + + // Normal Audio, eng.m3u8. + std::unique_ptr audio = CreateAudioPlaylist( + "eng.m3u8", "english", "audiogroup", "audiocodec", "en", 2, 50000, 30000, + kEC3JocComplexityZero, !kAC4IMSFlagEnabled, !kAC4CBIFlagEnabled); + + const char kBaseUrl[] = "http://playlists.org/"; + EXPECT_TRUE(master_playlist_->WriteMasterPlaylist( + kBaseUrl, test_output_dir_, {video.get(), dvs_audio.get(), audio.get()})); + + std::string actual; + ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); + + const std::string expected = + "#EXTM3U\n" + "## Generated with https://github.com/google/shaka-packager version " + "test\n" + "\n" + "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/dvs_eng.m3u8\"," + "GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"DVS english\"," + "AUTOSELECT=YES,CHARACTERISTICS=\"public.accessibility.describes-video\"," + "CHANNELS=\"2\"\n" + "#EXT-X-MEDIA:TYPE=AUDIO,URI=\"http://playlists.org/eng.m3u8\"," + "GROUP-ID=\"audiogroup\",LANGUAGE=\"en\",NAME=\"english\"," + "DEFAULT=YES,AUTOSELECT=YES,CHANNELS=\"2\"\n" + "\n" + "#EXT-X-STREAM-INF:BANDWIDTH=350000,AVERAGE-BANDWIDTH=230000," + "CODECS=\"sdvideocodec,audiocodec\",RESOLUTION=800x600," + "AUDIO=\"audiogroup\"\n" + "http://playlists.org/sd.m3u8\n"; + + ASSERT_EQ(expected, actual); +} + TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) { // Video, sd.m3u8. std::unique_ptr video = diff --git a/packager/hls/base/media_playlist.h b/packager/hls/base/media_playlist.h index 2b419b99c2..18d86494d4 100644 --- a/packager/hls/base/media_playlist.h +++ b/packager/hls/base/media_playlist.h @@ -221,6 +221,15 @@ class MediaPlaylist { return characteristics_; } + bool is_dvs() const { + // HLS Authoring Specification for Apple Devices + // https://developer.apple.com/documentation/http_live_streaming/hls_authoring_specification_for_apple_devices#overview + // Section 2.12. + const char DVS_CHARACTERISTICS[] = "public.accessibility.describes-video"; + return characteristics_.size() == 1 && + characteristics_[0] == DVS_CHARACTERISTICS; + } + private: // Add a SegmentInfoEntry (#EXTINF). void AddSegmentInfoEntry(const std::string& segment_file_name,