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.
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
;
28 using testing::Invoke
;
29 using testing::Return
;
30 using testing::WithArgs
;
31 using testing::StrictMock
;
32 using testing::Values
;
38 class MockRenderCallback
: public AudioRendererSink::RenderCallback
{
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
{
49 MockAudioOutputIPC() {}
50 virtual ~MockAudioOutputIPC() {}
52 MOCK_METHOD3(CreateStream
, void(AudioOutputIPCDelegate
* delegate
,
53 const AudioParameters
& params
,
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
,
65 class MockSwitchOutputDeviceCallback
{
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());
82 class AudioOutputDeviceTest
83 : public testing::Test
,
84 public testing::WithParamInterface
<bool> {
86 AudioOutputDeviceTest();
87 ~AudioOutputDeviceTest();
89 void StartAudioDevice();
91 void ExpectRenderCallback();
92 void WaitUntilRenderCallback();
93 void StopAudioDevice();
94 void SwitchOutputDevice();
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_
;
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(AudioParameters::AUDIO_PCM_LINEAR
,
125 CHANNEL_LAYOUT_STEREO
, 48000, 16, 1024);
127 audio_output_ipc_
= new MockAudioOutputIPC();
128 audio_device_
= new AudioOutputDevice(
129 scoped_ptr
<AudioOutputIPC
>(audio_output_ipc_
),
130 io_loop_
.task_runner());
132 audio_device_
->Initialize(default_audio_parameters_
,
135 io_loop_
.RunUntilIdle();
138 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
139 audio_device_
= NULL
;
142 void AudioOutputDeviceTest::StartAudioDevice() {
143 audio_device_
->Start();
145 EXPECT_CALL(*audio_output_ipc_
, CreateStream(audio_device_
.get(), _
, 0));
147 io_loop_
.RunUntilIdle();
150 void AudioOutputDeviceTest::CreateStream() {
151 const int kMemorySize
= CalculateMemorySize();
153 ASSERT_TRUE(shared_memory_
.CreateAndMapAnonymous(kMemorySize
));
154 memset(shared_memory_
.memory(), 0xff, kMemorySize
);
156 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_
,
159 // Create duplicates of the handles we pass to AudioOutputDevice since
160 // ownership will be transferred and AudioOutputDevice is responsible for
162 SyncSocket::TransitDescriptor audio_device_socket_descriptor
;
163 ASSERT_TRUE(renderer_socket_
.PrepareTransitDescriptor(
164 base::GetCurrentProcessHandle(), &audio_device_socket_descriptor
));
165 base::SharedMemoryHandle duplicated_memory_handle
;
166 ASSERT_TRUE(shared_memory_
.ShareToProcess(base::GetCurrentProcessHandle(),
167 &duplicated_memory_handle
));
169 audio_device_
->OnStreamCreated(
170 duplicated_memory_handle
,
171 SyncSocket::UnwrapHandle(audio_device_socket_descriptor
), kMemorySize
);
172 io_loop_
.RunUntilIdle();
175 void AudioOutputDeviceTest::ExpectRenderCallback() {
176 // We should get a 'play' notification when we call OnStreamCreated().
177 // Respond by asking for some audio data. This should ask our callback
178 // to provide some audio data that AudioOutputDevice then writes into the
179 // shared memory section.
180 const int kMemorySize
= CalculateMemorySize();
182 EXPECT_CALL(*audio_output_ipc_
, PlayStream())
183 .WillOnce(SendPendingBytes(&browser_socket_
, kMemorySize
));
185 // We expect calls to our audio renderer callback, which returns the number
186 // of frames written to the memory section.
187 // Here's the second place where it gets hacky: There's no way for us to
188 // know (without using a sleep loop!) when the AudioOutputDevice has finished
189 // writing the interleaved audio data into the shared memory section.
190 // So, for the sake of this test, we consider the call to Render a sign
191 // of success and quit the loop.
192 const int kNumberOfFramesToProcess
= 0;
193 EXPECT_CALL(callback_
, Render(_
, _
))
195 QuitLoop(io_loop_
.task_runner()),
196 Return(kNumberOfFramesToProcess
)));
199 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
200 // Don't hang the test if we never get the Render() callback.
201 io_loop_
.PostDelayedTask(FROM_HERE
, base::MessageLoop::QuitClosure(),
202 TestTimeouts::action_timeout());
206 void AudioOutputDeviceTest::StopAudioDevice() {
207 audio_device_
->Stop();
209 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
211 io_loop_
.RunUntilIdle();
214 void AudioOutputDeviceTest::SwitchOutputDevice() {
215 const GURL
security_origin("http://localhost");
216 const std::string device_id
;
217 const int request_id
= 1;
219 // Switch the output device and check that the IPC message is sent
220 EXPECT_CALL(*audio_output_ipc_
,
221 SwitchOutputDevice(device_id
, security_origin
, request_id
));
222 audio_device_
->SwitchOutputDevice(
223 device_id
, security_origin
,
224 base::Bind(&MockSwitchOutputDeviceCallback::Callback
,
225 base::Unretained(&switch_output_device_callback_
)));
226 io_loop_
.RunUntilIdle();
228 // Simulate the reception of a successful response from the browser
229 EXPECT_CALL(switch_output_device_callback_
,
230 Callback(SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS
));
231 audio_device_
->OnOutputDeviceSwitched(request_id
,
232 SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS
);
233 io_loop_
.RunUntilIdle();
236 TEST_P(AudioOutputDeviceTest
, Initialize
) {
237 // Tests that the object can be constructed, initialized and destructed
238 // without having ever been started/stopped.
241 // Calls Start() followed by an immediate Stop() and check for the basic message
242 // filter messages being sent in that case.
243 TEST_P(AudioOutputDeviceTest
, StartStop
) {
248 // AudioOutputDevice supports multiple start/stop sequences.
249 TEST_P(AudioOutputDeviceTest
, StartStopStartStop
) {
256 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
258 TEST_P(AudioOutputDeviceTest
, StopBeforeRender
) {
261 // Call Stop() but don't run the IO loop yet.
262 audio_device_
->Stop();
264 // Expect us to shutdown IPC but not to render anything despite the stream
266 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
270 // Full test with output only.
271 TEST_P(AudioOutputDeviceTest
, CreateStream
) {
273 ExpectRenderCallback();
275 WaitUntilRenderCallback();
279 // Switch the output device
280 TEST_P(AudioOutputDeviceTest
, SwitchOutputDevice
) {
282 SwitchOutputDevice();
286 INSTANTIATE_TEST_CASE_P(Render
, AudioOutputDeviceTest
, Values(false));
288 } // namespace media.