Home | History | Annotate | Download | only in alsa
      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:
     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.
     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.
    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:
    116   AlsaPcmOutputStreamTest() {
    117     mock_manager_.reset(new StrictMock<MockAudioManagerAlsa>());
    118   }
    119 
    120   virtual ~AlsaPcmOutputStreamTest() {
    121   }
    122 
    123   AlsaPcmOutputStream* CreateStream(ChannelLayout layout) {
    124     return CreateStream(layout, kTestFramesPerPacket);
    125   }
    126 
    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.
    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.
    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.
    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.
    218 ACTION(ClearBuffer) {
    219   arg0->Zero();
    220 }
    221 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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