Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / media / base / android / media_codec_player_unittest.cc
blobf818bac89b74ab4a650725ec41e6f0d889372bed
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/bind.h"
6 #include "base/logging.h"
7 #include "base/timer/timer.h"
8 #include "media/base/android/demuxer_android.h"
9 #include "media/base/android/media_codec_bridge.h"
10 #include "media/base/android/media_codec_player.h"
11 #include "media/base/android/media_player_manager.h"
12 #include "media/base/android/test_data_factory.h"
13 #include "media/base/android/test_statistics.h"
14 #include "media/base/buffers.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/gl/android/surface_texture.h"
18 namespace media {
20 // Helper macro to skip the test if MediaCodecBridge isn't available.
21 #define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
22 do { \
23 if (!MediaCodecBridge::IsAvailable()) { \
24 VLOG(0) << "Could not run test - not supported on device."; \
25 return; \
26 } \
27 } while (0)
29 #define RUN_ON_MEDIA_THREAD(CLASS, METHOD, ...) \
30 do { \
31 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
32 GetMediaTaskRunner()->PostTask( \
33 FROM_HERE, \
34 base::Bind(&CLASS::METHOD, base::Unretained(this), ##__VA_ARGS__)); \
35 return; \
36 } \
37 } while (0)
39 namespace {
41 const base::TimeDelta kDefaultTimeout = base::TimeDelta::FromMilliseconds(200);
42 const base::TimeDelta kAudioFramePeriod =
43 base::TimeDelta::FromSecondsD(1024.0 / 44100); // 1024 samples @ 44100 Hz
44 const base::TimeDelta kVideoFramePeriod = base::TimeDelta::FromMilliseconds(20);
46 // The predicate that always returns false, used for WaitForDelay implementation
47 bool AlwaysFalse() {
48 return false;
51 // The method used to compare two TimeDelta values in expectations.
52 bool AlmostEqual(base::TimeDelta a, base::TimeDelta b, double tolerance_ms) {
53 return (a - b).magnitude().InMilliseconds() <= tolerance_ms;
56 // Mock of MediaPlayerManager for testing purpose.
58 class MockMediaPlayerManager : public MediaPlayerManager {
59 public:
60 MockMediaPlayerManager()
61 : playback_completed_(false), weak_ptr_factory_(this) {}
62 ~MockMediaPlayerManager() override {}
64 MediaResourceGetter* GetMediaResourceGetter() override { return nullptr; }
65 MediaUrlInterceptor* GetMediaUrlInterceptor() override { return nullptr; }
67 void OnTimeUpdate(int player_id,
68 base::TimeDelta current_timestamp,
69 base::TimeTicks current_time_ticks) override {
70 pts_stat_.AddValue(current_timestamp);
73 void OnMediaMetadataChanged(int player_id,
74 base::TimeDelta duration,
75 int width,
76 int height,
77 bool success) override {
78 media_metadata_.duration = duration;
79 media_metadata_.width = width;
80 media_metadata_.height = height;
81 media_metadata_.modified = true;
84 void OnPlaybackComplete(int player_id) override {
85 playback_completed_ = true;
88 void OnMediaInterrupted(int player_id) override {}
89 void OnBufferingUpdate(int player_id, int percentage) override {}
90 void OnSeekComplete(int player_id,
91 const base::TimeDelta& current_time) override {}
92 void OnError(int player_id, int error) override {}
93 void OnVideoSizeChanged(int player_id, int width, int height) override {}
94 void OnAudibleStateChanged(int player_id, bool is_audible_now) override {}
95 void OnWaitingForDecryptionKey(int player_id) override {}
96 MediaPlayerAndroid* GetFullscreenPlayer() override { return nullptr; }
97 MediaPlayerAndroid* GetPlayer(int player_id) override { return nullptr; }
98 bool RequestPlay(int player_id) override { return true; }
100 void OnMediaResourcesRequested(int player_id) {}
102 base::WeakPtr<MockMediaPlayerManager> GetWeakPtr() {
103 return weak_ptr_factory_.GetWeakPtr();
106 // Conditions to wait for.
107 bool IsMetadataChanged() const { return media_metadata_.modified; }
108 bool IsPlaybackCompleted() const { return playback_completed_; }
109 bool IsPlaybackStarted() const { return pts_stat_.num_values() > 0; }
110 bool IsPlaybackBeyondPosition(const base::TimeDelta& pts) const {
111 return pts_stat_.max() > pts;
114 struct MediaMetadata {
115 base::TimeDelta duration;
116 int width;
117 int height;
118 bool modified;
119 MediaMetadata() : width(0), height(0), modified(false) {}
121 MediaMetadata media_metadata_;
123 Minimax<base::TimeDelta> pts_stat_;
125 private:
126 bool playback_completed_;
128 base::WeakPtrFactory<MockMediaPlayerManager> weak_ptr_factory_;
130 DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager);
133 // Helper method that creates demuxer configuration.
135 DemuxerConfigs CreateAudioVideoConfigs(const base::TimeDelta& duration,
136 const gfx::Size& video_size) {
137 DemuxerConfigs configs =
138 TestDataFactory::CreateAudioConfigs(kCodecAAC, duration);
139 configs.video_codec = kCodecVP8;
140 configs.video_size = video_size;
141 configs.is_video_encrypted = false;
142 return configs;
145 DemuxerConfigs CreateAudioVideoConfigs(const TestDataFactory* audio,
146 const TestDataFactory* video) {
147 DemuxerConfigs result = audio->GetConfigs();
148 DemuxerConfigs vconf = video->GetConfigs();
150 result.video_codec = vconf.video_codec;
151 result.video_size = vconf.video_size;
152 result.is_video_encrypted = vconf.is_video_encrypted;
153 return result;
156 // AudioFactory creates data chunks that simulate audio stream from demuxer.
158 class AudioFactory : public TestDataFactory {
159 public:
160 AudioFactory(base::TimeDelta duration)
161 : TestDataFactory("aac-44100-packet-%d", duration, kAudioFramePeriod) {}
163 DemuxerConfigs GetConfigs() const override {
164 return TestDataFactory::CreateAudioConfigs(kCodecAAC, duration_);
167 protected:
168 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override {
169 unit->is_key_frame = true;
173 // VideoFactory creates a video stream from demuxer.
175 class VideoFactory : public TestDataFactory {
176 public:
177 VideoFactory(base::TimeDelta duration)
178 : TestDataFactory("h264-320x180-frame-%d", duration, kVideoFramePeriod) {}
180 DemuxerConfigs GetConfigs() const override {
181 return TestDataFactory::CreateVideoConfigs(kCodecH264, duration_,
182 gfx::Size(320, 180));
185 protected:
186 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override {
187 // The frames are taken from High profile and some are B-frames.
188 // The first 4 frames appear in the file in the following order:
190 // Frames: I P B P
191 // Decoding order: 0 1 2 3
192 // Presentation order: 0 2 1 4(3)
194 // I keep the last PTS to be 3 for simplicity.
196 // Swap pts for second and third frames. Make first frame a key frame.
197 switch (index_in_chunk) {
198 case 0: // first frame
199 unit->is_key_frame = true;
200 break;
201 case 1: // second frame
202 unit->timestamp += frame_period_;
203 break;
204 case 2: // third frame
205 unit->timestamp -= frame_period_;
206 break;
207 case 3: // fourth frame, do not modify
208 break;
209 default:
210 NOTREACHED();
211 break;
216 // Mock of DemuxerAndroid for testing purpose.
218 class MockDemuxerAndroid : public DemuxerAndroid {
219 public:
220 MockDemuxerAndroid() : client_(nullptr) {}
221 ~MockDemuxerAndroid() override {}
223 // DemuxerAndroid implementation
224 void Initialize(DemuxerAndroidClient* client) override;
225 void RequestDemuxerData(DemuxerStream::Type type) override;
226 void RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
227 bool is_browser_seek) override;
229 // Sets the audio data factory.
230 void SetAudioFactory(scoped_ptr<TestDataFactory> factory) {
231 audio_factory_ = factory.Pass();
234 // Sets the video data factory.
235 void SetVideoFactory(scoped_ptr<TestDataFactory> factory) {
236 video_factory_ = factory.Pass();
239 // Post DemuxerConfigs to the client (i.e. the player) on correct thread.
240 void PostConfigs(const DemuxerConfigs& configs);
242 // Post DemuxerConfigs derived from data factories that has been set.
243 void PostInternalConfigs();
245 // Conditions to wait for.
246 bool IsInitialized() const { return client_; }
247 bool HasPendingConfigs() const { return pending_configs_; }
249 private:
250 DemuxerAndroidClient* client_;
251 scoped_ptr<DemuxerConfigs> pending_configs_;
252 scoped_ptr<TestDataFactory> audio_factory_;
253 scoped_ptr<TestDataFactory> video_factory_;
255 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid);
258 void MockDemuxerAndroid::Initialize(DemuxerAndroidClient* client) {
259 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__;
260 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
262 client_ = client;
263 if (pending_configs_)
264 client_->OnDemuxerConfigsAvailable(*pending_configs_);
267 void MockDemuxerAndroid::RequestDemuxerData(DemuxerStream::Type type) {
268 DemuxerData chunk;
269 base::TimeDelta delay;
271 bool created = false;
272 if (type == DemuxerStream::AUDIO && audio_factory_)
273 created = audio_factory_->CreateChunk(&chunk, &delay);
274 else if (type == DemuxerStream::VIDEO && video_factory_)
275 created = video_factory_->CreateChunk(&chunk, &delay);
277 if (!created)
278 return;
280 chunk.type = type;
282 // Post to Media thread.
283 DCHECK(client_);
284 GetMediaTaskRunner()->PostDelayedTask(
285 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerDataAvailable,
286 base::Unretained(client_), chunk),
287 delay);
290 void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
291 bool is_browser_seek) {
292 // Tell data factories to start next chunk with the new timestamp.
293 if (audio_factory_)
294 audio_factory_->SeekTo(time_to_seek);
295 if (video_factory_)
296 video_factory_->SeekTo(time_to_seek);
298 // Post OnDemuxerSeekDone() to the player.
299 DCHECK(client_);
300 base::TimeDelta reported_seek_time =
301 is_browser_seek ? time_to_seek : kNoTimestamp();
302 GetMediaTaskRunner()->PostTask(
303 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerSeekDone,
304 base::Unretained(client_), reported_seek_time));
307 void MockDemuxerAndroid::PostConfigs(const DemuxerConfigs& configs) {
308 RUN_ON_MEDIA_THREAD(MockDemuxerAndroid, PostConfigs, configs);
310 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__;
312 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
314 if (client_)
315 client_->OnDemuxerConfigsAvailable(configs);
316 else
317 pending_configs_ = scoped_ptr<DemuxerConfigs>(new DemuxerConfigs(configs));
320 void MockDemuxerAndroid::PostInternalConfigs() {
321 ASSERT_TRUE(audio_factory_ || video_factory_);
323 if (audio_factory_ && video_factory_) {
324 PostConfigs(
325 CreateAudioVideoConfigs(audio_factory_.get(), video_factory_.get()));
326 } else if (audio_factory_) {
327 PostConfigs(audio_factory_->GetConfigs());
328 } else if (video_factory_) {
329 PostConfigs(video_factory_->GetConfigs());
333 } // namespace (anonymous)
335 // The test fixture for MediaCodecPlayer
337 class MediaCodecPlayerTest : public testing::Test {
338 public:
339 MediaCodecPlayerTest();
340 ~MediaCodecPlayerTest() override;
342 // Conditions to wait for.
343 bool IsPaused() const { return !(player_ && player_->IsPlaying()); }
345 protected:
346 typedef base::Callback<bool()> Predicate;
348 void CreatePlayer();
349 void SetVideoSurface();
351 // Waits for condition to become true or for timeout to expire.
352 // Returns true if the condition becomes true.
353 bool WaitForCondition(const Predicate& condition,
354 const base::TimeDelta& timeout = kDefaultTimeout);
356 // Waits for timeout to expire.
357 void WaitForDelay(const base::TimeDelta& timeout);
359 // Waits till playback position as determined by maximal reported pts
360 // reaches the given value or for timeout to expire. Returns true if the
361 // playback has passed the given position.
362 bool WaitForPlaybackBeyondPosition(
363 const base::TimeDelta& pts,
364 const base::TimeDelta& timeout = kDefaultTimeout);
366 base::MessageLoop message_loop_;
367 MockMediaPlayerManager manager_;
368 MockDemuxerAndroid* demuxer_; // owned by player_
369 scoped_refptr<gfx::SurfaceTexture> surface_texture_;
370 MediaCodecPlayer* player_; // raw pointer due to DeleteOnCorrectThread()
372 private:
373 bool is_timeout_expired() const { return is_timeout_expired_; }
374 void SetTimeoutExpired(bool value) { is_timeout_expired_ = value; }
376 bool is_timeout_expired_;
378 DISALLOW_COPY_AND_ASSIGN(MediaCodecPlayerTest);
381 MediaCodecPlayerTest::MediaCodecPlayerTest()
382 : demuxer_(new MockDemuxerAndroid()), player_(nullptr) {
385 MediaCodecPlayerTest::~MediaCodecPlayerTest() {
386 if (player_)
387 player_->DeleteOnCorrectThread();
390 void MediaCodecPlayerTest::CreatePlayer() {
391 DCHECK(demuxer_);
392 player_ = new MediaCodecPlayer(
393 0, // player_id
394 manager_.GetWeakPtr(),
395 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested,
396 base::Unretained(&manager_)),
397 scoped_ptr<MockDemuxerAndroid>(demuxer_), GURL());
399 DCHECK(player_);
402 void MediaCodecPlayerTest::SetVideoSurface() {
403 surface_texture_ = gfx::SurfaceTexture::Create(0);
404 gfx::ScopedJavaSurface surface(surface_texture_.get());
406 ASSERT_NE(nullptr, player_);
407 player_->SetVideoSurface(surface.Pass());
410 bool MediaCodecPlayerTest::WaitForCondition(const Predicate& condition,
411 const base::TimeDelta& timeout) {
412 // Let the message_loop_ process events.
413 // We start the timer and RunUntilIdle() until it signals.
415 SetTimeoutExpired(false);
417 base::Timer timer(false, false);
418 timer.Start(FROM_HERE, timeout,
419 base::Bind(&MediaCodecPlayerTest::SetTimeoutExpired,
420 base::Unretained(this), true));
422 do {
423 if (condition.Run()) {
424 timer.Stop();
425 return true;
427 message_loop_.RunUntilIdle();
428 } while (!is_timeout_expired());
430 DCHECK(!timer.IsRunning());
431 return false;
434 void MediaCodecPlayerTest::WaitForDelay(const base::TimeDelta& timeout) {
435 WaitForCondition(base::Bind(&AlwaysFalse), timeout);
438 bool MediaCodecPlayerTest::WaitForPlaybackBeyondPosition(
439 const base::TimeDelta& pts,
440 const base::TimeDelta& timeout) {
441 return WaitForCondition(
442 base::Bind(&MockMediaPlayerManager::IsPlaybackBeyondPosition,
443 base::Unretained(&manager_), pts),
444 timeout);
447 TEST_F(MediaCodecPlayerTest, SetAudioConfigsBeforePlayerCreation) {
448 // Post configuration when there is no player yet.
449 EXPECT_EQ(nullptr, player_);
451 base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
453 demuxer_->PostConfigs(
454 TestDataFactory::CreateAudioConfigs(kCodecAAC, duration));
456 // Wait until the configuration gets to the media thread.
457 EXPECT_TRUE(WaitForCondition(base::Bind(
458 &MockDemuxerAndroid::HasPendingConfigs, base::Unretained(demuxer_))));
460 // Then create the player.
461 CreatePlayer();
463 // Configuration should propagate through the player and to the manager.
464 EXPECT_TRUE(
465 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsMetadataChanged,
466 base::Unretained(&manager_))));
468 EXPECT_EQ(duration, manager_.media_metadata_.duration);
469 EXPECT_EQ(0, manager_.media_metadata_.width);
470 EXPECT_EQ(0, manager_.media_metadata_.height);
473 TEST_F(MediaCodecPlayerTest, SetAudioConfigsAfterPlayerCreation) {
474 CreatePlayer();
476 // Wait till the player is initialized on media thread.
477 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
478 base::Unretained(demuxer_))));
480 // Post configuration after the player has been initialized.
481 base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
482 demuxer_->PostConfigs(
483 TestDataFactory::CreateAudioConfigs(kCodecAAC, duration));
485 // Configuration should propagate through the player and to the manager.
486 EXPECT_TRUE(
487 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsMetadataChanged,
488 base::Unretained(&manager_))));
490 EXPECT_EQ(duration, manager_.media_metadata_.duration);
491 EXPECT_EQ(0, manager_.media_metadata_.width);
492 EXPECT_EQ(0, manager_.media_metadata_.height);
495 TEST_F(MediaCodecPlayerTest, SetAudioVideoConfigsAfterPlayerCreation) {
496 CreatePlayer();
498 // Wait till the player is initialized on media thread.
499 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
500 base::Unretained(demuxer_))));
502 // Post configuration after the player has been initialized.
503 base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
504 demuxer_->PostConfigs(CreateAudioVideoConfigs(duration, gfx::Size(320, 240)));
506 // Configuration should propagate through the player and to the manager.
507 EXPECT_TRUE(
508 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsMetadataChanged,
509 base::Unretained(&manager_))));
511 EXPECT_EQ(duration, manager_.media_metadata_.duration);
512 EXPECT_EQ(320, manager_.media_metadata_.width);
513 EXPECT_EQ(240, manager_.media_metadata_.height);
516 TEST_F(MediaCodecPlayerTest, AudioPlayTillCompletion) {
517 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
519 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1000);
520 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(2000);
522 demuxer_->SetAudioFactory(
523 scoped_ptr<AudioFactory>(new AudioFactory(duration)));
525 CreatePlayer();
527 // Wait till the player is initialized on media thread.
528 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
529 base::Unretained(demuxer_))));
531 // Post configuration after the player has been initialized.
532 demuxer_->PostInternalConfigs();
534 EXPECT_FALSE(manager_.IsPlaybackCompleted());
536 player_->Start();
538 EXPECT_TRUE(
539 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted,
540 base::Unretained(&manager_)),
541 timeout));
543 // Current timestamp reflects "now playing" time. It might come with delay
544 // relative to the frame's PTS. Allow for 100 ms delay here.
545 base::TimeDelta audio_pts_delay = base::TimeDelta::FromMilliseconds(100);
546 EXPECT_LT(duration - audio_pts_delay, manager_.pts_stat_.max());
549 TEST_F(MediaCodecPlayerTest, VideoPlayTillCompletion) {
550 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
552 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
553 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1500);
555 demuxer_->SetVideoFactory(
556 scoped_ptr<VideoFactory>(new VideoFactory(duration)));
558 CreatePlayer();
559 SetVideoSurface();
561 // Wait till the player is initialized on media thread.
562 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
563 base::Unretained(demuxer_))));
565 // Post configuration after the player has been initialized.
566 demuxer_->PostInternalConfigs();
568 EXPECT_FALSE(manager_.IsPlaybackCompleted());
570 player_->Start();
572 EXPECT_TRUE(
573 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted,
574 base::Unretained(&manager_)),
575 timeout));
577 EXPECT_LE(duration, manager_.pts_stat_.max());
580 TEST_F(MediaCodecPlayerTest, AudioSeekAfterStop) {
581 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
583 // Play for 300 ms, then Pause, then Seek to beginning. The playback should
584 // start from the beginning.
586 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(2000);
588 demuxer_->SetAudioFactory(
589 scoped_ptr<AudioFactory>(new AudioFactory(duration)));
591 CreatePlayer();
593 // Post configuration.
594 demuxer_->PostInternalConfigs();
596 // Start the player.
597 player_->Start();
599 // Wait for playback to start.
600 EXPECT_TRUE(
601 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
602 base::Unretained(&manager_))));
604 // Wait for 300 ms and stop. The 300 ms interval takes into account potential
605 // audio delay: audio takes time reconfiguring after the first several packets
606 // get written to the audio track.
607 WaitForDelay(base::TimeDelta::FromMilliseconds(300));
609 player_->Pause(true);
611 // Make sure we played at least 100 ms.
612 EXPECT_LT(base::TimeDelta::FromMilliseconds(100), manager_.pts_stat_.max());
614 // Wait till the Pause is completed.
615 EXPECT_TRUE(WaitForCondition(
616 base::Bind(&MediaCodecPlayerTest::IsPaused, base::Unretained(this))));
618 // Clear statistics.
619 manager_.pts_stat_.Clear();
621 // Now we can seek to the beginning and start the playback.
622 player_->SeekTo(base::TimeDelta());
624 player_->Start();
626 // Wait for playback to start.
627 EXPECT_TRUE(
628 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
629 base::Unretained(&manager_))));
631 // Make sure we started from the beginninig
632 EXPECT_GT(base::TimeDelta::FromMilliseconds(40), manager_.pts_stat_.min());
635 TEST_F(MediaCodecPlayerTest, AudioSeekThenPlay) {
636 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
638 // Issue Seek command immediately followed by Start. The playback should
639 // start at the seek position.
641 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(2000);
642 base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(500);
644 demuxer_->SetAudioFactory(
645 scoped_ptr<AudioFactory>(new AudioFactory(duration)));
647 CreatePlayer();
649 // Post configuration.
650 demuxer_->PostInternalConfigs();
652 // Seek and immediately start.
653 player_->SeekTo(seek_position);
654 player_->Start();
656 // Wait for playback to start.
657 EXPECT_TRUE(
658 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
659 base::Unretained(&manager_))));
661 // The playback should start at |seek_position|
662 EXPECT_TRUE(AlmostEqual(seek_position, manager_.pts_stat_.min(), 1));
665 TEST_F(MediaCodecPlayerTest, AudioSeekThenPlayThenConfig) {
666 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
668 // Issue Seek command immediately followed by Start but without prior demuxer
669 // configuration. Start should wait for configuration. After it has been
670 // posted the playback should start at the seek position.
672 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(2000);
673 base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(500);
675 demuxer_->SetAudioFactory(
676 scoped_ptr<AudioFactory>(new AudioFactory(duration)));
678 CreatePlayer();
680 // Seek and immediately start.
681 player_->SeekTo(seek_position);
682 player_->Start();
684 // Make sure the player is waiting.
685 WaitForDelay(base::TimeDelta::FromMilliseconds(200));
686 EXPECT_FALSE(player_->IsPlaying());
688 // Post configuration.
689 demuxer_->PostInternalConfigs();
691 // Wait for playback to start.
692 EXPECT_TRUE(
693 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
694 base::Unretained(&manager_))));
696 // The playback should start at |seek_position|
697 EXPECT_TRUE(AlmostEqual(seek_position, manager_.pts_stat_.min(), 1));
700 TEST_F(MediaCodecPlayerTest, AudioSeekWhilePlaying) {
701 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
703 // Play for 300 ms, then issue several Seek commands in the row.
704 // The playback should continue at the last seek position.
706 // To test this condition without analyzing the reported time details
707 // and without introducing dependency on implementation I make a long (10s)
708 // duration and test that the playback resumes after big time jump (5s) in a
709 // short period of time (200 ms).
710 base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
712 demuxer_->SetAudioFactory(
713 scoped_ptr<AudioFactory>(new AudioFactory(duration)));
715 CreatePlayer();
717 // Post configuration.
718 demuxer_->PostInternalConfigs();
720 // Start the player.
721 player_->Start();
723 // Wait for playback to start.
724 EXPECT_TRUE(
725 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
726 base::Unretained(&manager_))));
728 // Wait for 300 ms.
729 WaitForDelay(base::TimeDelta::FromMilliseconds(300));
731 // Make sure we played at least 100 ms.
732 EXPECT_LT(base::TimeDelta::FromMilliseconds(100), manager_.pts_stat_.max());
734 // Seek forward several times.
735 player_->SeekTo(base::TimeDelta::FromSeconds(3));
736 player_->SeekTo(base::TimeDelta::FromSeconds(4));
737 player_->SeekTo(base::TimeDelta::FromSeconds(5));
739 // Make sure that we reached the last timestamp within default timeout,
740 // i.e. 200 ms.
741 EXPECT_TRUE(WaitForPlaybackBeyondPosition(base::TimeDelta::FromSeconds(5)));
742 EXPECT_TRUE(player_->IsPlaying());
745 } // namespace media