Create an initial chrome://supervised-user-internals page
[chromium-blink-merge.git] / media / audio / audio_output_device_unittest.cc
blob3b3ee512f5eedcc2df5137a9260276427e6aec74
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 class MockRenderCallback : public AudioRendererSink::RenderCallback {
39 public:
40 MockRenderCallback() {}
41 virtual ~MockRenderCallback() {}
43 MOCK_METHOD2(Render, int(AudioBus* dest, int audio_delay_milliseconds));
44 MOCK_METHOD0(OnRenderError, void());
47 class MockAudioOutputIPC : public AudioOutputIPC {
48 public:
49 MockAudioOutputIPC() {}
50 virtual ~MockAudioOutputIPC() {}
52 MOCK_METHOD3(CreateStream, void(AudioOutputIPCDelegate* delegate,
53 const AudioParameters& params,
54 int session_id));
55 MOCK_METHOD0(PlayStream, void());
56 MOCK_METHOD0(PauseStream, void());
57 MOCK_METHOD0(CloseStream, void());
58 MOCK_METHOD1(SetVolume, void(double volume));
59 MOCK_METHOD3(SwitchOutputDevice,
60 void(const std::string& device_id,
61 const GURL& security_origin,
62 int request_id));
65 class MockSwitchOutputDeviceCallback {
66 public:
67 MOCK_METHOD1(Callback, void(media::SwitchOutputDeviceResult result));
70 ACTION_P2(SendPendingBytes, socket, pending_bytes) {
71 socket->Send(&pending_bytes, sizeof(pending_bytes));
74 // Used to terminate a loop from a different thread than the loop belongs to.
75 // |task_runner| should be a SingleThreadTaskRunner.
76 ACTION_P(QuitLoop, task_runner) {
77 task_runner->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
80 } // namespace.
82 class AudioOutputDeviceTest
83 : public testing::Test,
84 public testing::WithParamInterface<bool> {
85 public:
86 AudioOutputDeviceTest();
87 ~AudioOutputDeviceTest();
89 void StartAudioDevice();
90 void CreateStream();
91 void ExpectRenderCallback();
92 void WaitUntilRenderCallback();
93 void StopAudioDevice();
94 void SwitchOutputDevice();
96 protected:
97 // Used to clean up TLS pointers that the test(s) will initialize.
98 // Must remain the first member of this class.
99 base::ShadowingAtExitManager at_exit_manager_;
100 base::MessageLoopForIO io_loop_;
101 AudioParameters default_audio_parameters_;
102 StrictMock<MockRenderCallback> callback_;
103 MockAudioOutputIPC* audio_output_ipc_; // owned by audio_device_
104 scoped_refptr<AudioOutputDevice> audio_device_;
105 MockSwitchOutputDeviceCallback switch_output_device_callback_;
107 private:
108 int CalculateMemorySize();
109 void SwitchOutputDeviceCallback(SwitchOutputDeviceResult result);
111 SharedMemory shared_memory_;
112 CancelableSyncSocket browser_socket_;
113 CancelableSyncSocket renderer_socket_;
115 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest);
118 int AudioOutputDeviceTest::CalculateMemorySize() {
119 // Calculate output memory size.
120 return AudioBus::CalculateMemorySize(default_audio_parameters_);
123 AudioOutputDeviceTest::AudioOutputDeviceTest() {
124 default_audio_parameters_.Reset(
125 AudioParameters::AUDIO_PCM_LINEAR,
126 CHANNEL_LAYOUT_STEREO, 2, 48000, 16, 1024);
128 audio_output_ipc_ = new MockAudioOutputIPC();
129 audio_device_ = new AudioOutputDevice(
130 scoped_ptr<AudioOutputIPC>(audio_output_ipc_),
131 io_loop_.task_runner());
133 audio_device_->Initialize(default_audio_parameters_,
134 &callback_);
136 io_loop_.RunUntilIdle();
139 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
140 audio_device_ = NULL;
143 void AudioOutputDeviceTest::StartAudioDevice() {
144 audio_device_->Start();
146 EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _, 0));
148 io_loop_.RunUntilIdle();
151 void AudioOutputDeviceTest::CreateStream() {
152 const int kMemorySize = CalculateMemorySize();
154 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize));
155 memset(shared_memory_.memory(), 0xff, kMemorySize);
157 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_,
158 &renderer_socket_));
160 // Create duplicates of the handles we pass to AudioOutputDevice since
161 // ownership will be transferred and AudioOutputDevice is responsible for
162 // freeing.
163 SyncSocket::TransitDescriptor audio_device_socket_descriptor;
164 ASSERT_TRUE(renderer_socket_.PrepareTransitDescriptor(
165 base::GetCurrentProcessHandle(), &audio_device_socket_descriptor));
166 base::SharedMemoryHandle duplicated_memory_handle;
167 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(),
168 &duplicated_memory_handle));
170 audio_device_->OnStreamCreated(
171 duplicated_memory_handle,
172 SyncSocket::UnwrapHandle(audio_device_socket_descriptor), kMemorySize);
173 io_loop_.RunUntilIdle();
176 void AudioOutputDeviceTest::ExpectRenderCallback() {
177 // We should get a 'play' notification when we call OnStreamCreated().
178 // Respond by asking for some audio data. This should ask our callback
179 // to provide some audio data that AudioOutputDevice then writes into the
180 // shared memory section.
181 const int kMemorySize = CalculateMemorySize();
183 EXPECT_CALL(*audio_output_ipc_, PlayStream())
184 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize));
186 // We expect calls to our audio renderer callback, which returns the number
187 // of frames written to the memory section.
188 // Here's the second place where it gets hacky: There's no way for us to
189 // know (without using a sleep loop!) when the AudioOutputDevice has finished
190 // writing the interleaved audio data into the shared memory section.
191 // So, for the sake of this test, we consider the call to Render a sign
192 // of success and quit the loop.
193 const int kNumberOfFramesToProcess = 0;
194 EXPECT_CALL(callback_, Render(_, _))
195 .WillOnce(DoAll(
196 QuitLoop(io_loop_.task_runner()),
197 Return(kNumberOfFramesToProcess)));
200 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
201 // Don't hang the test if we never get the Render() callback.
202 io_loop_.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
203 TestTimeouts::action_timeout());
204 io_loop_.Run();
207 void AudioOutputDeviceTest::StopAudioDevice() {
208 audio_device_->Stop();
210 EXPECT_CALL(*audio_output_ipc_, CloseStream());
212 io_loop_.RunUntilIdle();
215 void AudioOutputDeviceTest::SwitchOutputDevice() {
216 const GURL security_origin("http://localhost");
217 const std::string device_id;
218 const int request_id = 1;
220 // Switch the output device and check that the IPC message is sent
221 EXPECT_CALL(*audio_output_ipc_,
222 SwitchOutputDevice(device_id, security_origin, request_id));
223 audio_device_->SwitchOutputDevice(
224 device_id, security_origin,
225 base::Bind(&MockSwitchOutputDeviceCallback::Callback,
226 base::Unretained(&switch_output_device_callback_)));
227 io_loop_.RunUntilIdle();
229 // Simulate the reception of a successful response from the browser
230 EXPECT_CALL(switch_output_device_callback_,
231 Callback(SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS));
232 audio_device_->OnOutputDeviceSwitched(request_id,
233 SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS);
234 io_loop_.RunUntilIdle();
237 TEST_P(AudioOutputDeviceTest, Initialize) {
238 // Tests that the object can be constructed, initialized and destructed
239 // without having ever been started/stopped.
242 // Calls Start() followed by an immediate Stop() and check for the basic message
243 // filter messages being sent in that case.
244 TEST_P(AudioOutputDeviceTest, StartStop) {
245 StartAudioDevice();
246 StopAudioDevice();
249 // AudioOutputDevice supports multiple start/stop sequences.
250 TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
251 StartAudioDevice();
252 StopAudioDevice();
253 StartAudioDevice();
254 StopAudioDevice();
257 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
258 // on the IO loop.
259 TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
260 StartAudioDevice();
262 // Call Stop() but don't run the IO loop yet.
263 audio_device_->Stop();
265 // Expect us to shutdown IPC but not to render anything despite the stream
266 // getting created.
267 EXPECT_CALL(*audio_output_ipc_, CloseStream());
268 CreateStream();
271 // Full test with output only.
272 TEST_P(AudioOutputDeviceTest, CreateStream) {
273 StartAudioDevice();
274 ExpectRenderCallback();
275 CreateStream();
276 WaitUntilRenderCallback();
277 StopAudioDevice();
280 // Switch the output device
281 TEST_P(AudioOutputDeviceTest, SwitchOutputDevice) {
282 StartAudioDevice();
283 SwitchOutputDevice();
284 StopAudioDevice();
287 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
289 } // namespace media.