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

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

Issue 9255017: Add thread safety to AudioManagerBase to protect access to the audio thread member variable. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix style issue Created 8 years, 11 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_controller.h ('k') | media/audio/audio_output_dispatcher.h » ('j') | 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 "media/audio/audio_output_controller.h" 5 #include "media/audio/audio_output_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
(...skipping 24 matching lines...) Expand all
35 buffer_(0, capacity), 35 buffer_(0, capacity),
36 pending_request_(false), 36 pending_request_(false),
37 sync_reader_(sync_reader), 37 sync_reader_(sync_reader),
38 message_loop_(NULL), 38 message_loop_(NULL),
39 number_polling_attempts_left_(0), 39 number_polling_attempts_left_(0),
40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { 40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) {
41 } 41 }
42 42
43 AudioOutputController::~AudioOutputController() { 43 AudioOutputController::~AudioOutputController() {
44 DCHECK_EQ(kClosed, state_); 44 DCHECK_EQ(kClosed, state_);
45 if (message_loop_ == MessageLoop::current()) { 45 DCHECK(message_loop_);
46
47 if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) {
46 DoStopCloseAndClearStream(NULL); 48 DoStopCloseAndClearStream(NULL);
47 } else { 49 } else {
48 DCHECK(message_loop_);
49 WaitableEvent completion(true /* manual reset */, 50 WaitableEvent completion(true /* manual reset */,
50 false /* initial state */); 51 false /* initial state */);
51 message_loop_->PostTask(FROM_HERE, 52 message_loop_->PostTask(FROM_HERE,
52 base::Bind(&AudioOutputController::DoStopCloseAndClearStream, 53 base::Bind(&AudioOutputController::DoStopCloseAndClearStream,
53 base::Unretained(this), 54 base::Unretained(this),
54 &completion)); 55 &completion));
55 completion.Wait(); 56 completion.Wait();
56 } 57 }
57 } 58 }
58 59
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 // If |size| is set to 0, it indicates that the audio source doesn't have 139 // If |size| is set to 0, it indicates that the audio source doesn't have
139 // more data right now, and so it doesn't make sense to send additional 140 // more data right now, and so it doesn't make sense to send additional
140 // request. 141 // request.
141 if (size) { 142 if (size) {
142 buffer_.Append(data, size); 143 buffer_.Append(data, size);
143 SubmitOnMoreData_Locked(); 144 SubmitOnMoreData_Locked();
144 } 145 }
145 } 146 }
146 147
147 void AudioOutputController::DoCreate(const AudioParameters& params) { 148 void AudioOutputController::DoCreate(const AudioParameters& params) {
148 DCHECK_EQ(message_loop_, MessageLoop::current()); 149 DCHECK(message_loop_->BelongsToCurrentThread());
149 150
150 // Close() can be called before DoCreate() is executed. 151 // Close() can be called before DoCreate() is executed.
151 if (state_ == kClosed) 152 if (state_ == kClosed)
152 return; 153 return;
153 DCHECK_EQ(kEmpty, state_); 154 DCHECK_EQ(kEmpty, state_);
154 155
155 DoStopCloseAndClearStream(NULL); 156 DoStopCloseAndClearStream(NULL);
156 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); 157 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params);
157 if (!stream_) { 158 if (!stream_) {
158 // TODO(hclam): Define error types. 159 // TODO(hclam): Define error types.
(...skipping 19 matching lines...) Expand all
178 handler_->OnCreated(this); 179 handler_->OnCreated(this);
179 180
180 // If in normal latency mode then start buffering. 181 // If in normal latency mode then start buffering.
181 if (!LowLatencyMode()) { 182 if (!LowLatencyMode()) {
182 base::AutoLock auto_lock(lock_); 183 base::AutoLock auto_lock(lock_);
183 SubmitOnMoreData_Locked(); 184 SubmitOnMoreData_Locked();
184 } 185 }
185 } 186 }
186 187
187 void AudioOutputController::DoPlay() { 188 void AudioOutputController::DoPlay() {
188 DCHECK_EQ(message_loop_, MessageLoop::current()); 189 DCHECK(message_loop_->BelongsToCurrentThread());
189 190
190 // We can start from created or paused state. 191 // We can start from created or paused state.
191 if (state_ != kCreated && state_ != kPaused) 192 if (state_ != kCreated && state_ != kPaused)
192 return; 193 return;
193 194
194 if (LowLatencyMode()) { 195 if (LowLatencyMode()) {
195 state_ = kStarting; 196 state_ = kStarting;
196 197
197 // Ask for first packet. 198 // Ask for first packet.
198 sync_reader_->UpdatePendingBytes(0); 199 sync_reader_->UpdatePendingBytes(0);
199 200
200 // Cannot start stream immediately, should give renderer some time 201 // Cannot start stream immediately, should give renderer some time
201 // to deliver data. 202 // to deliver data.
202 number_polling_attempts_left_ = kPollNumAttempts; 203 number_polling_attempts_left_ = kPollNumAttempts;
203 message_loop_->PostDelayedTask( 204 message_loop_->PostDelayedTask(
204 FROM_HERE, 205 FROM_HERE,
205 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 206 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
206 weak_this_.GetWeakPtr()), 207 weak_this_.GetWeakPtr()),
207 base::TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 208 kPollPauseInMilliseconds);
208 } else { 209 } else {
209 StartStream(); 210 StartStream();
210 } 211 }
211 } 212 }
212 213
213 void AudioOutputController::PollAndStartIfDataReady() { 214 void AudioOutputController::PollAndStartIfDataReady() {
214 DCHECK_EQ(message_loop_, MessageLoop::current()); 215 DCHECK(message_loop_->BelongsToCurrentThread());
215 216
216 // Being paranoid: do nothing if state unexpectedly changed. 217 // Being paranoid: do nothing if state unexpectedly changed.
217 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) 218 if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
218 return; 219 return;
219 220
220 bool pausing = (state_ == kPausedWhenStarting); 221 bool pausing = (state_ == kPausedWhenStarting);
221 // If we are ready to start the stream, start it. 222 // If we are ready to start the stream, start it.
222 // Of course we may have to stop it immediately... 223 // Of course we may have to stop it immediately...
223 if (--number_polling_attempts_left_ == 0 || 224 if (--number_polling_attempts_left_ == 0 ||
224 pausing || 225 pausing ||
225 sync_reader_->DataReady()) { 226 sync_reader_->DataReady()) {
226 StartStream(); 227 StartStream();
227 if (pausing) { 228 if (pausing) {
228 DoPause(); 229 DoPause();
229 } 230 }
230 } else { 231 } else {
231 message_loop_->PostDelayedTask( 232 message_loop_->PostDelayedTask(
232 FROM_HERE, 233 FROM_HERE,
233 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 234 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
234 weak_this_.GetWeakPtr()), 235 weak_this_.GetWeakPtr()),
235 base::TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 236 kPollPauseInMilliseconds);
236 } 237 }
237 } 238 }
238 239
239 void AudioOutputController::StartStream() { 240 void AudioOutputController::StartStream() {
240 DCHECK_EQ(message_loop_, MessageLoop::current()); 241 DCHECK(message_loop_->BelongsToCurrentThread());
241 state_ = kPlaying; 242 state_ = kPlaying;
242 243
243 // We start the AudioOutputStream lazily. 244 // We start the AudioOutputStream lazily.
244 stream_->Start(this); 245 stream_->Start(this);
245 246
246 // Tell the event handler that we are now playing. 247 // Tell the event handler that we are now playing.
247 handler_->OnPlaying(this); 248 handler_->OnPlaying(this);
248 } 249 }
249 250
250 void AudioOutputController::DoPause() { 251 void AudioOutputController::DoPause() {
251 DCHECK_EQ(message_loop_, MessageLoop::current()); 252 DCHECK(message_loop_->BelongsToCurrentThread());
252 253
253 if (stream_) 254 if (stream_)
254 stream_->Stop(); 255 stream_->Stop();
255 256
256 switch (state_) { 257 switch (state_) {
257 case kStarting: 258 case kStarting:
258 // We were asked to pause while starting. There is delayed task that will 259 // We were asked to pause while starting. There is delayed task that will
259 // try starting playback, and there is no way to remove that task from the 260 // try starting playback, and there is no way to remove that task from the
260 // queue. If we stop now that task will be executed anyway. 261 // queue. If we stop now that task will be executed anyway.
261 // Delay pausing, let delayed task to do pause after it start playback. 262 // Delay pausing, let delayed task to do pause after it start playback.
(...skipping 13 matching lines...) Expand all
275 } 276 }
276 277
277 handler_->OnPaused(this); 278 handler_->OnPaused(this);
278 break; 279 break;
279 default: 280 default:
280 return; 281 return;
281 } 282 }
282 } 283 }
283 284
284 void AudioOutputController::DoFlush() { 285 void AudioOutputController::DoFlush() {
285 DCHECK_EQ(message_loop_, MessageLoop::current()); 286 DCHECK(message_loop_->BelongsToCurrentThread());
286 287
287 // TODO(hclam): Actually flush the audio device. 288 // TODO(hclam): Actually flush the audio device.
288 289
289 // If we are in the regular latency mode then flush the push source. 290 // If we are in the regular latency mode then flush the push source.
290 if (!sync_reader_) { 291 if (!sync_reader_) {
291 if (state_ != kPaused) 292 if (state_ != kPaused)
292 return; 293 return;
293 base::AutoLock auto_lock(lock_); 294 base::AutoLock auto_lock(lock_);
294 buffer_.Clear(); 295 buffer_.Clear();
295 } 296 }
296 } 297 }
297 298
298 void AudioOutputController::DoClose(const base::Closure& closed_task) { 299 void AudioOutputController::DoClose(const base::Closure& closed_task) {
299 DCHECK_EQ(message_loop_, MessageLoop::current()); 300 DCHECK(message_loop_->BelongsToCurrentThread());
300 301
301 if (state_ != kClosed) { 302 if (state_ != kClosed) {
302 DoStopCloseAndClearStream(NULL); 303 DoStopCloseAndClearStream(NULL);
303 304
304 if (LowLatencyMode()) { 305 if (LowLatencyMode()) {
305 sync_reader_->Close(); 306 sync_reader_->Close();
306 } 307 }
307 308
308 state_ = kClosed; 309 state_ = kClosed;
309 } 310 }
310 311
311 closed_task.Run(); 312 closed_task.Run();
312 } 313 }
313 314
314 void AudioOutputController::DoSetVolume(double volume) { 315 void AudioOutputController::DoSetVolume(double volume) {
315 DCHECK_EQ(message_loop_, MessageLoop::current()); 316 DCHECK(message_loop_->BelongsToCurrentThread());
316 317
317 // Saves the volume to a member first. We may not be able to set the volume 318 // Saves the volume to a member first. We may not be able to set the volume
318 // right away but when the stream is created we'll set the volume. 319 // right away but when the stream is created we'll set the volume.
319 volume_ = volume; 320 volume_ = volume;
320 321
321 switch (state_) { 322 switch (state_) {
322 case kCreated: 323 case kCreated:
323 case kStarting: 324 case kStarting:
324 case kPausedWhenStarting: 325 case kPausedWhenStarting:
325 case kPlaying: 326 case kPlaying:
326 case kPaused: 327 case kPaused:
327 stream_->SetVolume(volume_); 328 stream_->SetVolume(volume_);
328 break; 329 break;
329 default: 330 default:
330 return; 331 return;
331 } 332 }
332 } 333 }
333 334
334 void AudioOutputController::DoReportError(int code) { 335 void AudioOutputController::DoReportError(int code) {
335 DCHECK_EQ(message_loop_, MessageLoop::current()); 336 DCHECK(message_loop_->BelongsToCurrentThread());
336 if (state_ != kClosed) 337 if (state_ != kClosed)
337 handler_->OnError(this, code); 338 handler_->OnError(this, code);
338 } 339 }
339 340
340 uint32 AudioOutputController::OnMoreData( 341 uint32 AudioOutputController::OnMoreData(
341 AudioOutputStream* stream, uint8* dest, 342 AudioOutputStream* stream, uint8* dest,
342 uint32 max_size, AudioBuffersState buffers_state) { 343 uint32 max_size, AudioBuffersState buffers_state) {
343 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); 344 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");
344 345
345 // If regular latency mode is used. 346 // If regular latency mode is used.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 buffers_state.pending_bytes += buffer_.forward_bytes(); 409 buffers_state.pending_bytes += buffer_.forward_bytes();
409 410
410 // If we need more data then call the event handler to ask for more data. 411 // If we need more data then call the event handler to ask for more data.
411 // It is okay that we don't lock in this block because the parameters are 412 // It is okay that we don't lock in this block because the parameters are
412 // correct and in the worst case we are just asking more data than needed. 413 // correct and in the worst case we are just asking more data than needed.
413 base::AutoUnlock auto_unlock(lock_); 414 base::AutoUnlock auto_unlock(lock_);
414 handler_->OnMoreData(this, buffers_state); 415 handler_->OnMoreData(this, buffers_state);
415 } 416 }
416 417
417 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) { 418 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) {
418 DCHECK_EQ(message_loop_, MessageLoop::current()); 419 DCHECK(message_loop_->BelongsToCurrentThread());
419 420
420 // Allow calling unconditionally and bail if we don't have a stream_ to close. 421 // Allow calling unconditionally and bail if we don't have a stream_ to close.
421 if (stream_ != NULL) { 422 if (stream_ != NULL) {
422 stream_->Stop(); 423 stream_->Stop();
423 stream_->Close(); 424 stream_->Close();
424 stream_ = NULL; 425 stream_ = NULL;
425 weak_this_.InvalidateWeakPtrs(); 426 weak_this_.InvalidateWeakPtrs();
426 } 427 }
427 428
428 // Should be last in the method, do not touch "this" from here on. 429 // Should be last in the method, do not touch "this" from here on.
429 if (done != NULL) 430 if (done != NULL)
430 done->Signal(); 431 done->Signal();
431 } 432 }
432 433
433 } // namespace media 434 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_dispatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698