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