Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / media / audio / linux / alsa_output_unittest.cc
blobd5d6be90854614cdfa70644195e630648a48f736
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.h"
6 #include "base/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"
15 using testing::_;
16 using testing::AllOf;
17 using testing::AtLeast;
18 using testing::DoAll;
19 using testing::Field;
20 using testing::InSequence;
21 using testing::Invoke;
22 using testing::InvokeWithoutArgs;
23 using testing::Mock;
24 using testing::MockFunction;
25 using testing::Return;
26 using testing::SetArgumentPointee;
27 using testing::StrictMock;
28 using testing::StrEq;
29 using testing::Unused;
31 namespace media {
33 class MockAlsaWrapper : public AlsaWrapper {
34 public:
35 MOCK_METHOD3(DeviceNameHint, int(int card,
36 const char* iface,
37 void*** hints));
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,
48 const void* buffer,
49 snd_pcm_uframes_t size));
50 MOCK_METHOD3(PcmReadi, snd_pcm_sframes_t(snd_pcm_t* handle,
51 void* buffer,
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 {
70 public:
71 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus,
72 AudioBuffersState buffers_state));
73 MOCK_METHOD3(OnMoreIOData, int(AudioBus* source,
74 AudioBus* dest,
75 AudioBuffersState buffers_state));
76 MOCK_METHOD1(OnError, void(AudioOutputStream* stream));
79 class MockAudioManagerLinux : public AudioManagerLinux {
80 public:
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_METHOD1(MakeLowLatencyOutputStream, AudioOutputStream*(
87 const AudioParameters& params));
88 MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*(
89 const AudioParameters& params, const std::string& device_id));
91 // We need to override this function in order to skip the checking the number
92 // of active output streams. It is because the number of active streams
93 // is managed inside MakeAudioOutputStream, and we don't use
94 // MakeAudioOutputStream to create the stream in the tests.
95 virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE {
96 DCHECK(stream);
97 delete stream;
100 // We don't mock this method since all tests will do the same thing
101 // and use the current message loop.
102 virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE {
103 return MessageLoop::current()->message_loop_proxy();
107 class AlsaPcmOutputStreamTest : public testing::Test {
108 protected:
109 AlsaPcmOutputStreamTest() {
110 mock_manager_.reset(new StrictMock<MockAudioManagerLinux>());
113 virtual ~AlsaPcmOutputStreamTest() {
116 AlsaPcmOutputStream* CreateStream(ChannelLayout layout) {
117 return CreateStream(layout, kTestFramesPerPacket);
120 AlsaPcmOutputStream* CreateStream(ChannelLayout layout,
121 int32 samples_per_packet) {
122 AudioParameters params(kTestFormat, layout, kTestSampleRate,
123 kTestBitsPerSample, samples_per_packet);
124 return new AlsaPcmOutputStream(kTestDeviceName,
125 params,
126 &mock_alsa_wrapper_,
127 mock_manager_.get());
130 // Helper function to malloc the string returned by DeviceNameHint for NAME.
131 static char* EchoHint(const void* name, Unused) {
132 return strdup(static_cast<const char*>(name));
135 // Helper function to malloc the string returned by DeviceNameHint for IOID.
136 static char* OutputHint(Unused, Unused) {
137 return strdup("Output");
140 // Helper function to initialize |test_stream->buffer_|. Must be called
141 // in all tests that use buffer_ without opening the stream.
142 void InitBuffer(AlsaPcmOutputStream* test_stream) {
143 DCHECK(test_stream);
144 packet_ = new media::DataBuffer(kTestPacketSize);
145 packet_->SetDataSize(kTestPacketSize);
146 test_stream->buffer_.reset(new media::SeekableBuffer(0, kTestPacketSize));
147 test_stream->buffer_->Append(packet_.get());
150 static const ChannelLayout kTestChannelLayout;
151 static const int kTestSampleRate;
152 static const int kTestBitsPerSample;
153 static const int kTestBytesPerFrame;
154 static const AudioParameters::Format kTestFormat;
155 static const char kTestDeviceName[];
156 static const char kDummyMessage[];
157 static const uint32 kTestFramesPerPacket;
158 static const int kTestPacketSize;
159 static const int kTestFailedErrno;
160 static snd_pcm_t* const kFakeHandle;
162 // Used to simulate DeviceNameHint.
163 static char kSurround40[];
164 static char kSurround41[];
165 static char kSurround50[];
166 static char kSurround51[];
167 static char kSurround70[];
168 static char kSurround71[];
169 static void* kFakeHints[];
171 StrictMock<MockAlsaWrapper> mock_alsa_wrapper_;
172 scoped_ptr<StrictMock<MockAudioManagerLinux> > mock_manager_;
173 MessageLoop message_loop_;
174 scoped_refptr<media::DataBuffer> packet_;
176 private:
177 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest);
180 const ChannelLayout AlsaPcmOutputStreamTest::kTestChannelLayout =
181 CHANNEL_LAYOUT_STEREO;
182 const int AlsaPcmOutputStreamTest::kTestSampleRate =
183 AudioParameters::kAudioCDSampleRate;
184 const int AlsaPcmOutputStreamTest::kTestBitsPerSample = 8;
185 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame =
186 AlsaPcmOutputStreamTest::kTestBitsPerSample / 8 *
187 ChannelLayoutToChannelCount(AlsaPcmOutputStreamTest::kTestChannelLayout);
188 const AudioParameters::Format AlsaPcmOutputStreamTest::kTestFormat =
189 AudioParameters::AUDIO_PCM_LINEAR;
190 const char AlsaPcmOutputStreamTest::kTestDeviceName[] = "TestDevice";
191 const char AlsaPcmOutputStreamTest::kDummyMessage[] = "dummy";
192 const uint32 AlsaPcmOutputStreamTest::kTestFramesPerPacket = 1000;
193 const int AlsaPcmOutputStreamTest::kTestPacketSize =
194 AlsaPcmOutputStreamTest::kTestFramesPerPacket *
195 AlsaPcmOutputStreamTest::kTestBytesPerFrame;
196 const int AlsaPcmOutputStreamTest::kTestFailedErrno = -EACCES;
197 snd_pcm_t* const AlsaPcmOutputStreamTest::kFakeHandle =
198 reinterpret_cast<snd_pcm_t*>(1);
200 char AlsaPcmOutputStreamTest::kSurround40[] = "surround40:CARD=foo,DEV=0";
201 char AlsaPcmOutputStreamTest::kSurround41[] = "surround41:CARD=foo,DEV=0";
202 char AlsaPcmOutputStreamTest::kSurround50[] = "surround50:CARD=foo,DEV=0";
203 char AlsaPcmOutputStreamTest::kSurround51[] = "surround51:CARD=foo,DEV=0";
204 char AlsaPcmOutputStreamTest::kSurround70[] = "surround70:CARD=foo,DEV=0";
205 char AlsaPcmOutputStreamTest::kSurround71[] = "surround71:CARD=foo,DEV=0";
206 void* AlsaPcmOutputStreamTest::kFakeHints[] = {
207 kSurround40, kSurround41, kSurround50, kSurround51,
208 kSurround70, kSurround71, NULL };
210 // Custom action to clear a memory buffer.
211 ACTION(ClearBuffer) {
212 arg0->Zero();
215 TEST_F(AlsaPcmOutputStreamTest, ConstructedState) {
216 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
217 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state());
218 test_stream->Close();
220 // Should support mono.
221 test_stream = CreateStream(CHANNEL_LAYOUT_MONO);
222 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state());
223 test_stream->Close();
225 // Should support multi-channel.
226 test_stream = CreateStream(CHANNEL_LAYOUT_SURROUND);
227 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state());
228 test_stream->Close();
230 // Bad bits per sample.
231 AudioParameters bad_bps_params(kTestFormat, kTestChannelLayout,
232 kTestSampleRate, kTestBitsPerSample - 1,
233 kTestFramesPerPacket);
234 test_stream = new AlsaPcmOutputStream(kTestDeviceName,
235 bad_bps_params,
236 &mock_alsa_wrapper_,
237 mock_manager_.get());
238 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
239 test_stream->Close();
241 // Bad format.
242 AudioParameters bad_format_params(
243 AudioParameters::AUDIO_LAST_FORMAT, kTestChannelLayout, kTestSampleRate,
244 kTestBitsPerSample, kTestFramesPerPacket);
245 test_stream = new AlsaPcmOutputStream(kTestDeviceName,
246 bad_format_params,
247 &mock_alsa_wrapper_,
248 mock_manager_.get());
249 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
250 test_stream->Close();
253 TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) {
254 const double kMicrosPerFrame =
255 static_cast<double>(1000000) / kTestSampleRate;
256 const double kPacketFramesInMinLatency =
257 AlsaPcmOutputStream::kMinLatencyMicros / kMicrosPerFrame / 2.0;
259 // Test that packets which would cause a latency under less than
260 // AlsaPcmOutputStream::kMinLatencyMicros will get clipped to
261 // AlsaPcmOutputStream::kMinLatencyMicros,
262 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
263 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
264 Return(0)));
265 EXPECT_CALL(mock_alsa_wrapper_,
266 PcmSetParams(_, _, _, _, _, _,
267 AlsaPcmOutputStream::kMinLatencyMicros))
268 .WillOnce(Return(0));
269 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
270 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
271 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
272 Return(0)));
274 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout,
275 kPacketFramesInMinLatency);
276 ASSERT_TRUE(test_stream->Open());
278 // Now close it and test that everything was released.
279 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)).WillOnce(Return(0));
280 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
281 .WillOnce(Return(kTestDeviceName));
282 test_stream->Close();
284 Mock::VerifyAndClear(&mock_alsa_wrapper_);
285 Mock::VerifyAndClear(mock_manager_.get());
287 // Test that having more packets ends up with a latency based on packet size.
288 const int kOverMinLatencyPacketSize = kPacketFramesInMinLatency + 1;
289 int64 expected_micros = AlsaPcmOutputStream::FramesToTimeDelta(
290 kOverMinLatencyPacketSize * 2, kTestSampleRate).InMicroseconds();
292 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
293 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
294 EXPECT_CALL(mock_alsa_wrapper_,
295 PcmSetParams(_, _, _, _, _, _, expected_micros))
296 .WillOnce(Return(0));
297 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
298 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
299 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
300 Return(0)));
302 test_stream = CreateStream(kTestChannelLayout,
303 kOverMinLatencyPacketSize);
304 ASSERT_TRUE(test_stream->Open());
306 // Now close it and test that everything was released.
307 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
308 .WillOnce(Return(0));
309 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
310 .WillOnce(Return(kTestDeviceName));
311 test_stream->Close();
313 Mock::VerifyAndClear(&mock_alsa_wrapper_);
314 Mock::VerifyAndClear(mock_manager_.get());
317 TEST_F(AlsaPcmOutputStreamTest, OpenClose) {
318 int64 expected_micros = AlsaPcmOutputStream::FramesToTimeDelta(
319 2 * kTestFramesPerPacket, kTestSampleRate).InMicroseconds();
321 // Open() call opens the playback device, sets the parameters, posts a task
322 // with the resulting configuration data, and transitions the object state to
323 // kIsOpened.
324 EXPECT_CALL(mock_alsa_wrapper_,
325 PcmOpen(_, StrEq(kTestDeviceName),
326 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))
327 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
328 Return(0)));
329 EXPECT_CALL(mock_alsa_wrapper_,
330 PcmSetParams(kFakeHandle,
331 SND_PCM_FORMAT_U8,
332 SND_PCM_ACCESS_RW_INTERLEAVED,
333 ChannelLayoutToChannelCount(kTestChannelLayout),
334 kTestSampleRate,
336 expected_micros))
337 .WillOnce(Return(0));
338 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(kFakeHandle, _, _))
339 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
340 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
341 Return(0)));
343 // Open the stream.
344 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
345 ASSERT_TRUE(test_stream->Open());
347 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, test_stream->state());
348 EXPECT_EQ(kFakeHandle, test_stream->playback_handle_);
349 EXPECT_EQ(kTestFramesPerPacket, test_stream->frames_per_packet_);
350 EXPECT_TRUE(test_stream->buffer_.get());
351 EXPECT_FALSE(test_stream->stop_stream_);
353 // Now close it and test that everything was released.
354 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
355 .WillOnce(Return(0));
356 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
357 .WillOnce(Return(kTestDeviceName));
358 test_stream->Close();
361 TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) {
362 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
363 .WillOnce(Return(kTestFailedErrno));
364 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
365 .WillOnce(Return(kDummyMessage));
367 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
368 ASSERT_FALSE(test_stream->Open());
369 ASSERT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
371 // Ensure internal state is set for a no-op stream if PcmOpen() failes.
372 EXPECT_TRUE(test_stream->stop_stream_);
373 EXPECT_TRUE(test_stream->playback_handle_ == NULL);
374 EXPECT_FALSE(test_stream->buffer_.get());
376 // Close the stream since we opened it to make destruction happy.
377 test_stream->Close();
380 TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) {
381 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
382 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
383 Return(0)));
384 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
385 .WillOnce(Return(kTestFailedErrno));
386 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
387 .WillOnce(Return(0));
388 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
389 .WillOnce(Return(kTestDeviceName));
390 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
391 .WillOnce(Return(kDummyMessage));
393 // If open fails, the stream stays in kCreated because it has effectively had
394 // no changes.
395 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
396 ASSERT_FALSE(test_stream->Open());
397 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state());
399 // Ensure internal state is set for a no-op stream if PcmSetParams() failes.
400 EXPECT_TRUE(test_stream->stop_stream_);
401 EXPECT_TRUE(test_stream->playback_handle_ == NULL);
402 EXPECT_FALSE(test_stream->buffer_.get());
404 // Close the stream since we opened it to make destruction happy.
405 test_stream->Close();
408 TEST_F(AlsaPcmOutputStreamTest, StartStop) {
409 // Open() call opens the playback device, sets the parameters, posts a task
410 // with the resulting configuration data, and transitions the object state to
411 // kIsOpened.
412 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
413 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
414 Return(0)));
415 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
416 .WillOnce(Return(0));
417 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
418 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
419 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
420 Return(0)));
422 // Open the stream.
423 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
424 ASSERT_TRUE(test_stream->Open());
426 // Expect Device setup.
427 EXPECT_CALL(mock_alsa_wrapper_, PcmDrop(kFakeHandle))
428 .WillOnce(Return(0));
429 EXPECT_CALL(mock_alsa_wrapper_, PcmPrepare(kFakeHandle))
430 .WillOnce(Return(0));
432 // Expect the pre-roll.
433 MockAudioSourceCallback mock_callback;
434 EXPECT_CALL(mock_alsa_wrapper_, PcmState(kFakeHandle))
435 .WillRepeatedly(Return(SND_PCM_STATE_RUNNING));
436 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(kFakeHandle, _))
437 .WillRepeatedly(DoAll(SetArgumentPointee<1>(0), Return(0)));
438 EXPECT_CALL(mock_callback, OnMoreData(_, _))
439 .WillRepeatedly(DoAll(ClearBuffer(), Return(kTestFramesPerPacket)));
440 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
441 .WillRepeatedly(Return(kTestFramesPerPacket));
443 // Expect scheduling.
444 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
445 .Times(AtLeast(2))
446 .WillRepeatedly(Return(kTestFramesPerPacket));
448 test_stream->Start(&mock_callback);
449 // Start() will issue a WriteTask() directly and then schedule the next one,
450 // call Stop() immediately after to ensure we don't run the message loop
451 // forever.
452 test_stream->Stop();
453 message_loop_.RunUntilIdle();
455 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
456 .WillOnce(Return(0));
457 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
458 .WillOnce(Return(kTestDeviceName));
459 test_stream->Close();
462 TEST_F(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket) {
463 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
464 InitBuffer(test_stream);
465 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
466 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
468 // Nothing should happen. Don't set any expectations and Our strict mocks
469 // should verify most of this.
471 // Test empty buffer.
472 test_stream->buffer_->Clear();
473 test_stream->WritePacket();
474 test_stream->Close();
477 TEST_F(AlsaPcmOutputStreamTest, WritePacket_NormalPacket) {
478 // We need to open the stream before writing data to ALSA.
479 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
480 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
481 Return(0)));
482 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
483 .WillOnce(Return(0));
484 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
485 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
486 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
487 Return(0)));
488 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
489 ASSERT_TRUE(test_stream->Open());
490 InitBuffer(test_stream);
491 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
493 // Write a little less than half the data.
494 int written = packet_->GetDataSize() / kTestBytesPerFrame / 2 - 1;
495 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
496 .WillOnce(Return(written));
497 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, packet_->GetData(), _))
498 .WillOnce(Return(written));
500 test_stream->WritePacket();
502 ASSERT_EQ(test_stream->buffer_->forward_bytes(),
503 packet_->GetDataSize() - written * kTestBytesPerFrame);
505 // Write the rest.
506 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
507 .WillOnce(Return(kTestFramesPerPacket - written));
508 EXPECT_CALL(mock_alsa_wrapper_,
509 PcmWritei(kFakeHandle,
510 packet_->GetData() + written * kTestBytesPerFrame,
512 .WillOnce(Return(packet_->GetDataSize() / kTestBytesPerFrame - written));
513 test_stream->WritePacket();
514 EXPECT_EQ(0, test_stream->buffer_->forward_bytes());
516 // Now close it and test that everything was released.
517 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
518 .WillOnce(Return(0));
519 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
520 .WillOnce(Return(kTestDeviceName));
521 test_stream->Close();
524 TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) {
525 // We need to open the stream before writing data to ALSA.
526 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
527 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
528 Return(0)));
529 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
530 .WillOnce(Return(0));
531 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _))
532 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
533 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
534 Return(0)));
535 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
536 ASSERT_TRUE(test_stream->Open());
537 InitBuffer(test_stream);
538 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
540 // Fail due to a recoverable error and see that PcmRecover code path
541 // continues normally.
542 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
543 .WillOnce(Return(kTestFramesPerPacket));
544 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
545 .WillOnce(Return(-EINTR));
546 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(kFakeHandle, _, _))
547 .WillOnce(Return(0));
549 test_stream->WritePacket();
551 ASSERT_EQ(test_stream->buffer_->forward_bytes(), packet_->GetDataSize());
553 // Fail the next write, and see that stop_stream_ is set.
554 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
555 .WillOnce(Return(kTestFramesPerPacket));
556 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
557 .WillOnce(Return(kTestFailedErrno));
558 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(kFakeHandle, _, _))
559 .WillOnce(Return(kTestFailedErrno));
560 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
561 .WillOnce(Return(kDummyMessage));
562 test_stream->WritePacket();
563 EXPECT_EQ(test_stream->buffer_->forward_bytes(), packet_->GetDataSize());
564 EXPECT_TRUE(test_stream->stop_stream_);
566 // Now close it and test that everything was released.
567 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
568 .WillOnce(Return(0));
569 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle))
570 .WillOnce(Return(kTestDeviceName));
571 test_stream->Close();
574 TEST_F(AlsaPcmOutputStreamTest, WritePacket_StopStream) {
575 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
576 InitBuffer(test_stream);
577 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
578 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
580 // No expectations set on the strict mock because nothing should be called.
581 test_stream->stop_stream_ = true;
582 test_stream->WritePacket();
583 EXPECT_EQ(0, test_stream->buffer_->forward_bytes());
584 test_stream->Close();
587 TEST_F(AlsaPcmOutputStreamTest, BufferPacket) {
588 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
589 InitBuffer(test_stream);
590 test_stream->buffer_->Clear();
592 MockAudioSourceCallback mock_callback;
593 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_))
594 .WillOnce(Return(SND_PCM_STATE_RUNNING));
595 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(_, _))
596 .WillOnce(DoAll(SetArgumentPointee<1>(1), Return(0)));
597 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
598 .WillRepeatedly(Return(0)); // Buffer is full.
600 // Return a partially filled packet.
601 EXPECT_CALL(mock_callback, OnMoreData(_, _))
602 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
604 bool source_exhausted;
605 test_stream->set_source_callback(&mock_callback);
606 test_stream->packet_size_ = kTestPacketSize;
607 test_stream->BufferPacket(&source_exhausted);
609 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes());
610 EXPECT_FALSE(source_exhausted);
611 test_stream->Close();
614 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) {
615 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
616 InitBuffer(test_stream);
617 test_stream->buffer_->Clear();
619 // Simulate where the underrun has occurred right after checking the delay.
620 MockAudioSourceCallback mock_callback;
621 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_))
622 .WillOnce(Return(SND_PCM_STATE_RUNNING));
623 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(_, _))
624 .WillOnce(DoAll(SetArgumentPointee<1>(-1), Return(0)));
625 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
626 .WillRepeatedly(Return(0)); // Buffer is full.
627 EXPECT_CALL(mock_callback, OnMoreData(_, _))
628 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
630 bool source_exhausted;
631 test_stream->set_source_callback(&mock_callback);
632 test_stream->packet_size_ = kTestPacketSize;
633 test_stream->BufferPacket(&source_exhausted);
635 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes());
636 EXPECT_FALSE(source_exhausted);
637 test_stream->Close();
640 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) {
641 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
642 InitBuffer(test_stream);
643 test_stream->buffer_->Clear();
645 // If ALSA has underrun then we should assume a delay of zero.
646 MockAudioSourceCallback mock_callback;
647 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_))
648 .WillOnce(Return(SND_PCM_STATE_XRUN));
649 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
650 .WillRepeatedly(Return(0)); // Buffer is full.
651 EXPECT_CALL(mock_callback,
652 OnMoreData(_, AllOf(
653 Field(&AudioBuffersState::pending_bytes, 0),
654 Field(&AudioBuffersState::hardware_delay_bytes, 0))))
655 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
657 bool source_exhausted;
658 test_stream->set_source_callback(&mock_callback);
659 test_stream->packet_size_ = kTestPacketSize;
660 test_stream->BufferPacket(&source_exhausted);
662 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes());
663 EXPECT_FALSE(source_exhausted);
664 test_stream->Close();
667 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer) {
668 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
669 InitBuffer(test_stream);
670 // No expectations set on the strict mock because nothing should be called.
671 bool source_exhausted;
672 test_stream->packet_size_ = kTestPacketSize;
673 test_stream->BufferPacket(&source_exhausted);
674 EXPECT_EQ(kTestPacketSize, test_stream->buffer_->forward_bytes());
675 EXPECT_FALSE(source_exhausted);
676 test_stream->Close();
679 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) {
680 // Try channels from 1 -> 9. and see that we get the more specific surroundXX
681 // device opened for channels 4-8. For all other channels, the device should
682 // default to |AlsaPcmOutputStream::kDefaultDevice|. We should also not
683 // downmix any channel in this case because downmixing is only defined for
684 // channels 4-8, which we are guaranteeing to work.
686 // Note that the loop starts at "1", so the first parameter is ignored in
687 // these arrays.
688 const char* kExpectedDeviceName[] = { NULL,
689 AlsaPcmOutputStream::kDefaultDevice,
690 AlsaPcmOutputStream::kDefaultDevice,
691 AlsaPcmOutputStream::kDefaultDevice,
692 kSurround40, kSurround50, kSurround51,
693 kSurround70, kSurround71,
694 AlsaPcmOutputStream::kDefaultDevice };
695 bool kExpectedDownmix[] = { false, false, false, false, false, true,
696 false, false, false, false };
697 ChannelLayout kExpectedLayouts[] = { CHANNEL_LAYOUT_NONE,
698 CHANNEL_LAYOUT_MONO,
699 CHANNEL_LAYOUT_STEREO,
700 CHANNEL_LAYOUT_SURROUND,
701 CHANNEL_LAYOUT_4_0,
702 CHANNEL_LAYOUT_5_0,
703 CHANNEL_LAYOUT_5_1,
704 CHANNEL_LAYOUT_7_0,
705 CHANNEL_LAYOUT_7_1 };
708 for (int i = 1; i < 9; ++i) {
709 if (i == 3 || i == 4 || i == 5) // invalid number of channels
710 continue;
711 SCOPED_TRACE(base::StringPrintf("Attempting %d Channel", i));
713 // Hints will only be grabbed for channel numbers that have non-default
714 // devices associated with them.
715 if (kExpectedDeviceName[i] != AlsaPcmOutputStream::kDefaultDevice) {
716 // The DeviceNameHint and DeviceNameFreeHint need to be paired to avoid a
717 // memory leak.
718 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _))
719 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0)));
720 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0]))
721 .Times(1);
724 EXPECT_CALL(mock_alsa_wrapper_,
725 PcmOpen(_, StrEq(kExpectedDeviceName[i]), _, _))
726 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
727 EXPECT_CALL(mock_alsa_wrapper_,
728 PcmSetParams(kFakeHandle, _, _, i, _, _, _))
729 .WillOnce(Return(0));
731 // The parameters are specified by ALSA documentation, and are in constants
732 // in the implementation files.
733 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID")))
734 .WillRepeatedly(Invoke(OutputHint));
735 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME")))
736 .WillRepeatedly(Invoke(EchoHint));
738 AlsaPcmOutputStream* test_stream = CreateStream(kExpectedLayouts[i]);
739 EXPECT_TRUE(test_stream->AutoSelectDevice(i));
740 EXPECT_EQ(kExpectedDownmix[i],
741 static_cast<bool>(test_stream->channel_mixer_));
743 Mock::VerifyAndClearExpectations(&mock_alsa_wrapper_);
744 Mock::VerifyAndClearExpectations(mock_manager_.get());
745 test_stream->Close();
749 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices) {
750 using std::string;
752 // If there are problems opening a multi-channel device, it the fallbacks
753 // operations should be as follows. Assume the multi-channel device name is
754 // surround50:
756 // 1) Try open "surround50"
757 // 2) Try open "plug:surround50".
758 // 3) Try open "default".
759 // 4) Try open "plug:default".
760 // 5) Give up trying to open.
762 const string first_try = kSurround50;
763 const string second_try = string(AlsaPcmOutputStream::kPlugPrefix) +
764 kSurround50;
765 const string third_try = AlsaPcmOutputStream::kDefaultDevice;
766 const string fourth_try = string(AlsaPcmOutputStream::kPlugPrefix) +
767 AlsaPcmOutputStream::kDefaultDevice;
769 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _))
770 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0)));
771 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0]))
772 .Times(1);
773 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID")))
774 .WillRepeatedly(Invoke(OutputHint));
775 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME")))
776 .WillRepeatedly(Invoke(EchoHint));
777 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
778 .WillRepeatedly(Return(kDummyMessage));
780 InSequence s;
781 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(first_try.c_str()), _, _))
782 .WillOnce(Return(kTestFailedErrno));
783 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(second_try.c_str()), _, _))
784 .WillOnce(Return(kTestFailedErrno));
785 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(third_try.c_str()), _, _))
786 .WillOnce(Return(kTestFailedErrno));
787 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(fourth_try.c_str()), _, _))
788 .WillOnce(Return(kTestFailedErrno));
790 AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5_0);
791 EXPECT_FALSE(test_stream->AutoSelectDevice(5));
792 test_stream->Close();
795 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) {
796 // Should get |kDefaultDevice|, and force a 2-channel downmix on a failure to
797 // enumerate devices.
798 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _))
799 .WillRepeatedly(Return(kTestFailedErrno));
800 EXPECT_CALL(mock_alsa_wrapper_,
801 PcmOpen(_, StrEq(AlsaPcmOutputStream::kDefaultDevice), _, _))
802 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0)));
803 EXPECT_CALL(mock_alsa_wrapper_,
804 PcmSetParams(kFakeHandle, _, _, 2, _, _, _))
805 .WillOnce(Return(0));
806 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
807 .WillOnce(Return(kDummyMessage));
809 AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5_0);
810 EXPECT_TRUE(test_stream->AutoSelectDevice(5));
811 EXPECT_TRUE(test_stream->channel_mixer_);
812 test_stream->Close();
815 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) {
816 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
817 InitBuffer(test_stream);
818 test_stream->stop_stream_ = true;
819 bool source_exhausted;
820 test_stream->BufferPacket(&source_exhausted);
821 EXPECT_EQ(0, test_stream->buffer_->forward_bytes());
822 EXPECT_TRUE(source_exhausted);
823 test_stream->Close();
826 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) {
827 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
828 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
829 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
830 InitBuffer(test_stream);
831 DVLOG(1) << test_stream->state();
832 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
833 .WillOnce(Return(10));
834 test_stream->ScheduleNextWrite(false);
835 DVLOG(1) << test_stream->state();
836 // TODO(sergeyu): Figure out how to check that the task has been added to the
837 // message loop.
839 // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending
840 // tasks unless running on valgrind. The code below is needed to keep
841 // heapcheck happy.
843 test_stream->stop_stream_ = true;
844 DVLOG(1) << test_stream->state();
845 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed);
846 DVLOG(1) << test_stream->state();
847 test_stream->Close();
850 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream) {
851 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
852 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened);
853 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying);
855 InitBuffer(test_stream);
857 test_stream->stop_stream_ = true;
858 test_stream->ScheduleNextWrite(true);
860 // TODO(ajwong): Find a way to test whether or not another task has been
861 // posted so we can verify that the Alsa code will indeed break the task
862 // posting loop.
864 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed);
865 test_stream->Close();
868 } // namespace media