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