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
3 // found in the LICENSE file.
5 #include "base/message_loop/message_loop.h"
6 #include "base/strings/stringprintf.h"
7 #include "media/audio/linux/alsa_output.h"
8 #include "media/audio/linux/alsa_wrapper.h"
9 #include "media/audio/linux/audio_manager_linux.h"
10 #include "media/base/data_buffer.h"
11 #include "media/base/seekable_buffer.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 using testing::AtLeast;
20 using testing::InSequence;
21 using testing::Invoke;
22 using testing::InvokeWithoutArgs;
24 using testing::MockFunction;
25 using testing::Return;
26 using testing::SetArgumentPointee;
27 using testing::StrictMock;
29 using testing::Unused;
33 class MockAlsaWrapper : public AlsaWrapper {
35 MOCK_METHOD3(DeviceNameHint, int(int card,
38 MOCK_METHOD2(DeviceNameGetHint, char*(const void* hint, const char* id));
39 MOCK_METHOD1(DeviceNameFreeHint, int(void** hints));
41 MOCK_METHOD4(PcmOpen, int(snd_pcm_t** handle, const char* name,
42 snd_pcm_stream_t stream, int mode));
43 MOCK_METHOD1(PcmClose, int(snd_pcm_t* handle));
44 MOCK_METHOD1(PcmPrepare, int(snd_pcm_t* handle));
45 MOCK_METHOD1(PcmDrop, int(snd_pcm_t* handle));
46 MOCK_METHOD2(PcmDelay, int(snd_pcm_t* handle, snd_pcm_sframes_t* delay));
47 MOCK_METHOD3(PcmWritei, snd_pcm_sframes_t(snd_pcm_t* handle,
49 snd_pcm_uframes_t size));
50 MOCK_METHOD3(PcmReadi, snd_pcm_sframes_t(snd_pcm_t* handle,
52 snd_pcm_uframes_t size));
53 MOCK_METHOD3(PcmRecover, int(snd_pcm_t* handle, int err, int silent));
54 MOCK_METHOD7(PcmSetParams, int(snd_pcm_t* handle, snd_pcm_format_t format,
55 snd_pcm_access_t access, unsigned int channels,
56 unsigned int rate, int soft_resample,
57 unsigned int latency));
58 MOCK_METHOD3(PcmGetParams, int(snd_pcm_t* handle,
59 snd_pcm_uframes_t* buffer_size,
60 snd_pcm_uframes_t* period_size));
61 MOCK_METHOD1(PcmName, const char*(snd_pcm_t* handle));
62 MOCK_METHOD1(PcmAvailUpdate, snd_pcm_sframes_t(snd_pcm_t* handle));
63 MOCK_METHOD1(PcmState, snd_pcm_state_t(snd_pcm_t* handle));
64 MOCK_METHOD1(PcmStart, int(snd_pcm_t* handle));
66 MOCK_METHOD1(StrError, const char*(int errnum));
69 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
71 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus,
72 AudioBuffersState buffers_state));
73 MOCK_METHOD3(OnMoreIOData, int(AudioBus* source,
75 AudioBuffersState buffers_state));
76 MOCK_METHOD1(OnError, void(AudioOutputStream* stream));
79 class MockAudioManagerLinux : public AudioManagerLinux {
81 MOCK_METHOD0(Init, void());
82 MOCK_METHOD0(HasAudioOutputDevices, bool());
83 MOCK_METHOD0(HasAudioInputDevices, bool());
84 MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*(
85 const AudioParameters& params));
86 MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*(
87 const AudioParameters& params,
88 const std::string& device_id,
89 const std::string& input_device_id));
90 MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*(
91 const AudioParameters& params, const std::string& device_id));
93 // We need to override this function in order to skip the checking the number
94 // of active output streams. It is because the number of active streams
95 // is managed inside MakeAudioOutputStream, and we don't use
96 // MakeAudioOutputStream to create the stream in the tests.
97 virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE {
102 // We don't mock this method since all tests will do the same thing
103 // and use the current message loop.
104 virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE {
105 return base::MessageLoop::current()->message_loop_proxy();
109 class AlsaPcmOutputStreamTest : public testing::Test {
111 AlsaPcmOutputStreamTest() {
112 mock_manager_.reset(new StrictMock<MockAudioManagerLinux>());
115 virtual ~AlsaPcmOutputStreamTest() {
118 AlsaPcmOutputStream* CreateStream(ChannelLayout layout) {
119 return CreateStream(layout, kTestFramesPerPacket);
122 AlsaPcmOutputStream* CreateStream(ChannelLayout layout,
123 int32 samples_per_packet) {
124 AudioParameters params(kTestFormat, layout, kTestSampleRate,
125 kTestBitsPerSample, samples_per_packet);
126 return new AlsaPcmOutputStream(kTestDeviceName,
129 mock_manager_.get());
132 // Helper function to malloc the string returned by DeviceNameHint for NAME.
133 static char* EchoHint(const void* name, Unused) {
134 return strdup(static_cast<const char*>(name));
137 // Helper function to malloc the string returned by DeviceNameHint for IOID.
138 static char* OutputHint(Unused, Unused) {
139 return strdup("Output");
142 // Helper function to initialize |test_stream->buffer_|. Must be called
143 // in all tests that use buffer_ without opening the stream.
144 void InitBuffer(AlsaPcmOutputStream* test_stream) {
146 packet_ = new media::DataBuffer(kTestPacketSize);
147 packet_->set_data_size(kTestPacketSize);
148 test_stream->buffer_.reset(new media::SeekableBuffer(0, kTestPacketSize));
149 test_stream->buffer_->Append(packet_.get());
152 static const ChannelLayout kTestChannelLayout;
153 static const int kTestSampleRate;
154 static const int kTestBitsPerSample;
155 static const int kTestBytesPerFrame;
156 static const AudioParameters::Format kTestFormat;
157 static const char kTestDeviceName[];
158 static const char kDummyMessage[];
159 static const uint32 kTestFramesPerPacket;
160 static const int kTestPacketSize;
161 static const int kTestFailedErrno;
162 static snd_pcm_t* const kFakeHandle;
164 // Used to simulate DeviceNameHint.
165 static char kSurround40[];
166 static char kSurround41[];
167 static char kSurround50[];
168 static char kSurround51[];
169 static char kSurround70[];
170 static char kSurround71[];
171 static void* kFakeHints[];
173 StrictMock<MockAlsaWrapper> mock_alsa_wrapper_;
174 scoped_ptr<StrictMock<MockAudioManagerLinux> > mock_manager_;
175 base::MessageLoop message_loop_;
176 scoped_refptr<media::DataBuffer> packet_;
179 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest);
182 const ChannelLayout AlsaPcmOutputStreamTest::kTestChannelLayout =
183 CHANNEL_LAYOUT_STEREO;
184 const int AlsaPcmOutputStreamTest::kTestSampleRate =
185 AudioParameters::kAudioCDSampleRate;
186 const int AlsaPcmOutputStreamTest::kTestBitsPerSample = 8;
187 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame =
188 AlsaPcmOutputStreamTest::kTestBitsPerSample / 8 *
189 ChannelLayoutToChannelCount(AlsaPcmOutputStreamTest::kTestChannelLayout);
190 const AudioParameters::Format AlsaPcmOutputStreamTest::kTestFormat =
191 AudioParameters::AUDIO_PCM_LINEAR;
192 const char AlsaPcmOutputStreamTest::kTestDeviceName[] = "TestDevice";
193 const char AlsaPcmOutputStreamTest::kDummyMessage[] = "dummy";
194 const uint32 AlsaPcmOutputStreamTest::kTestFramesPerPacket = 1000;
195 const int AlsaPcmOutputStreamTest::kTestPacketSize =
196 AlsaPcmOutputStreamTest::kTestFramesPerPacket *
197 AlsaPcmOutputStreamTest::kTestBytesPerFrame;
198 const int AlsaPcmOutputStreamTest::kTestFailedErrno = -EACCES;
199 snd_pcm_t* const AlsaPcmOutputStreamTest::kFakeHandle =
200 reinterpret_cast<snd_pcm_t*>(1);
202 char AlsaPcmOutputStreamTest::kSurround40[] = "surround40:CARD=foo,DEV=0";
203 char AlsaPcmOutputStreamTest::kSurround41[] = "surround41:CARD=foo,DEV=0";
204 char AlsaPcmOutputStreamTest::kSurround50[] = "surround50:CARD=foo,DEV=0";
205 char AlsaPcmOutputStreamTest::kSurround51[] = "surround51:CARD=foo,DEV=0";
206 char AlsaPcmOutputStreamTest::kSurround70[] = "surround70:CARD=foo,DEV=0";
207 char AlsaPcmOutputStreamTest::kSurround71[] = "surround71:CARD=foo,DEV=0";
208 void* AlsaPcmOutputStreamTest::kFakeHints[] = {
209 kSurround40, kSurround41, kSurround50, kSurround51,
210 kSurround70, kSurround71, NULL };
212 // Custom action to clear a memory buffer.
213 ACTION(ClearBuffer) {
217 TEST_F(AlsaPcmOutputStreamTest, ConstructedState) {
218 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
219 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state());
220 test_stream->Close();
222 // Should support mono.
223 test_stream = CreateStream(CHANNEL_LAYOUT_MONO);
224 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state());
225 test_stream->Close();
227 // Should support multi-channel.
228 test_stream = CreateStream(CHANNEL_LAYOUT_SURROUND);
229 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state());
230 test_stream->Close();
232 // Bad bits per sample.
233 AudioParameters bad_bps_params(kTestFormat, kTestChannelLayout,
234 kTestSampleRate, kTestBitsPerSample - 1,
235 kTestFramesPerPacket);
236 test_stream = new AlsaPcmOutputStream(kTestDeviceName,
239 mock_manager_.get());
240 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
241 test_stream->Close();
244 AudioParameters bad_format_params(
245 AudioParameters::AUDIO_LAST_FORMAT, kTestChannelLayout, kTestSampleRate,
246 kTestBitsPerSample, kTestFramesPerPacket);
247 test_stream = new AlsaPcmOutputStream(kTestDeviceName,
250 mock_manager_.get());
251 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
252 test_stream->Close();
255 TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) {
256 const double kMicrosPerFrame =
257 static_cast<double>(1000000) / kTestSampleRate;
258 const double kPacketFramesInMinLatency =
259 AlsaPcmOutputStream::kMinLatencyMicros / kMicrosPerFrame / 2.0;
261 // Test that packets which would cause a latency under less than
262 // AlsaPcmOutputStream::kMinLatencyMicros will get clipped to
263 // AlsaPcmOutputStream::kMinLatencyMicros,
264 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
265 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
267 EXPECT_CALL(mock_alsa_wrapper_,
268 PcmSetParams(_, _, _, _, _, _,
269 AlsaPcmOutputStream::kMinLatencyMicros))
270 .WillOnce(Return(0));
271 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
272 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
273 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
276 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout,
277 kPacketFramesInMinLatency);
278 ASSERT_TRUE(test_stream->Open());
280 // Now close it and test that everything was released.
281 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)).WillOnce(Return(0));
282 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
283 .WillOnce(Return(kTestDeviceName));
284 test_stream->Close();
286 Mock::VerifyAndClear(&mock_alsa_wrapper_);
287 Mock::VerifyAndClear(mock_manager_.get());
289 // Test that having more packets ends up with a latency based on packet size.
290 const int kOverMinLatencyPacketSize = kPacketFramesInMinLatency + 1;
291 int64 expected_micros = AlsaPcmOutputStream::FramesToTimeDelta(
292 kOverMinLatencyPacketSize * 2, kTestSampleRate).InMicroseconds();
294 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
295 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
296 EXPECT_CALL(mock_alsa_wrapper_,
297 PcmSetParams(_, _, _, _, _, _, expected_micros))
298 .WillOnce(Return(0));
299 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
300 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
301 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
304 test_stream = CreateStream(kTestChannelLayout,
305 kOverMinLatencyPacketSize);
306 ASSERT_TRUE(test_stream->Open());
308 // Now close it and test that everything was released.
309 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
310 .WillOnce(Return(0));
311 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
312 .WillOnce(Return(kTestDeviceName));
313 test_stream->Close();
315 Mock::VerifyAndClear(&mock_alsa_wrapper_);
316 Mock::VerifyAndClear(mock_manager_.get());
319 TEST_F(AlsaPcmOutputStreamTest, OpenClose) {
320 int64 expected_micros = AlsaPcmOutputStream::FramesToTimeDelta(
321 2 * kTestFramesPerPacket, kTestSampleRate).InMicroseconds();
323 // Open() call opens the playback device, sets the parameters, posts a task
324 // with the resulting configuration data, and transitions the object state to
326 EXPECT_CALL(mock_alsa_wrapper_,
327 PcmOpen(_, StrEq(kTestDeviceName),
328 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))
329 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
331 EXPECT_CALL(mock_alsa_wrapper_,
332 PcmSetParams(kFakeHandle,
334 SND_PCM_ACCESS_RW_INTERLEAVED,
335 ChannelLayoutToChannelCount(kTestChannelLayout),
339 .WillOnce(Return(0));
340 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(kFakeHandle, _, _))
341 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
342 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
346 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
347 ASSERT_TRUE(test_stream->Open());
349 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, test_stream->state());
350 EXPECT_EQ(kFakeHandle, test_stream->playback_handle_);
351 EXPECT_EQ(kTestFramesPerPacket, test_stream->frames_per_packet_);
352 EXPECT_TRUE(test_stream->buffer_.get());
353 EXPECT_FALSE(test_stream->stop_stream_);
355 // Now close it and test that everything was released.
356 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
357 .WillOnce(Return(0));
358 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
359 .WillOnce(Return(kTestDeviceName));
360 test_stream->Close();
363 TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) {
364 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
365 .WillOnce(Return(kTestFailedErrno));
366 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
367 .WillOnce(Return(kDummyMessage));
369 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
370 ASSERT_FALSE(test_stream->Open());
371 ASSERT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
373 // Ensure internal state is set for a no-op stream if PcmOpen() failes.
374 EXPECT_TRUE(test_stream->stop_stream_);
375 EXPECT_TRUE(test_stream->playback_handle_ == NULL);
376 EXPECT_FALSE(test_stream->buffer_.get());
378 // Close the stream since we opened it to make destruction happy.
379 test_stream->Close();
382 TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) {
383 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
384 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
386 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
387 .WillOnce(Return(kTestFailedErrno));
388 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
389 .WillOnce(Return(0));
390 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
391 .WillOnce(Return(kTestDeviceName));
392 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
393 .WillOnce(Return(kDummyMessage));
395 // If open fails, the stream stays in kCreated because it has effectively had
397 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
398 ASSERT_FALSE(test_stream->Open());
399 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
401 // Ensure internal state is set for a no-op stream if PcmSetParams() failes.
402 EXPECT_TRUE(test_stream->stop_stream_);
403 EXPECT_TRUE(test_stream->playback_handle_ == NULL);
404 EXPECT_FALSE(test_stream->buffer_.get());
406 // Close the stream since we opened it to make destruction happy.
407 test_stream->Close();
410 TEST_F(AlsaPcmOutputStreamTest, StartStop) {
411 // Open() call opens the playback device, sets the parameters, posts a task
412 // with the resulting configuration data, and transitions the object state to
414 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
415 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
417 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
418 .WillOnce(Return(0));
419 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
420 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
421 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
425 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
426 ASSERT_TRUE(test_stream->Open());
428 // Expect Device setup.
429 EXPECT_CALL(mock_alsa_wrapper_, PcmDrop(kFakeHandle))
430 .WillOnce(Return(0));
431 EXPECT_CALL(mock_alsa_wrapper_, PcmPrepare(kFakeHandle))
432 .WillOnce(Return(0));
434 // Expect the pre-roll.
435 MockAudioSourceCallback mock_callback;
436 EXPECT_CALL(mock_alsa_wrapper_, PcmState(kFakeHandle))
437 .WillRepeatedly(Return(SND_PCM_STATE_RUNNING));
438 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(kFakeHandle, _))
439 .WillRepeatedly(DoAll(SetArgumentPointee<1>(0), Return(0)));
440 EXPECT_CALL(mock_callback, OnMoreData(_, _))
441 .WillRepeatedly(DoAll(ClearBuffer(), Return(kTestFramesPerPacket)));
442 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
443 .WillRepeatedly(Return(kTestFramesPerPacket));
445 // Expect scheduling.
446 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
448 .WillRepeatedly(Return(kTestFramesPerPacket));
450 test_stream->Start(&mock_callback);
451 // Start() will issue a WriteTask() directly and then schedule the next one,
452 // call Stop() immediately after to ensure we don't run the message loop
455 message_loop_.RunUntilIdle();
457 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
458 .WillOnce(Return(0));
459 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
460 .WillOnce(Return(kTestDeviceName));
461 test_stream->Close();
464 TEST_F(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket) {
465 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
466 InitBuffer(test_stream);
467 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
468 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
470 // Nothing should happen. Don't set any expectations and Our strict mocks
471 // should verify most of this.
473 // Test empty buffer.
474 test_stream->buffer_->Clear();
475 test_stream->WritePacket();
476 test_stream->Close();
479 TEST_F(AlsaPcmOutputStreamTest, WritePacket_NormalPacket) {
480 // We need to open the stream before writing data to ALSA.
481 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
482 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
484 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
485 .WillOnce(Return(0));
486 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
487 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
488 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
490 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
491 ASSERT_TRUE(test_stream->Open());
492 InitBuffer(test_stream);
493 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
495 // Write a little less than half the data.
496 int written = packet_->data_size() / kTestBytesPerFrame / 2 - 1;
497 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
498 .WillOnce(Return(written));
499 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, packet_->data(), _))
500 .WillOnce(Return(written));
502 test_stream->WritePacket();
504 ASSERT_EQ(test_stream->buffer_->forward_bytes(),
505 packet_->data_size() - written * kTestBytesPerFrame);
508 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
509 .WillOnce(Return(kTestFramesPerPacket - written));
510 EXPECT_CALL(mock_alsa_wrapper_,
511 PcmWritei(kFakeHandle,
512 packet_->data() + written * kTestBytesPerFrame,
514 .WillOnce(Return(packet_->data_size() / kTestBytesPerFrame - written));
515 test_stream->WritePacket();
516 EXPECT_EQ(0, test_stream->buffer_->forward_bytes());
518 // Now close it and test that everything was released.
519 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
520 .WillOnce(Return(0));
521 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
522 .WillOnce(Return(kTestDeviceName));
523 test_stream->Close();
526 TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) {
527 // We need to open the stream before writing data to ALSA.
528 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
529 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
531 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
532 .WillOnce(Return(0));
533 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
534 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
535 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
537 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
538 ASSERT_TRUE(test_stream->Open());
539 InitBuffer(test_stream);
540 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
542 // Fail due to a recoverable error and see that PcmRecover code path
543 // continues normally.
544 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
545 .WillOnce(Return(kTestFramesPerPacket));
546 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
547 .WillOnce(Return(-EINTR));
548 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(kFakeHandle, _, _))
549 .WillOnce(Return(0));
551 test_stream->WritePacket();
553 ASSERT_EQ(test_stream->buffer_->forward_bytes(), packet_->data_size());
555 // Fail the next write, and see that stop_stream_ is set.
556 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
557 .WillOnce(Return(kTestFramesPerPacket));
558 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
559 .WillOnce(Return(kTestFailedErrno));
560 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(kFakeHandle, _, _))
561 .WillOnce(Return(kTestFailedErrno));
562 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
563 .WillOnce(Return(kDummyMessage));
564 test_stream->WritePacket();
565 EXPECT_EQ(test_stream->buffer_->forward_bytes(), packet_->data_size());
566 EXPECT_TRUE(test_stream->stop_stream_);
568 // Now close it and test that everything was released.
569 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
570 .WillOnce(Return(0));
571 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
572 .WillOnce(Return(kTestDeviceName));
573 test_stream->Close();
576 TEST_F(AlsaPcmOutputStreamTest, WritePacket_StopStream) {
577 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
578 InitBuffer(test_stream);
579 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
580 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
582 // No expectations set on the strict mock because nothing should be called.
583 test_stream->stop_stream_ = true;
584 test_stream->WritePacket();
585 EXPECT_EQ(0, test_stream->buffer_->forward_bytes());
586 test_stream->Close();
589 TEST_F(AlsaPcmOutputStreamTest, BufferPacket) {
590 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
591 InitBuffer(test_stream);
592 test_stream->buffer_->Clear();
594 MockAudioSourceCallback mock_callback;
595 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_))
596 .WillOnce(Return(SND_PCM_STATE_RUNNING));
597 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(_, _))
598 .WillOnce(DoAll(SetArgumentPointee<1>(1), Return(0)));
599 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
600 .WillRepeatedly(Return(0)); // Buffer is full.
602 // Return a partially filled packet.
603 EXPECT_CALL(mock_callback, OnMoreData(_, _))
604 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
606 bool source_exhausted;
607 test_stream->set_source_callback(&mock_callback);
608 test_stream->packet_size_ = kTestPacketSize;
609 test_stream->BufferPacket(&source_exhausted);
611 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes());
612 EXPECT_FALSE(source_exhausted);
613 test_stream->Close();
616 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) {
617 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
618 InitBuffer(test_stream);
619 test_stream->buffer_->Clear();
621 // Simulate where the underrun has occurred right after checking the delay.
622 MockAudioSourceCallback mock_callback;
623 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_))
624 .WillOnce(Return(SND_PCM_STATE_RUNNING));
625 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(_, _))
626 .WillOnce(DoAll(SetArgumentPointee<1>(-1), Return(0)));
627 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
628 .WillRepeatedly(Return(0)); // Buffer is full.
629 EXPECT_CALL(mock_callback, OnMoreData(_, _))
630 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
632 bool source_exhausted;
633 test_stream->set_source_callback(&mock_callback);
634 test_stream->packet_size_ = kTestPacketSize;
635 test_stream->BufferPacket(&source_exhausted);
637 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes());
638 EXPECT_FALSE(source_exhausted);
639 test_stream->Close();
642 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) {
643 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
644 InitBuffer(test_stream);
645 test_stream->buffer_->Clear();
647 // If ALSA has underrun then we should assume a delay of zero.
648 MockAudioSourceCallback mock_callback;
649 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_))
650 .WillOnce(Return(SND_PCM_STATE_XRUN));
651 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
652 .WillRepeatedly(Return(0)); // Buffer is full.
653 EXPECT_CALL(mock_callback,
655 Field(&AudioBuffersState::pending_bytes, 0),
656 Field(&AudioBuffersState::hardware_delay_bytes, 0))))
657 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
659 bool source_exhausted;
660 test_stream->set_source_callback(&mock_callback);
661 test_stream->packet_size_ = kTestPacketSize;
662 test_stream->BufferPacket(&source_exhausted);
664 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes());
665 EXPECT_FALSE(source_exhausted);
666 test_stream->Close();
669 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer) {
670 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
671 InitBuffer(test_stream);
672 // No expectations set on the strict mock because nothing should be called.
673 bool source_exhausted;
674 test_stream->packet_size_ = kTestPacketSize;
675 test_stream->BufferPacket(&source_exhausted);
676 EXPECT_EQ(kTestPacketSize, test_stream->buffer_->forward_bytes());
677 EXPECT_FALSE(source_exhausted);
678 test_stream->Close();
681 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) {
682 // Try channels from 1 -> 9. and see that we get the more specific surroundXX
683 // device opened for channels 4-8. For all other channels, the device should
684 // default to |AlsaPcmOutputStream::kDefaultDevice|. We should also not
685 // downmix any channel in this case because downmixing is only defined for
686 // channels 4-8, which we are guaranteeing to work.
688 // Note that the loop starts at "1", so the first parameter is ignored in
690 const char* kExpectedDeviceName[] = { NULL,
691 AlsaPcmOutputStream::kDefaultDevice,
692 AlsaPcmOutputStream::kDefaultDevice,
693 AlsaPcmOutputStream::kDefaultDevice,
694 kSurround40, kSurround50, kSurround51,
695 kSurround70, kSurround71,
696 AlsaPcmOutputStream::kDefaultDevice };
697 bool kExpectedDownmix[] = { false, false, false, false, false, true,
698 false, false, false, false };
699 ChannelLayout kExpectedLayouts[] = { CHANNEL_LAYOUT_NONE,
701 CHANNEL_LAYOUT_STEREO,
702 CHANNEL_LAYOUT_SURROUND,
707 CHANNEL_LAYOUT_7_1 };
710 for (int i = 1; i < 9; ++i) {
711 if (i == 3 || i == 4 || i == 5) // invalid number of channels
713 SCOPED_TRACE(base::StringPrintf("Attempting %d Channel", i));
715 // Hints will only be grabbed for channel numbers that have non-default
716 // devices associated with them.
717 if (kExpectedDeviceName[i] != AlsaPcmOutputStream::kDefaultDevice) {
718 // The DeviceNameHint and DeviceNameFreeHint need to be paired to avoid a
720 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _))
721 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0)));
722 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0]))
726 EXPECT_CALL(mock_alsa_wrapper_,
727 PcmOpen(_, StrEq(kExpectedDeviceName[i]), _, _))
728 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
729 EXPECT_CALL(mock_alsa_wrapper_,
730 PcmSetParams(kFakeHandle, _, _, i, _, _, _))
731 .WillOnce(Return(0));
733 // The parameters are specified by ALSA documentation, and are in constants
734 // in the implementation files.
735 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID")))
736 .WillRepeatedly(Invoke(OutputHint));
737 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME")))
738 .WillRepeatedly(Invoke(EchoHint));
740 AlsaPcmOutputStream* test_stream = CreateStream(kExpectedLayouts[i]);
741 EXPECT_TRUE(test_stream->AutoSelectDevice(i));
742 EXPECT_EQ(kExpectedDownmix[i],
743 static_cast<bool>(test_stream->channel_mixer_));
745 Mock::VerifyAndClearExpectations(&mock_alsa_wrapper_);
746 Mock::VerifyAndClearExpectations(mock_manager_.get());
747 test_stream->Close();
751 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices) {
754 // If there are problems opening a multi-channel device, it the fallbacks
755 // operations should be as follows. Assume the multi-channel device name is
758 // 1) Try open "surround50"
759 // 2) Try open "plug:surround50".
760 // 3) Try open "default".
761 // 4) Try open "plug:default".
762 // 5) Give up trying to open.
764 const string first_try = kSurround50;
765 const string second_try = string(AlsaPcmOutputStream::kPlugPrefix) +
767 const string third_try = AlsaPcmOutputStream::kDefaultDevice;
768 const string fourth_try = string(AlsaPcmOutputStream::kPlugPrefix) +
769 AlsaPcmOutputStream::kDefaultDevice;
771 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _))
772 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0)));
773 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0]))
775 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID")))
776 .WillRepeatedly(Invoke(OutputHint));
777 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME")))
778 .WillRepeatedly(Invoke(EchoHint));
779 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
780 .WillRepeatedly(Return(kDummyMessage));
783 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(first_try.c_str()), _, _))
784 .WillOnce(Return(kTestFailedErrno));
785 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(second_try.c_str()), _, _))
786 .WillOnce(Return(kTestFailedErrno));
787 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(third_try.c_str()), _, _))
788 .WillOnce(Return(kTestFailedErrno));
789 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(fourth_try.c_str()), _, _))
790 .WillOnce(Return(kTestFailedErrno));
792 AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5_0);
793 EXPECT_FALSE(test_stream->AutoSelectDevice(5));
794 test_stream->Close();
797 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) {
798 // Should get |kDefaultDevice|, and force a 2-channel downmix on a failure to
799 // enumerate devices.
800 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _))
801 .WillRepeatedly(Return(kTestFailedErrno));
802 EXPECT_CALL(mock_alsa_wrapper_,
803 PcmOpen(_, StrEq(AlsaPcmOutputStream::kDefaultDevice), _, _))
804 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
805 EXPECT_CALL(mock_alsa_wrapper_,
806 PcmSetParams(kFakeHandle, _, _, 2, _, _, _))
807 .WillOnce(Return(0));
808 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
809 .WillOnce(Return(kDummyMessage));
811 AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5_0);
812 EXPECT_TRUE(test_stream->AutoSelectDevice(5));
813 EXPECT_TRUE(test_stream->channel_mixer_);
814 test_stream->Close();
817 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) {
818 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
819 InitBuffer(test_stream);
820 test_stream->stop_stream_ = true;
821 bool source_exhausted;
822 test_stream->BufferPacket(&source_exhausted);
823 EXPECT_EQ(0, test_stream->buffer_->forward_bytes());
824 EXPECT_TRUE(source_exhausted);
825 test_stream->Close();
828 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) {
829 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
830 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
831 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
832 InitBuffer(test_stream);
833 DVLOG(1) << test_stream->state();
834 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
835 .WillOnce(Return(10));
836 test_stream->ScheduleNextWrite(false);
837 DVLOG(1) << test_stream->state();
838 // TODO(sergeyu): Figure out how to check that the task has been added to the
841 // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending
842 // tasks unless running on valgrind. The code below is needed to keep
845 test_stream->stop_stream_ = true;
846 DVLOG(1) << test_stream->state();
847 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed);
848 DVLOG(1) << test_stream->state();
849 test_stream->Close();
852 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream) {
853 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
854 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
855 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
857 InitBuffer(test_stream);
859 test_stream->stop_stream_ = true;
860 test_stream->ScheduleNextWrite(true);
862 // TODO(ajwong): Find a way to test whether or not another task has been
863 // posted so we can verify that the Alsa code will indeed break the task
866 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed);
867 test_stream->Close();