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_METHOD0(OnRenderError
, void());
43 class MockAudioOutputIPC
: public AudioOutputIPC
{
45 MockAudioOutputIPC() {}
46 virtual ~MockAudioOutputIPC() {}
48 MOCK_METHOD3(CreateStream
, void(AudioOutputIPCDelegate
* delegate
,
49 const AudioParameters
& params
,
51 MOCK_METHOD0(PlayStream
, void());
52 MOCK_METHOD0(PauseStream
, void());
53 MOCK_METHOD0(CloseStream
, void());
54 MOCK_METHOD1(SetVolume
, void(double volume
));
57 ACTION_P2(SendPendingBytes
, socket
, pending_bytes
) {
58 socket
->Send(&pending_bytes
, sizeof(pending_bytes
));
61 // Used to terminate a loop from a different thread than the loop belongs to.
62 // |loop| should be a MessageLoopProxy.
63 ACTION_P(QuitLoop
, loop
) {
64 loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
69 class AudioOutputDeviceTest
70 : public testing::Test
,
71 public testing::WithParamInterface
<bool> {
73 AudioOutputDeviceTest();
74 ~AudioOutputDeviceTest();
76 void StartAudioDevice();
78 void ExpectRenderCallback();
79 void WaitUntilRenderCallback();
80 void StopAudioDevice();
83 // Used to clean up TLS pointers that the test(s) will initialize.
84 // Must remain the first member of this class.
85 base::ShadowingAtExitManager at_exit_manager_
;
86 base::MessageLoopForIO io_loop_
;
87 AudioParameters default_audio_parameters_
;
88 StrictMock
<MockRenderCallback
> callback_
;
89 MockAudioOutputIPC
* audio_output_ipc_
; // owned by audio_device_
90 scoped_refptr
<AudioOutputDevice
> audio_device_
;
93 int CalculateMemorySize();
95 SharedMemory shared_memory_
;
96 CancelableSyncSocket browser_socket_
;
97 CancelableSyncSocket renderer_socket_
;
99 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest
);
102 int AudioOutputDeviceTest::CalculateMemorySize() {
103 // Calculate output memory size.
104 return AudioBus::CalculateMemorySize(default_audio_parameters_
);
107 AudioOutputDeviceTest::AudioOutputDeviceTest() {
108 default_audio_parameters_
.Reset(
109 AudioParameters::AUDIO_PCM_LINEAR
,
110 CHANNEL_LAYOUT_STEREO
, 2, 48000, 16, 1024);
112 audio_output_ipc_
= new MockAudioOutputIPC();
113 audio_device_
= new AudioOutputDevice(
114 scoped_ptr
<AudioOutputIPC
>(audio_output_ipc_
),
115 io_loop_
.message_loop_proxy());
117 audio_device_
->Initialize(default_audio_parameters_
,
120 io_loop_
.RunUntilIdle();
123 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
124 audio_device_
= NULL
;
127 void AudioOutputDeviceTest::StartAudioDevice() {
128 audio_device_
->Start();
130 EXPECT_CALL(*audio_output_ipc_
, CreateStream(audio_device_
.get(), _
, 0));
132 io_loop_
.RunUntilIdle();
135 void AudioOutputDeviceTest::CreateStream() {
136 const int kMemorySize
= CalculateMemorySize();
138 ASSERT_TRUE(shared_memory_
.CreateAndMapAnonymous(kMemorySize
));
139 memset(shared_memory_
.memory(), 0xff, kMemorySize
);
141 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_
,
144 // Create duplicates of the handles we pass to AudioOutputDevice since
145 // ownership will be transferred and AudioOutputDevice is responsible for
147 SyncSocket::TransitDescriptor audio_device_socket_descriptor
;
148 ASSERT_TRUE(renderer_socket_
.PrepareTransitDescriptor(
149 base::GetCurrentProcessHandle(), &audio_device_socket_descriptor
));
150 base::SharedMemoryHandle duplicated_memory_handle
;
151 ASSERT_TRUE(shared_memory_
.ShareToProcess(base::GetCurrentProcessHandle(),
152 &duplicated_memory_handle
));
154 audio_device_
->OnStreamCreated(
155 duplicated_memory_handle
,
156 SyncSocket::UnwrapHandle(audio_device_socket_descriptor
), kMemorySize
);
157 io_loop_
.RunUntilIdle();
160 void AudioOutputDeviceTest::ExpectRenderCallback() {
161 // We should get a 'play' notification when we call OnStreamCreated().
162 // Respond by asking for some audio data. This should ask our callback
163 // to provide some audio data that AudioOutputDevice then writes into the
164 // shared memory section.
165 const int kMemorySize
= CalculateMemorySize();
167 EXPECT_CALL(*audio_output_ipc_
, PlayStream())
168 .WillOnce(SendPendingBytes(&browser_socket_
, kMemorySize
));
170 // We expect calls to our audio renderer callback, which returns the number
171 // of frames written to the memory section.
172 // Here's the second place where it gets hacky: There's no way for us to
173 // know (without using a sleep loop!) when the AudioOutputDevice has finished
174 // writing the interleaved audio data into the shared memory section.
175 // So, for the sake of this test, we consider the call to Render a sign
176 // of success and quit the loop.
177 const int kNumberOfFramesToProcess
= 0;
178 EXPECT_CALL(callback_
, Render(_
, _
))
180 QuitLoop(io_loop_
.message_loop_proxy()),
181 Return(kNumberOfFramesToProcess
)));
184 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
185 // Don't hang the test if we never get the Render() callback.
186 io_loop_
.PostDelayedTask(FROM_HERE
, base::MessageLoop::QuitClosure(),
187 TestTimeouts::action_timeout());
191 void AudioOutputDeviceTest::StopAudioDevice() {
192 audio_device_
->Stop();
194 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
196 io_loop_
.RunUntilIdle();
199 TEST_P(AudioOutputDeviceTest
, Initialize
) {
200 // Tests that the object can be constructed, initialized and destructed
201 // without having ever been started/stopped.
204 // Calls Start() followed by an immediate Stop() and check for the basic message
205 // filter messages being sent in that case.
206 TEST_P(AudioOutputDeviceTest
, StartStop
) {
211 // AudioOutputDevice supports multiple start/stop sequences.
212 TEST_P(AudioOutputDeviceTest
, StartStopStartStop
) {
219 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
221 TEST_P(AudioOutputDeviceTest
, StopBeforeRender
) {
224 // Call Stop() but don't run the IO loop yet.
225 audio_device_
->Stop();
227 // Expect us to shutdown IPC but not to render anything despite the stream
229 EXPECT_CALL(*audio_output_ipc_
, CloseStream());
233 // Full test with output only.
234 TEST_P(AudioOutputDeviceTest
, CreateStream
) {
236 ExpectRenderCallback();
238 WaitUntilRenderCallback();
242 INSTANTIATE_TEST_CASE_P(Render
, AudioOutputDeviceTest
, Values(false));
244 } // namespace media.