Home | History | Annotate | Download | only in audio
      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 <vector>
      6 
      7 #include "base/at_exit.h"
      8 #include "base/memory/shared_memory.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/process/process_handle.h"
     11 #include "base/sync_socket.h"
     12 #include "base/test/test_timeouts.h"
     13 #include "media/audio/audio_output_device.h"
     14 #include "media/audio/sample_rates.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gmock_mutant.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 using base::CancelableSyncSocket;
     20 using base::SharedMemory;
     21 using base::SyncSocket;
     22 using testing::_;
     23 using testing::DoAll;
     24 using testing::Invoke;
     25 using testing::Return;
     26 using testing::WithArgs;
     27 using testing::StrictMock;
     28 using testing::Values;
     29 
     30 namespace media {
     31 
     32 namespace {
     33 
     34 class MockRenderCallback : public AudioRendererSink::RenderCallback {
     35  public:
     36   MockRenderCallback() {}
     37   virtual ~MockRenderCallback() {}
     38 
     39   MOCK_METHOD2(Render, int(AudioBus* dest, int audio_delay_milliseconds));
     40   MOCK_METHOD0(OnRenderError, void());
     41 };
     42 
     43 class MockAudioOutputIPC : public AudioOutputIPC {
     44  public:
     45   MockAudioOutputIPC() {}
     46   virtual ~MockAudioOutputIPC() {}
     47 
     48   MOCK_METHOD3(CreateStream, void(AudioOutputIPCDelegate* delegate,
     49                                   const AudioParameters& params,
     50                                   int session_id));
     51   MOCK_METHOD0(PlayStream, void());
     52   MOCK_METHOD0(PauseStream, void());
     53   MOCK_METHOD0(CloseStream, void());
     54   MOCK_METHOD1(SetVolume, void(double volume));
     55 };
     56 
     57 ACTION_P2(SendPendingBytes, socket, pending_bytes) {
     58   socket->Send(&pending_bytes, sizeof(pending_bytes));
     59 }
     60 
     61 // Used to terminate a loop from a different thread than the loop belongs to.
     62 // |loop| should be a MessageLoopProxy.
     63 ACTION_P(QuitLoop, loop) {
     64   loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     65 }
     66 
     67 }  // namespace.
     68 
     69 class AudioOutputDeviceTest
     70     : public testing::Test,
     71       public testing::WithParamInterface<bool> {
     72  public:
     73   AudioOutputDeviceTest();
     74   ~AudioOutputDeviceTest();
     75 
     76   void StartAudioDevice();
     77   void CreateStream();
     78   void ExpectRenderCallback();
     79   void WaitUntilRenderCallback();
     80   void StopAudioDevice();
     81 
     82  protected:
     83   // Used to clean up TLS pointers that the test(s) will initialize.
     84   // Must remain the first member of this class.
     85   base::ShadowingAtExitManager at_exit_manager_;
     86   base::MessageLoopForIO io_loop_;
     87   AudioParameters default_audio_parameters_;
     88   StrictMock<MockRenderCallback> callback_;
     89   MockAudioOutputIPC* audio_output_ipc_;  // owned by audio_device_
     90   scoped_refptr<AudioOutputDevice> audio_device_;
     91 
     92  private:
     93   int CalculateMemorySize();
     94 
     95   SharedMemory shared_memory_;
     96   CancelableSyncSocket browser_socket_;
     97   CancelableSyncSocket renderer_socket_;
     98 
     99   DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest);
    100 };
    101 
    102 int AudioOutputDeviceTest::CalculateMemorySize() {
    103   // Calculate output memory size.
    104   return AudioBus::CalculateMemorySize(default_audio_parameters_);
    105 }
    106 
    107 AudioOutputDeviceTest::AudioOutputDeviceTest() {
    108   default_audio_parameters_.Reset(
    109       AudioParameters::AUDIO_PCM_LINEAR,
    110       CHANNEL_LAYOUT_STEREO, 2, 48000, 16, 1024);
    111 
    112   audio_output_ipc_ = new MockAudioOutputIPC();
    113   audio_device_ = new AudioOutputDevice(
    114       scoped_ptr<AudioOutputIPC>(audio_output_ipc_),
    115       io_loop_.message_loop_proxy());
    116 
    117   audio_device_->Initialize(default_audio_parameters_,
    118                             &callback_);
    119 
    120   io_loop_.RunUntilIdle();
    121 }
    122 
    123 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
    124   audio_device_ = NULL;
    125 }
    126 
    127 void AudioOutputDeviceTest::StartAudioDevice() {
    128   audio_device_->Start();
    129 
    130   EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _, 0));
    131 
    132   io_loop_.RunUntilIdle();
    133 }
    134 
    135 void AudioOutputDeviceTest::CreateStream() {
    136   const int kMemorySize = CalculateMemorySize();
    137 
    138   ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize));
    139   memset(shared_memory_.memory(), 0xff, kMemorySize);
    140 
    141   ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_,
    142                                                &renderer_socket_));
    143 
    144   // Create duplicates of the handles we pass to AudioOutputDevice since
    145   // ownership will be transferred and AudioOutputDevice is responsible for
    146   // freeing.
    147   SyncSocket::TransitDescriptor audio_device_socket_descriptor;
    148   ASSERT_TRUE(renderer_socket_.PrepareTransitDescriptor(
    149       base::GetCurrentProcessHandle(), &audio_device_socket_descriptor));
    150   base::SharedMemoryHandle duplicated_memory_handle;
    151   ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(),
    152                                             &duplicated_memory_handle));
    153 
    154   audio_device_->OnStreamCreated(
    155       duplicated_memory_handle,
    156       SyncSocket::UnwrapHandle(audio_device_socket_descriptor), kMemorySize);
    157   io_loop_.RunUntilIdle();
    158 }
    159 
    160 void AudioOutputDeviceTest::ExpectRenderCallback() {
    161   // We should get a 'play' notification when we call OnStreamCreated().
    162   // Respond by asking for some audio data.  This should ask our callback
    163   // to provide some audio data that AudioOutputDevice then writes into the
    164   // shared memory section.
    165   const int kMemorySize = CalculateMemorySize();
    166 
    167   EXPECT_CALL(*audio_output_ipc_, PlayStream())
    168       .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize));
    169 
    170   // We expect calls to our audio renderer callback, which returns the number
    171   // of frames written to the memory section.
    172   // Here's the second place where it gets hacky:  There's no way for us to
    173   // know (without using a sleep loop!) when the AudioOutputDevice has finished
    174   // writing the interleaved audio data into the shared memory section.
    175   // So, for the sake of this test, we consider the call to Render a sign
    176   // of success and quit the loop.
    177   const int kNumberOfFramesToProcess = 0;
    178   EXPECT_CALL(callback_, Render(_, _))
    179       .WillOnce(DoAll(
    180           QuitLoop(io_loop_.message_loop_proxy()),
    181           Return(kNumberOfFramesToProcess)));
    182 }
    183 
    184 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
    185   // Don't hang the test if we never get the Render() callback.
    186   io_loop_.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
    187                            TestTimeouts::action_timeout());
    188   io_loop_.Run();
    189 }
    190 
    191 void AudioOutputDeviceTest::StopAudioDevice() {
    192   audio_device_->Stop();
    193 
    194   EXPECT_CALL(*audio_output_ipc_, CloseStream());
    195 
    196   io_loop_.RunUntilIdle();
    197 }
    198 
    199 TEST_P(AudioOutputDeviceTest, Initialize) {
    200   // Tests that the object can be constructed, initialized and destructed
    201   // without having ever been started/stopped.
    202 }
    203 
    204 // Calls Start() followed by an immediate Stop() and check for the basic message
    205 // filter messages being sent in that case.
    206 TEST_P(AudioOutputDeviceTest, StartStop) {
    207   StartAudioDevice();
    208   StopAudioDevice();
    209 }
    210 
    211 // AudioOutputDevice supports multiple start/stop sequences.
    212 TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
    213   StartAudioDevice();
    214   StopAudioDevice();
    215   StartAudioDevice();
    216   StopAudioDevice();
    217 }
    218 
    219 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
    220 // on the IO loop.
    221 TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
    222   StartAudioDevice();
    223 
    224   // Call Stop() but don't run the IO loop yet.
    225   audio_device_->Stop();
    226 
    227   // Expect us to shutdown IPC but not to render anything despite the stream
    228   // getting created.
    229   EXPECT_CALL(*audio_output_ipc_, CloseStream());
    230   CreateStream();
    231 }
    232 
    233 // Full test with output only.
    234 TEST_P(AudioOutputDeviceTest, CreateStream) {
    235   StartAudioDevice();
    236   ExpectRenderCallback();
    237   CreateStream();
    238   WaitUntilRenderCallback();
    239   StopAudioDevice();
    240 }
    241 
    242 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
    243 
    244 }  // namespace media.
    245