Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(908)

Side by Side Diff: media/audio/audio_output_device_unittest.cc

Issue 10958004: Prevent AudioDeviceThread from starting if clients have called Stop() (round 2). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/audio_output_device.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <vector> 5 #include <vector>
6 6
7 #include "base/at_exit.h" 7 #include "base/at_exit.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/process_util.h" 9 #include "base/process_util.h"
10 #include "base/shared_memory.h" 10 #include "base/shared_memory.h"
11 #include "base/sync_socket.h" 11 #include "base/sync_socket.h"
12 #include "base/test/test_timeouts.h" 12 #include "base/test/test_timeouts.h"
13 #include "media/audio/audio_output_device.h" 13 #include "media/audio/audio_output_device.h"
14 #include "media/audio/sample_rates.h" 14 #include "media/audio/sample_rates.h"
15 #include "media/audio/shared_memory_util.h" 15 #include "media/audio/shared_memory_util.h"
16 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gmock_mutant.h" 17 #include "testing/gmock_mutant.h"
18 #include "testing/gtest/include/gtest/gtest.h" 18 #include "testing/gtest/include/gtest/gtest.h"
19 19
20 using base::CancelableSyncSocket; 20 using base::CancelableSyncSocket;
21 using base::SharedMemory; 21 using base::SharedMemory;
22 using base::SyncSocket; 22 using base::SyncSocket;
23 using testing::_; 23 using testing::_;
24 using testing::DoAll; 24 using testing::DoAll;
25 using testing::Invoke; 25 using testing::Invoke;
26 using testing::Return; 26 using testing::Return;
27 using testing::WithArgs; 27 using testing::WithArgs;
28 using testing::StrictMock; 28 using testing::StrictMock;
29 using testing::Values;
29 30
30 namespace media { 31 namespace media {
31 32
32 namespace { 33 namespace {
33 34
34 class MockRenderCallback : public AudioRendererSink::RenderCallback { 35 class MockRenderCallback : public AudioRendererSink::RenderCallback {
35 public: 36 public:
36 MockRenderCallback() {} 37 MockRenderCallback() {}
37 virtual ~MockRenderCallback() {} 38 virtual ~MockRenderCallback() {}
38 39
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 } 85 }
85 86
86 // Used to terminate a loop from a different thread than the loop belongs to. 87 // Used to terminate a loop from a different thread than the loop belongs to.
87 // |loop| should be a MessageLoopProxy. 88 // |loop| should be a MessageLoopProxy.
88 ACTION_P(QuitLoop, loop) { 89 ACTION_P(QuitLoop, loop) {
89 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 90 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
90 } 91 }
91 92
92 } // namespace. 93 } // namespace.
93 94
94 class AudioOutputDeviceTest : public testing::Test { 95 class AudioOutputDeviceTest
96 : public testing::Test,
97 public testing::WithParamInterface<bool> {
95 public: 98 public:
96 AudioOutputDeviceTest() 99 AudioOutputDeviceTest()
97 : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR, 100 : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR,
98 CHANNEL_LAYOUT_STEREO, 101 CHANNEL_LAYOUT_STEREO,
99 48000, 16, 1024), 102 48000, 16, 1024),
100 audio_device_(new AudioOutputDevice( 103 audio_device_(new AudioOutputDevice(
101 &audio_output_ipc_, io_loop_.message_loop_proxy())) { 104 &audio_output_ipc_, io_loop_.message_loop_proxy())),
105 synchronized_io_(GetParam()),
106 input_channels_(synchronized_io_ ? 2 : 0) {
102 } 107 }
103 108
104 ~AudioOutputDeviceTest() {} 109 ~AudioOutputDeviceTest() {}
105 110
106 int CalculateMemorySize(bool synchronized_io); 111 void Initialize();
107 112 void StartAudioDevice();
108 void StartAudioDevice(bool synchronized_io); 113 void CreateStream();
109 void CreateStream(bool synchronized_io); 114 void ExpectRenderCallback();
110 void ExpectRenderCallback(bool synchronized_io);
111 void WaitUntilRenderCallback(); 115 void WaitUntilRenderCallback();
112 void StopAudioDevice(); 116 void StopAudioDevice();
113 117
114 protected: 118 protected:
115 // Used to clean up TLS pointers that the test(s) will initialize. 119 // Used to clean up TLS pointers that the test(s) will initialize.
116 // Must remain the first member of this class. 120 // Must remain the first member of this class.
117 base::ShadowingAtExitManager at_exit_manager_; 121 base::ShadowingAtExitManager at_exit_manager_;
118 MessageLoopForIO io_loop_; 122 MessageLoopForIO io_loop_;
119 const AudioParameters default_audio_parameters_; 123 const AudioParameters default_audio_parameters_;
120 StrictMock<MockRenderCallback> callback_; 124 StrictMock<MockRenderCallback> callback_;
121 StrictMock<MockAudioOutputIPC> audio_output_ipc_; 125 StrictMock<MockAudioOutputIPC> audio_output_ipc_;
122 scoped_refptr<AudioOutputDevice> audio_device_; 126 scoped_refptr<AudioOutputDevice> audio_device_;
123 127
124 private: 128 private:
129 int CalculateMemorySize();
130
131 const bool synchronized_io_;
132 const int input_channels_;
125 SharedMemory shared_memory_; 133 SharedMemory shared_memory_;
126 CancelableSyncSocket browser_socket_; 134 CancelableSyncSocket browser_socket_;
127 CancelableSyncSocket renderer_socket_; 135 CancelableSyncSocket renderer_socket_;
128 136
129 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest); 137 DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest);
130 }; 138 };
131 139
132 static const int kStreamId = 123; 140 static const int kStreamId = 123;
133 141
134 int AudioOutputDeviceTest::CalculateMemorySize(bool synchronized_io) { 142 int AudioOutputDeviceTest::CalculateMemorySize() {
135 int kInputChannels = synchronized_io ? 2 : 0;
136
137 // Calculate output and input memory size. 143 // Calculate output and input memory size.
138 int output_memory_size = 144 int output_memory_size =
139 AudioBus::CalculateMemorySize(default_audio_parameters_); 145 AudioBus::CalculateMemorySize(default_audio_parameters_);
140 146
141 int frames = default_audio_parameters_.frames_per_buffer(); 147 int frames = default_audio_parameters_.frames_per_buffer();
142 int input_memory_size = 148 int input_memory_size =
143 AudioBus::CalculateMemorySize(kInputChannels, frames); 149 AudioBus::CalculateMemorySize(input_channels_, frames);
144 150
145 int io_buffer_size = output_memory_size + input_memory_size; 151 int io_buffer_size = output_memory_size + input_memory_size;
146 152
147 // This is where it gets a bit hacky. The shared memory contract between 153 // This is where it gets a bit hacky. The shared memory contract between
148 // AudioOutputDevice and its browser side counter part includes a bit more 154 // AudioOutputDevice and its browser side counter part includes a bit more
149 // than just the audio data, so we must call TotalSharedMemorySizeInBytes() 155 // than just the audio data, so we must call TotalSharedMemorySizeInBytes()
150 // to get the actual size needed to fit the audio data plus the extra data. 156 // to get the actual size needed to fit the audio data plus the extra data.
151 return TotalSharedMemorySizeInBytes(io_buffer_size); 157 return TotalSharedMemorySizeInBytes(io_buffer_size);
152 } 158 }
153 159
154 void AudioOutputDeviceTest::StartAudioDevice(bool synchronized_io) { 160 void AudioOutputDeviceTest::Initialize() {
155 const int kInputChannels = synchronized_io ? 2 : 0; 161 if (synchronized_io_) {
156
157 if (synchronized_io) {
158 // Request output and synchronized input.
159 audio_device_->InitializeIO(default_audio_parameters_, 162 audio_device_->InitializeIO(default_audio_parameters_,
160 kInputChannels, 163 input_channels_,
161 &callback_); 164 &callback_);
162 } else { 165 } else {
163 // Output only. 166 audio_device_->Initialize(default_audio_parameters_,
164 audio_device_->Initialize(default_audio_parameters_, &callback_); 167 &callback_);
165 } 168 }
169 io_loop_.RunAllPending();
170 }
166 171
172 void AudioOutputDeviceTest::StartAudioDevice() {
167 audio_device_->Start(); 173 audio_device_->Start();
168 174
169 EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device_.get())) 175 EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device_.get()))
170 .WillOnce(Return(kStreamId)); 176 .WillOnce(Return(kStreamId));
171 EXPECT_CALL(audio_output_ipc_, CreateStream(kStreamId, _, _)); 177 EXPECT_CALL(audio_output_ipc_, CreateStream(kStreamId, _, _));
172 178
173 io_loop_.RunAllPending(); 179 io_loop_.RunAllPending();
174 } 180 }
175 181
176 void AudioOutputDeviceTest::CreateStream(bool synchronized_io) { 182 void AudioOutputDeviceTest::CreateStream() {
177 const int kMemorySize = CalculateMemorySize(synchronized_io); 183 const int kMemorySize = CalculateMemorySize();
184
178 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize)); 185 ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize));
179 memset(shared_memory_.memory(), 0xff, kMemorySize); 186 memset(shared_memory_.memory(), 0xff, kMemorySize);
180 187
181 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_, 188 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_,
182 &renderer_socket_)); 189 &renderer_socket_));
183 190
184 // Create duplicates of the handles we pass to AudioOutputDevice since 191 // Create duplicates of the handles we pass to AudioOutputDevice since
185 // ownership will be transferred and AudioOutputDevice is responsible for 192 // ownership will be transferred and AudioOutputDevice is responsible for
186 // freeing. 193 // freeing.
187 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle; 194 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle;
188 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_.handle(), 195 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_.handle(),
189 &audio_device_socket)); 196 &audio_device_socket));
190 base::SharedMemoryHandle duplicated_memory_handle; 197 base::SharedMemoryHandle duplicated_memory_handle;
191 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), 198 ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(),
192 &duplicated_memory_handle)); 199 &duplicated_memory_handle));
193 200
194 audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket, 201 audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket,
195 PacketSizeInBytes(kMemorySize)); 202 PacketSizeInBytes(kMemorySize));
196 io_loop_.RunAllPending(); 203 io_loop_.RunAllPending();
197 } 204 }
198 205
199 void AudioOutputDeviceTest::ExpectRenderCallback(bool synchronized_io) { 206 void AudioOutputDeviceTest::ExpectRenderCallback() {
200 // We should get a 'play' notification when we call OnStreamCreated(). 207 // We should get a 'play' notification when we call OnStreamCreated().
201 // Respond by asking for some audio data. This should ask our callback 208 // Respond by asking for some audio data. This should ask our callback
202 // to provide some audio data that AudioOutputDevice then writes into the 209 // to provide some audio data that AudioOutputDevice then writes into the
203 // shared memory section. 210 // shared memory section.
204 const int kMemorySize = CalculateMemorySize(synchronized_io); 211 const int kMemorySize = CalculateMemorySize();
212
205 EXPECT_CALL(audio_output_ipc_, PlayStream(kStreamId)) 213 EXPECT_CALL(audio_output_ipc_, PlayStream(kStreamId))
206 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize)); 214 .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize));
207 215
208 // We expect calls to our audio renderer callback, which returns the number 216 // We expect calls to our audio renderer callback, which returns the number
209 // of frames written to the memory section. 217 // of frames written to the memory section.
210 // Here's the second place where it gets hacky: There's no way for us to 218 // Here's the second place where it gets hacky: There's no way for us to
211 // know (without using a sleep loop!) when the AudioOutputDevice has finished 219 // know (without using a sleep loop!) when the AudioOutputDevice has finished
212 // writing the interleaved audio data into the shared memory section. 220 // writing the interleaved audio data into the shared memory section.
213 // So, for the sake of this test, we consider the call to Render a sign 221 // So, for the sake of this test, we consider the call to Render a sign
214 // of success and quit the loop. 222 // of success and quit the loop.
215 if (synchronized_io) { 223 if (synchronized_io_) {
216 // For synchronized I/O, we expect RenderIO(). 224 // For synchronized I/O, we expect RenderIO().
217 EXPECT_CALL(callback_, RenderIO(_, _, _)) 225 EXPECT_CALL(callback_, RenderIO(_, _, _))
218 .WillOnce(QuitLoop(io_loop_.message_loop_proxy())); 226 .WillOnce(QuitLoop(io_loop_.message_loop_proxy()));
219 } else { 227 } else {
220 // For output only we expect Render(). 228 // For output only we expect Render().
221 const int kNumberOfFramesToProcess = 0; 229 const int kNumberOfFramesToProcess = 0;
222 EXPECT_CALL(callback_, Render(_, _)) 230 EXPECT_CALL(callback_, Render(_, _))
223 .WillOnce(DoAll( 231 .WillOnce(DoAll(
224 QuitLoop(io_loop_.message_loop_proxy()), 232 QuitLoop(io_loop_.message_loop_proxy()),
225 Return(kNumberOfFramesToProcess))); 233 Return(kNumberOfFramesToProcess)));
226 } 234 }
227 } 235 }
228 236
229 void AudioOutputDeviceTest::WaitUntilRenderCallback() { 237 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
230 // Don't hang the test if we never get the Render() callback. 238 // Don't hang the test if we never get the Render() callback.
231 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), 239 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
232 TestTimeouts::action_timeout()); 240 TestTimeouts::action_timeout());
233 io_loop_.Run(); 241 io_loop_.Run();
234 } 242 }
235 243
236 void AudioOutputDeviceTest::StopAudioDevice() { 244 void AudioOutputDeviceTest::StopAudioDevice() {
245 audio_device_->Stop();
246
237 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId)); 247 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId));
238 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId)); 248 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId));
239 249
240 audio_device_->Stop();
241 io_loop_.RunAllPending(); 250 io_loop_.RunAllPending();
242 } 251 }
243 252
244 // The simplest test for AudioOutputDevice. Used to test construction of 253 TEST_P(AudioOutputDeviceTest, Initialize) {
245 // AudioOutputDevice and that the runtime environment is set up correctly. 254 Initialize();
246 TEST_F(AudioOutputDeviceTest, Initialize) {
247 audio_device_->Initialize(default_audio_parameters_, &callback_);
248 io_loop_.RunAllPending();
249 }
250
251 // Similar to Initialize() test, but using synchronized I/O.
252 TEST_F(AudioOutputDeviceTest, InitializeIO) {
253 const int kInputChannels = 2; // Test stereo synchronized input.
254 audio_device_->InitializeIO(default_audio_parameters_,
255 kInputChannels,
256 &callback_);
257 io_loop_.RunAllPending();
258 } 255 }
259 256
260 // Calls Start() followed by an immediate Stop() and check for the basic message 257 // Calls Start() followed by an immediate Stop() and check for the basic message
261 // filter messages being sent in that case. 258 // filter messages being sent in that case.
262 TEST_F(AudioOutputDeviceTest, StartStop) { 259 TEST_P(AudioOutputDeviceTest, StartStop) {
263 StartAudioDevice(false); 260 Initialize();
261 StartAudioDevice();
264 StopAudioDevice(); 262 StopAudioDevice();
265 } 263 }
266 264
267 TEST_F(AudioOutputDeviceTest, DISABLED_StopBeforeRender) { 265 // AudioOutputDevice supports multiple start/stop sequences.
268 StartAudioDevice(false); 266 TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
267 Initialize();
268 StartAudioDevice();
269 StopAudioDevice();
270 StartAudioDevice();
271 StopAudioDevice();
272 }
273
274 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
275 // on the IO loop.
276 TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
277 Initialize();
278 StartAudioDevice();
269 279
270 // Call Stop() but don't run the IO loop yet. 280 // Call Stop() but don't run the IO loop yet.
271 audio_device_->Stop(); 281 audio_device_->Stop();
272 282
273 // Expect us to shutdown IPC but not to render anything despite the stream 283 // Expect us to shutdown IPC but not to render anything despite the stream
274 // getting created. 284 // getting created.
275 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId)); 285 EXPECT_CALL(audio_output_ipc_, CloseStream(kStreamId));
276 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId)); 286 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(kStreamId));
277 CreateStream(false); 287 CreateStream();
278 } 288 }
279 289
280 // Full test with output only. 290 // Full test with output only.
281 TEST_F(AudioOutputDeviceTest, CreateStream) { 291 TEST_P(AudioOutputDeviceTest, CreateStream) {
282 StartAudioDevice(false); 292 Initialize();
283 ExpectRenderCallback(false); 293 StartAudioDevice();
284 CreateStream(false); 294 ExpectRenderCallback();
295 CreateStream();
285 WaitUntilRenderCallback(); 296 WaitUntilRenderCallback();
286 StopAudioDevice(); 297 StopAudioDevice();
287 } 298 }
288 299
289 // Same as CreateStream() test, but also tests synchronized I/O. 300 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
290 TEST_F(AudioOutputDeviceTest, CreateStreamWithInput) { 301 INSTANTIATE_TEST_CASE_P(RenderIO, AudioOutputDeviceTest, Values(true));
291 StartAudioDevice(true);
292 ExpectRenderCallback(true);
293 CreateStream(true);
294 WaitUntilRenderCallback();
295 StopAudioDevice();
296 }
297 302
298 } // namespace media. 303 } // namespace media.
OLDNEW
« no previous file with comments | « media/audio/audio_output_device.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698