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