Elim cr-checkbox
[chromium-blink-merge.git] / media / audio / audio_output_device_unittest.cc
blob8b0b9f8b8d8a725a6283ffa7fb3f57cf331cdc51
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.
5 #include <vector>
7 #include "base/at_exit.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/process/process_handle.h"
13 #include "base/sync_socket.h"
14 #include "base/task_runner.h"
15 #include "base/test/test_timeouts.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "media/audio/audio_output_device.h"
18 #include "media/audio/sample_rates.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gmock_mutant.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using base::CancelableSyncSocket;
24 using base::SharedMemory;
25 using base::SyncSocket;
26 using testing::_;
27 using testing::DoAll;
28 using testing::Invoke;
29 using testing::Return;
30 using testing::WithArgs;
31 using testing::StrictMock;
32 using testing::Values;
34 namespace media {
36 namespace {
38 const std::string kNonDefaultDeviceId("fake-device-id");
40 class MockRenderCallback : public AudioRendererSink::RenderCallback {
41 public:
42 MockRenderCallback() {}
43 virtual ~MockRenderCallback() {}
45 MOCK_METHOD2(Render, int(AudioBus* dest, int audio_delay_milliseconds));
46 MOCK_METHOD0(OnRenderError, void());
49 class MockAudioOutputIPC : public AudioOutputIPC {
50 public:
51 MockAudioOutputIPC() {}
52 virtual ~MockAudioOutputIPC() {}
54 MOCK_METHOD4(RequestDeviceAuthorization,
55 void(AudioOutputIPCDelegate* delegate,
56 int session_id,
57 const std::string& device_id,
58 const url::Origin& security_origin));
59 MOCK_METHOD2(CreateStream,
60 void(AudioOutputIPCDelegate* delegate,
61 const AudioParameters& params));
62 MOCK_METHOD0(PlayStream, void());
63 MOCK_METHOD0(PauseStream, void());
64 MOCK_METHOD0(CloseStream, void());
65 MOCK_METHOD1(SetVolume, void(double volume));
66 MOCK_METHOD2(SwitchOutputDevice,
67 void(const std::string& device_id,
68 const url::Origin& security_origin));
71 class MockSwitchOutputDeviceCallback {
72 public:
73 MOCK_METHOD1(Callback, void(media::SwitchOutputDeviceResult result));
76 ACTION_P2(SendPendingBytes, socket, pending_bytes) {
77 socket->Send(&pending_bytes, sizeof(pending_bytes));
80 // Used to terminate a loop from a different thread than the loop belongs to.
81 // |task_runner| should be a SingleThreadTaskRunner.
82 ACTION_P(QuitLoop, task_runner) {
83 task_runner->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
86 } // namespace.
88 class AudioOutputDeviceTest
89 : public testing::Test,
90 public testing::WithParamInterface<bool> {
91 public:
92 AudioOutputDeviceTest();
93 ~AudioOutputDeviceTest();
95 void ReceiveAuthorization();
96 void StartAudioDevice();
97 void CreateStream();
98 void ExpectRenderCallback();
99 void WaitUntilRenderCallback();
100 void StopAudioDevice();
101 void SwitchOutputDevice();
102 void SetDevice(const std::string& device_id);
104 protected:
105 // Used to clean up TLS pointers that the test(s) will initialize.
106 // Must remain the first member of this class.
107 base::ShadowingAtExitManager at_exit_manager_;
108 base::MessageLoopForIO io_loop_;
109 AudioParameters default_audio_parameters_;
110 StrictMock<MockRenderCallback> callback_;
111 MockAudioOutputIPC* audio_output_ipc_; // owned by audio_device_
112 scoped_refptr<AudioOutputDevice> audio_device_;
113 MockSwitchOutputDeviceCallback switch_output_device_callback_;
115 private:
116 int CalculateMemorySize();
117 void SwitchOutputDeviceCallback(SwitchOutputDeviceResult result);
119 SharedMemory shared_memory_;
120 CancelableSyncSocket browser_socket_;
121 CancelableSyncSocket renderer_socket_;
123 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest);
126 int AudioOutputDeviceTest::CalculateMemorySize() {
127 // Calculate output memory size.
128 return AudioBus::CalculateMemorySize(default_audio_parameters_);
131 AudioOutputDeviceTest::AudioOutputDeviceTest() {
132 default_audio_parameters_.Reset(AudioParameters::AUDIO_PCM_LINEAR,
133 CHANNEL_LAYOUT_STEREO, 48000, 16, 1024);
134 SetDevice(std::string()); // Use default device
137 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
138 audio_device_ = NULL;
141 void AudioOutputDeviceTest::SetDevice(const std::string& device_id) {
142 audio_output_ipc_ = new MockAudioOutputIPC();
143 audio_device_ = new AudioOutputDevice(
144 scoped_ptr<AudioOutputIPC>(audio_output_ipc_), io_loop_.task_runner(), 0,
145 device_id, url::Origin());
146 audio_device_->RequestDeviceAuthorization();
147 EXPECT_CALL(*audio_output_ipc_,
148 RequestDeviceAuthorization(audio_device_.get(), 0, device_id, _));
149 io_loop_.RunUntilIdle();
151 // Simulate response from browser
152 ReceiveAuthorization();
154 audio_device_->Initialize(default_audio_parameters_,
155 &callback_);
158 void AudioOutputDeviceTest::ReceiveAuthorization() {
159 audio_device_->OnDeviceAuthorized(true, default_audio_parameters_);
160 io_loop_.RunUntilIdle();
163 void AudioOutputDeviceTest::StartAudioDevice() {
164 audio_device_->Start();
165 EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _));
167 io_loop_.RunUntilIdle();
170 void AudioOutputDeviceTest::CreateStream() {
171 const int kMemorySize = CalculateMemorySize();
173 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize));
174 memset(shared_memory_.memory(), 0xff, kMemorySize);
176 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_,
177 &renderer_socket_));
179 // Create duplicates of the handles we pass to AudioOutputDevice since
180 // ownership will be transferred and AudioOutputDevice is responsible for
181 // freeing.
182 SyncSocket::TransitDescriptor audio_device_socket_descriptor;
183 ASSERT_TRUE(renderer_socket_.PrepareTransitDescriptor(
184 base::GetCurrentProcessHandle(), &audio_device_socket_descriptor));
185 base::SharedMemoryHandle duplicated_memory_handle;
186 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(),
187 &duplicated_memory_handle));
189 audio_device_->OnStreamCreated(
190 duplicated_memory_handle,
191 SyncSocket::UnwrapHandle(audio_device_socket_descriptor), kMemorySize);
192 io_loop_.RunUntilIdle();
195 void AudioOutputDeviceTest::ExpectRenderCallback() {
196 // We should get a 'play' notification when we call OnStreamCreated().
197 // Respond by asking for some audio data. This should ask our callback
198 // to provide some audio data that AudioOutputDevice then writes into the
199 // shared memory section.
200 const int kMemorySize = CalculateMemorySize();
202 EXPECT_CALL(*audio_output_ipc_, PlayStream())
203 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize));
205 // We expect calls to our audio renderer callback, which returns the number
206 // of frames written to the memory section.
207 // Here's the second place where it gets hacky: There's no way for us to
208 // know (without using a sleep loop!) when the AudioOutputDevice has finished
209 // writing the interleaved audio data into the shared memory section.
210 // So, for the sake of this test, we consider the call to Render a sign
211 // of success and quit the loop.
212 const int kNumberOfFramesToProcess = 0;
213 EXPECT_CALL(callback_, Render(_, _))
214 .WillOnce(DoAll(
215 QuitLoop(io_loop_.task_runner()),
216 Return(kNumberOfFramesToProcess)));
219 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
220 // Don't hang the test if we never get the Render() callback.
221 io_loop_.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
222 TestTimeouts::action_timeout());
223 io_loop_.Run();
226 void AudioOutputDeviceTest::StopAudioDevice() {
227 audio_device_->Stop();
229 EXPECT_CALL(*audio_output_ipc_, CloseStream());
231 io_loop_.RunUntilIdle();
234 void AudioOutputDeviceTest::SwitchOutputDevice() {
235 // Switch the output device and check that the IPC message is sent
236 EXPECT_CALL(*audio_output_ipc_, SwitchOutputDevice(kNonDefaultDeviceId, _));
237 audio_device_->SwitchOutputDevice(
238 kNonDefaultDeviceId, url::Origin(),
239 base::Bind(&MockSwitchOutputDeviceCallback::Callback,
240 base::Unretained(&switch_output_device_callback_)));
241 io_loop_.RunUntilIdle();
243 // Simulate the reception of a successful response from the browser
244 EXPECT_CALL(switch_output_device_callback_,
245 Callback(SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS));
246 audio_device_->OnOutputDeviceSwitched(SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS);
247 io_loop_.RunUntilIdle();
250 TEST_P(AudioOutputDeviceTest, Initialize) {
251 // Tests that the object can be constructed, initialized and destructed
252 // without having ever been started.
253 StopAudioDevice();
256 // Calls Start() followed by an immediate Stop() and check for the basic message
257 // filter messages being sent in that case.
258 TEST_P(AudioOutputDeviceTest, StartStop) {
259 StartAudioDevice();
260 StopAudioDevice();
263 // AudioOutputDevice supports multiple start/stop sequences.
264 TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
265 StartAudioDevice();
266 StopAudioDevice();
267 StartAudioDevice();
268 StopAudioDevice();
271 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
272 // on the IO loop.
273 TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
274 StartAudioDevice();
276 // Call Stop() but don't run the IO loop yet.
277 audio_device_->Stop();
279 // Expect us to shutdown IPC but not to render anything despite the stream
280 // getting created.
281 EXPECT_CALL(*audio_output_ipc_, CloseStream());
282 CreateStream();
285 // Full test with output only.
286 TEST_P(AudioOutputDeviceTest, CreateStream) {
287 StartAudioDevice();
288 ExpectRenderCallback();
289 CreateStream();
290 WaitUntilRenderCallback();
291 StopAudioDevice();
294 // Switch the output device
295 TEST_P(AudioOutputDeviceTest, SwitchOutputDevice) {
296 StartAudioDevice();
297 SwitchOutputDevice();
298 StopAudioDevice();
301 // Full test with output only with nondefault device.
302 TEST_P(AudioOutputDeviceTest, NonDefaultCreateStream) {
303 SetDevice(kNonDefaultDeviceId);
304 StartAudioDevice();
305 ExpectRenderCallback();
306 CreateStream();
307 WaitUntilRenderCallback();
308 StopAudioDevice();
311 // Multiple start/stop with nondefault device
312 TEST_P(AudioOutputDeviceTest, NonDefaultStartStopStartStop) {
313 SetDevice(kNonDefaultDeviceId);
314 StartAudioDevice();
315 StopAudioDevice();
317 EXPECT_CALL(*audio_output_ipc_,
318 RequestDeviceAuthorization(audio_device_.get(), 0, _, _));
319 StartAudioDevice();
320 // Simulate reply from browser
321 ReceiveAuthorization();
323 StopAudioDevice();
326 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
328 } // namespace media.