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"
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_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
{
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
{
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
,
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
) {
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_
;
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
) {
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
,
237 mock_manager_
.get());
238 EXPECT_EQ(AlsaPcmOutputStream::kInError
, test_stream
->state());
239 test_stream
->Close();
242 AudioParameters
bad_format_params(
243 AudioParameters::AUDIO_LAST_FORMAT
, kTestChannelLayout
, kTestSampleRate
,
244 kTestBitsPerSample
, kTestFramesPerPacket
);
245 test_stream
= new AlsaPcmOutputStream(kTestDeviceName
,
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
),
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),
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),
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
324 EXPECT_CALL(mock_alsa_wrapper_
,
325 PcmOpen(_
, StrEq(kTestDeviceName
),
326 SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
))
327 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
329 EXPECT_CALL(mock_alsa_wrapper_
,
330 PcmSetParams(kFakeHandle
,
332 SND_PCM_ACCESS_RW_INTERLEAVED
,
333 ChannelLayoutToChannelCount(kTestChannelLayout
),
337 .WillOnce(Return(0));
338 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(kFakeHandle
, _
, _
))
339 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
340 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
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
),
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
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
412 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
413 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
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),
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
))
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
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
),
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),
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
);
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
),
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),
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
,
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
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
,
699 CHANNEL_LAYOUT_STEREO
,
700 CHANNEL_LAYOUT_SURROUND
,
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
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
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]))
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
) {
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
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
) +
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]))
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
));
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
839 // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending
840 // tasks unless running on valgrind. The code below is needed to keep
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
864 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsClosed
);
865 test_stream
->Close();