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