[M120 Migration][hbbtv] Audio tracks count notification
[platform/framework/web/chromium-efl.git] / media / filters / manifest_demuxer_unittest.cc
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6
7 #include "base/test/gmock_callback_support.h"
8 #include "base/test/task_environment.h"
9 #include "base/threading/thread.h"
10 #include "media/base/media_track.h"
11 #include "media/base/media_util.h"
12 #include "media/base/mock_demuxer_host.h"
13 #include "media/base/mock_media_log.h"
14 #include "media/base/test_data_util.h"
15 #include "media/filters/manifest_demuxer.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace media {
20 using ::base::test::RunOnceCallback;
21 using ::testing::_;
22 using ::testing::NiceMock;
23 using ::testing::Return;
24 using ::testing::SaveArg;
25
26 // Define a mock implementation of ManifestDemuxer::Engine for testing.
27 class MockEngine : public ManifestDemuxer::Engine {
28  public:
29   MOCK_METHOD(void,
30               Initialize,
31               (ManifestDemuxerEngineHost * demuxer,
32                PipelineStatusCallback status_cb),
33               (override));
34   MOCK_METHOD(std::string, GetName, (), (const, override));
35   MOCK_METHOD(void,
36               OnTimeUpdate,
37               (base::TimeDelta time,
38                double playback_rate,
39                ManifestDemuxer::DelayCallback cb),
40               (override));
41   MOCK_METHOD(void,
42               Seek,
43               (base::TimeDelta time, ManifestDemuxer::SeekCallback cb),
44               (override));
45   MOCK_METHOD(void, StartWaitingForSeek, (), (override));
46   MOCK_METHOD(void, AbortPendingReads, (), (override));
47   MOCK_METHOD(bool, IsSeekable, (), (const override));
48   MOCK_METHOD(int64_t, GetMemoryUsage, (), (const, override));
49   MOCK_METHOD(void, Stop, (), (override));
50 };
51
52 // Fixture for ManifestDemuxer tests.
53 class ManifestDemuxerTest : public ::testing::Test {
54  public:
55   ManifestDemuxerTest()
56       : media_log_(std::make_unique<NiceMock<media::MockMediaLog>>()),
57         mock_host_(std::make_unique<NiceMock<MockDemuxerHost>>()) {
58     auto mock_engine = std::make_unique<MockEngine>();
59     mock_engine_ = mock_engine.get();
60     manifest_demuxer_ = std::make_unique<ManifestDemuxer>(
61         task_environment_.GetMainThreadTaskRunner(),
62         base::BindRepeating(&ManifestDemuxerTest::DemuxerRequestsSeek,
63                             base::Unretained(this)),
64         std::move(mock_engine), media_log_.get());
65   }
66
67   ~ManifestDemuxerTest() override {
68     manifest_demuxer_->GetChunkDemuxerForTesting()->MarkEndOfStream(
69         PIPELINE_OK);
70     // Reset pointer so that it does not dangle.
71     mock_engine_ = nullptr;
72     manifest_demuxer_.reset();
73     base::RunLoop().RunUntilIdle();
74   }
75
76   MOCK_METHOD(void, DemuxerRequestsSeek, (base::TimeDelta), ());
77   MOCK_METHOD(void, MockInitComplete, (PipelineStatus status), ());
78   MOCK_METHOD(void, MockSeekComplete, (PipelineStatus status), ());
79
80   void CreateIdAndAppendInitSegment(const std::string& id) {
81     auto* demuxer = manifest_demuxer_->GetChunkDemuxerForTesting();
82     ASSERT_EQ(demuxer->AddId(id, "video/webm", "vorbis,vp8"),
83               ChunkDemuxer::Status::kOk);
84
85     demuxer->SetTracksWatcher(
86         id, base::BindRepeating([](std::unique_ptr<MediaTracks>) {}));
87     demuxer->SetParseWarningCallback(
88         id, base::BindRepeating([](SourceBufferParseWarning) {}));
89
90     scoped_refptr<DecoderBuffer> bear1 = ReadTestDataFile("bear-320x240.webm");
91     ASSERT_TRUE(
92         demuxer->AppendToParseBuffer(id, bear1->data(), bear1->data_size()));
93     for (;;) {
94       base::TimeDelta start = base::Seconds(0), end = base::Seconds(10), offset;
95       auto result = demuxer->RunSegmentParserLoop(id, start, end, &offset);
96       if (result != StreamParser::ParseStatus::kSuccessHasMoreData) {
97         ASSERT_EQ(result, StreamParser::ParseStatus::kSuccess);
98         return;
99       }
100     }
101   }
102
103   void InitializeDemuxer() {
104     // Chunk demuxer won't finish initialization until content starts being
105     // added, and we don't have any mock content at this point.
106     EXPECT_CALL(*this, MockInitComplete(_)).Times(1);
107
108     // Mark the engine as initialized successfully.
109     EXPECT_CALL(*mock_engine_, Initialize(_, _))
110         .WillOnce(RunOnceCallback<1>(media::PIPELINE_OK));
111
112     manifest_demuxer_->Initialize(
113         mock_host_.get(), base::BindOnce(&ManifestDemuxerTest::MockInitComplete,
114                                          base::Unretained(this)));
115     CreateIdAndAppendInitSegment("test");
116   }
117
118  protected:
119   base::test::TaskEnvironment task_environment_;
120   std::unique_ptr<MediaLog> media_log_;
121   std::unique_ptr<MockDemuxerHost> mock_host_;
122   raw_ptr<MockEngine> mock_engine_;
123   std::unique_ptr<ManifestDemuxer> manifest_demuxer_;
124 };
125
126 TEST_F(ManifestDemuxerTest, InitializeStartsTimeUpdate) {
127   // When the engine is initialized and the chunk demuxer is opened
128   // (not initialized), the |OnTimeUpdate| events start coming in.
129   // posting `kNoTimestamp` back to this callback signals that we won't delay
130   // and get another event.
131   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _))
132       .WillOnce(RunOnceCallback<2>(kNoTimestamp));
133   InitializeDemuxer();
134
135   task_environment_.RunUntilIdle();
136   ASSERT_FALSE(manifest_demuxer_->has_next_task_for_testing());
137 }
138
139 TEST_F(ManifestDemuxerTest, PlaybackRateChangeUpTriggersTimeUpdate) {
140   ManifestDemuxer::DelayCallback delay_cb;
141   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _))
142       .WillRepeatedly([&delay_cb](base::TimeDelta, double,
143                                   ManifestDemuxer::DelayCallback cb) {
144         delay_cb = std::move(cb);
145       });
146
147   // Initializing the demuxer will cause a time update event at time = 0.
148   InitializeDemuxer();
149   ASSERT_TRUE(!!delay_cb);
150
151   // Setting the playback rate up while there is a pending event should do
152   // nothing.
153   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)).Times(0);
154   manifest_demuxer_->SetPlaybackRate(0.2);
155
156   // Respond to the loop, but request no new events.
157   std::move(delay_cb).Run(kNoTimestamp);
158   task_environment_.RunUntilIdle();
159
160   // Setting the playback rate up again while there is not pending event
161   // should trigger a new event.
162   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _))
163       .WillRepeatedly([&delay_cb](base::TimeDelta, double,
164                                   ManifestDemuxer::DelayCallback cb) {
165         delay_cb = std::move(cb);
166       });
167   manifest_demuxer_->SetPlaybackRate(0.4);
168   task_environment_.RunUntilIdle();
169   ASSERT_TRUE(!!delay_cb);
170
171   // Respond to the loop, but request no new events.
172   std::move(delay_cb).Run(kNoTimestamp);
173   task_environment_.RunUntilIdle();
174
175   // Setting the playback rate down should not trigger a new event, even
176   // while there is no event pending.
177   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _)).Times(0);
178   manifest_demuxer_->SetPlaybackRate(0.2);
179
180   task_environment_.RunUntilIdle();
181   ASSERT_FALSE(manifest_demuxer_->has_next_task_for_testing());
182 }
183
184 TEST_F(ManifestDemuxerTest, OnTimeUpdateUninterruptedBySeek) {
185   ManifestDemuxer::DelayCallback delay_cb;
186   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _))
187       .WillRepeatedly([&delay_cb](base::TimeDelta, double,
188                                   ManifestDemuxer::DelayCallback cb) {
189         delay_cb = std::move(cb);
190       });
191   InitializeDemuxer();
192   ASSERT_TRUE(!!delay_cb);
193
194   // a pending event is set, which won't be cleared until `delay_cb` is
195   // executed.
196   ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing());
197   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
198
199   // Seek won't be called until we post delay_cb.
200   EXPECT_CALL(*mock_engine_, Seek(_, _)).Times(0);
201   EXPECT_CALL(*mock_engine_, StartWaitingForSeek()).Times(1);
202   EXPECT_CALL(*this, MockSeekComplete(_)).Times(0);
203   manifest_demuxer_->StartWaitingForSeek(base::Seconds(1));
204   manifest_demuxer_->Seek(base::Seconds(1),
205                           base::BindOnce(&ManifestDemuxerTest::MockSeekComplete,
206                                          base::Unretained(this)));
207
208   // we not have a pending seek and a pending event.
209   ASSERT_TRUE(manifest_demuxer_->has_pending_seek_for_testing());
210   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
211
212   // Return from the pending event. The pending seek will start, which will
213   // kick off an async call to the chunk demuxer. We can make the engine
214   // also request a new event to be called, which means that delay_cb will be
215   // set again.
216   EXPECT_CALL(*mock_engine_, Seek(_, _))
217       .WillOnce(RunOnceCallback<1>(ManifestDemuxer::SeekState::kNeedsData));
218   std::move(delay_cb).Run(base::Seconds(10));
219   task_environment_.RunUntilIdle();
220
221   // There is still a pending seek, and we now have a new event.
222   ASSERT_TRUE(!!delay_cb);
223   ASSERT_TRUE(manifest_demuxer_->has_pending_seek_for_testing());
224   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
225
226   // Executing this delay CB will trigger the seek to finish, since chunk
227   // demuxer has already finished it's seek. After the seek is finished, it
228   // will kick off another event, making the pending event check true and
229   // causing a new `delay_cb` to be set.
230   EXPECT_CALL(*this, MockSeekComplete(_)).Times(1);
231   std::move(delay_cb).Run(base::Seconds(10));
232   task_environment_.RunUntilIdle();
233   ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing());
234   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
235
236   // Running this event with no timestamp will cause the event loop to no longer
237   // run. Only kicking off a seek or playback rate change will re-trigger it.
238   ASSERT_TRUE(!!delay_cb);
239   std::move(delay_cb).Run(kNoTimestamp);
240   task_environment_.RunUntilIdle();
241   ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing());
242   ASSERT_FALSE(manifest_demuxer_->has_pending_event_for_testing());
243
244   task_environment_.RunUntilIdle();
245   ASSERT_FALSE(manifest_demuxer_->has_next_task_for_testing());
246 }
247
248 TEST_F(ManifestDemuxerTest, SeekInterruptedByError) {
249   ManifestDemuxer::DelayCallback delay_cb;
250   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _))
251       .WillRepeatedly([&delay_cb](base::TimeDelta, double,
252                                   ManifestDemuxer::DelayCallback cb) {
253         delay_cb = std::move(cb);
254       });
255   InitializeDemuxer();
256   ASSERT_TRUE(!!delay_cb);
257   ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing());
258   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
259
260   // Seek won't be called until we post delay_cb.
261   EXPECT_CALL(*mock_engine_, StartWaitingForSeek());
262   EXPECT_CALL(*mock_engine_, Seek(_, _)).Times(0);
263   EXPECT_CALL(*this, MockSeekComplete(_)).Times(0);
264   manifest_demuxer_->StartWaitingForSeek(base::Seconds(100));
265   manifest_demuxer_->Seek(base::Seconds(100),
266                           base::BindOnce(&ManifestDemuxerTest::MockSeekComplete,
267                                          base::Unretained(this)));
268   task_environment_.RunUntilIdle();
269
270   // respond that data is needed, this will set chunk demuxer waiting for data.
271   EXPECT_CALL(*mock_engine_, Seek(_, _))
272       .WillOnce(RunOnceCallback<1>(ManifestDemuxer::SeekState::kNeedsData));
273   std::move(delay_cb).Run(kNoTimestamp);
274   task_environment_.RunUntilIdle();
275
276   // Send some generic pipeline error while the pipeline is still waiting for
277   // data.
278   EXPECT_CALL(*this, MockSeekComplete(_));
279   manifest_demuxer_->OnError(PIPELINE_ERROR_ABORT);
280   task_environment_.RunUntilIdle();
281
282   // Now let the delay_cb "execute", even though the error handler should have
283   // shut down all weak_ptrs and canceled all callbacks.
284   std::move(delay_cb).Run(kNoTimestamp);
285   task_environment_.RunUntilIdle();
286 }
287
288 TEST_F(ManifestDemuxerTest, CancelSeekAfterDemuxerBeforeEngine) {
289   // What happens if we seek, the demuxer replies, and while waiting for the
290   // engine to reply, we get a notice to cancel pending seek?
291
292   ManifestDemuxer::DelayCallback delay_cb;
293   EXPECT_CALL(*mock_engine_, OnTimeUpdate(_, _, _))
294       .WillRepeatedly([&delay_cb](base::TimeDelta, double,
295                                   ManifestDemuxer::DelayCallback cb) {
296         delay_cb = std::move(cb);
297       });
298
299   // a pending event is set, which won't be cleared until `delay_cb` is
300   // executed.
301   InitializeDemuxer();
302   ASSERT_TRUE(!!delay_cb);
303   ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing());
304   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
305
306   // Seek won't be called until we post delay_cb.
307   EXPECT_CALL(*mock_engine_, StartWaitingForSeek());
308   EXPECT_CALL(*mock_engine_, Seek(_, _)).Times(0);
309   EXPECT_CALL(*this, MockSeekComplete(_)).Times(0);
310   manifest_demuxer_->StartWaitingForSeek(base::Seconds(100));
311   manifest_demuxer_->Seek(base::Seconds(100),
312                           base::BindOnce(&ManifestDemuxerTest::MockSeekComplete,
313                                          base::Unretained(this)));
314   task_environment_.RunUntilIdle();
315
316   // When we execute `delay_cb`, it will trigger `SeekInternal`, which will kick
317   // off a call to ChunkDemuxer::Seek and will also recapture a new `delay_cb`.
318   // The new `delay_cb` is bound to a task which completes the enigne seek step.
319   // The chunk demuxer should have already responded, and the pending seek
320   // should only be waiting on the engine.
321   EXPECT_CALL(*mock_engine_, Seek(_, _))
322       .WillOnce(RunOnceCallback<1>(ManifestDemuxer::SeekState::kNeedsData));
323   std::move(delay_cb).Run(kNoTimestamp);
324   task_environment_.RunUntilIdle();
325   ASSERT_TRUE(!!delay_cb);
326   ASSERT_TRUE(manifest_demuxer_->has_pending_seek_for_testing());
327   ASSERT_TRUE(manifest_demuxer_->has_pending_event_for_testing());
328
329   EXPECT_CALL(*mock_engine_, AbortPendingReads());
330   manifest_demuxer_->CancelPendingSeek(base::Seconds(5));
331   task_environment_.RunUntilIdle();
332   ASSERT_EQ(manifest_demuxer_->get_media_time_for_testing(),
333             base::Seconds(100));
334
335   // Running `delay_cb` will finish the seek, and start a new update, even if
336   // it runs with kNoTimestamp.
337   EXPECT_CALL(*this, MockSeekComplete(_));
338   std::move(delay_cb).Run(kNoTimestamp);
339   task_environment_.RunUntilIdle();
340   ASSERT_TRUE(!!delay_cb);
341   ASSERT_EQ(manifest_demuxer_->get_media_time_for_testing(),
342             base::Seconds(100));
343
344   // Run it again to end the loop.
345   std::move(delay_cb).Run(kNoTimestamp);
346   task_environment_.RunUntilIdle();
347   ASSERT_TRUE(!delay_cb);
348   ASSERT_FALSE(manifest_demuxer_->has_pending_seek_for_testing());
349   ASSERT_FALSE(manifest_demuxer_->has_pending_event_for_testing());
350 }
351
352 }  // namespace media