Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / media / audio / alsa / alsa_output_unittest.cc
blob8996dbc1a88a8497f905285f0726df4ee02c1513
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"
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;
32 namespace media {
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));
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));
67 MOCK_METHOD1(StrError, const char*(int errnum));
70 class MockAudioManagerAlsa : public AudioManagerAlsa {
71 public:
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 {
89 DCHECK(stream);
90 delete stream;
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();
99 private:
100 FakeAudioLogFactory fake_audio_log_factory_;
103 class AlsaPcmOutputStreamTest : public testing::Test {
104 protected:
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,
121 params,
122 &mock_alsa_wrapper_,
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) {
139 DCHECK(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_;
173 private:
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) {
210 arg0->Zero();
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,
233 bad_bps_params,
234 &mock_alsa_wrapper_,
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),
251 Return(0)));
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),
259 Return(0)));
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),
287 Return(0)));
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
310 // kIsOpened.
311 EXPECT_CALL(mock_alsa_wrapper_,
312 PcmOpen(_, StrEq(kTestDeviceName),
313 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))
314 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
315 Return(0)));
316 EXPECT_CALL(mock_alsa_wrapper_,
317 PcmSetParams(kFakeHandle,
318 SND_PCM_FORMAT_U8,
319 SND_PCM_ACCESS_RW_INTERLEAVED,
320 ChannelLayoutToChannelCount(kTestChannelLayout),
321 kTestSampleRate,
323 expected_micros))
324 .WillOnce(Return(0));
325 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(kFakeHandle, _, _))
326 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket),
327 SetArgumentPointee<2>(kTestFramesPerPacket / 2),
328 Return(0)));
330 // Open the stream.
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),
370 Return(0)));
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
381 // no changes.
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
398 // kIsOpened.
399 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
400 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
401 Return(0)));
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),
407 Return(0)));
409 // Open the stream.
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))
432 .Times(AtLeast(2))
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
438 // forever.
439 test_stream->Stop();
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),
468 Return(0)));
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),
474 Return(0)));
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);
492 // Write the rest.
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),
515 Return(0)));
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),
521 Return(0)));
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
671 // these arrays.
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,
682 CHANNEL_LAYOUT_MONO,
683 CHANNEL_LAYOUT_STEREO,
684 CHANNEL_LAYOUT_SURROUND,
685 CHANNEL_LAYOUT_4_0,
686 CHANNEL_LAYOUT_5_0,
687 CHANNEL_LAYOUT_5_1,
688 CHANNEL_LAYOUT_7_0,
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
694 continue;
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
701 // memory leak.
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]))
705 .Times(1);
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) {
734 using std::string;
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
738 // surround50:
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) +
749 kSurround50;
750 const string third_try = string(AlsaPcmOutputStream::kPlugPrefix) +
751 kGenericSurround50;
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]))
759 .Times(1);
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));
767 InSequence s;
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
826 // message loop.
828 // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending
829 // tasks unless running on valgrind. The code below is needed to keep
830 // heapcheck happy.
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
851 // posting loop.
853 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed);
854 test_stream->Close();
857 } // namespace media