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 "media/audio/shared_memory_util.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gmock_mutant.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using base::CancelableSyncSocket
;
21 using base::SharedMemory
;
22 using base::SyncSocket
;
25 using testing::Invoke
;
26 using testing::Return
;
27 using testing::WithArgs
;
28 using testing::StrictMock
;
29 using testing::Values
;
35 class MockRenderCallback
: public AudioRendererSink::RenderCallback
{
37 MockRenderCallback() {}
38 virtual ~MockRenderCallback() {}
40 MOCK_METHOD2(Render
, int(AudioBus
* dest
, int audio_delay_milliseconds
));
41 MOCK_METHOD3(RenderIO
, void(AudioBus
* source
,
43 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
));
61 // Creates a copy of a SyncSocket handle that we can give to AudioOutputDevice.
62 // On Windows this means duplicating the pipe handle so that AudioOutputDevice
63 // can call CloseHandle() (since ownership has been transferred), but on other
64 // platforms, we just copy the same socket handle since AudioOutputDevice on
65 // those platforms won't actually own the socket (FileDescriptor.auto_close is
67 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle
,
68 SyncSocket::Handle
* copy
) {
70 HANDLE process
= GetCurrentProcess();
71 ::DuplicateHandle(process
, socket_handle
, process
, copy
,
72 0, FALSE
, DUPLICATE_SAME_ACCESS
);
75 *copy
= socket_handle
;
80 ACTION_P2(SendPendingBytes
, socket
, pending_bytes
) {
81 socket
->Send(&pending_bytes
, sizeof(pending_bytes
));
84 // Used to terminate a loop from a different thread than the loop belongs to.
85 // |loop| should be a MessageLoopProxy.
86 ACTION_P(QuitLoop
, loop
) {
87 loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
92 class AudioOutputDeviceTest
93 : public testing::Test
,
94 public testing::WithParamInterface
<bool> {
96 AudioOutputDeviceTest();
97 ~AudioOutputDeviceTest();
99 void StartAudioDevice();
101 void ExpectRenderCallback();
102 void WaitUntilRenderCallback();
103 void StopAudioDevice();
106 // Used to clean up TLS pointers that the test(s) will initialize.
107 // Must remain the first member of this class.
108 base::ShadowingAtExitManager at_exit_manager_
;
109 base::MessageLoopForIO io_loop_
;
110 AudioParameters default_audio_parameters_
;
111 StrictMock
<MockRenderCallback
> callback_
;
112 MockAudioOutputIPC
* audio_output_ipc_
; // owned by audio_device_
113 scoped_refptr
<AudioOutputDevice
> audio_device_
;
116 int CalculateMemorySize();
118 const bool synchronized_io_
;
119 const int input_channels_
;
120 SharedMemory shared_memory_
;
121 CancelableSyncSocket browser_socket_
;
122 CancelableSyncSocket renderer_socket_
;
124 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest
);
127 int AudioOutputDeviceTest::CalculateMemorySize() {
128 // Calculate output and input memory size.
129 int output_memory_size
=
130 AudioBus::CalculateMemorySize(default_audio_parameters_
);
132 int frames
= default_audio_parameters_
.frames_per_buffer();
133 int input_memory_size
=
134 AudioBus::CalculateMemorySize(input_channels_
, frames
);
136 int io_buffer_size
= output_memory_size
+ input_memory_size
;
138 // This is where it gets a bit hacky. The shared memory contract between
139 // AudioOutputDevice and its browser side counter part includes a bit more
140 // than just the audio data, so we must call TotalSharedMemorySizeInBytes()
141 // to get the actual size needed to fit the audio data plus the extra data.
142 return TotalSharedMemorySizeInBytes(io_buffer_size
);
145 AudioOutputDeviceTest::AudioOutputDeviceTest()
146 : synchronized_io_(GetParam()),
147 input_channels_(synchronized_io_
? 2 : 0) {
148 default_audio_parameters_
.Reset(
149 AudioParameters::AUDIO_PCM_LINEAR
,
150 CHANNEL_LAYOUT_STEREO
, 2, input_channels_
,
153 audio_output_ipc_
= new MockAudioOutputIPC();
154 audio_device_
= new AudioOutputDevice(
155 scoped_ptr
<AudioOutputIPC
>(audio_output_ipc_
),
156 io_loop_
.message_loop_proxy());
158 audio_device_
->Initialize(default_audio_parameters_
,
161 io_loop_
.RunUntilIdle();
164 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
165 audio_device_
= NULL
;
168 void AudioOutputDeviceTest::StartAudioDevice() {
169 audio_device_
->Start();
171 EXPECT_CALL(*audio_output_ipc_
, CreateStream(audio_device_
.get(), _
, 0));
173 io_loop_
.RunUntilIdle();
176 void AudioOutputDeviceTest::CreateStream() {
177 const int kMemorySize
= CalculateMemorySize();
179 ASSERT_TRUE(shared_memory_
.CreateAndMapAnonymous(kMemorySize
));
180 memset(shared_memory_
.memory(), 0xff, kMemorySize
);
182 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_
,
185 // Create duplicates of the handles we pass to AudioOutputDevice since
186 // ownership will be transferred and AudioOutputDevice is responsible for
188 SyncSocket::Handle audio_device_socket
= SyncSocket::kInvalidHandle
;
189 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_
.handle(),
190 &audio_device_socket
));
191 base::SharedMemoryHandle duplicated_memory_handle
;
192 ASSERT_TRUE(shared_memory_
.ShareToProcess(base::GetCurrentProcessHandle(),
193 &duplicated_memory_handle
));
195 audio_device_
->OnStreamCreated(duplicated_memory_handle
, audio_device_socket
,
196 PacketSizeInBytes(kMemorySize
));
197 io_loop_
.RunUntilIdle();
200 void AudioOutputDeviceTest::ExpectRenderCallback() {
201 // We should get a 'play' notification when we call OnStreamCreated().
202 // Respond by asking for some audio data. This should ask our callback
203 // to provide some audio data that AudioOutputDevice then writes into the
204 // shared memory section.
205 const int kMemorySize
= CalculateMemorySize();
207 EXPECT_CALL(*audio_output_ipc_
, PlayStream())
208 .WillOnce(SendPendingBytes(&browser_socket_
, kMemorySize
));
210 // We expect calls to our audio renderer callback, which returns the number
211 // of frames written to the memory section.
212 // Here's the second place where it gets hacky: There's no way for us to
213 // know (without using a sleep loop!) when the AudioOutputDevice has finished
214 // writing the interleaved audio data into the shared memory section.
215 // So, for the sake of this test, we consider the call to Render a sign
216 // of success and quit the loop.
217 if (synchronized_io_
) {
218 // For synchronized I/O, we expect RenderIO().
219 EXPECT_CALL(callback_
, RenderIO(_
, _
, _
))
220 .WillOnce(QuitLoop(io_loop_
.message_loop_proxy()));
222 // For output only we expect Render().
223 const int kNumberOfFramesToProcess
= 0;
224 EXPECT_CALL(callback_
, Render(_
, _
))
226 QuitLoop(io_loop_
.message_loop_proxy()),
227 Return(kNumberOfFramesToProcess
)));
231 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
232 // Don't hang the test if we never get the Render() callback.
233 io_loop_
.PostDelayedTask(FROM_HERE
, base::MessageLoop::QuitClosure(),
234 TestTimeouts::action_timeout());
238 void AudioOutputDeviceTest::StopAudioDevice() {
239 audio_device_
->Stop();
241 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
243 io_loop_
.RunUntilIdle();
246 TEST_P(AudioOutputDeviceTest
, Initialize
) {
247 // Tests that the object can be constructed, initialized and destructed
248 // without having ever been started/stopped.
251 // Calls Start() followed by an immediate Stop() and check for the basic message
252 // filter messages being sent in that case.
253 TEST_P(AudioOutputDeviceTest
, StartStop
) {
258 // AudioOutputDevice supports multiple start/stop sequences.
259 TEST_P(AudioOutputDeviceTest
, StartStopStartStop
) {
266 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
268 TEST_P(AudioOutputDeviceTest
, StopBeforeRender
) {
271 // Call Stop() but don't run the IO loop yet.
272 audio_device_
->Stop();
274 // Expect us to shutdown IPC but not to render anything despite the stream
276 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
280 // Full test with output only.
281 TEST_P(AudioOutputDeviceTest
, CreateStream
) {
283 ExpectRenderCallback();
285 WaitUntilRenderCallback();
289 INSTANTIATE_TEST_CASE_P(Render
, AudioOutputDeviceTest
, Values(false));
290 INSTANTIATE_TEST_CASE_P(RenderIO
, AudioOutputDeviceTest
, Values(true));
292 } // namespace media.