diff --git a/packager/hls/base/master_playlist.cc b/packager/hls/base/master_playlist.cc index 419620fe53..a068dd7d75 100644 --- a/packager/hls/base/master_playlist.cc +++ b/packager/hls/base/master_playlist.cc @@ -25,6 +25,14 @@ const char* kDefaultAudioGroupId = "default-audio-group"; const char* kDefaultSubtitleGroupId = "default-text-group"; const char* kUnexpectedGroupId = "unexpected-group"; +void AppendVersionString(std::string* content) { + const std::string version = GetPackagerVersion(); + if (version.empty()) + return; + base::StringAppendF(content, "## Generated with %s version %s\n", + GetPackagerProjectUrl().c_str(), version.c_str()); +} + struct Variant { std::string audio_codec; const std::string* audio_group_id = nullptr; @@ -271,6 +279,47 @@ void BuildMediaTags( } } } + +void AppendPlaylists(const std::string& default_language, + const std::string& base_url, + const std::list& playlists, + std::string* content) { + std::map> audio_playlist_groups; + std::map> + subtitle_playlist_groups; + std::list video_playlists; + std::list iframe_playlists; + for (const MediaPlaylist* playlist : playlists) { + switch (playlist->stream_type()) { + case MediaPlaylist::MediaPlaylistStreamType::kAudio: + audio_playlist_groups[GetGroupId(*playlist)].push_back(playlist); + break; + case MediaPlaylist::MediaPlaylistStreamType::kVideo: + video_playlists.push_back(playlist); + break; + case MediaPlaylist::MediaPlaylistStreamType::kSubtitle: + subtitle_playlist_groups[GetGroupId(*playlist)].push_back(playlist); + break; + default: + NOTIMPLEMENTED() << static_cast(playlist->stream_type()) + << " not handled."; + } + } + + BuildMediaTags(audio_playlist_groups, default_language, base_url, content); + BuildMediaTags(subtitle_playlist_groups, default_language, base_url, content); + + std::list variants = + BuildVariants(audio_playlist_groups, subtitle_playlist_groups); + for (const auto& playlist : video_playlists) { + for (const auto& variant : variants) { + BuildVideoTag(*playlist, variant.audio_bitrate, variant.audio_codec, + variant.audio_group_id, variant.text_group_id, base_url, + content); + } + } +} + } // namespace MasterPlaylist::MasterPlaylist(const std::string& file_name, @@ -278,73 +327,13 @@ MasterPlaylist::MasterPlaylist(const std::string& file_name, : file_name_(file_name), default_language_(default_language) {} MasterPlaylist::~MasterPlaylist() {} -void MasterPlaylist::AddMediaPlaylist(MediaPlaylist* media_playlist) { - DCHECK(media_playlist); - switch (media_playlist->stream_type()) { - case MediaPlaylist::MediaPlaylistStreamType::kAudio: { - std::string group_id = GetGroupId(*media_playlist); - audio_playlist_groups_[group_id].push_back(media_playlist); - break; - } - case MediaPlaylist::MediaPlaylistStreamType::kVideo: { - video_playlists_.push_back(media_playlist); - break; - } - case MediaPlaylist::MediaPlaylistStreamType::kSubtitle: { - std::string group_id = GetGroupId(*media_playlist); - subtitle_playlist_groups_[group_id].push_back(media_playlist); - break; - } - default: { - NOTIMPLEMENTED() << static_cast(media_playlist->stream_type()) - << " not handled."; - break; - } - } - // Sometimes we need to iterate over all playlists, so keep a collection - // of all playlists to make iterating easier. - all_playlists_.push_back(media_playlist); -} - -bool MasterPlaylist::WriteMasterPlaylist(const std::string& base_url, - const std::string& output_dir) { - // TODO(rkuroiwa): Handle audio only. - std::string audio_output; - std::string video_output; - std::string subtitle_output; - - // Write out all the audio tags. - BuildMediaTags(audio_playlist_groups_, default_language_, base_url, - &audio_output); - - // Write out all the text tags. - BuildMediaTags(subtitle_playlist_groups_, default_language_, base_url, - &subtitle_output); - - std::list variants = - BuildVariants(audio_playlist_groups_, subtitle_playlist_groups_); - - // Write all the video tags out. - for (const auto& playlist : video_playlists_) { - for (const auto& variant : variants) { - BuildVideoTag(*playlist, variant.audio_bitrate, variant.audio_codec, - variant.audio_group_id, variant.text_group_id, base_url, - &video_output); - } - } - - const std::string version = GetPackagerVersion(); - std::string version_line; - if (!version.empty()) { - version_line = - base::StringPrintf("## Generated with %s version %s\n", - GetPackagerProjectUrl().c_str(), version.c_str()); - } - - std::string content = ""; - base::StringAppendF(&content, "#EXTM3U\n%s%s%s%s", version_line.c_str(), - audio_output.c_str(), subtitle_output.c_str(), - video_output.c_str()); +bool MasterPlaylist::WriteMasterPlaylist( + const std::string& base_url, + const std::string& output_dir, + const std::list& playlists) { + std::string content = "#EXTM3U\n"; + AppendVersionString(&content); + AppendPlaylists(default_language_, base_url, playlists, &content); // Skip if the playlist is already written. if (content == written_playlist_) diff --git a/packager/hls/base/master_playlist.h b/packager/hls/base/master_playlist.h index 9a49cd2a50..18590f73a1 100644 --- a/packager/hls/base/master_playlist.h +++ b/packager/hls/base/master_playlist.h @@ -8,11 +8,8 @@ #define PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_ #include -#include #include -#include "packager/base/macros.h" - namespace shaka { namespace hls { @@ -29,11 +26,6 @@ class MasterPlaylist { const std::string& default_language); virtual ~MasterPlaylist(); - /// @param media_playlist is a MediaPlaylist that should get added to this - /// master playlist. Ownership does not transfer. - /// @return true on success, false otherwise. - virtual void AddMediaPlaylist(MediaPlaylist* media_playlist); - /// Writes Master Playlist to output_dir + . /// This assumes that @a base_url is used as the prefix for Media Playlists. /// @param base_url is the prefix for the Media Playlist files. This should be @@ -44,23 +36,16 @@ class MasterPlaylist { /// @return true if the playlist is updated successfully or there is no /// difference since the last write, false otherwise. virtual bool WriteMasterPlaylist(const std::string& base_url, - const std::string& output_dir); + const std::string& output_dir, + const std::list& playlists); private: + MasterPlaylist(const MasterPlaylist&) = delete; + MasterPlaylist& operator=(const MasterPlaylist&) = delete; + std::string written_playlist_; const std::string file_name_; const std::string default_language_; - std::list all_playlists_; - std::list video_playlists_; - - // The ID is the group name, and the value is the list of all media playlists - // in that group. Keep audio and subtitle separate as they are processed - // separately. - std::map> audio_playlist_groups_; - std::map> - subtitle_playlist_groups_; - - DISALLOW_COPY_AND_ASSIGN(MasterPlaylist); }; } // namespace hls diff --git a/packager/hls/base/master_playlist_unittest.cc b/packager/hls/base/master_playlist_unittest.cc index 7b8bb41158..7d357f3df6 100644 --- a/packager/hls/base/master_playlist_unittest.cc +++ b/packager/hls/base/master_playlist_unittest.cc @@ -117,21 +117,15 @@ class MasterPlaylistTest : public ::testing::Test { std::string master_playlist_path_; }; -TEST_F(MasterPlaylistTest, AddMediaPlaylist) { - MockMediaPlaylist mock_playlist(kVodPlaylist, "playlist1.m3u8", "somename", - "somegroupid"); - master_playlist_.AddMediaPlaylist(&mock_playlist); -} - TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) { const uint64_t kBitRate = 435889; std::unique_ptr mock_playlist = CreateVideoPlaylist("media1.m3u8", "avc1", kBitRate); - master_playlist_.AddMediaPlaylist(mock_playlist.get()); const char kBaseUrl[] = "http://myplaylistdomain.com/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_, + {mock_playlist.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -159,27 +153,26 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) { // First video, sd.m3u8. std::unique_ptr sd_video_playlist = CreateVideoPlaylist("sd.m3u8", "sdvideocodec", kVideo1BitRate); - master_playlist_.AddMediaPlaylist(sd_video_playlist.get()); // Second video, hd.m3u8. std::unique_ptr hd_video_playlist = CreateVideoPlaylist("hd.m3u8", "hdvideocodec", kVideo2BitRate); - master_playlist_.AddMediaPlaylist(hd_video_playlist.get()); // First audio, english.m3u8. std::unique_ptr english_playlist = CreateAudioPlaylist("eng.m3u8", "english", "audiogroup", "audiocodec", "en", kAudio1Channels, kAudio1BitRate); - master_playlist_.AddMediaPlaylist(english_playlist.get()); // Second audio, spanish.m3u8. std::unique_ptr spanish_playlist = CreateAudioPlaylist("spa.m3u8", "espanol", "audiogroup", "audiocodec", "es", kAudio2Channels, kAudio2BitRate); - master_playlist_.AddMediaPlaylist(spanish_playlist.get()); const char kBaseUrl[] = "http://playlists.org/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist( + kBaseUrl, test_output_dir_, + {sd_video_playlist.get(), hd_video_playlist.get(), english_playlist.get(), + spanish_playlist.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -216,22 +209,21 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) { // First video, sd.m3u8. std::unique_ptr video_playlist = CreateVideoPlaylist("video.m3u8", "videocodec", kVideoBitRate); - master_playlist_.AddMediaPlaylist(video_playlist.get()); // First audio, eng_lo.m3u8. std::unique_ptr eng_lo_playlist = CreateAudioPlaylist( "eng_lo.m3u8", "english_lo", "audio_lo", "audiocodec_lo", "en", kAudio1Channels, kAudio1BitRate); - master_playlist_.AddMediaPlaylist(eng_lo_playlist.get()); // Second audio, eng_hi.m3u8. std::unique_ptr eng_hi_playlist = CreateAudioPlaylist( "eng_hi.m3u8", "english_hi", "audio_hi", "audiocodec_hi", "en", kAudio2Channels, kAudio2BitRate); - master_playlist_.AddMediaPlaylist(eng_hi_playlist.get()); const char kBaseUrl[] = "http://anydomain.com/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist( + kBaseUrl, test_output_dir_, + {video_playlist.get(), eng_lo_playlist.get(), eng_hi_playlist.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -260,19 +252,18 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistSameAudioGroupSameLanguage) { // First video, video.m3u8. std::unique_ptr video_playlist = CreateVideoPlaylist("video.m3u8", "videocodec", 300000); - master_playlist_.AddMediaPlaylist(video_playlist.get()); // First audio, eng_lo.m3u8. std::unique_ptr eng_lo_playlist = CreateAudioPlaylist( "eng_lo.m3u8", "english", "audio", "audiocodec", "en", 1, 50000); - master_playlist_.AddMediaPlaylist(eng_lo_playlist.get()); std::unique_ptr eng_hi_playlist = CreateAudioPlaylist( "eng_hi.m3u8", "english", "audio", "audiocodec", "en", 8, 100000); - master_playlist_.AddMediaPlaylist(eng_hi_playlist.get()); const char kBaseUrl[] = "http://anydomain.com/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist( + kBaseUrl, test_output_dir_, + {video_playlist.get(), eng_lo_playlist.get(), eng_hi_playlist.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -297,25 +288,23 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) { // Video, sd.m3u8. std::unique_ptr video1 = CreateVideoPlaylist("sd.m3u8", "sdvideocodec", 300000); - master_playlist_.AddMediaPlaylist(video1.get()); // Video, hd.m3u8. std::unique_ptr video2 = CreateVideoPlaylist("hd.m3u8", "sdvideocodec", 600000); - master_playlist_.AddMediaPlaylist(video2.get()); // Text, eng.m3u8. std::unique_ptr text_eng = MakeText("eng.m3u8", "english", "textgroup", "en"); - master_playlist_.AddMediaPlaylist(text_eng.get()); // Text, fr.m3u8. std::unique_ptr text_fr = MakeText("fr.m3u8", "french", "textgroup", "fr"); - master_playlist_.AddMediaPlaylist(text_fr.get()); const char kBaseUrl[] = "http://playlists.org/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist( + kBaseUrl, test_output_dir_, + {video1.get(), video2.get(), text_eng.get(), text_fr.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -343,20 +332,19 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) { // Video, sd.m3u8. std::unique_ptr video = CreateVideoPlaylist("sd.m3u8", "sdvideocodec", 300000); - master_playlist_.AddMediaPlaylist(video.get()); // Text, eng.m3u8. std::unique_ptr text_eng = MakeText("eng.m3u8", "english", "en-text-group", "en"); - master_playlist_.AddMediaPlaylist(text_eng.get()); // Text, fr.m3u8. std::unique_ptr text_fr = MakeText("fr.m3u8", "french", "fr-text-group", "fr"); - master_playlist_.AddMediaPlaylist(text_fr.get()); const char kBaseUrl[] = "http://playlists.org/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist( + kBaseUrl, test_output_dir_, + {video.get(), text_eng.get(), text_fr.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -385,20 +373,18 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) { // Video, sd.m3u8. std::unique_ptr video = CreateVideoPlaylist("sd.m3u8", "sdvideocodec", 300000); - master_playlist_.AddMediaPlaylist(video.get()); // Audio, english.m3u8. std::unique_ptr audio = CreateAudioPlaylist( "eng.m3u8", "english", "audiogroup", "audiocodec", "en", 2, 50000); - master_playlist_.AddMediaPlaylist(audio.get()); // Text, english.m3u8. std::unique_ptr text = MakeText("eng.m3u8", "english", "textgroup", "en"); - master_playlist_.AddMediaPlaylist(text.get()); const char kBaseUrl[] = "http://playlists.org/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist( + kBaseUrl, test_output_dir_, {video.get(), audio.get(), text.get()})); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); @@ -442,12 +428,14 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVidesAudiosTextsDifferentGroups) { }; // Add all the media playlists to the master playlist. + std::list media_playlist_list; for (const auto& media_playlist : media_playlists) { - master_playlist_.AddMediaPlaylist(media_playlist.get()); + media_playlist_list.push_back(media_playlist.get()); } const char kBaseUrl[] = "http://playlists.org/"; - EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_)); + EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(kBaseUrl, test_output_dir_, + media_playlist_list)); std::string actual; ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); diff --git a/packager/hls/base/simple_hls_notifier.cc b/packager/hls/base/simple_hls_notifier.cc index 73bb572242..32d5289b10 100644 --- a/packager/hls/base/simple_hls_notifier.cc +++ b/packager/hls/base/simple_hls_notifier.cc @@ -312,7 +312,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info, *stream_id = sequence_number_.GetNext(); base::AutoLock auto_lock(lock_); - master_playlist_->AddMediaPlaylist(media_playlist.get()); + media_playlists_.push_back(media_playlist.get()); stream_map_[*stream_id].reset( new StreamEntry{std::move(media_playlist), encryption_method}); return true; @@ -348,14 +348,14 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id, // Update the playlists when there is new segments in live mode. if (playlist_type() == HlsPlaylistType::kLive || playlist_type() == HlsPlaylistType::kEvent) { - if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_)) { + if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_, + media_playlists_)) { LOG(ERROR) << "Failed to write master playlist."; return false; } // Update all playlists if target duration is updated. if (target_duration_updated) { - for (auto& streams : stream_map_) { - MediaPlaylist* playlist = streams.second->media_playlist.get(); + for (MediaPlaylist* playlist : media_playlists_) { playlist->SetTargetDuration(target_duration_); if (!WriteMediaPlaylist(output_dir_, playlist)) return false; @@ -461,12 +461,12 @@ bool SimpleHlsNotifier::NotifyEncryptionUpdate( bool SimpleHlsNotifier::Flush() { base::AutoLock auto_lock(lock_); - if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_)) { + if (!master_playlist_->WriteMasterPlaylist(prefix_, output_dir_, + media_playlists_)) { LOG(ERROR) << "Failed to write master playlist."; return false; } - for (auto& streams : stream_map_) { - MediaPlaylist* playlist = streams.second->media_playlist.get(); + for (MediaPlaylist* playlist : media_playlists_) { playlist->SetTargetDuration(target_duration_); if (!WriteMediaPlaylist(output_dir_, playlist)) return false; diff --git a/packager/hls/base/simple_hls_notifier.h b/packager/hls/base/simple_hls_notifier.h index fc10caca4a..cfe499f282 100644 --- a/packager/hls/base/simple_hls_notifier.h +++ b/packager/hls/base/simple_hls_notifier.h @@ -7,6 +7,7 @@ #ifndef PACKAGER_HLS_BASE_SIMPLE_HLS_NOTIFIER_H_ #define PACKAGER_HLS_BASE_SIMPLE_HLS_NOTIFIER_H_ +#include #include #include #include @@ -89,6 +90,7 @@ class SimpleHlsNotifier : public HlsNotifier { // Maps to unique_ptr because StreamEntry also holds unique_ptr std::map> stream_map_; + std::list media_playlists_; base::AtomicSequenceNumber sequence_number_; diff --git a/packager/hls/base/simple_hls_notifier_unittest.cc b/packager/hls/base/simple_hls_notifier_unittest.cc index 7a9d67b842..023bebe4c5 100644 --- a/packager/hls/base/simple_hls_notifier_unittest.cc +++ b/packager/hls/base/simple_hls_notifier_unittest.cc @@ -21,13 +21,14 @@ namespace shaka { namespace hls { +using ::testing::_; +using ::testing::ElementsAre; using ::testing::Eq; using ::testing::InSequence; using ::testing::Mock; using ::testing::Property; using ::testing::Return; using ::testing::StrEq; -using ::testing::_; namespace { const char kMasterPlaylistName[] = "master.m3u8"; @@ -43,9 +44,10 @@ class MockMasterPlaylist : public MasterPlaylist { MockMasterPlaylist() : MasterPlaylist(kMasterPlaylistName, kDefaultLanguage) {} - MOCK_METHOD1(AddMediaPlaylist, void(MediaPlaylist* media_playlist)); - MOCK_METHOD2(WriteMasterPlaylist, - bool(const std::string& prefix, const std::string& output_dir)); + MOCK_METHOD3(WriteMasterPlaylist, + bool(const std::string& prefix, + const std::string& output_dir, + const std::list& playlists)); }; class MockMediaPlaylistFactory : public MediaPlaylistFactory { @@ -128,9 +130,6 @@ class SimpleHlsNotifierTest : public ::testing::Test { std::unique_ptr factory( new MockMediaPlaylistFactory()); - EXPECT_CALL( - *mock_master_playlist, - AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); EXPECT_CALL(*factory, CreateMock(_, _, _, _, _)) .WillOnce(Return(mock_media_playlist)); @@ -167,7 +166,6 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrl) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); - EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(Property(&MediaInfo::init_segment_name, StrEq("")))) @@ -207,7 +205,6 @@ TEST_F(SimpleHlsNotifierTest, RebaseInitSegmentUrl) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); - EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); // Verify that the common prefix is stripped in init segment. EXPECT_CALL( @@ -243,7 +240,6 @@ TEST_F(SimpleHlsNotifierTest, RebaseSegmentUrlRelativeToPlaylist) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "video/playlist.m3u8", "", ""); - EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); // Verify that the init segment URL is relative to playlist path. EXPECT_CALL(*mock_media_playlist, @@ -292,7 +288,6 @@ TEST_F(SimpleHlsNotifierTest, RebaseAbsoluteSegmentPrefixAndOutputDirMatch) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); - EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); @@ -334,7 +329,6 @@ TEST_F(SimpleHlsNotifierTest, // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); - EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_media_playlist, @@ -363,7 +357,7 @@ TEST_F(SimpleHlsNotifierTest, Flush) { std::unique_ptr mock_master_playlist( new MockMasterPlaylist()); EXPECT_CALL(*mock_master_playlist, - WriteMasterPlaylist(StrEq(kTestPrefix), StrEq(kAnyOutputDir))) + WriteMasterPlaylist(StrEq(kTestPrefix), StrEq(kAnyOutputDir), _)) .WillOnce(Return(true)); InjectMasterPlaylist(std::move(mock_master_playlist), ¬ifier); EXPECT_TRUE(notifier.Init()); @@ -379,7 +373,6 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewStream) { // Pointer released by SimpleHlsNotifier. MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); - EXPECT_CALL(*mock_master_playlist, AddMediaPlaylist(mock_media_playlist)); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); EXPECT_CALL(*factory, CreateMock(kVodPlaylist, Eq(kTestTimeShiftBufferDepth), @@ -409,9 +402,6 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(kVodPlaylist, "playlist.m3u8", "", ""); - EXPECT_CALL( - *mock_master_playlist, - AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); EXPECT_CALL(*factory, CreateMock(_, _, _, _, _)) .WillOnce(Return(mock_media_playlist)); @@ -446,7 +436,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) { Mock::VerifyAndClearExpectations(mock_media_playlist); EXPECT_CALL(*mock_master_playlist_ptr, - WriteMasterPlaylist(StrEq(kTestPrefix), StrEq(kAnyOutputDir))) + WriteMasterPlaylist(StrEq(kTestPrefix), StrEq(kAnyOutputDir), + ElementsAre(mock_media_playlist))) .WillOnce(Return(true)); EXPECT_CALL(*mock_media_playlist, SetTargetDuration(kTargetDuration)) .Times(1); @@ -908,9 +899,6 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegment) { MockMediaPlaylist* mock_media_playlist = new MockMediaPlaylist(expected_playlist_type_, "playlist.m3u8", "", ""); - EXPECT_CALL( - *mock_master_playlist, - AddMediaPlaylist(static_cast(mock_media_playlist))); EXPECT_CALL(*mock_media_playlist, SetMediaInfo(_)).WillOnce(Return(true)); EXPECT_CALL(*factory, CreateMock(expected_playlist_type_, _, _, _, _)) .WillOnce(Return(mock_media_playlist)); @@ -929,7 +917,7 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegment) { .WillOnce(Return(kLongestSegmentDuration)); EXPECT_CALL(*mock_master_playlist, - WriteMasterPlaylist(StrEq(kTestPrefix), StrEq(kAnyOutputDir))) + WriteMasterPlaylist(StrEq(kTestPrefix), StrEq(kAnyOutputDir), _)) .WillOnce(Return(true)); EXPECT_CALL(*mock_media_playlist, SetTargetDuration(kTargetDuration)) .Times(1); @@ -975,15 +963,9 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) { EXPECT_CALL(*factory, CreateMock(_, _, StrEq("playlist1.m3u8"), _, _)) .WillOnce(Return(mock_media_playlist1)); EXPECT_CALL(*mock_media_playlist1, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL( - *mock_master_playlist, - AddMediaPlaylist(static_cast(mock_media_playlist1))); EXPECT_CALL(*factory, CreateMock(_, _, StrEq("playlist2.m3u8"), _, _)) .WillOnce(Return(mock_media_playlist2)); EXPECT_CALL(*mock_media_playlist2, SetMediaInfo(_)).WillOnce(Return(true)); - EXPECT_CALL( - *mock_master_playlist, - AddMediaPlaylist(static_cast(mock_media_playlist2))); hls_params_.playlist_type = GetParam(); SimpleHlsNotifier notifier(hls_params_); @@ -1006,7 +988,10 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) { EXPECT_CALL(*mock_media_playlist1, GetLongestSegmentDuration()) .WillOnce(Return(kLongestSegmentDuration)); - EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _)) + EXPECT_CALL( + *mock_master_playlist_ptr, + WriteMasterPlaylist( + _, _, ElementsAre(mock_media_playlist1, mock_media_playlist2))) .WillOnce(Return(true)); // SetTargetDuration and update all playlists as target duration is updated. EXPECT_CALL(*mock_media_playlist1, SetTargetDuration(kTargetDuration)) @@ -1031,7 +1016,7 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) { EXPECT_CALL(*mock_media_playlist2, AddSegment(_, _, _, _, _)).Times(1); EXPECT_CALL(*mock_media_playlist2, GetLongestSegmentDuration()) .WillOnce(Return(kLongestSegmentDuration)); - EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _)) + EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _, _)) .WillOnce(Return(true)); // Not updating other playlists as target duration does not change. EXPECT_CALL(*mock_media_playlist2,