| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <vector> | 5 #include <vector> |
| 6 | 6 |
| 7 #include "base/at_exit.h" | 7 #include "base/at_exit.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/process_util.h" | 9 #include "base/process_util.h" |
| 10 #include "base/shared_memory.h" | 10 #include "base/shared_memory.h" |
| 11 #include "base/sync_socket.h" | 11 #include "base/sync_socket.h" |
| 12 #include "base/test/test_timeouts.h" | 12 #include "base/test/test_timeouts.h" |
| 13 #include "media/audio/audio_output_device.h" | 13 #include "media/audio/audio_output_device.h" |
| 14 #include "media/audio/sample_rates.h" | 14 #include "media/audio/sample_rates.h" |
| 15 #include "media/audio/shared_memory_util.h" | 15 #include "media/audio/shared_memory_util.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gmock_mutant.h" | 17 #include "testing/gmock_mutant.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 | 19 |
| 20 using base::CancelableSyncSocket; | 20 using base::CancelableSyncSocket; |
| 21 using base::SharedMemory; | 21 using base::SharedMemory; |
| 22 using base::SyncSocket; | 22 using base::SyncSocket; |
| 23 using testing::_; | 23 using testing::_; |
| 24 using testing::DoAll; | 24 using testing::DoAll; |
| 25 using testing::Invoke; | 25 using testing::Invoke; |
| 26 using testing::Return; | 26 using testing::Return; |
| 27 using testing::WithArgs; | 27 using testing::WithArgs; |
| 28 using testing::StrictMock; | 28 using testing::StrictMock; |
| 29 using testing::Values; |
| 29 | 30 |
| 30 namespace media { | 31 namespace media { |
| 31 | 32 |
| 32 namespace { | 33 namespace { |
| 33 | 34 |
| 34 class MockRenderCallback : public AudioRendererSink::RenderCallback { | 35 class MockRenderCallback : public AudioRendererSink::RenderCallback { |
| 35 public: | 36 public: |
| 36 MockRenderCallback() {} | 37 MockRenderCallback() {} |
| 37 virtual ~MockRenderCallback() {} | 38 virtual ~MockRenderCallback() {} |
| 38 | 39 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 } | 85 } |
| 85 | 86 |
| 86 // Used to terminate a loop from a different thread than the loop belongs to. | 87 // Used to terminate a loop from a different thread than the loop belongs to. |
| 87 // |loop| should be a MessageLoopProxy. | 88 // |loop| should be a MessageLoopProxy. |
| 88 ACTION_P(QuitLoop, loop) { | 89 ACTION_P(QuitLoop, loop) { |
| 89 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 90 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
| 90 } | 91 } |
| 91 | 92 |
| 92 } // namespace. | 93 } // namespace. |
| 93 | 94 |
| 94 class AudioOutputDeviceTest : public testing::Test { | 95 class AudioOutputDeviceTest |
| 96 : public testing::Test, |
| 97 public testing::WithParamInterface<bool> { |
| 95 public: | 98 public: |
| 96 AudioOutputDeviceTest() | 99 AudioOutputDeviceTest() |
| 97 : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR, | 100 : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR, |
| 98 CHANNEL_LAYOUT_STEREO, | 101 CHANNEL_LAYOUT_STEREO, |
| 99 48000, 16, 1024), | 102 48000, 16, 1024), |
| 100 audio_device_(new AudioOutputDevice( | 103 audio_device_(new AudioOutputDevice( |
| 101 &audio_output_ipc_, io_loop_.message_loop_proxy())) { | 104 &audio_output_ipc_, io_loop_.message_loop_proxy())), |
| 105 synchronized_io_(GetParam()), |
| 106 input_channels_(synchronized_io_ ? 2 : 0) { |
| 102 } | 107 } |
| 103 | 108 |
| 104 ~AudioOutputDeviceTest() {} | 109 ~AudioOutputDeviceTest() {} |
| 105 | 110 |
| 106 int CalculateMemorySize(bool synchronized_io); | 111 void Initialize(); |
| 107 | 112 void StartAudioDevice(); |
| 108 void StartAudioDevice(bool synchronized_io); | 113 void CreateStream(); |
| 109 void CreateStream(bool synchronized_io); | 114 void ExpectRenderCallback(); |
| 110 void ExpectRenderCallback(bool synchronized_io); | |
| 111 void WaitUntilRenderCallback(); | 115 void WaitUntilRenderCallback(); |
| 112 void StopAudioDevice(); | 116 void StopAudioDevice(); |
| 113 | 117 |
| 114 protected: | 118 protected: |
| 115 // Used to clean up TLS pointers that the test(s) will initialize. | 119 // Used to clean up TLS pointers that the test(s) will initialize. |
| 116 // Must remain the first member of this class. | 120 // Must remain the first member of this class. |
| 117 base::ShadowingAtExitManager at_exit_manager_; | 121 base::ShadowingAtExitManager at_exit_manager_; |
| 118 MessageLoopForIO io_loop_; | 122 MessageLoopForIO io_loop_; |
| 119 const AudioParameters default_audio_parameters_; | 123 const AudioParameters default_audio_parameters_; |
| 120 StrictMock<MockRenderCallback> callback_; | 124 StrictMock<MockRenderCallback> callback_; |
| 121 StrictMock<MockAudioOutputIPC> audio_output_ipc_; | 125 StrictMock<MockAudioOutputIPC> audio_output_ipc_; |
| 122 scoped_refptr<AudioOutputDevice> audio_device_; | 126 scoped_refptr<AudioOutputDevice> audio_device_; |
| 123 | 127 |
| 124 private: | 128 private: |
| 129 int CalculateMemorySize(); |
| 130 |
| 131 const bool synchronized_io_; |
| 132 const int input_channels_; |
| 125 SharedMemory shared_memory_; | 133 SharedMemory shared_memory_; |
| 126 CancelableSyncSocket browser_socket_; | 134 CancelableSyncSocket browser_socket_; |
| 127 CancelableSyncSocket renderer_socket_; | 135 CancelableSyncSocket renderer_socket_; |
| 128 | 136 |
| 129 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest); | 137 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest); |
| 130 }; | 138 }; |
| 131 | 139 |
| 132 static const int kStreamId = 123; | 140 static const int kStreamId = 123; |
| 133 | 141 |
| 134 int AudioOutputDeviceTest::CalculateMemorySize(bool synchronized_io) { | 142 int AudioOutputDeviceTest::CalculateMemorySize() { |
| 135 int kInputChannels = synchronized_io ? 2 : 0; | |
| 136 | |
| 137 // Calculate output and input memory size. | 143 // Calculate output and input memory size. |
| 138 int output_memory_size = | 144 int output_memory_size = |
| 139 AudioBus::CalculateMemorySize(default_audio_parameters_); | 145 AudioBus::CalculateMemorySize(default_audio_parameters_); |
| 140 | 146 |
| 141 int frames = default_audio_parameters_.frames_per_buffer(); | 147 int frames = default_audio_parameters_.frames_per_buffer(); |
| 142 int input_memory_size = | 148 int input_memory_size = |
| 143 AudioBus::CalculateMemorySize(kInputChannels, frames); | 149 AudioBus::CalculateMemorySize(input_channels_, frames); |
| 144 | 150 |
| 145 int io_buffer_size = output_memory_size + input_memory_size; | 151 int io_buffer_size = output_memory_size + input_memory_size; |
| 146 | 152 |
| 147 // This is where it gets a bit hacky. The shared memory contract between | 153 // This is where it gets a bit hacky. The shared memory contract between |
| 148 // AudioOutputDevice and its browser side counter part includes a bit more | 154 // AudioOutputDevice and its browser side counter part includes a bit more |
| 149 // than just the audio data, so we must call TotalSharedMemorySizeInBytes() | 155 // than just the audio data, so we must call TotalSharedMemorySizeInBytes() |
| 150 // to get the actual size needed to fit the audio data plus the extra data. | 156 // to get the actual size needed to fit the audio data plus the extra data. |
| 151 return TotalSharedMemorySizeInBytes(io_buffer_size); | 157 return TotalSharedMemorySizeInBytes(io_buffer_size); |
| 152 } | 158 } |
| 153 | 159 |
| 154 void AudioOutputDeviceTest::StartAudioDevice(bool synchronized_io) { | 160 void AudioOutputDeviceTest::Initialize() { |
| 155 const int kInputChannels = synchronized_io ? 2 : 0; | 161 if (synchronized_io_) { |
| 156 | |
| 157 if (synchronized_io) { | |
| 158 // Request output and synchronized input. | |
| 159 audio_device_->InitializeIO(default_audio_parameters_, | 162 audio_device_->InitializeIO(default_audio_parameters_, |
| 160 kInputChannels, | 163 input_channels_, |
| 161 &callback_); | 164 &callback_); |
| 162 } else { | 165 } else { |
| 163 // Output only. | 166 audio_device_->Initialize(default_audio_parameters_, |
| 164 audio_device_->Initialize(default_audio_parameters_, &callback_); | 167 &callback_); |
| 165 } | 168 } |
| 169 io_loop_.RunAllPending(); |
| 170 } |
| 166 | 171 |
| 172 void AudioOutputDeviceTest::StartAudioDevice() { |
| 167 audio_device_->Start(); | 173 audio_device_->Start(); |
| 168 | 174 |
| 169 EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device_.get())) | 175 EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device_.get())) |
| 170 .WillOnce(Return(kStreamId)); | 176 .WillOnce(Return(kStreamId)); |
| 171 EXPECT_CALL(audio_output_ipc_, CreateStream(kStreamId, _, _)); | 177 EXPECT_CALL(audio_output_ipc_, CreateStream(kStreamId, _, _)); |
| 172 | 178 |
| 173 io_loop_.RunAllPending(); | 179 io_loop_.RunAllPending(); |
| 174 } | 180 } |
| 175 | 181 |
| 176 void AudioOutputDeviceTest::CreateStream(bool synchronized_io) { | 182 void AudioOutputDeviceTest::CreateStream() { |
| 177 const int kMemorySize = CalculateMemorySize(synchronized_io); | 183 const int kMemorySize = CalculateMemorySize(); |
| 184 |
| 178 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize)); | 185 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize)); |
| 179 memset(shared_memory_.memory(), 0xff, kMemorySize); | 186 memset(shared_memory_.memory(), 0xff, kMemorySize); |
| 180 | 187 |
| 181 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_, | 188 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_, |
| 182 &renderer_socket_)); | 189 &renderer_socket_)); |
| 183 | 190 |
| 184 // Create duplicates of the handles we pass to AudioOutputDevice since | 191 // Create duplicates of the handles we pass to AudioOutputDevice since |
| 185 // ownership will be transferred and AudioOutputDevice is responsible for | 192 // ownership will be transferred and AudioOutputDevice is responsible for |
| 186 // freeing. | 193 // freeing. |
| 187 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle; | 194 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle; |
| 188 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_.handle(), | 195 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_.handle(), |
| 189 &audio_device_socket)); | 196 &audio_device_socket)); |
| 190 base::SharedMemoryHandle duplicated_memory_handle; | 197 base::SharedMemoryHandle duplicated_memory_handle; |
| 191 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), | 198 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), |
| 192 &duplicated_memory_handle)); | 199 &duplicated_memory_handle)); |
| 193 | 200 |
| 194 audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket, | 201 audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket, |
| 195 PacketSizeInBytes(kMemorySize)); | 202 PacketSizeInBytes(kMemorySize)); |
| 196 io_loop_.RunAllPending(); | 203 io_loop_.RunAllPending(); |
| 197 } | 204 } |
| 198 | 205 |
| 199 void AudioOutputDeviceTest::ExpectRenderCallback(bool synchronized_io) { | 206 void AudioOutputDeviceTest::ExpectRenderCallback() { |
| 200 // We should get a 'play' notification when we call OnStreamCreated(). | 207 // We should get a 'play' notification when we call OnStreamCreated(). |
| 201 // Respond by asking for some audio data. This should ask our callback | 208 // Respond by asking for some audio data. This should ask our callback |
| 202 // to provide some audio data that AudioOutputDevice then writes into the | 209 // to provide some audio data that AudioOutputDevice then writes into the |
| 203 // shared memory section. | 210 // shared memory section. |
| 204 const int kMemorySize = CalculateMemorySize(synchronized_io); | 211 const int kMemorySize = CalculateMemorySize(); |
| 212 |
| 205 EXPECT_CALL(audio_output_ipc_, PlayStream(kStreamId)) | 213 EXPECT_CALL(audio_output_ipc_, PlayStream(kStreamId)) |
| 206 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize)); | 214 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize)); |
| 207 | 215 |
| 208 // We expect calls to our audio renderer callback, which returns the number | 216 // We expect calls to our audio renderer callback, which returns the number |
| 209 // of frames written to the memory section. | 217 // of frames written to the memory section. |
| 210 // Here's the second place where it gets hacky: There's no way for us to | 218 // Here's the second place where it gets hacky: There's no way for us to |
| 211 // know (without using a sleep loop!) when the AudioOutputDevice has finished | 219 // know (without using a sleep loop!) when the AudioOutputDevice has finished |
| 212 // writing the interleaved audio data into the shared memory section. | 220 // writing the interleaved audio data into the shared memory section. |
| 213 // So, for the sake of this test, we consider the call to Render a sign | 221 // So, for the sake of this test, we consider the call to Render a sign |
| 214 // of success and quit the loop. | 222 // of success and quit the loop. |
| 215 if (synchronized_io) { | 223 if (synchronized_io_) { |
| 216 // For synchronized I/O, we expect RenderIO(). | 224 // For synchronized I/O, we expect RenderIO(). |
| 217 EXPECT_CALL(callback_, RenderIO(_, _, _)) | 225 EXPECT_CALL(callback_, RenderIO(_, _, _)) |
| 218 .WillOnce(QuitLoop(io_loop_.message_loop_proxy())); | 226 .WillOnce(QuitLoop(io_loop_.message_loop_proxy())); |
| 219 } else { | 227 } else { |
| 220 // For output only we expect Render(). | 228 // For output only we expect Render(). |
| 221 const int kNumberOfFramesToProcess = 0; | 229 const int kNumberOfFramesToProcess = 0; |
| 222 EXPECT_CALL(callback_, Render(_, _)) | 230 EXPECT_CALL(callback_, Render(_, _)) |
| 223 .WillOnce(DoAll( | 231 .WillOnce(DoAll( |
| 224 QuitLoop(io_loop_.message_loop_proxy()), | 232 QuitLoop(io_loop_.message_loop_proxy()), |
| 225 Return(kNumberOfFramesToProcess))); | 233 Return(kNumberOfFramesToProcess))); |
| 226 } | 234 } |
| 227 } | 235 } |
| 228 | 236 |
| 229 void AudioOutputDeviceTest::WaitUntilRenderCallback() { | 237 void AudioOutputDeviceTest::WaitUntilRenderCallback() { |
| 230 // Don't hang the test if we never get the Render() callback. | 238 // Don't hang the test if we never get the Render() callback. |
| 231 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 239 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 232 TestTimeouts::action_timeout()); | 240 TestTimeouts::action_timeout()); |
| 233 io_loop_.Run(); | 241 io_loop_.Run(); |
| 234 } | 242 } |
| 235 | 243 |
| 236 void AudioOutputDeviceTest::StopAudioDevice() { | 244 void AudioOutputDeviceTest::StopAudioDevice() { |
| 245 audio_device_->Stop(); |
| 246 |
| 237 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId)); | 247 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId)); |
| 238 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId)); | 248 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId)); |
| 239 | 249 |
| 240 audio_device_->Stop(); | |
| 241 io_loop_.RunAllPending(); | 250 io_loop_.RunAllPending(); |
| 242 } | 251 } |
| 243 | 252 |
| 244 // The simplest test for AudioOutputDevice. Used to test construction of | 253 TEST_P(AudioOutputDeviceTest, Initialize) { |
| 245 // AudioOutputDevice and that the runtime environment is set up correctly. | 254 Initialize(); |
| 246 TEST_F(AudioOutputDeviceTest, Initialize) { | |
| 247 audio_device_->Initialize(default_audio_parameters_, &callback_); | |
| 248 io_loop_.RunAllPending(); | |
| 249 } | |
| 250 | |
| 251 // Similar to Initialize() test, but using synchronized I/O. | |
| 252 TEST_F(AudioOutputDeviceTest, InitializeIO) { | |
| 253 const int kInputChannels = 2; // Test stereo synchronized input. | |
| 254 audio_device_->InitializeIO(default_audio_parameters_, | |
| 255 kInputChannels, | |
| 256 &callback_); | |
| 257 io_loop_.RunAllPending(); | |
| 258 } | 255 } |
| 259 | 256 |
| 260 // Calls Start() followed by an immediate Stop() and check for the basic message | 257 // Calls Start() followed by an immediate Stop() and check for the basic message |
| 261 // filter messages being sent in that case. | 258 // filter messages being sent in that case. |
| 262 TEST_F(AudioOutputDeviceTest, StartStop) { | 259 TEST_P(AudioOutputDeviceTest, StartStop) { |
| 263 StartAudioDevice(false); | 260 Initialize(); |
| 261 StartAudioDevice(); |
| 264 StopAudioDevice(); | 262 StopAudioDevice(); |
| 265 } | 263 } |
| 266 | 264 |
| 267 TEST_F(AudioOutputDeviceTest, DISABLED_StopBeforeRender) { | 265 // AudioOutputDevice supports multiple start/stop sequences. |
| 268 StartAudioDevice(false); | 266 TEST_P(AudioOutputDeviceTest, StartStopStartStop) { |
| 267 Initialize(); |
| 268 StartAudioDevice(); |
| 269 StopAudioDevice(); |
| 270 StartAudioDevice(); |
| 271 StopAudioDevice(); |
| 272 } |
| 273 |
| 274 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread() |
| 275 // on the IO loop. |
| 276 TEST_P(AudioOutputDeviceTest, StopBeforeRender) { |
| 277 Initialize(); |
| 278 StartAudioDevice(); |
| 269 | 279 |
| 270 // Call Stop() but don't run the IO loop yet. | 280 // Call Stop() but don't run the IO loop yet. |
| 271 audio_device_->Stop(); | 281 audio_device_->Stop(); |
| 272 | 282 |
| 273 // Expect us to shutdown IPC but not to render anything despite the stream | 283 // Expect us to shutdown IPC but not to render anything despite the stream |
| 274 // getting created. | 284 // getting created. |
| 275 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId)); | 285 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId)); |
| 276 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId)); | 286 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId)); |
| 277 CreateStream(false); | 287 CreateStream(); |
| 278 } | 288 } |
| 279 | 289 |
| 280 // Full test with output only. | 290 // Full test with output only. |
| 281 TEST_F(AudioOutputDeviceTest, CreateStream) { | 291 TEST_P(AudioOutputDeviceTest, CreateStream) { |
| 282 StartAudioDevice(false); | 292 Initialize(); |
| 283 ExpectRenderCallback(false); | 293 StartAudioDevice(); |
| 284 CreateStream(false); | 294 ExpectRenderCallback(); |
| 295 CreateStream(); |
| 285 WaitUntilRenderCallback(); | 296 WaitUntilRenderCallback(); |
| 286 StopAudioDevice(); | 297 StopAudioDevice(); |
| 287 } | 298 } |
| 288 | 299 |
| 289 // Same as CreateStream() test, but also tests synchronized I/O. | 300 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false)); |
| 290 TEST_F(AudioOutputDeviceTest, CreateStreamWithInput) { | 301 INSTANTIATE_TEST_CASE_P(RenderIO, AudioOutputDeviceTest, Values(true)); |
| 291 StartAudioDevice(true); | |
| 292 ExpectRenderCallback(true); | |
| 293 CreateStream(true); | |
| 294 WaitUntilRenderCallback(); | |
| 295 StopAudioDevice(); | |
| 296 } | |
| 297 | 302 |
| 298 } // namespace media. | 303 } // namespace media. |
| OLD | NEW |