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