OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chromecast/base/task_runner_impl.h" | |
6 #include "chromecast/media/audio/audio_manager.h" | |
7 #include "chromecast/media/audio/audio_output_stream.h" | |
8 #include "chromecast/public/media/audio_pipeline_device.h" | |
9 #include "chromecast/public/media/cast_decoder_buffer.h" | |
10 #include "chromecast/public/media/decoder_config.h" | |
11 #include "chromecast/public/media/decrypt_context.h" | |
12 #include "chromecast/public/media/media_clock_device.h" | |
13 #include "chromecast/public/media/media_pipeline_backend.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 namespace { | |
17 const char kDefaultDeviceId[] = ""; | |
gunsch
2015/09/18 21:23:07
can this be inside the another anonymous namespace
alokp
2015/09/18 21:42:15
Done.
| |
18 } // namespace | |
19 | |
20 namespace chromecast { | |
21 namespace media { | |
22 namespace { | |
23 | |
24 class FakeClockDevice : public MediaClockDevice { | |
25 public: | |
26 FakeClockDevice() : state_(kStateUninitialized), rate_(0.f) {} | |
27 ~FakeClockDevice() override {} | |
28 | |
29 State GetState() const override { return state_; } | |
30 bool SetState(State new_state) override { | |
31 state_ = new_state; | |
32 return true; | |
33 } | |
34 bool ResetTimeline(int64_t time_microseconds) override { return true; } | |
35 bool SetRate(float rate) override { | |
36 rate_ = rate; | |
37 return true; | |
38 } | |
39 int64_t GetTimeMicroseconds() override { return 0; } | |
40 | |
41 float rate() const { return rate_; } | |
42 | |
43 private: | |
44 State state_; | |
45 float rate_; | |
46 }; | |
47 | |
48 class FakeAudioPipelineDevice : public AudioPipelineDevice { | |
49 public: | |
50 enum PipelineStatus { | |
51 PIPELINE_STATUS_OK, | |
52 PIPELINE_STATUS_BUSY, | |
53 PIPELINE_STATUS_ERROR | |
54 }; | |
55 | |
56 FakeAudioPipelineDevice() | |
57 : state_(kStateUninitialized), | |
58 volume_multiplier_(1.0f), | |
59 pipeline_status_(PIPELINE_STATUS_OK), | |
60 pushed_frame_count_(0) {} | |
61 ~FakeAudioPipelineDevice() override {} | |
62 | |
63 // AudioPipelineDevice overrides. | |
64 void SetClient(Client* client) override {} | |
65 bool SetState(State new_state) override { | |
66 state_ = new_state; | |
67 return true; | |
68 } | |
69 State GetState() const override { return state_; } | |
70 bool SetStartPts(int64_t microseconds) override { return false; } | |
71 FrameStatus PushFrame(DecryptContext* decrypt_context, | |
72 CastDecoderBuffer* buffer, | |
73 FrameStatusCB* completion_cb) override { | |
74 last_frame_decrypt_context_.reset(decrypt_context); | |
75 last_frame_buffer_.reset(buffer); | |
76 last_frame_completion_cb_.reset(completion_cb); | |
77 ++pushed_frame_count_; | |
78 | |
79 switch (pipeline_status_) { | |
80 case PIPELINE_STATUS_OK: | |
81 return kFrameSuccess; | |
82 case PIPELINE_STATUS_BUSY: | |
83 return kFramePending; | |
84 case PIPELINE_STATUS_ERROR: | |
85 return kFrameFailed; | |
86 } | |
87 NOTREACHED(); | |
88 } | |
89 RenderingDelay GetRenderingDelay() const override { return RenderingDelay(); } | |
90 bool GetStatistics(Statistics* stats) const override { return false; } | |
91 bool SetConfig(const AudioConfig& config) override { | |
92 config_ = config; | |
93 return true; | |
94 } | |
95 void SetStreamVolumeMultiplier(float multiplier) override { | |
96 volume_multiplier_ = multiplier; | |
97 } | |
98 | |
99 const AudioConfig& config() const { return config_; } | |
100 float volume_multiplier() const { return volume_multiplier_; } | |
101 void set_pipeline_status(PipelineStatus status) { pipeline_status_ = status; } | |
102 unsigned pushed_frame_count() const { return pushed_frame_count_; } | |
103 DecryptContext* last_frame_decrypt_context() { | |
104 return last_frame_decrypt_context_.get(); | |
105 } | |
106 CastDecoderBuffer* last_frame_buffer() { return last_frame_buffer_.get(); } | |
107 FrameStatusCB* last_frame_completion_cb() { | |
108 return last_frame_completion_cb_.get(); | |
109 } | |
110 | |
111 private: | |
112 State state_; | |
113 AudioConfig config_; | |
114 float volume_multiplier_; | |
115 | |
116 PipelineStatus pipeline_status_; | |
117 unsigned pushed_frame_count_; | |
118 scoped_ptr<DecryptContext> last_frame_decrypt_context_; | |
119 scoped_ptr<CastDecoderBuffer> last_frame_buffer_; | |
120 scoped_ptr<FrameStatusCB> last_frame_completion_cb_; | |
121 }; | |
122 | |
123 class FakeMediaPipelineBackend : public MediaPipelineBackend { | |
124 public: | |
125 ~FakeMediaPipelineBackend() override {} | |
126 | |
127 MediaClockDevice* GetClock() override { | |
128 if (!clock_device_) | |
129 clock_device_.reset(new FakeClockDevice); | |
130 return clock_device_.get(); | |
131 } | |
132 AudioPipelineDevice* GetAudio() override { | |
133 if (!audio_device_) | |
134 audio_device_.reset(new FakeAudioPipelineDevice); | |
135 return audio_device_.get(); | |
136 } | |
137 VideoPipelineDevice* GetVideo() override { | |
138 NOTREACHED(); | |
139 return nullptr; | |
140 } | |
141 | |
142 private: | |
143 scoped_ptr<FakeClockDevice> clock_device_; | |
144 scoped_ptr<FakeAudioPipelineDevice> audio_device_; | |
145 }; | |
146 | |
147 class FakeAudioSourceCallback | |
148 : public ::media::AudioOutputStream::AudioSourceCallback { | |
149 public: | |
150 FakeAudioSourceCallback() : error_(false) {} | |
151 | |
152 bool error() const { return error_; } | |
153 | |
154 // ::media::AudioOutputStream::AudioSourceCallback overrides. | |
155 int OnMoreData(::media::AudioBus* audio_bus, | |
156 uint32 total_bytes_delay) override { | |
157 audio_bus->Zero(); | |
158 return audio_bus->frames(); | |
159 } | |
160 void OnError(::media::AudioOutputStream* stream) override { error_ = true; } | |
161 | |
162 private: | |
163 bool error_; | |
164 }; | |
165 | |
166 class FakeAudioManager : public AudioManager { | |
167 public: | |
168 FakeAudioManager() | |
169 : AudioManager(nullptr), media_pipeline_backend_(nullptr) {} | |
170 ~FakeAudioManager() override {} | |
171 | |
172 // AudioManager overrides. | |
173 scoped_ptr<MediaPipelineBackend> CreateMediaPipelineBackend() override { | |
174 DCHECK(!media_pipeline_backend_); | |
175 scoped_ptr<FakeMediaPipelineBackend> backend(new FakeMediaPipelineBackend); | |
176 // Cache the backend locally to be used by tests. | |
177 media_pipeline_backend_ = backend.get(); | |
178 return backend.Pass(); | |
179 } | |
180 void ReleaseOutputStream(::media::AudioOutputStream* stream) override { | |
181 DCHECK(media_pipeline_backend_); | |
182 media_pipeline_backend_ = nullptr; | |
183 AudioManager::ReleaseOutputStream(stream); | |
184 } | |
185 | |
186 // Returns the MediaPipelineBackend being used by the AudioOutputStream. | |
187 // Note: here is a valid MediaPipelineBackend only while the stream is open. | |
188 // Returns NULL at all other times. | |
189 FakeMediaPipelineBackend* media_pipeline_backend() { | |
190 return media_pipeline_backend_; | |
191 } | |
192 | |
193 private: | |
194 FakeMediaPipelineBackend* media_pipeline_backend_; | |
195 }; | |
196 | |
197 class AudioOutputStreamTest : public ::testing::Test { | |
198 public: | |
199 AudioOutputStreamTest() | |
200 : format_(::media::AudioParameters::AUDIO_PCM_LINEAR), | |
201 channel_layout_(::media::CHANNEL_LAYOUT_MONO), | |
202 sample_rate_(::media::AudioParameters::kAudioCDSampleRate), | |
203 bits_per_sample_(16), | |
204 frames_per_buffer_(256) {} | |
205 ~AudioOutputStreamTest() override {} | |
206 | |
207 protected: | |
208 void SetUp() override { | |
209 message_loop_.reset(new base::MessageLoop()); | |
210 audio_manager_.reset(new FakeAudioManager); | |
211 } | |
212 | |
213 void TearDown() override { | |
214 audio_manager_.reset(); | |
215 message_loop_.reset(); | |
216 } | |
217 | |
218 ::media::AudioParameters GetAudioParams() { | |
219 return ::media::AudioParameters(format_, channel_layout_, sample_rate_, | |
220 bits_per_sample_, frames_per_buffer_); | |
221 } | |
222 ::media::AudioOutputStream* CreateStream() { | |
223 return audio_manager_->MakeAudioOutputStream(GetAudioParams(), | |
224 kDefaultDeviceId); | |
225 } | |
226 FakeClockDevice* GetClock() { | |
227 MediaPipelineBackend* backend = audio_manager_->media_pipeline_backend(); | |
228 return backend ? static_cast<FakeClockDevice*>(backend->GetClock()) | |
229 : nullptr; | |
230 } | |
231 FakeAudioPipelineDevice* GetAudio() { | |
232 MediaPipelineBackend* backend = audio_manager_->media_pipeline_backend(); | |
233 return backend ? static_cast<FakeAudioPipelineDevice*>(backend->GetAudio()) | |
234 : nullptr; | |
235 } | |
236 | |
237 scoped_ptr<base::MessageLoop> message_loop_; | |
238 scoped_ptr<FakeAudioManager> audio_manager_; | |
239 scoped_ptr<TaskRunnerImpl> audio_task_runner_; | |
240 | |
241 // AudioParameters used to create AudioOutputStream. | |
242 // Tests can modify these parameters before calling CreateStream. | |
243 ::media::AudioParameters::Format format_; | |
244 ::media::ChannelLayout channel_layout_; | |
245 int sample_rate_; | |
246 int bits_per_sample_; | |
247 int frames_per_buffer_; | |
248 }; | |
249 | |
250 TEST_F(AudioOutputStreamTest, Format) { | |
251 ::media::AudioParameters::Format format[] = { | |
252 ::media::AudioParameters::AUDIO_PCM_LINEAR, | |
253 ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY}; | |
254 for (size_t i = 0; i < arraysize(format); ++i) { | |
255 format_ = format[i]; | |
256 ::media::AudioOutputStream* stream = CreateStream(); | |
257 ASSERT_TRUE(stream); | |
258 EXPECT_TRUE(stream->Open()); | |
259 | |
260 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
261 ASSERT_TRUE(audio_device); | |
262 const AudioConfig& audio_config = audio_device->config(); | |
263 EXPECT_EQ(kCodecPCM, audio_config.codec); | |
264 EXPECT_EQ(kSampleFormatS16, audio_config.sample_format); | |
265 EXPECT_FALSE(audio_config.is_encrypted); | |
266 | |
267 stream->Close(); | |
268 } | |
269 } | |
270 | |
271 TEST_F(AudioOutputStreamTest, ChannelLayout) { | |
272 ::media::ChannelLayout layout[] = {::media::CHANNEL_LAYOUT_MONO, | |
273 ::media::CHANNEL_LAYOUT_STEREO}; | |
274 for (size_t i = 0; i < arraysize(layout); ++i) { | |
275 channel_layout_ = layout[i]; | |
276 ::media::AudioOutputStream* stream = CreateStream(); | |
277 ASSERT_TRUE(stream); | |
278 EXPECT_TRUE(stream->Open()); | |
279 | |
280 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
281 ASSERT_TRUE(audio_device); | |
282 const AudioConfig& audio_config = audio_device->config(); | |
283 EXPECT_EQ(::media::ChannelLayoutToChannelCount(channel_layout_), | |
284 audio_config.channel_number); | |
285 | |
286 stream->Close(); | |
287 } | |
288 } | |
289 | |
290 TEST_F(AudioOutputStreamTest, SampleRate) { | |
291 sample_rate_ = ::media::AudioParameters::kAudioCDSampleRate; | |
292 ::media::AudioOutputStream* stream = CreateStream(); | |
293 ASSERT_TRUE(stream); | |
294 EXPECT_TRUE(stream->Open()); | |
295 | |
296 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
297 ASSERT_TRUE(audio_device); | |
298 const AudioConfig& audio_config = audio_device->config(); | |
299 EXPECT_EQ(sample_rate_, audio_config.samples_per_second); | |
300 | |
301 stream->Close(); | |
302 } | |
303 | |
304 TEST_F(AudioOutputStreamTest, BitsPerSample) { | |
305 bits_per_sample_ = 16; | |
306 ::media::AudioOutputStream* stream = CreateStream(); | |
307 ASSERT_TRUE(stream); | |
308 EXPECT_TRUE(stream->Open()); | |
309 | |
310 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
311 ASSERT_TRUE(audio_device); | |
312 const AudioConfig& audio_config = audio_device->config(); | |
313 EXPECT_EQ(bits_per_sample_ / 8, audio_config.bytes_per_channel); | |
314 | |
315 stream->Close(); | |
316 } | |
317 | |
318 TEST_F(AudioOutputStreamTest, DeviceState) { | |
319 ::media::AudioOutputStream* stream = CreateStream(); | |
320 ASSERT_TRUE(stream); | |
321 EXPECT_FALSE(GetAudio()); | |
322 | |
323 EXPECT_TRUE(stream->Open()); | |
324 AudioPipelineDevice* audio_device = GetAudio(); | |
325 ASSERT_TRUE(audio_device); | |
326 FakeClockDevice* clock_device = GetClock(); | |
327 ASSERT_TRUE(clock_device); | |
328 EXPECT_EQ(AudioPipelineDevice::kStateIdle, audio_device->GetState()); | |
329 EXPECT_EQ(MediaClockDevice::kStateIdle, clock_device->GetState()); | |
330 EXPECT_EQ(1.f, clock_device->rate()); | |
331 | |
332 scoped_ptr<FakeAudioSourceCallback> source_callback( | |
333 new FakeAudioSourceCallback); | |
334 stream->Start(source_callback.get()); | |
335 EXPECT_EQ(AudioPipelineDevice::kStateRunning, audio_device->GetState()); | |
336 EXPECT_EQ(MediaClockDevice::kStateRunning, clock_device->GetState()); | |
337 EXPECT_EQ(1.f, clock_device->rate()); | |
338 | |
339 stream->Stop(); | |
340 EXPECT_EQ(AudioPipelineDevice::kStatePaused, audio_device->GetState()); | |
341 EXPECT_EQ(MediaClockDevice::kStateIdle, clock_device->GetState()); | |
342 EXPECT_EQ(0.f, clock_device->rate()); | |
343 | |
344 stream->Close(); | |
345 EXPECT_FALSE(GetAudio()); | |
346 } | |
347 | |
348 TEST_F(AudioOutputStreamTest, PushFrame) { | |
349 ::media::AudioOutputStream* stream = CreateStream(); | |
350 ASSERT_TRUE(stream); | |
351 EXPECT_TRUE(stream->Open()); | |
352 | |
353 scoped_ptr<FakeAudioSourceCallback> source_callback( | |
354 new FakeAudioSourceCallback); | |
355 stream->Start(source_callback.get()); | |
356 | |
357 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
358 ASSERT_TRUE(audio_device); | |
359 | |
360 EXPECT_EQ(0u, audio_device->pushed_frame_count()); | |
361 EXPECT_FALSE(audio_device->last_frame_decrypt_context()); | |
362 EXPECT_FALSE(audio_device->last_frame_buffer()); | |
363 EXPECT_FALSE(audio_device->last_frame_completion_cb()); | |
364 | |
365 // Let the stream push frames. | |
366 message_loop_->RunUntilIdle(); | |
367 | |
368 EXPECT_LT(0u, audio_device->pushed_frame_count()); | |
369 // DecryptContext is always NULL becuase of "raw" audio. | |
370 EXPECT_FALSE(audio_device->last_frame_decrypt_context()); | |
371 EXPECT_TRUE(audio_device->last_frame_buffer()); | |
372 EXPECT_TRUE(audio_device->last_frame_completion_cb()); | |
373 | |
374 // Verify decoder buffer. | |
375 ::media::AudioParameters audio_params = GetAudioParams(); | |
376 const size_t expected_frame_size = | |
377 static_cast<size_t>(audio_params.GetBytesPerBuffer()); | |
378 const CastDecoderBuffer* buffer = audio_device->last_frame_buffer(); | |
379 EXPECT_TRUE(buffer->data()); | |
380 EXPECT_EQ(expected_frame_size, buffer->data_size()); | |
381 EXPECT_FALSE(buffer->decrypt_config()); // Null because of raw audio. | |
382 EXPECT_FALSE(buffer->end_of_stream()); | |
383 | |
384 // No error must be reported to source callback. | |
385 EXPECT_FALSE(source_callback->error()); | |
386 | |
387 stream->Stop(); | |
388 stream->Close(); | |
389 } | |
390 | |
391 TEST_F(AudioOutputStreamTest, DeviceBusy) { | |
392 ::media::AudioOutputStream* stream = CreateStream(); | |
393 ASSERT_TRUE(stream); | |
394 EXPECT_TRUE(stream->Open()); | |
395 | |
396 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
397 ASSERT_TRUE(audio_device); | |
398 audio_device->set_pipeline_status( | |
399 FakeAudioPipelineDevice::PIPELINE_STATUS_BUSY); | |
400 | |
401 scoped_ptr<FakeAudioSourceCallback> source_callback( | |
402 new FakeAudioSourceCallback); | |
403 stream->Start(source_callback.get()); | |
404 | |
405 // Let the stream push frames. | |
406 message_loop_->RunUntilIdle(); | |
407 | |
408 // Make sure that one frame was pushed. | |
409 EXPECT_EQ(1u, audio_device->pushed_frame_count()); | |
410 // No error must be reported to source callback. | |
411 EXPECT_FALSE(source_callback->error()); | |
412 | |
413 // Sleep for a few frames so that when the message loop is drained | |
414 // AudioOutputStream would have the opportunity to push more frames. | |
415 ::media::AudioParameters audio_params = GetAudioParams(); | |
416 base::TimeDelta pause = audio_params.GetBufferDuration() * 5; | |
417 base::PlatformThread::Sleep(pause); | |
418 | |
419 // Let the stream attempt to push more frames. | |
420 message_loop_->RunUntilIdle(); | |
421 // But since the device was busy, it must not push more frames. | |
422 EXPECT_EQ(1u, audio_device->pushed_frame_count()); | |
423 | |
424 // Unblock the pipeline and verify that PushFrame resumes. | |
425 audio_device->set_pipeline_status( | |
426 FakeAudioPipelineDevice::PIPELINE_STATUS_OK); | |
427 audio_device->last_frame_completion_cb()->Run( | |
428 MediaComponentDevice::kFrameSuccess); | |
429 base::PlatformThread::Sleep(pause); | |
430 message_loop_->RunUntilIdle(); | |
431 EXPECT_EQ(2u, audio_device->pushed_frame_count()); | |
432 EXPECT_FALSE(source_callback->error()); | |
433 | |
434 // Make the pipeline busy again, but this time send kFrameFailed. | |
435 audio_device->set_pipeline_status( | |
436 FakeAudioPipelineDevice::PIPELINE_STATUS_BUSY); | |
437 base::PlatformThread::Sleep(pause); | |
438 message_loop_->RunUntilIdle(); | |
439 EXPECT_EQ(3u, audio_device->pushed_frame_count()); | |
440 EXPECT_FALSE(source_callback->error()); | |
441 | |
442 audio_device->last_frame_completion_cb()->Run( | |
443 MediaComponentDevice::kFrameFailed); | |
444 EXPECT_TRUE(source_callback->error()); | |
445 | |
446 stream->Stop(); | |
447 stream->Close(); | |
448 } | |
449 | |
450 TEST_F(AudioOutputStreamTest, DeviceError) { | |
451 ::media::AudioOutputStream* stream = CreateStream(); | |
452 ASSERT_TRUE(stream); | |
453 EXPECT_TRUE(stream->Open()); | |
454 | |
455 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
456 ASSERT_TRUE(audio_device); | |
457 audio_device->set_pipeline_status( | |
458 FakeAudioPipelineDevice::PIPELINE_STATUS_ERROR); | |
459 | |
460 scoped_ptr<FakeAudioSourceCallback> source_callback( | |
461 new FakeAudioSourceCallback); | |
462 stream->Start(source_callback.get()); | |
463 | |
464 // Let the stream push frames. | |
465 message_loop_->RunUntilIdle(); | |
466 | |
467 // Make sure that AudioOutputStream attempted to push the initial frame. | |
468 EXPECT_LT(0u, audio_device->pushed_frame_count()); | |
469 // AudioOutputStream must report error to source callback. | |
470 EXPECT_TRUE(source_callback->error()); | |
471 | |
472 stream->Stop(); | |
473 stream->Close(); | |
474 } | |
475 | |
476 TEST_F(AudioOutputStreamTest, Volume) { | |
477 ::media::AudioOutputStream* stream = CreateStream(); | |
478 ASSERT_TRUE(stream); | |
479 ASSERT_TRUE(stream->Open()); | |
480 FakeAudioPipelineDevice* audio_device = GetAudio(); | |
481 ASSERT_TRUE(audio_device); | |
482 | |
483 double volume = 0.0; | |
484 stream->GetVolume(&volume); | |
485 EXPECT_EQ(1.0, volume); | |
486 EXPECT_EQ(1.0f, audio_device->volume_multiplier()); | |
487 | |
488 stream->SetVolume(0.5); | |
489 stream->GetVolume(&volume); | |
490 EXPECT_EQ(0.5, volume); | |
491 EXPECT_EQ(0.5f, audio_device->volume_multiplier()); | |
492 | |
493 stream->Close(); | |
494 } | |
495 | |
496 } // namespace | |
497 } // namespace media | |
498 } // namespace chromecast | |
OLD | NEW |