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/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"
19 using base::CancelableSyncSocket
;
20 using base::SharedMemory
;
21 using base::SyncSocket
;
24 using testing::Invoke
;
25 using testing::Return
;
26 using testing::WithArgs
;
27 using testing::StrictMock
;
28 using testing::Values
;
34 class MockRenderCallback
: public AudioRendererSink::RenderCallback
{
36 MockRenderCallback() {}
37 virtual ~MockRenderCallback() {}
39 MOCK_METHOD2(Render
, int(AudioBus
* dest
, int audio_delay_milliseconds
));
40 MOCK_METHOD3(RenderIO
, void(AudioBus
* source
,
42 int audio_delay_milliseconds
));
43 MOCK_METHOD0(OnRenderError
, void());
46 class MockAudioOutputIPC
: public AudioOutputIPC
{
48 MockAudioOutputIPC() {}
49 virtual ~MockAudioOutputIPC() {}
51 MOCK_METHOD3(CreateStream
, void(AudioOutputIPCDelegate
* delegate
,
52 const AudioParameters
& params
,
54 MOCK_METHOD0(PlayStream
, void());
55 MOCK_METHOD0(PauseStream
, void());
56 MOCK_METHOD0(CloseStream
, void());
57 MOCK_METHOD1(SetVolume
, void(double volume
));
60 // Creates a copy of a SyncSocket handle that we can give to AudioOutputDevice.
61 // On Windows this means duplicating the pipe handle so that AudioOutputDevice
62 // can call CloseHandle() (since ownership has been transferred), but on other
63 // platforms, we just copy the same socket handle since AudioOutputDevice on
64 // those platforms won't actually own the socket (FileDescriptor.auto_close is
66 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle
,
67 SyncSocket::Handle
* copy
) {
69 HANDLE process
= GetCurrentProcess();
70 ::DuplicateHandle(process
, socket_handle
, process
, copy
,
71 0, FALSE
, DUPLICATE_SAME_ACCESS
);
74 *copy
= socket_handle
;
79 ACTION_P2(SendPendingBytes
, socket
, pending_bytes
) {
80 socket
->Send(&pending_bytes
, sizeof(pending_bytes
));
83 // Used to terminate a loop from a different thread than the loop belongs to.
84 // |loop| should be a MessageLoopProxy.
85 ACTION_P(QuitLoop
, loop
) {
86 loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
91 class AudioOutputDeviceTest
92 : public testing::Test
,
93 public testing::WithParamInterface
<bool> {
95 AudioOutputDeviceTest();
96 ~AudioOutputDeviceTest();
98 void StartAudioDevice();
100 void ExpectRenderCallback();
101 void WaitUntilRenderCallback();
102 void StopAudioDevice();
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_
;
115 int CalculateMemorySize();
117 const bool synchronized_io_
;
118 const int input_channels_
;
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 and input memory size.
128 int output_memory_size
=
129 AudioBus::CalculateMemorySize(default_audio_parameters_
);
131 int frames
= default_audio_parameters_
.frames_per_buffer();
132 int input_memory_size
=
133 AudioBus::CalculateMemorySize(input_channels_
, frames
);
135 return output_memory_size
+ input_memory_size
;
138 AudioOutputDeviceTest::AudioOutputDeviceTest()
139 : synchronized_io_(GetParam()),
140 input_channels_(synchronized_io_
? 2 : 0) {
141 default_audio_parameters_
.Reset(
142 AudioParameters::AUDIO_PCM_LINEAR
,
143 CHANNEL_LAYOUT_STEREO
, 2, input_channels_
,
146 audio_output_ipc_
= new MockAudioOutputIPC();
147 audio_device_
= new AudioOutputDevice(
148 scoped_ptr
<AudioOutputIPC
>(audio_output_ipc_
),
149 io_loop_
.message_loop_proxy());
151 audio_device_
->Initialize(default_audio_parameters_
,
154 io_loop_
.RunUntilIdle();
157 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
158 audio_device_
= NULL
;
161 void AudioOutputDeviceTest::StartAudioDevice() {
162 audio_device_
->Start();
164 EXPECT_CALL(*audio_output_ipc_
, CreateStream(audio_device_
.get(), _
, 0));
166 io_loop_
.RunUntilIdle();
169 void AudioOutputDeviceTest::CreateStream() {
170 const int kMemorySize
= CalculateMemorySize();
172 ASSERT_TRUE(shared_memory_
.CreateAndMapAnonymous(kMemorySize
));
173 memset(shared_memory_
.memory(), 0xff, kMemorySize
);
175 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_
,
178 // Create duplicates of the handles we pass to AudioOutputDevice since
179 // ownership will be transferred and AudioOutputDevice is responsible for
181 SyncSocket::Handle audio_device_socket
= SyncSocket::kInvalidHandle
;
182 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_
.handle(),
183 &audio_device_socket
));
184 base::SharedMemoryHandle duplicated_memory_handle
;
185 ASSERT_TRUE(shared_memory_
.ShareToProcess(base::GetCurrentProcessHandle(),
186 &duplicated_memory_handle
));
188 audio_device_
->OnStreamCreated(duplicated_memory_handle
, audio_device_socket
,
190 io_loop_
.RunUntilIdle();
193 void AudioOutputDeviceTest::ExpectRenderCallback() {
194 // We should get a 'play' notification when we call OnStreamCreated().
195 // Respond by asking for some audio data. This should ask our callback
196 // to provide some audio data that AudioOutputDevice then writes into the
197 // shared memory section.
198 const int kMemorySize
= CalculateMemorySize();
200 EXPECT_CALL(*audio_output_ipc_
, PlayStream())
201 .WillOnce(SendPendingBytes(&browser_socket_
, kMemorySize
));
203 // We expect calls to our audio renderer callback, which returns the number
204 // of frames written to the memory section.
205 // Here's the second place where it gets hacky: There's no way for us to
206 // know (without using a sleep loop!) when the AudioOutputDevice has finished
207 // writing the interleaved audio data into the shared memory section.
208 // So, for the sake of this test, we consider the call to Render a sign
209 // of success and quit the loop.
210 if (synchronized_io_
) {
211 // For synchronized I/O, we expect RenderIO().
212 EXPECT_CALL(callback_
, RenderIO(_
, _
, _
))
213 .WillOnce(QuitLoop(io_loop_
.message_loop_proxy()));
215 // For output only we expect Render().
216 const int kNumberOfFramesToProcess
= 0;
217 EXPECT_CALL(callback_
, Render(_
, _
))
219 QuitLoop(io_loop_
.message_loop_proxy()),
220 Return(kNumberOfFramesToProcess
)));
224 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
225 // Don't hang the test if we never get the Render() callback.
226 io_loop_
.PostDelayedTask(FROM_HERE
, base::MessageLoop::QuitClosure(),
227 TestTimeouts::action_timeout());
231 void AudioOutputDeviceTest::StopAudioDevice() {
232 audio_device_
->Stop();
234 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
236 io_loop_
.RunUntilIdle();
239 TEST_P(AudioOutputDeviceTest
, Initialize
) {
240 // Tests that the object can be constructed, initialized and destructed
241 // without having ever been started/stopped.
244 // Calls Start() followed by an immediate Stop() and check for the basic message
245 // filter messages being sent in that case.
246 TEST_P(AudioOutputDeviceTest
, StartStop
) {
251 // AudioOutputDevice supports multiple start/stop sequences.
252 TEST_P(AudioOutputDeviceTest
, StartStopStartStop
) {
259 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
261 TEST_P(AudioOutputDeviceTest
, StopBeforeRender
) {
264 // Call Stop() but don't run the IO loop yet.
265 audio_device_
->Stop();
267 // Expect us to shutdown IPC but not to render anything despite the stream
269 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
273 // Full test with output only.
274 TEST_P(AudioOutputDeviceTest
, CreateStream
) {
276 ExpectRenderCallback();
278 WaitUntilRenderCallback();
282 INSTANTIATE_TEST_CASE_P(Render
, AudioOutputDeviceTest
, Values(false));
283 INSTANTIATE_TEST_CASE_P(RenderIO
, AudioOutputDeviceTest
, Values(true));
285 } // namespace media.