1 // Copyright 2013 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/strings/stringprintf.h"
6 #include "media/audio/alsa/alsa_output.h"
7 #include "media/audio/alsa/alsa_wrapper.h"
8 #include "media/audio/alsa/audio_manager_alsa.h"
9 #include "media/audio/fake_audio_log_factory.h"
10 #include "media/audio/mock_audio_source_callback.h"
11 #include "media/base/data_buffer.h"
12 #include "media/base/seekable_buffer.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
18 using testing::AtLeast
;
21 using testing::InSequence
;
22 using testing::Invoke
;
23 using testing::InvokeWithoutArgs
;
25 using testing::MockFunction
;
26 using testing::Return
;
27 using testing::SetArgumentPointee
;
28 using testing::StrictMock
;
30 using testing::Unused
;
34 class MockAlsaWrapper
: public AlsaWrapper
{
36 MOCK_METHOD3(DeviceNameHint
, int(int card
,
39 MOCK_METHOD2(DeviceNameGetHint
, char*(const void* hint
, const char* id
));
40 MOCK_METHOD1(DeviceNameFreeHint
, int(void** hints
));
42 MOCK_METHOD4(PcmOpen
, int(snd_pcm_t
** handle
, const char* name
,
43 snd_pcm_stream_t stream
, int mode
));
44 MOCK_METHOD1(PcmClose
, int(snd_pcm_t
* handle
));
45 MOCK_METHOD1(PcmPrepare
, int(snd_pcm_t
* handle
));
46 MOCK_METHOD1(PcmDrop
, int(snd_pcm_t
* handle
));
47 MOCK_METHOD2(PcmDelay
, int(snd_pcm_t
* handle
, snd_pcm_sframes_t
* delay
));
48 MOCK_METHOD3(PcmWritei
, snd_pcm_sframes_t(snd_pcm_t
* handle
,
50 snd_pcm_uframes_t size
));
51 MOCK_METHOD3(PcmReadi
, snd_pcm_sframes_t(snd_pcm_t
* handle
,
53 snd_pcm_uframes_t size
));
54 MOCK_METHOD3(PcmRecover
, int(snd_pcm_t
* handle
, int err
, int silent
));
55 MOCK_METHOD7(PcmSetParams
, int(snd_pcm_t
* handle
, snd_pcm_format_t format
,
56 snd_pcm_access_t access
, unsigned int channels
,
57 unsigned int rate
, int soft_resample
,
58 unsigned int latency
));
59 MOCK_METHOD3(PcmGetParams
, int(snd_pcm_t
* handle
,
60 snd_pcm_uframes_t
* buffer_size
,
61 snd_pcm_uframes_t
* period_size
));
62 MOCK_METHOD1(PcmName
, const char*(snd_pcm_t
* handle
));
63 MOCK_METHOD1(PcmAvailUpdate
, snd_pcm_sframes_t(snd_pcm_t
* handle
));
64 MOCK_METHOD1(PcmState
, snd_pcm_state_t(snd_pcm_t
* handle
));
65 MOCK_METHOD1(PcmStart
, int(snd_pcm_t
* handle
));
67 MOCK_METHOD1(StrError
, const char*(int errnum
));
70 class MockAudioManagerAlsa
: public AudioManagerAlsa
{
72 MockAudioManagerAlsa() : AudioManagerAlsa(&fake_audio_log_factory_
) {}
73 MOCK_METHOD0(Init
, void());
74 MOCK_METHOD0(HasAudioOutputDevices
, bool());
75 MOCK_METHOD0(HasAudioInputDevices
, bool());
76 MOCK_METHOD1(MakeLinearOutputStream
, AudioOutputStream
*(
77 const AudioParameters
& params
));
78 MOCK_METHOD2(MakeLowLatencyOutputStream
, AudioOutputStream
*(
79 const AudioParameters
& params
,
80 const std::string
& device_id
));
81 MOCK_METHOD2(MakeLowLatencyInputStream
, AudioInputStream
*(
82 const AudioParameters
& params
, const std::string
& device_id
));
84 // We need to override this function in order to skip the checking the number
85 // of active output streams. It is because the number of active streams
86 // is managed inside MakeAudioOutputStream, and we don't use
87 // MakeAudioOutputStream to create the stream in the tests.
88 void ReleaseOutputStream(AudioOutputStream
* stream
) override
{
93 // We don't mock this method since all tests will do the same thing
94 // and use the current task runner.
95 scoped_refptr
<base::SingleThreadTaskRunner
> GetTaskRunner() override
{
96 return base::MessageLoop::current()->task_runner();
100 FakeAudioLogFactory fake_audio_log_factory_
;
103 class AlsaPcmOutputStreamTest
: public testing::Test
{
105 AlsaPcmOutputStreamTest() {
106 mock_manager_
.reset(new StrictMock
<MockAudioManagerAlsa
>());
109 virtual ~AlsaPcmOutputStreamTest() {
112 AlsaPcmOutputStream
* CreateStream(ChannelLayout layout
) {
113 return CreateStream(layout
, kTestFramesPerPacket
);
116 AlsaPcmOutputStream
* CreateStream(ChannelLayout layout
,
117 int32 samples_per_packet
) {
118 AudioParameters
params(kTestFormat
, layout
, kTestSampleRate
,
119 kTestBitsPerSample
, samples_per_packet
);
120 return new AlsaPcmOutputStream(kTestDeviceName
,
123 mock_manager_
.get());
126 // Helper function to malloc the string returned by DeviceNameHint for NAME.
127 static char* EchoHint(const void* name
, Unused
) {
128 return strdup(static_cast<const char*>(name
));
131 // Helper function to malloc the string returned by DeviceNameHint for IOID.
132 static char* OutputHint(Unused
, Unused
) {
133 return strdup("Output");
136 // Helper function to initialize |test_stream->buffer_|. Must be called
137 // in all tests that use buffer_ without opening the stream.
138 void InitBuffer(AlsaPcmOutputStream
* test_stream
) {
140 packet_
= new media::DataBuffer(kTestPacketSize
);
141 packet_
->set_data_size(kTestPacketSize
);
142 test_stream
->buffer_
.reset(new media::SeekableBuffer(0, kTestPacketSize
));
143 test_stream
->buffer_
->Append(packet_
.get());
146 static const ChannelLayout kTestChannelLayout
;
147 static const int kTestSampleRate
;
148 static const int kTestBitsPerSample
;
149 static const int kTestBytesPerFrame
;
150 static const AudioParameters::Format kTestFormat
;
151 static const char kTestDeviceName
[];
152 static const char kDummyMessage
[];
153 static const uint32 kTestFramesPerPacket
;
154 static const int kTestPacketSize
;
155 static const int kTestFailedErrno
;
156 static snd_pcm_t
* const kFakeHandle
;
158 // Used to simulate DeviceNameHint.
159 static char kSurround40
[];
160 static char kSurround41
[];
161 static char kSurround50
[];
162 static char kSurround51
[];
163 static char kSurround70
[];
164 static char kSurround71
[];
165 static void* kFakeHints
[];
166 static char kGenericSurround50
[];
168 StrictMock
<MockAlsaWrapper
> mock_alsa_wrapper_
;
169 scoped_ptr
<StrictMock
<MockAudioManagerAlsa
> > mock_manager_
;
170 base::MessageLoop message_loop_
;
171 scoped_refptr
<media::DataBuffer
> packet_
;
174 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest
);
177 const ChannelLayout
AlsaPcmOutputStreamTest::kTestChannelLayout
=
178 CHANNEL_LAYOUT_STEREO
;
179 const int AlsaPcmOutputStreamTest::kTestSampleRate
=
180 AudioParameters::kAudioCDSampleRate
;
181 const int AlsaPcmOutputStreamTest::kTestBitsPerSample
= 8;
182 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame
=
183 AlsaPcmOutputStreamTest::kTestBitsPerSample
/ 8 *
184 ChannelLayoutToChannelCount(AlsaPcmOutputStreamTest::kTestChannelLayout
);
185 const AudioParameters::Format
AlsaPcmOutputStreamTest::kTestFormat
=
186 AudioParameters::AUDIO_PCM_LINEAR
;
187 const char AlsaPcmOutputStreamTest::kTestDeviceName
[] = "TestDevice";
188 const char AlsaPcmOutputStreamTest::kDummyMessage
[] = "dummy";
189 const uint32
AlsaPcmOutputStreamTest::kTestFramesPerPacket
= 1000;
190 const int AlsaPcmOutputStreamTest::kTestPacketSize
=
191 AlsaPcmOutputStreamTest::kTestFramesPerPacket
*
192 AlsaPcmOutputStreamTest::kTestBytesPerFrame
;
193 const int AlsaPcmOutputStreamTest::kTestFailedErrno
= -EACCES
;
194 snd_pcm_t
* const AlsaPcmOutputStreamTest::kFakeHandle
=
195 reinterpret_cast<snd_pcm_t
*>(1);
197 char AlsaPcmOutputStreamTest::kSurround40
[] = "surround40:CARD=foo,DEV=0";
198 char AlsaPcmOutputStreamTest::kSurround41
[] = "surround41:CARD=foo,DEV=0";
199 char AlsaPcmOutputStreamTest::kSurround50
[] = "surround50:CARD=foo,DEV=0";
200 char AlsaPcmOutputStreamTest::kSurround51
[] = "surround51:CARD=foo,DEV=0";
201 char AlsaPcmOutputStreamTest::kSurround70
[] = "surround70:CARD=foo,DEV=0";
202 char AlsaPcmOutputStreamTest::kSurround71
[] = "surround71:CARD=foo,DEV=0";
203 void* AlsaPcmOutputStreamTest::kFakeHints
[] = {
204 kSurround40
, kSurround41
, kSurround50
, kSurround51
,
205 kSurround70
, kSurround71
, NULL
};
206 char AlsaPcmOutputStreamTest::kGenericSurround50
[] = "surround50";
208 // Custom action to clear a memory buffer.
209 ACTION(ClearBuffer
) {
213 TEST_F(AlsaPcmOutputStreamTest
, ConstructedState
) {
214 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
215 EXPECT_EQ(AlsaPcmOutputStream::kCreated
, test_stream
->state());
216 test_stream
->Close();
218 // Should support mono.
219 test_stream
= CreateStream(CHANNEL_LAYOUT_MONO
);
220 EXPECT_EQ(AlsaPcmOutputStream::kCreated
, test_stream
->state());
221 test_stream
->Close();
223 // Should support multi-channel.
224 test_stream
= CreateStream(CHANNEL_LAYOUT_SURROUND
);
225 EXPECT_EQ(AlsaPcmOutputStream::kCreated
, test_stream
->state());
226 test_stream
->Close();
228 // Bad bits per sample.
229 AudioParameters
bad_bps_params(kTestFormat
, kTestChannelLayout
,
230 kTestSampleRate
, kTestBitsPerSample
- 1,
231 kTestFramesPerPacket
);
232 test_stream
= new AlsaPcmOutputStream(kTestDeviceName
,
235 mock_manager_
.get());
236 EXPECT_EQ(AlsaPcmOutputStream::kInError
, test_stream
->state());
237 test_stream
->Close();
240 TEST_F(AlsaPcmOutputStreamTest
, LatencyFloor
) {
241 const double kMicrosPerFrame
=
242 static_cast<double>(1000000) / kTestSampleRate
;
243 const double kPacketFramesInMinLatency
=
244 AlsaPcmOutputStream::kMinLatencyMicros
/ kMicrosPerFrame
/ 2.0;
246 // Test that packets which would cause a latency under less than
247 // AlsaPcmOutputStream::kMinLatencyMicros will get clipped to
248 // AlsaPcmOutputStream::kMinLatencyMicros,
249 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
250 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
252 EXPECT_CALL(mock_alsa_wrapper_
,
253 PcmSetParams(_
, _
, _
, _
, _
, _
,
254 AlsaPcmOutputStream::kMinLatencyMicros
))
255 .WillOnce(Return(0));
256 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(_
, _
, _
))
257 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
258 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
261 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
,
262 kPacketFramesInMinLatency
);
263 ASSERT_TRUE(test_stream
->Open());
265 // Now close it and test that everything was released.
266 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
)).WillOnce(Return(0));
267 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
268 .WillOnce(Return(kTestDeviceName
));
269 test_stream
->Close();
271 Mock::VerifyAndClear(&mock_alsa_wrapper_
);
272 Mock::VerifyAndClear(mock_manager_
.get());
274 // Test that having more packets ends up with a latency based on packet size.
275 const int kOverMinLatencyPacketSize
= kPacketFramesInMinLatency
+ 1;
276 int64 expected_micros
= AlsaPcmOutputStream::FramesToTimeDelta(
277 kOverMinLatencyPacketSize
* 2, kTestSampleRate
).InMicroseconds();
279 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
280 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
), Return(0)));
281 EXPECT_CALL(mock_alsa_wrapper_
,
282 PcmSetParams(_
, _
, _
, _
, _
, _
, expected_micros
))
283 .WillOnce(Return(0));
284 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(_
, _
, _
))
285 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
286 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
289 test_stream
= CreateStream(kTestChannelLayout
,
290 kOverMinLatencyPacketSize
);
291 ASSERT_TRUE(test_stream
->Open());
293 // Now close it and test that everything was released.
294 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
))
295 .WillOnce(Return(0));
296 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
297 .WillOnce(Return(kTestDeviceName
));
298 test_stream
->Close();
300 Mock::VerifyAndClear(&mock_alsa_wrapper_
);
301 Mock::VerifyAndClear(mock_manager_
.get());
304 TEST_F(AlsaPcmOutputStreamTest
, OpenClose
) {
305 int64 expected_micros
= AlsaPcmOutputStream::FramesToTimeDelta(
306 2 * kTestFramesPerPacket
, kTestSampleRate
).InMicroseconds();
308 // Open() call opens the playback device, sets the parameters, posts a task
309 // with the resulting configuration data, and transitions the object state to
311 EXPECT_CALL(mock_alsa_wrapper_
,
312 PcmOpen(_
, StrEq(kTestDeviceName
),
313 SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
))
314 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
316 EXPECT_CALL(mock_alsa_wrapper_
,
317 PcmSetParams(kFakeHandle
,
319 SND_PCM_ACCESS_RW_INTERLEAVED
,
320 ChannelLayoutToChannelCount(kTestChannelLayout
),
324 .WillOnce(Return(0));
325 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(kFakeHandle
, _
, _
))
326 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
327 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
331 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
332 ASSERT_TRUE(test_stream
->Open());
334 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened
, test_stream
->state());
335 EXPECT_EQ(kFakeHandle
, test_stream
->playback_handle_
);
336 EXPECT_EQ(kTestFramesPerPacket
, test_stream
->frames_per_packet_
);
337 EXPECT_TRUE(test_stream
->buffer_
.get());
338 EXPECT_FALSE(test_stream
->stop_stream_
);
340 // Now close it and test that everything was released.
341 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
))
342 .WillOnce(Return(0));
343 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
344 .WillOnce(Return(kTestDeviceName
));
345 test_stream
->Close();
348 TEST_F(AlsaPcmOutputStreamTest
, PcmOpenFailed
) {
349 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
350 .WillOnce(Return(kTestFailedErrno
));
351 EXPECT_CALL(mock_alsa_wrapper_
, StrError(kTestFailedErrno
))
352 .WillOnce(Return(kDummyMessage
));
354 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
355 ASSERT_FALSE(test_stream
->Open());
356 ASSERT_EQ(AlsaPcmOutputStream::kInError
, test_stream
->state());
358 // Ensure internal state is set for a no-op stream if PcmOpen() failes.
359 EXPECT_TRUE(test_stream
->stop_stream_
);
360 EXPECT_TRUE(test_stream
->playback_handle_
== NULL
);
361 EXPECT_FALSE(test_stream
->buffer_
.get());
363 // Close the stream since we opened it to make destruction happy.
364 test_stream
->Close();
367 TEST_F(AlsaPcmOutputStreamTest
, PcmSetParamsFailed
) {
368 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
369 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
371 EXPECT_CALL(mock_alsa_wrapper_
, PcmSetParams(_
, _
, _
, _
, _
, _
, _
))
372 .WillOnce(Return(kTestFailedErrno
));
373 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
))
374 .WillOnce(Return(0));
375 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
376 .WillOnce(Return(kTestDeviceName
));
377 EXPECT_CALL(mock_alsa_wrapper_
, StrError(kTestFailedErrno
))
378 .WillOnce(Return(kDummyMessage
));
380 // If open fails, the stream stays in kCreated because it has effectively had
382 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
383 ASSERT_FALSE(test_stream
->Open());
384 EXPECT_EQ(AlsaPcmOutputStream::kInError
, test_stream
->state());
386 // Ensure internal state is set for a no-op stream if PcmSetParams() failes.
387 EXPECT_TRUE(test_stream
->stop_stream_
);
388 EXPECT_TRUE(test_stream
->playback_handle_
== NULL
);
389 EXPECT_FALSE(test_stream
->buffer_
.get());
391 // Close the stream since we opened it to make destruction happy.
392 test_stream
->Close();
395 TEST_F(AlsaPcmOutputStreamTest
, StartStop
) {
396 // Open() call opens the playback device, sets the parameters, posts a task
397 // with the resulting configuration data, and transitions the object state to
399 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
400 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
402 EXPECT_CALL(mock_alsa_wrapper_
, PcmSetParams(_
, _
, _
, _
, _
, _
, _
))
403 .WillOnce(Return(0));
404 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(_
, _
, _
))
405 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
406 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
410 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
411 ASSERT_TRUE(test_stream
->Open());
413 // Expect Device setup.
414 EXPECT_CALL(mock_alsa_wrapper_
, PcmDrop(kFakeHandle
))
415 .WillOnce(Return(0));
416 EXPECT_CALL(mock_alsa_wrapper_
, PcmPrepare(kFakeHandle
))
417 .WillOnce(Return(0));
419 // Expect the pre-roll.
420 MockAudioSourceCallback mock_callback
;
421 EXPECT_CALL(mock_alsa_wrapper_
, PcmState(kFakeHandle
))
422 .WillRepeatedly(Return(SND_PCM_STATE_RUNNING
));
423 EXPECT_CALL(mock_alsa_wrapper_
, PcmDelay(kFakeHandle
, _
))
424 .WillRepeatedly(DoAll(SetArgumentPointee
<1>(0), Return(0)));
425 EXPECT_CALL(mock_callback
, OnMoreData(_
, _
))
426 .WillRepeatedly(DoAll(ClearBuffer(), Return(kTestFramesPerPacket
)));
427 EXPECT_CALL(mock_alsa_wrapper_
, PcmWritei(kFakeHandle
, _
, _
))
428 .WillRepeatedly(Return(kTestFramesPerPacket
));
430 // Expect scheduling.
431 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(kFakeHandle
))
433 .WillRepeatedly(Return(kTestFramesPerPacket
));
435 test_stream
->Start(&mock_callback
);
436 // Start() will issue a WriteTask() directly and then schedule the next one,
437 // call Stop() immediately after to ensure we don't run the message loop
440 message_loop_
.RunUntilIdle();
442 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
))
443 .WillOnce(Return(0));
444 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
445 .WillOnce(Return(kTestDeviceName
));
446 test_stream
->Close();
449 TEST_F(AlsaPcmOutputStreamTest
, WritePacket_FinishedPacket
) {
450 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
451 InitBuffer(test_stream
);
452 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsOpened
);
453 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsPlaying
);
455 // Nothing should happen. Don't set any expectations and Our strict mocks
456 // should verify most of this.
458 // Test empty buffer.
459 test_stream
->buffer_
->Clear();
460 test_stream
->WritePacket();
461 test_stream
->Close();
464 TEST_F(AlsaPcmOutputStreamTest
, WritePacket_NormalPacket
) {
465 // We need to open the stream before writing data to ALSA.
466 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
467 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
469 EXPECT_CALL(mock_alsa_wrapper_
, PcmSetParams(_
, _
, _
, _
, _
, _
, _
))
470 .WillOnce(Return(0));
471 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(_
, _
, _
))
472 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
473 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
475 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
476 ASSERT_TRUE(test_stream
->Open());
477 InitBuffer(test_stream
);
478 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsPlaying
);
480 // Write a little less than half the data.
481 int written
= packet_
->data_size() / kTestBytesPerFrame
/ 2 - 1;
482 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(kFakeHandle
))
483 .WillOnce(Return(written
));
484 EXPECT_CALL(mock_alsa_wrapper_
, PcmWritei(kFakeHandle
, packet_
->data(), _
))
485 .WillOnce(Return(written
));
487 test_stream
->WritePacket();
489 ASSERT_EQ(test_stream
->buffer_
->forward_bytes(),
490 packet_
->data_size() - written
* kTestBytesPerFrame
);
493 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(kFakeHandle
))
494 .WillOnce(Return(kTestFramesPerPacket
- written
));
495 EXPECT_CALL(mock_alsa_wrapper_
,
496 PcmWritei(kFakeHandle
,
497 packet_
->data() + written
* kTestBytesPerFrame
,
499 .WillOnce(Return(packet_
->data_size() / kTestBytesPerFrame
- written
));
500 test_stream
->WritePacket();
501 EXPECT_EQ(0, test_stream
->buffer_
->forward_bytes());
503 // Now close it and test that everything was released.
504 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
))
505 .WillOnce(Return(0));
506 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
507 .WillOnce(Return(kTestDeviceName
));
508 test_stream
->Close();
511 TEST_F(AlsaPcmOutputStreamTest
, WritePacket_WriteFails
) {
512 // We need to open the stream before writing data to ALSA.
513 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, _
, _
, _
))
514 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
),
516 EXPECT_CALL(mock_alsa_wrapper_
, PcmSetParams(_
, _
, _
, _
, _
, _
, _
))
517 .WillOnce(Return(0));
518 EXPECT_CALL(mock_alsa_wrapper_
, PcmGetParams(_
, _
, _
))
519 .WillOnce(DoAll(SetArgumentPointee
<1>(kTestFramesPerPacket
),
520 SetArgumentPointee
<2>(kTestFramesPerPacket
/ 2),
522 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
523 ASSERT_TRUE(test_stream
->Open());
524 InitBuffer(test_stream
);
525 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsPlaying
);
527 // Fail due to a recoverable error and see that PcmRecover code path
528 // continues normally.
529 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(kFakeHandle
))
530 .WillOnce(Return(kTestFramesPerPacket
));
531 EXPECT_CALL(mock_alsa_wrapper_
, PcmWritei(kFakeHandle
, _
, _
))
532 .WillOnce(Return(-EINTR
));
533 EXPECT_CALL(mock_alsa_wrapper_
, PcmRecover(kFakeHandle
, _
, _
))
534 .WillOnce(Return(0));
536 test_stream
->WritePacket();
538 ASSERT_EQ(test_stream
->buffer_
->forward_bytes(), packet_
->data_size());
540 // Fail the next write, and see that stop_stream_ is set.
541 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(kFakeHandle
))
542 .WillOnce(Return(kTestFramesPerPacket
));
543 EXPECT_CALL(mock_alsa_wrapper_
, PcmWritei(kFakeHandle
, _
, _
))
544 .WillOnce(Return(kTestFailedErrno
));
545 EXPECT_CALL(mock_alsa_wrapper_
, PcmRecover(kFakeHandle
, _
, _
))
546 .WillOnce(Return(kTestFailedErrno
));
547 EXPECT_CALL(mock_alsa_wrapper_
, StrError(kTestFailedErrno
))
548 .WillOnce(Return(kDummyMessage
));
549 test_stream
->WritePacket();
550 EXPECT_EQ(test_stream
->buffer_
->forward_bytes(), packet_
->data_size());
551 EXPECT_TRUE(test_stream
->stop_stream_
);
553 // Now close it and test that everything was released.
554 EXPECT_CALL(mock_alsa_wrapper_
, PcmClose(kFakeHandle
))
555 .WillOnce(Return(0));
556 EXPECT_CALL(mock_alsa_wrapper_
, PcmName(kFakeHandle
))
557 .WillOnce(Return(kTestDeviceName
));
558 test_stream
->Close();
561 TEST_F(AlsaPcmOutputStreamTest
, WritePacket_StopStream
) {
562 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
563 InitBuffer(test_stream
);
564 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsOpened
);
565 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsPlaying
);
567 // No expectations set on the strict mock because nothing should be called.
568 test_stream
->stop_stream_
= true;
569 test_stream
->WritePacket();
570 EXPECT_EQ(0, test_stream
->buffer_
->forward_bytes());
571 test_stream
->Close();
574 TEST_F(AlsaPcmOutputStreamTest
, BufferPacket
) {
575 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
576 InitBuffer(test_stream
);
577 test_stream
->buffer_
->Clear();
579 MockAudioSourceCallback mock_callback
;
580 EXPECT_CALL(mock_alsa_wrapper_
, PcmState(_
))
581 .WillOnce(Return(SND_PCM_STATE_RUNNING
));
582 EXPECT_CALL(mock_alsa_wrapper_
, PcmDelay(_
, _
))
583 .WillOnce(DoAll(SetArgumentPointee
<1>(1), Return(0)));
584 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(_
))
585 .WillRepeatedly(Return(0)); // Buffer is full.
587 // Return a partially filled packet.
588 EXPECT_CALL(mock_callback
, OnMoreData(_
, _
))
589 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket
/ 2)));
591 bool source_exhausted
;
592 test_stream
->set_source_callback(&mock_callback
);
593 test_stream
->packet_size_
= kTestPacketSize
;
594 test_stream
->BufferPacket(&source_exhausted
);
596 EXPECT_EQ(kTestPacketSize
/ 2, test_stream
->buffer_
->forward_bytes());
597 EXPECT_FALSE(source_exhausted
);
598 test_stream
->Close();
601 TEST_F(AlsaPcmOutputStreamTest
, BufferPacket_Negative
) {
602 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
603 InitBuffer(test_stream
);
604 test_stream
->buffer_
->Clear();
606 // Simulate where the underrun has occurred right after checking the delay.
607 MockAudioSourceCallback mock_callback
;
608 EXPECT_CALL(mock_alsa_wrapper_
, PcmState(_
))
609 .WillOnce(Return(SND_PCM_STATE_RUNNING
));
610 EXPECT_CALL(mock_alsa_wrapper_
, PcmDelay(_
, _
))
611 .WillOnce(DoAll(SetArgumentPointee
<1>(-1), Return(0)));
612 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(_
))
613 .WillRepeatedly(Return(0)); // Buffer is full.
614 EXPECT_CALL(mock_callback
, OnMoreData(_
, _
))
615 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket
/ 2)));
617 bool source_exhausted
;
618 test_stream
->set_source_callback(&mock_callback
);
619 test_stream
->packet_size_
= kTestPacketSize
;
620 test_stream
->BufferPacket(&source_exhausted
);
622 EXPECT_EQ(kTestPacketSize
/ 2, test_stream
->buffer_
->forward_bytes());
623 EXPECT_FALSE(source_exhausted
);
624 test_stream
->Close();
627 TEST_F(AlsaPcmOutputStreamTest
, BufferPacket_Underrun
) {
628 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
629 InitBuffer(test_stream
);
630 test_stream
->buffer_
->Clear();
632 // If ALSA has underrun then we should assume a delay of zero.
633 MockAudioSourceCallback mock_callback
;
634 EXPECT_CALL(mock_alsa_wrapper_
, PcmState(_
))
635 .WillOnce(Return(SND_PCM_STATE_XRUN
));
636 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(_
))
637 .WillRepeatedly(Return(0)); // Buffer is full.
638 EXPECT_CALL(mock_callback
, OnMoreData(_
, 0))
639 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket
/ 2)));
641 bool source_exhausted
;
642 test_stream
->set_source_callback(&mock_callback
);
643 test_stream
->packet_size_
= kTestPacketSize
;
644 test_stream
->BufferPacket(&source_exhausted
);
646 EXPECT_EQ(kTestPacketSize
/ 2, test_stream
->buffer_
->forward_bytes());
647 EXPECT_FALSE(source_exhausted
);
648 test_stream
->Close();
651 TEST_F(AlsaPcmOutputStreamTest
, BufferPacket_FullBuffer
) {
652 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
653 InitBuffer(test_stream
);
654 // No expectations set on the strict mock because nothing should be called.
655 bool source_exhausted
;
656 test_stream
->packet_size_
= kTestPacketSize
;
657 test_stream
->BufferPacket(&source_exhausted
);
658 EXPECT_EQ(kTestPacketSize
, test_stream
->buffer_
->forward_bytes());
659 EXPECT_FALSE(source_exhausted
);
660 test_stream
->Close();
663 TEST_F(AlsaPcmOutputStreamTest
, AutoSelectDevice_DeviceSelect
) {
664 // Try channels from 1 -> 9. and see that we get the more specific surroundXX
665 // device opened for channels 4-8. For all other channels, the device should
666 // default to |AlsaPcmOutputStream::kDefaultDevice|. We should also not
667 // downmix any channel in this case because downmixing is only defined for
668 // channels 4-8, which we are guaranteeing to work.
670 // Note that the loop starts at "1", so the first parameter is ignored in
672 const char* kExpectedDeviceName
[] = { NULL
,
673 AlsaPcmOutputStream::kDefaultDevice
,
674 AlsaPcmOutputStream::kDefaultDevice
,
675 AlsaPcmOutputStream::kDefaultDevice
,
676 kSurround40
, kSurround50
, kSurround51
,
677 kSurround70
, kSurround71
,
678 AlsaPcmOutputStream::kDefaultDevice
};
679 bool kExpectedDownmix
[] = { false, false, false, false, false, true,
680 false, false, false, false };
681 ChannelLayout kExpectedLayouts
[] = { CHANNEL_LAYOUT_NONE
,
683 CHANNEL_LAYOUT_STEREO
,
684 CHANNEL_LAYOUT_SURROUND
,
689 CHANNEL_LAYOUT_7_1
};
692 for (int i
= 1; i
< 9; ++i
) {
693 if (i
== 3 || i
== 4 || i
== 5) // invalid number of channels
695 SCOPED_TRACE(base::StringPrintf("Attempting %d Channel", i
));
697 // Hints will only be grabbed for channel numbers that have non-default
698 // devices associated with them.
699 if (kExpectedDeviceName
[i
] != AlsaPcmOutputStream::kDefaultDevice
) {
700 // The DeviceNameHint and DeviceNameFreeHint need to be paired to avoid a
702 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameHint(_
, _
, _
))
703 .WillOnce(DoAll(SetArgumentPointee
<2>(&kFakeHints
[0]), Return(0)));
704 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameFreeHint(&kFakeHints
[0]))
708 EXPECT_CALL(mock_alsa_wrapper_
,
709 PcmOpen(_
, StrEq(kExpectedDeviceName
[i
]), _
, _
))
710 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
), Return(0)));
711 EXPECT_CALL(mock_alsa_wrapper_
,
712 PcmSetParams(kFakeHandle
, _
, _
, i
, _
, _
, _
))
713 .WillOnce(Return(0));
715 // The parameters are specified by ALSA documentation, and are in constants
716 // in the implementation files.
717 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameGetHint(_
, StrEq("IOID")))
718 .WillRepeatedly(Invoke(OutputHint
));
719 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameGetHint(_
, StrEq("NAME")))
720 .WillRepeatedly(Invoke(EchoHint
));
722 AlsaPcmOutputStream
* test_stream
= CreateStream(kExpectedLayouts
[i
]);
723 EXPECT_TRUE(test_stream
->AutoSelectDevice(i
));
724 EXPECT_EQ(kExpectedDownmix
[i
],
725 static_cast<bool>(test_stream
->channel_mixer_
));
727 Mock::VerifyAndClearExpectations(&mock_alsa_wrapper_
);
728 Mock::VerifyAndClearExpectations(mock_manager_
.get());
729 test_stream
->Close();
733 TEST_F(AlsaPcmOutputStreamTest
, AutoSelectDevice_FallbackDevices
) {
736 // If there are problems opening a multi-channel device, it the fallbacks
737 // operations should be as follows. Assume the multi-channel device name is
740 // 1) Try open "surround50:CARD=foo,DEV=0"
741 // 2) Try open "plug:surround50:CARD=foo,DEV=0".
742 // 3) Try open "plug:surround50".
743 // 4) Try open "default".
744 // 5) Try open "plug:default".
745 // 6) Give up trying to open.
747 const string first_try
= kSurround50
;
748 const string second_try
= string(AlsaPcmOutputStream::kPlugPrefix
) +
750 const string third_try
= string(AlsaPcmOutputStream::kPlugPrefix
) +
752 const string fourth_try
= AlsaPcmOutputStream::kDefaultDevice
;
753 const string fifth_try
= string(AlsaPcmOutputStream::kPlugPrefix
) +
754 AlsaPcmOutputStream::kDefaultDevice
;
756 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameHint(_
, _
, _
))
757 .WillOnce(DoAll(SetArgumentPointee
<2>(&kFakeHints
[0]), Return(0)));
758 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameFreeHint(&kFakeHints
[0]))
760 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameGetHint(_
, StrEq("IOID")))
761 .WillRepeatedly(Invoke(OutputHint
));
762 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameGetHint(_
, StrEq("NAME")))
763 .WillRepeatedly(Invoke(EchoHint
));
764 EXPECT_CALL(mock_alsa_wrapper_
, StrError(kTestFailedErrno
))
765 .WillRepeatedly(Return(kDummyMessage
));
768 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, StrEq(first_try
.c_str()), _
, _
))
769 .WillOnce(Return(kTestFailedErrno
));
770 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, StrEq(second_try
.c_str()), _
, _
))
771 .WillOnce(Return(kTestFailedErrno
));
772 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, StrEq(third_try
.c_str()), _
, _
))
773 .WillOnce(Return(kTestFailedErrno
));
774 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, StrEq(fourth_try
.c_str()), _
, _
))
775 .WillOnce(Return(kTestFailedErrno
));
776 EXPECT_CALL(mock_alsa_wrapper_
, PcmOpen(_
, StrEq(fifth_try
.c_str()), _
, _
))
777 .WillOnce(Return(kTestFailedErrno
));
779 AlsaPcmOutputStream
* test_stream
= CreateStream(CHANNEL_LAYOUT_5_0
);
780 EXPECT_FALSE(test_stream
->AutoSelectDevice(5));
781 test_stream
->Close();
784 TEST_F(AlsaPcmOutputStreamTest
, AutoSelectDevice_HintFail
) {
785 // Should get |kDefaultDevice|, and force a 2-channel downmix on a failure to
786 // enumerate devices.
787 EXPECT_CALL(mock_alsa_wrapper_
, DeviceNameHint(_
, _
, _
))
788 .WillRepeatedly(Return(kTestFailedErrno
));
789 EXPECT_CALL(mock_alsa_wrapper_
,
790 PcmOpen(_
, StrEq(AlsaPcmOutputStream::kDefaultDevice
), _
, _
))
791 .WillOnce(DoAll(SetArgumentPointee
<0>(kFakeHandle
), Return(0)));
792 EXPECT_CALL(mock_alsa_wrapper_
,
793 PcmSetParams(kFakeHandle
, _
, _
, 2, _
, _
, _
))
794 .WillOnce(Return(0));
795 EXPECT_CALL(mock_alsa_wrapper_
, StrError(kTestFailedErrno
))
796 .WillOnce(Return(kDummyMessage
));
798 AlsaPcmOutputStream
* test_stream
= CreateStream(CHANNEL_LAYOUT_5_0
);
799 EXPECT_TRUE(test_stream
->AutoSelectDevice(5));
800 EXPECT_TRUE(test_stream
->channel_mixer_
);
801 test_stream
->Close();
804 TEST_F(AlsaPcmOutputStreamTest
, BufferPacket_StopStream
) {
805 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
806 InitBuffer(test_stream
);
807 test_stream
->stop_stream_
= true;
808 bool source_exhausted
;
809 test_stream
->BufferPacket(&source_exhausted
);
810 EXPECT_EQ(0, test_stream
->buffer_
->forward_bytes());
811 EXPECT_TRUE(source_exhausted
);
812 test_stream
->Close();
815 TEST_F(AlsaPcmOutputStreamTest
, ScheduleNextWrite
) {
816 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
817 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsOpened
);
818 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsPlaying
);
819 InitBuffer(test_stream
);
820 DVLOG(1) << test_stream
->state();
821 EXPECT_CALL(mock_alsa_wrapper_
, PcmAvailUpdate(_
))
822 .WillOnce(Return(10));
823 test_stream
->ScheduleNextWrite(false);
824 DVLOG(1) << test_stream
->state();
825 // TODO(sergeyu): Figure out how to check that the task has been added to the
828 // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending
829 // tasks unless running on valgrind. The code below is needed to keep
832 test_stream
->stop_stream_
= true;
833 DVLOG(1) << test_stream
->state();
834 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsClosed
);
835 DVLOG(1) << test_stream
->state();
836 test_stream
->Close();
839 TEST_F(AlsaPcmOutputStreamTest
, ScheduleNextWrite_StopStream
) {
840 AlsaPcmOutputStream
* test_stream
= CreateStream(kTestChannelLayout
);
841 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsOpened
);
842 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsPlaying
);
844 InitBuffer(test_stream
);
846 test_stream
->stop_stream_
= true;
847 test_stream
->ScheduleNextWrite(true);
849 // TODO(ajwong): Find a way to test whether or not another task has been
850 // posted so we can verify that the Alsa code will indeed break the task
853 test_stream
->TransitionTo(AlsaPcmOutputStream::kIsClosed
);
854 test_stream
->Close();