OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/callback_helpers.h" | 6 #include "base/callback_helpers.h" |
7 #include "base/gtest_prod_util.h" | 7 #include "base/gtest_prod_util.h" |
8 #include "base/memory/scoped_vector.h" | 8 #include "base/memory/scoped_vector.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 #include "media/filters/audio_renderer_impl.h" | 22 #include "media/filters/audio_renderer_impl.h" |
23 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
24 | 24 |
25 using ::base::Time; | 25 using ::base::Time; |
26 using ::base::TimeTicks; | 26 using ::base::TimeTicks; |
27 using ::base::TimeDelta; | 27 using ::base::TimeDelta; |
28 using ::testing::_; | 28 using ::testing::_; |
29 using ::testing::AnyNumber; | 29 using ::testing::AnyNumber; |
30 using ::testing::Invoke; | 30 using ::testing::Invoke; |
31 using ::testing::Return; | 31 using ::testing::Return; |
32 using ::testing::SaveArg; | |
32 | 33 |
33 namespace media { | 34 namespace media { |
34 | 35 |
35 // Constants to specify the type of audio data used. | 36 // Constants to specify the type of audio data used. |
36 static AudioCodec kCodec = kCodecVorbis; | 37 static AudioCodec kCodec = kCodecVorbis; |
37 static SampleFormat kSampleFormat = kSampleFormatPlanarF32; | 38 static SampleFormat kSampleFormat = kSampleFormatPlanarF32; |
38 static ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; | 39 static ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; |
39 static int kChannelCount = 2; | 40 static int kChannelCount = 2; |
40 static int kChannels = ChannelLayoutToChannelCount(kChannelLayout); | 41 static int kChannels = ChannelLayoutToChannelCount(kChannelLayout); |
41 static int kSamplesPerSecond = 44100; | 42 static int kSamplesPerSecond = 44100; |
(...skipping 28 matching lines...) Expand all Loading... | |
70 0, | 71 0, |
71 false); | 72 false); |
72 demuxer_stream_.set_audio_decoder_config(audio_config); | 73 demuxer_stream_.set_audio_decoder_config(audio_config); |
73 | 74 |
74 // Used to save callbacks and run them at a later time. | 75 // Used to save callbacks and run them at a later time. |
75 EXPECT_CALL(*decoder_, Decode(_, _)) | 76 EXPECT_CALL(*decoder_, Decode(_, _)) |
76 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::DecodeDecoder)); | 77 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::DecodeDecoder)); |
77 EXPECT_CALL(*decoder_, Reset(_)) | 78 EXPECT_CALL(*decoder_, Reset(_)) |
78 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::ResetDecoder)); | 79 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::ResetDecoder)); |
79 | 80 |
80 // Mock out demuxer reads | 81 // Mock out demuxer reads. |
81 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly( | 82 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly( |
82 RunCallback<0>(DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer())); | 83 RunCallback<0>(DemuxerStream::kOk, |
84 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0)))); | |
xhwang
2014/06/05 21:53:49
why making this change?
Sergey Ulanov
2014/06/06 22:49:39
DecoderStream<StreamType>::OnBufferReady() stops r
| |
83 EXPECT_CALL(demuxer_stream_, SupportsConfigChanges()) | 85 EXPECT_CALL(demuxer_stream_, SupportsConfigChanges()) |
84 .WillRepeatedly(Return(true)); | 86 .WillRepeatedly(Return(true)); |
85 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY, | 87 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
86 kChannelLayout, | 88 kChannelLayout, |
87 kOutputSamplesPerSecond, | 89 kOutputSamplesPerSecond, |
88 SampleFormatToBytesPerChannel(kSampleFormat) * 8, | 90 SampleFormatToBytesPerChannel(kSampleFormat) * 8, |
89 512); | 91 512); |
90 hardware_config_.UpdateOutputConfig(out_params); | 92 hardware_config_.UpdateOutputConfig(out_params); |
91 ScopedVector<AudioDecoder> decoders; | 93 ScopedVector<AudioDecoder> decoders; |
92 decoders.push_back(decoder_); | 94 decoders.push_back(decoder_); |
(...skipping 12 matching lines...) Expand all Loading... | |
105 virtual ~AudioRendererImplTest() { | 107 virtual ~AudioRendererImplTest() { |
106 SCOPED_TRACE("~AudioRendererImplTest()"); | 108 SCOPED_TRACE("~AudioRendererImplTest()"); |
107 if (needs_stop_) { | 109 if (needs_stop_) { |
108 WaitableMessageLoopEvent event; | 110 WaitableMessageLoopEvent event; |
109 renderer_->Stop(event.GetClosure()); | 111 renderer_->Stop(event.GetClosure()); |
110 event.RunAndWait(); | 112 event.RunAndWait(); |
111 } | 113 } |
112 } | 114 } |
113 | 115 |
114 void ExpectUnsupportedAudioDecoder() { | 116 void ExpectUnsupportedAudioDecoder() { |
115 EXPECT_CALL(*decoder_, Initialize(_, _)) | 117 EXPECT_CALL(*decoder_, Initialize(_, _, _)) |
116 .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED)); | 118 .WillOnce(DoAll(SaveArg<2>(&output_cb_), |
119 RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED))); | |
117 } | 120 } |
118 | 121 |
119 MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&)); | 122 MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&)); |
120 MOCK_METHOD0(OnUnderflow, void()); | 123 MOCK_METHOD0(OnUnderflow, void()); |
121 MOCK_METHOD1(OnError, void(PipelineStatus)); | 124 MOCK_METHOD1(OnError, void(PipelineStatus)); |
122 | 125 |
123 void OnAudioTimeCallback(TimeDelta current_time, TimeDelta max_time) { | 126 void OnAudioTimeCallback(TimeDelta current_time, TimeDelta max_time) { |
124 CHECK(current_time <= max_time); | 127 CHECK(current_time <= max_time); |
125 last_time_update_ = current_time; | 128 last_time_update_ = current_time; |
126 } | 129 } |
127 | 130 |
128 void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) { | 131 void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) { |
129 renderer_->Initialize( | 132 renderer_->Initialize( |
130 &demuxer_stream_, | 133 &demuxer_stream_, |
131 pipeline_status_cb, | 134 pipeline_status_cb, |
132 base::Bind(&AudioRendererImplTest::OnStatistics, | 135 base::Bind(&AudioRendererImplTest::OnStatistics, |
133 base::Unretained(this)), | 136 base::Unretained(this)), |
134 base::Bind(&AudioRendererImplTest::OnUnderflow, | 137 base::Bind(&AudioRendererImplTest::OnUnderflow, |
135 base::Unretained(this)), | 138 base::Unretained(this)), |
136 base::Bind(&AudioRendererImplTest::OnAudioTimeCallback, | 139 base::Bind(&AudioRendererImplTest::OnAudioTimeCallback, |
137 base::Unretained(this)), | 140 base::Unretained(this)), |
138 ended_event_.GetClosure(), | 141 ended_event_.GetClosure(), |
139 base::Bind(&AudioRendererImplTest::OnError, | 142 base::Bind(&AudioRendererImplTest::OnError, |
140 base::Unretained(this))); | 143 base::Unretained(this))); |
141 } | 144 } |
142 | 145 |
143 void Initialize() { | 146 void Initialize() { |
144 EXPECT_CALL(*decoder_, Initialize(_, _)) | 147 EXPECT_CALL(*decoder_, Initialize(_, _, _)) |
145 .WillOnce(RunCallback<1>(PIPELINE_OK)); | 148 .WillOnce(DoAll(SaveArg<2>(&output_cb_), |
149 RunCallback<1>(PIPELINE_OK))); | |
146 EXPECT_CALL(*decoder_, Stop()); | 150 EXPECT_CALL(*decoder_, Stop()); |
147 InitializeWithStatus(PIPELINE_OK); | 151 InitializeWithStatus(PIPELINE_OK); |
148 | 152 |
149 next_timestamp_.reset(new AudioTimestampHelper( | 153 next_timestamp_.reset(new AudioTimestampHelper( |
150 hardware_config_.GetOutputConfig().sample_rate())); | 154 hardware_config_.GetOutputConfig().sample_rate())); |
151 } | 155 } |
152 | 156 |
153 void InitializeWithStatus(PipelineStatus expected) { | 157 void InitializeWithStatus(PipelineStatus expected) { |
154 SCOPED_TRACE(base::StringPrintf("InitializeWithStatus(%d)", expected)); | 158 SCOPED_TRACE(base::StringPrintf("InitializeWithStatus(%d)", expected)); |
155 | 159 |
156 WaitableMessageLoopEvent event; | 160 WaitableMessageLoopEvent event; |
157 InitializeRenderer(event.GetPipelineStatusCB()); | 161 InitializeRenderer(event.GetPipelineStatusCB()); |
158 event.RunAndWaitForStatus(expected); | 162 event.RunAndWaitForStatus(expected); |
159 | 163 |
160 // We should have no reads. | 164 // We should have no reads. |
161 EXPECT_TRUE(decode_cb_.is_null()); | 165 EXPECT_TRUE(decode_cb_.is_null()); |
162 } | 166 } |
163 | 167 |
164 void InitializeAndStop() { | 168 void InitializeAndStop() { |
165 EXPECT_CALL(*decoder_, Initialize(_, _)) | 169 EXPECT_CALL(*decoder_, Initialize(_, _, _)) |
166 .WillOnce(RunCallback<1>(PIPELINE_OK)); | 170 .WillOnce(DoAll(SaveArg<2>(&output_cb_), |
171 RunCallback<1>(PIPELINE_OK))); | |
167 EXPECT_CALL(*decoder_, Stop()); | 172 EXPECT_CALL(*decoder_, Stop()); |
168 | 173 |
169 WaitableMessageLoopEvent event; | 174 WaitableMessageLoopEvent event; |
170 InitializeRenderer(event.GetPipelineStatusCB()); | 175 InitializeRenderer(event.GetPipelineStatusCB()); |
171 | 176 |
172 // Stop before we let the MessageLoop run, this simulates an interleaving | 177 // Stop before we let the MessageLoop run, this simulates an interleaving |
173 // in which we end up calling Stop() while the OnDecoderSelected callback | 178 // in which we end up calling Stop() while the OnDecoderSelected callback |
174 // is in flight. | 179 // is in flight. |
175 renderer_->Stop(NewExpectedClosure()); | 180 renderer_->Stop(NewExpectedClosure()); |
176 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT); | 181 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT); |
177 EXPECT_EQ(renderer_->state_, AudioRendererImpl::kStopped); | 182 EXPECT_EQ(renderer_->state_, AudioRendererImpl::kStopped); |
178 } | 183 } |
179 | 184 |
180 void InitializeAndStopDuringDecoderInit() { | 185 void InitializeAndStopDuringDecoderInit() { |
181 EXPECT_CALL(*decoder_, Initialize(_, _)) | 186 EXPECT_CALL(*decoder_, Initialize(_, _, _)) |
182 .WillOnce(EnterPendingDecoderInitStateAction(this)); | 187 .WillOnce(DoAll(SaveArg<2>(&output_cb_), |
188 EnterPendingDecoderInitStateAction(this))); | |
183 EXPECT_CALL(*decoder_, Stop()); | 189 EXPECT_CALL(*decoder_, Stop()); |
184 | 190 |
185 WaitableMessageLoopEvent event; | 191 WaitableMessageLoopEvent event; |
186 InitializeRenderer(event.GetPipelineStatusCB()); | 192 InitializeRenderer(event.GetPipelineStatusCB()); |
187 | 193 |
188 base::RunLoop().RunUntilIdle(); | 194 base::RunLoop().RunUntilIdle(); |
189 DCHECK(!init_decoder_cb_.is_null()); | 195 DCHECK(!init_decoder_cb_.is_null()); |
190 | 196 |
191 renderer_->Stop(NewExpectedClosure()); | 197 renderer_->Stop(NewExpectedClosure()); |
192 base::ResetAndReturn(&init_decoder_cb_).Run(PIPELINE_OK); | 198 base::ResetAndReturn(&init_decoder_cb_).Run(PIPELINE_OK); |
(...skipping 23 matching lines...) Expand all Loading... | |
216 | 222 |
217 TimeDelta timestamp = TimeDelta::FromMilliseconds(timestamp_ms); | 223 TimeDelta timestamp = TimeDelta::FromMilliseconds(timestamp_ms); |
218 next_timestamp_->SetBaseTimestamp(timestamp); | 224 next_timestamp_->SetBaseTimestamp(timestamp); |
219 | 225 |
220 // Fill entire buffer to complete prerolling. | 226 // Fill entire buffer to complete prerolling. |
221 WaitableMessageLoopEvent event; | 227 WaitableMessageLoopEvent event; |
222 renderer_->Preroll(timestamp, event.GetPipelineStatusCB()); | 228 renderer_->Preroll(timestamp, event.GetPipelineStatusCB()); |
223 WaitForPendingRead(); | 229 WaitForPendingRead(); |
224 DeliverRemainingAudio(); | 230 DeliverRemainingAudio(); |
225 event.RunAndWaitForStatus(PIPELINE_OK); | 231 event.RunAndWaitForStatus(PIPELINE_OK); |
226 | |
227 // We should have no reads. | |
228 EXPECT_TRUE(decode_cb_.is_null()); | |
229 } | 232 } |
230 | 233 |
231 void StartRendering() { | 234 void StartRendering() { |
232 renderer_->StartRendering(); | 235 renderer_->StartRendering(); |
233 renderer_->SetPlaybackRate(1.0f); | 236 renderer_->SetPlaybackRate(1.0f); |
234 } | 237 } |
235 | 238 |
236 void StopRendering() { | 239 void StopRendering() { |
237 renderer_->StopRendering(); | 240 renderer_->StopRendering(); |
238 } | 241 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 kChannelLayout, | 280 kChannelLayout, |
278 kChannelCount, | 281 kChannelCount, |
279 kSamplesPerSecond, | 282 kSamplesPerSecond, |
280 kPlayingAudio, | 283 kPlayingAudio, |
281 0.0f, | 284 0.0f, |
282 size, | 285 size, |
283 next_timestamp_->GetTimestamp()); | 286 next_timestamp_->GetTimestamp()); |
284 next_timestamp_->AddFrames(size); | 287 next_timestamp_->AddFrames(size); |
285 | 288 |
286 DeliverBuffer(AudioDecoder::kOk, buffer); | 289 DeliverBuffer(AudioDecoder::kOk, buffer); |
290 message_loop_.RunUntilIdle(); | |
287 } | 291 } |
288 | 292 |
289 void AbortPendingRead() { | 293 void AbortPendingRead() { |
290 DeliverBuffer(AudioDecoder::kAborted, NULL); | 294 DeliverBuffer(AudioDecoder::kAborted, NULL); |
291 } | 295 } |
292 | 296 |
293 void DeliverEndOfStream() { | 297 void DeliverEndOfStream() { |
294 DeliverBuffer(AudioDecoder::kOk, AudioBuffer::CreateEOSBuffer()); | 298 while (!decode_cb_.is_null()) { |
299 DeliverBuffer(AudioDecoder::kOk, AudioBuffer::CreateEOSBuffer()); | |
300 message_loop_.RunUntilIdle(); | |
xhwang
2014/06/05 21:53:49
Run the message loop in DeliverBuffer()?
Sergey Ulanov
2014/06/06 22:49:40
Done.
| |
301 } | |
xhwang
2014/06/05 21:53:49
why "while" loop? There could be only one pending
Sergey Ulanov
2014/06/06 22:49:40
DecoderStream::OnDecodeDone() may get another buff
| |
295 } | 302 } |
296 | 303 |
297 // Delivers frames until |renderer_|'s internal buffer is full and no longer | 304 // Delivers frames until |renderer_|'s internal buffer is full and no longer |
298 // has pending reads. | 305 // has pending reads. |
299 void DeliverRemainingAudio() { | 306 void DeliverRemainingAudio() { |
300 SatisfyPendingRead(frames_remaining_in_buffer()); | 307 SatisfyPendingRead(frames_remaining_in_buffer()); |
308 message_loop_.RunUntilIdle(); | |
xhwang
2014/06/05 21:53:49
SatisfyPendingRead() already runs the message loop
Sergey Ulanov
2014/06/06 22:49:39
Done.
| |
301 } | 309 } |
302 | 310 |
303 // Attempts to consume |requested_frames| frames from |renderer_|'s internal | 311 // Attempts to consume |requested_frames| frames from |renderer_|'s internal |
304 // buffer, returning true if all |requested_frames| frames were consumed, | 312 // buffer, returning true if all |requested_frames| frames were consumed, |
305 // false if less than |requested_frames| frames were consumed. | 313 // false if less than |requested_frames| frames were consumed. |
306 // | 314 // |
307 // |muted| is optional and if passed will get set if the value of | 315 // |muted| is optional and if passed will get set if the value of |
308 // the consumed data is muted audio. | 316 // the consumed data is muted audio. |
309 bool ConsumeBufferedData(int requested_frames, bool* muted) { | 317 bool ConsumeBufferedData(int requested_frames, bool* muted) { |
310 scoped_ptr<AudioBus> bus = | 318 scoped_ptr<AudioBus> bus = |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
458 | 466 |
459 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not permitted"; | 467 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not permitted"; |
460 decode_cb_ = decode_cb; | 468 decode_cb_ = decode_cb; |
461 | 469 |
462 // Wake up WaitForPendingRead() if needed. | 470 // Wake up WaitForPendingRead() if needed. |
463 if (!wait_for_pending_decode_cb_.is_null()) | 471 if (!wait_for_pending_decode_cb_.is_null()) |
464 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run(); | 472 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run(); |
465 } | 473 } |
466 | 474 |
467 void ResetDecoder(const base::Closure& reset_cb) { | 475 void ResetDecoder(const base::Closure& reset_cb) { |
468 CHECK(decode_cb_.is_null()) | 476 if (!decode_cb_.is_null()) { |
469 << "Reset overlapping with reads is not permitted"; | 477 reset_cb_ = reset_cb; |
xhwang
2014/06/05 21:53:49
Add a comment that in this case the |reset_cb| is
Sergey Ulanov
2014/06/06 22:49:39
Done.
| |
478 return; | |
479 } | |
470 | 480 |
471 message_loop_.PostTask(FROM_HERE, reset_cb); | 481 message_loop_.PostTask(FROM_HERE, reset_cb); |
472 } | 482 } |
473 | 483 |
474 void DeliverBuffer(AudioDecoder::Status status, | 484 void DeliverBuffer(AudioDecoder::Status status, |
475 const scoped_refptr<AudioBuffer>& buffer) { | 485 const scoped_refptr<AudioBuffer>& buffer) { |
476 CHECK(!decode_cb_.is_null()); | 486 CHECK(!decode_cb_.is_null()); |
477 base::ResetAndReturn(&decode_cb_).Run(status, buffer); | 487 if (buffer) |
488 output_cb_.Run(buffer); | |
489 base::ResetAndReturn(&decode_cb_).Run(status); | |
490 | |
491 if (!reset_cb_.is_null()) | |
492 base::ResetAndReturn(&reset_cb_).Run(); | |
478 } | 493 } |
479 | 494 |
480 MockDemuxerStream demuxer_stream_; | 495 MockDemuxerStream demuxer_stream_; |
481 MockAudioDecoder* decoder_; | 496 MockAudioDecoder* decoder_; |
482 | 497 |
483 // Used for stubbing out time in the audio callback thread. | 498 // Used for stubbing out time in the audio callback thread. |
484 base::Lock lock_; | 499 base::Lock lock_; |
485 TimeTicks time_; | 500 TimeTicks time_; |
486 | 501 |
487 // Used for satisfying reads. | 502 // Used for satisfying reads. |
503 AudioDecoder::OutputCB output_cb_; | |
488 AudioDecoder::DecodeCB decode_cb_; | 504 AudioDecoder::DecodeCB decode_cb_; |
505 base::Closure reset_cb_; | |
489 scoped_ptr<AudioTimestampHelper> next_timestamp_; | 506 scoped_ptr<AudioTimestampHelper> next_timestamp_; |
490 | 507 |
491 WaitableMessageLoopEvent ended_event_; | 508 WaitableMessageLoopEvent ended_event_; |
492 | 509 |
493 // Run during DecodeDecoder() to unblock WaitForPendingRead(). | 510 // Run during DecodeDecoder() to unblock WaitForPendingRead(). |
494 base::Closure wait_for_pending_decode_cb_; | 511 base::Closure wait_for_pending_decode_cb_; |
495 base::Closure stop_decoder_cb_; | 512 base::Closure stop_decoder_cb_; |
496 | 513 |
497 PipelineStatusCB init_decoder_cb_; | 514 PipelineStatusCB init_decoder_cb_; |
498 base::TimeDelta last_time_update_; | 515 base::TimeDelta last_time_update_; |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
993 // Start rendering with zero playback rate. Sink should be paused until | 1010 // Start rendering with zero playback rate. Sink should be paused until |
994 // non-zero rate is set. | 1011 // non-zero rate is set. |
995 renderer_->SetPlaybackRate(0.0f); | 1012 renderer_->SetPlaybackRate(0.0f); |
996 renderer_->StartRendering(); | 1013 renderer_->StartRendering(); |
997 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state()); | 1014 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state()); |
998 renderer_->SetPlaybackRate(1.0f); | 1015 renderer_->SetPlaybackRate(1.0f); |
999 EXPECT_EQ(FakeAudioRendererSink::kPlaying, sink_->state()); | 1016 EXPECT_EQ(FakeAudioRendererSink::kPlaying, sink_->state()); |
1000 } | 1017 } |
1001 | 1018 |
1002 } // namespace media | 1019 } // namespace media |
OLD | NEW |