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.
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"
20 // Helper macro to skip the test if MediaCodecBridge isn't available.
21 #define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
23 if (!MediaCodecBridge::IsAvailable()) { \
24 VLOG(0) << "Could not run test - not supported on device."; \
29 #define RUN_ON_MEDIA_THREAD(CLASS, METHOD, ...) \
31 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
32 GetMediaTaskRunner()->PostTask( \
34 base::Bind(&CLASS::METHOD, base::Unretained(this), ##__VA_ARGS__)); \
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
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
{
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
,
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
;
119 MediaMetadata() : width(0), height(0), modified(false) {}
121 MediaMetadata media_metadata_
;
123 Minimax
<base::TimeDelta
> pts_stat_
;
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;
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
;
156 // AudioFactory creates data chunks that simulate audio stream from demuxer.
158 class AudioFactory
: public TestDataFactory
{
160 AudioFactory(base::TimeDelta duration
)
161 : TestDataFactory("aac-44100-packet-%d", duration
, kAudioFramePeriod
) {}
163 DemuxerConfigs
GetConfigs() const override
{
164 return TestDataFactory::CreateAudioConfigs(kCodecAAC
, duration_
);
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
{
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));
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:
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;
201 case 1: // second frame
202 unit
->timestamp
+= frame_period_
;
204 case 2: // third frame
205 unit
->timestamp
-= frame_period_
;
207 case 3: // fourth frame, do not modify
216 // Mock of DemuxerAndroid for testing purpose.
218 class MockDemuxerAndroid
: public DemuxerAndroid
{
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_
; }
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());
263 if (pending_configs_
)
264 client_
->OnDemuxerConfigsAvailable(*pending_configs_
);
267 void MockDemuxerAndroid::RequestDemuxerData(DemuxerStream::Type type
) {
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
);
282 // Post to Media thread.
284 GetMediaTaskRunner()->PostDelayedTask(
285 FROM_HERE
, base::Bind(&DemuxerAndroidClient::OnDemuxerDataAvailable
,
286 base::Unretained(client_
), chunk
),
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.
294 audio_factory_
->SeekTo(time_to_seek
);
296 video_factory_
->SeekTo(time_to_seek
);
298 // Post OnDemuxerSeekDone() to the player.
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());
315 client_
->OnDemuxerConfigsAvailable(configs
);
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_
) {
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
{
339 MediaCodecPlayerTest();
340 ~MediaCodecPlayerTest() override
;
342 // Conditions to wait for.
343 bool IsPaused() const { return !(player_
&& player_
->IsPlaying()); }
346 typedef base::Callback
<bool()> Predicate
;
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()
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() {
387 player_
->DeleteOnCorrectThread();
390 void MediaCodecPlayerTest::CreatePlayer() {
392 player_
= new MediaCodecPlayer(
394 manager_
.GetWeakPtr(),
395 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested
,
396 base::Unretained(&manager_
)),
397 scoped_ptr
<MockDemuxerAndroid
>(demuxer_
), GURL());
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));
423 if (condition
.Run()) {
427 message_loop_
.RunUntilIdle();
428 } while (!is_timeout_expired());
430 DCHECK(!timer
.IsRunning());
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
),
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.
463 // Configuration should propagate through the player and to the manager.
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
) {
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.
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
) {
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.
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
)));
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());
539 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted
,
540 base::Unretained(&manager_
)),
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
)));
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());
573 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted
,
574 base::Unretained(&manager_
)),
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
)));
593 // Post configuration.
594 demuxer_
->PostInternalConfigs();
599 // Wait for playback to start.
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))));
619 manager_
.pts_stat_
.Clear();
621 // Now we can seek to the beginning and start the playback.
622 player_
->SeekTo(base::TimeDelta());
626 // Wait for playback to start.
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
)));
649 // Post configuration.
650 demuxer_
->PostInternalConfigs();
652 // Seek and immediately start.
653 player_
->SeekTo(seek_position
);
656 // Wait for playback to start.
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
)));
680 // Seek and immediately start.
681 player_
->SeekTo(seek_position
);
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.
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
)));
717 // Post configuration.
718 demuxer_
->PostInternalConfigs();
723 // Wait for playback to start.
725 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted
,
726 base::Unretained(&manager_
))));
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,
741 EXPECT_TRUE(WaitForPlaybackBeyondPosition(base::TimeDelta::FromSeconds(5)));
742 EXPECT_TRUE(player_
->IsPlaying());