Report errors from ChromiumEnv::GetChildren in Posix.
[chromium-blink-merge.git] / media / audio / audio_output_device_unittest.cc
blobe667c086ab090096e1b7c15df27df54958e17292
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/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;
23 using testing::_;
24 using testing::DoAll;
25 using testing::Invoke;
26 using testing::Return;
27 using testing::WithArgs;
28 using testing::StrictMock;
29 using testing::Values;
31 namespace media {
33 namespace {
35 class MockRenderCallback : public AudioRendererSink::RenderCallback {
36 public:
37 MockRenderCallback() {}
38 virtual ~MockRenderCallback() {}
40 MOCK_METHOD2(Render, int(AudioBus* dest, int audio_delay_milliseconds));
41 MOCK_METHOD3(RenderIO, void(AudioBus* source,
42 AudioBus* dest,
43 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));
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
66 // false).
67 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle,
68 SyncSocket::Handle* copy) {
69 #if defined(OS_WIN)
70 HANDLE process = GetCurrentProcess();
71 ::DuplicateHandle(process, socket_handle, process, copy,
72 0, FALSE, DUPLICATE_SAME_ACCESS);
73 return *copy != NULL;
74 #else
75 *copy = socket_handle;
76 return *copy != -1;
77 #endif
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());
90 } // namespace.
92 class AudioOutputDeviceTest
93 : public testing::Test,
94 public testing::WithParamInterface<bool> {
95 public:
96 AudioOutputDeviceTest();
97 ~AudioOutputDeviceTest();
99 void StartAudioDevice();
100 void CreateStream();
101 void ExpectRenderCallback();
102 void WaitUntilRenderCallback();
103 void StopAudioDevice();
105 protected:
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_;
115 private:
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_,
151 48000, 16, 1024);
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_,
159 &callback_);
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_,
183 &renderer_socket_));
185 // Create duplicates of the handles we pass to AudioOutputDevice since
186 // ownership will be transferred and AudioOutputDevice is responsible for
187 // freeing.
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()));
221 } else {
222 // For output only we expect Render().
223 const int kNumberOfFramesToProcess = 0;
224 EXPECT_CALL(callback_, Render(_, _))
225 .WillOnce(DoAll(
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());
235 io_loop_.Run();
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) {
254 StartAudioDevice();
255 StopAudioDevice();
258 // AudioOutputDevice supports multiple start/stop sequences.
259 TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
260 StartAudioDevice();
261 StopAudioDevice();
262 StartAudioDevice();
263 StopAudioDevice();
266 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
267 // on the IO loop.
268 TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
269 StartAudioDevice();
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
275 // getting created.
276 EXPECT_CALL(*audio_output_ipc_, CloseStream());
277 CreateStream();
280 // Full test with output only.
281 TEST_P(AudioOutputDeviceTest, CreateStream) {
282 StartAudioDevice();
283 ExpectRenderCallback();
284 CreateStream();
285 WaitUntilRenderCallback();
286 StopAudioDevice();
289 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
290 INSTANTIATE_TEST_CASE_P(RenderIO, AudioOutputDeviceTest, Values(true));
292 } // namespace media.