Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Side by Side Diff: chromecast/media/audio/cast_audio_output_stream_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698