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 // Creates a copy of a SyncSocket handle that we can give to AudioOutputDevice. 58 // On Windows this means duplicating the pipe handle so that AudioOutputDevice 59 // can call CloseHandle() (since ownership has been transferred), but on other 60 // platforms, we just copy the same socket handle since AudioOutputDevice on 61 // those platforms won't actually own the socket (FileDescriptor.auto_close is 62 // false). 63 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle, 64 SyncSocket::Handle* copy) { 65 #if defined(OS_WIN) 66 HANDLE process = GetCurrentProcess(); 67 ::DuplicateHandle(process, socket_handle, process, copy, 68 0, FALSE, DUPLICATE_SAME_ACCESS); 69 return *copy != NULL; 70 #else 71 *copy = socket_handle; 72 return *copy != -1; 73 #endif 74 } 75 76 ACTION_P2(SendPendingBytes, socket, pending_bytes) { 77 socket->Send(&pending_bytes, sizeof(pending_bytes)); 78 } 79 80 // Used to terminate a loop from a different thread than the loop belongs to. 81 // |loop| should be a MessageLoopProxy. 82 ACTION_P(QuitLoop, loop) { 83 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 84 } 85 86 } // namespace. 87 88 class AudioOutputDeviceTest 89 : public testing::Test, 90 public testing::WithParamInterface<bool> { 91 public: 92 AudioOutputDeviceTest(); 93 ~AudioOutputDeviceTest(); 94 95 void StartAudioDevice(); 96 void CreateStream(); 97 void ExpectRenderCallback(); 98 void WaitUntilRenderCallback(); 99 void StopAudioDevice(); 100 101 protected: 102 // Used to clean up TLS pointers that the test(s) will initialize. 103 // Must remain the first member of this class. 104 base::ShadowingAtExitManager at_exit_manager_; 105 base::MessageLoopForIO io_loop_; 106 AudioParameters default_audio_parameters_; 107 StrictMock<MockRenderCallback> callback_; 108 MockAudioOutputIPC* audio_output_ipc_; // owned by audio_device_ 109 scoped_refptr<AudioOutputDevice> audio_device_; 110 111 private: 112 int CalculateMemorySize(); 113 114 SharedMemory shared_memory_; 115 CancelableSyncSocket browser_socket_; 116 CancelableSyncSocket renderer_socket_; 117 118 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest); 119 }; 120 121 int AudioOutputDeviceTest::CalculateMemorySize() { 122 // Calculate output memory size. 123 return AudioBus::CalculateMemorySize(default_audio_parameters_); 124 } 125 126 AudioOutputDeviceTest::AudioOutputDeviceTest() { 127 default_audio_parameters_.Reset( 128 AudioParameters::AUDIO_PCM_LINEAR, 129 CHANNEL_LAYOUT_STEREO, 2, 0, 48000, 16, 1024); 130 131 audio_output_ipc_ = new MockAudioOutputIPC(); 132 audio_device_ = new AudioOutputDevice( 133 scoped_ptr<AudioOutputIPC>(audio_output_ipc_), 134 io_loop_.message_loop_proxy()); 135 136 audio_device_->Initialize(default_audio_parameters_, 137 &callback_); 138 139 io_loop_.RunUntilIdle(); 140 } 141 142 AudioOutputDeviceTest::~AudioOutputDeviceTest() { 143 audio_device_ = NULL; 144 } 145 146 void AudioOutputDeviceTest::StartAudioDevice() { 147 audio_device_->Start(); 148 149 EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _, 0)); 150 151 io_loop_.RunUntilIdle(); 152 } 153 154 void AudioOutputDeviceTest::CreateStream() { 155 const int kMemorySize = CalculateMemorySize(); 156 157 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize)); 158 memset(shared_memory_.memory(), 0xff, kMemorySize); 159 160 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_, 161 &renderer_socket_)); 162 163 // Create duplicates of the handles we pass to AudioOutputDevice since 164 // ownership will be transferred and AudioOutputDevice is responsible for 165 // freeing. 166 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle; 167 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_.handle(), 168 &audio_device_socket)); 169 base::SharedMemoryHandle duplicated_memory_handle; 170 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), 171 &duplicated_memory_handle)); 172 173 audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket, 174 kMemorySize); 175 io_loop_.RunUntilIdle(); 176 } 177 178 void AudioOutputDeviceTest::ExpectRenderCallback() { 179 // We should get a 'play' notification when we call OnStreamCreated(). 180 // Respond by asking for some audio data. This should ask our callback 181 // to provide some audio data that AudioOutputDevice then writes into the 182 // shared memory section. 183 const int kMemorySize = CalculateMemorySize(); 184 185 EXPECT_CALL(*audio_output_ipc_, PlayStream()) 186 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize)); 187 188 // We expect calls to our audio renderer callback, which returns the number 189 // of frames written to the memory section. 190 // Here's the second place where it gets hacky: There's no way for us to 191 // know (without using a sleep loop!) when the AudioOutputDevice has finished 192 // writing the interleaved audio data into the shared memory section. 193 // So, for the sake of this test, we consider the call to Render a sign 194 // of success and quit the loop. 195 const int kNumberOfFramesToProcess = 0; 196 EXPECT_CALL(callback_, Render(_, _)) 197 .WillOnce(DoAll( 198 QuitLoop(io_loop_.message_loop_proxy()), 199 Return(kNumberOfFramesToProcess))); 200 } 201 202 void AudioOutputDeviceTest::WaitUntilRenderCallback() { 203 // Don't hang the test if we never get the Render() callback. 204 io_loop_.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), 205 TestTimeouts::action_timeout()); 206 io_loop_.Run(); 207 } 208 209 void AudioOutputDeviceTest::StopAudioDevice() { 210 audio_device_->Stop(); 211 212 EXPECT_CALL(*audio_output_ipc_, CloseStream()); 213 214 io_loop_.RunUntilIdle(); 215 } 216 217 TEST_P(AudioOutputDeviceTest, Initialize) { 218 // Tests that the object can be constructed, initialized and destructed 219 // without having ever been started/stopped. 220 } 221 222 // Calls Start() followed by an immediate Stop() and check for the basic message 223 // filter messages being sent in that case. 224 TEST_P(AudioOutputDeviceTest, StartStop) { 225 StartAudioDevice(); 226 StopAudioDevice(); 227 } 228 229 // AudioOutputDevice supports multiple start/stop sequences. 230 TEST_P(AudioOutputDeviceTest, StartStopStartStop) { 231 StartAudioDevice(); 232 StopAudioDevice(); 233 StartAudioDevice(); 234 StopAudioDevice(); 235 } 236 237 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread() 238 // on the IO loop. 239 TEST_P(AudioOutputDeviceTest, StopBeforeRender) { 240 StartAudioDevice(); 241 242 // Call Stop() but don't run the IO loop yet. 243 audio_device_->Stop(); 244 245 // Expect us to shutdown IPC but not to render anything despite the stream 246 // getting created. 247 EXPECT_CALL(*audio_output_ipc_, CloseStream()); 248 CreateStream(); 249 } 250 251 // Full test with output only. 252 TEST_P(AudioOutputDeviceTest, CreateStream) { 253 StartAudioDevice(); 254 ExpectRenderCallback(); 255 CreateStream(); 256 WaitUntilRenderCallback(); 257 StopAudioDevice(); 258 } 259 260 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false)); 261 262 } // namespace media. 263