OLD | NEW |
---|---|
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 11 matching lines...) Expand all Loading... | |
22 | 22 |
23 // Polling-related constants. | 23 // Polling-related constants. |
24 const int AudioOutputController::kPollNumAttempts = 3; | 24 const int AudioOutputController::kPollNumAttempts = 3; |
25 const int AudioOutputController::kPollPauseInMilliseconds = 3; | 25 const int AudioOutputController::kPollPauseInMilliseconds = 3; |
26 | 26 |
27 AudioOutputController::AudioOutputController(AudioManager* audio_manager, | 27 AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
28 EventHandler* handler, | 28 EventHandler* handler, |
29 const AudioParameters& params, | 29 const AudioParameters& params, |
30 SyncReader* sync_reader) | 30 SyncReader* sync_reader) |
31 : audio_manager_(audio_manager), | 31 : audio_manager_(audio_manager), |
32 params_(params), | |
32 handler_(handler), | 33 handler_(handler), |
33 stream_(NULL), | 34 stream_(NULL), |
35 diverting_to_stream_(NULL), | |
34 volume_(1.0), | 36 volume_(1.0), |
35 state_(kEmpty), | 37 state_(kEmpty), |
36 sync_reader_(sync_reader), | 38 sync_reader_(sync_reader), |
37 message_loop_(audio_manager->GetMessageLoop()), | 39 message_loop_(audio_manager->GetMessageLoop()), |
38 number_polling_attempts_left_(0), | 40 number_polling_attempts_left_(0), |
39 params_(params), | |
40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { | 41 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { |
41 } | 42 } |
42 | 43 |
43 AudioOutputController::~AudioOutputController() { | 44 AudioOutputController::~AudioOutputController() { |
44 DCHECK_EQ(kClosed, state_); | 45 DCHECK_EQ(kClosed, state_); |
45 | 46 |
46 if (message_loop_->BelongsToCurrentThread()) { | 47 if (message_loop_->BelongsToCurrentThread()) { |
47 DoStopCloseAndClearStream(NULL); | 48 DoStopCloseAndClearStream(NULL); |
48 } else { | 49 } else { |
49 // http://crbug.com/120973 | 50 // http://crbug.com/120973 |
(...skipping 13 matching lines...) Expand all Loading... | |
63 AudioManager* audio_manager, | 64 AudioManager* audio_manager, |
64 EventHandler* event_handler, | 65 EventHandler* event_handler, |
65 const AudioParameters& params, | 66 const AudioParameters& params, |
66 SyncReader* sync_reader) { | 67 SyncReader* sync_reader) { |
67 DCHECK(audio_manager); | 68 DCHECK(audio_manager); |
68 DCHECK(sync_reader); | 69 DCHECK(sync_reader); |
69 | 70 |
70 if (!params.IsValid() || !audio_manager) | 71 if (!params.IsValid() || !audio_manager) |
71 return NULL; | 72 return NULL; |
72 | 73 |
73 // Starts the audio controller thread. | |
74 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 74 scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
75 audio_manager, event_handler, params, sync_reader)); | 75 audio_manager, event_handler, params, sync_reader)); |
76 | |
77 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 76 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
78 &AudioOutputController::DoCreate, controller)); | 77 &AudioOutputController::DoCreate, controller)); |
79 | |
80 return controller; | 78 return controller; |
81 } | 79 } |
82 | 80 |
83 void AudioOutputController::Play() { | 81 void AudioOutputController::Play() { |
84 DCHECK(message_loop_); | 82 DCHECK(message_loop_); |
85 message_loop_->PostTask(FROM_HERE, base::Bind( | 83 message_loop_->PostTask(FROM_HERE, base::Bind( |
86 &AudioOutputController::DoPlay, this)); | 84 &AudioOutputController::DoPlay, this)); |
87 } | 85 } |
88 | 86 |
89 void AudioOutputController::Pause() { | 87 void AudioOutputController::Pause() { |
(...skipping 24 matching lines...) Expand all Loading... | |
114 void AudioOutputController::DoCreate() { | 112 void AudioOutputController::DoCreate() { |
115 DCHECK(message_loop_->BelongsToCurrentThread()); | 113 DCHECK(message_loop_->BelongsToCurrentThread()); |
116 | 114 |
117 // Close() can be called before DoCreate() is executed. | 115 // Close() can be called before DoCreate() is executed. |
118 if (state_ == kClosed) | 116 if (state_ == kClosed) |
119 return; | 117 return; |
120 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_; | 118 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_; |
121 | 119 |
122 DoStopCloseAndClearStream(NULL); // Calls RemoveOutputDeviceChangeListener(). | 120 DoStopCloseAndClearStream(NULL); // Calls RemoveOutputDeviceChangeListener(). |
123 | 121 |
124 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params_); | 122 stream_ = diverting_to_stream_ ? diverting_to_stream_ : |
123 audio_manager_->MakeAudioOutputStreamProxy(params_); | |
125 if (!stream_) { | 124 if (!stream_) { |
126 state_ = kError; | 125 state_ = kError; |
127 | 126 |
128 // TODO(hclam): Define error types. | 127 // TODO(hclam): Define error types. |
129 handler_->OnError(this, 0); | 128 handler_->OnError(this, 0); |
130 return; | 129 return; |
131 } | 130 } |
132 | 131 |
133 if (!stream_->Open()) { | 132 if (!stream_->Open()) { |
134 state_ = kError; | 133 state_ = kError; |
135 DoStopCloseAndClearStream(NULL); | 134 DoStopCloseAndClearStream(NULL); |
136 | 135 |
137 // TODO(hclam): Define error types. | 136 // TODO(hclam): Define error types. |
138 handler_->OnError(this, 0); | 137 handler_->OnError(this, 0); |
139 return; | 138 return; |
140 } | 139 } |
141 | 140 |
142 // Everything started okay, so register for state change callbacks if we have | 141 // Everything started okay, so re-register for state change callbacks if |
143 // not already done so. | 142 // stream_ was created via AudioManager. |
144 audio_manager_->AddOutputDeviceChangeListener(this); | 143 if (stream_ != diverting_to_stream_) |
144 audio_manager_->AddOutputDeviceChangeListener(this); | |
145 | 145 |
146 // We have successfully opened the stream. Set the initial volume. | 146 // We have successfully opened the stream. Set the initial volume. |
147 stream_->SetVolume(volume_); | 147 stream_->SetVolume(volume_); |
148 | 148 |
149 // Finally set the state to kCreated. | 149 // Finally set the state to kCreated. |
150 State original_state = state_; | 150 State original_state = state_; |
151 state_ = kCreated; | 151 state_ = kCreated; |
152 | 152 |
153 // And then report we have been created if we haven't done so already. | 153 // And then report we have been created if we haven't done so already. |
154 if (original_state != kRecreating) | 154 if (original_state != kRecreating) |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
298 int AudioOutputController::OnMoreData(AudioBus* dest, | 298 int AudioOutputController::OnMoreData(AudioBus* dest, |
299 AudioBuffersState buffers_state) { | 299 AudioBuffersState buffers_state) { |
300 return OnMoreIOData(NULL, dest, buffers_state); | 300 return OnMoreIOData(NULL, dest, buffers_state); |
301 } | 301 } |
302 | 302 |
303 int AudioOutputController::OnMoreIOData(AudioBus* source, | 303 int AudioOutputController::OnMoreIOData(AudioBus* source, |
304 AudioBus* dest, | 304 AudioBus* dest, |
305 AudioBuffersState buffers_state) { | 305 AudioBuffersState buffers_state) { |
306 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); | 306 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); |
307 | 307 |
308 { | 308 { |
DaleCurtis
2013/01/08 19:23:33
Can you submit the removal CL for this that we dis
miu
2013/01/09 02:19:41
Done. Thanks for reminding me. Link: http://crbu
| |
309 // Check state and do nothing if we are not playing. | 309 // Check state and do nothing if we are not playing. |
310 // We are on the hardware audio thread, so lock is needed. | 310 // We are on the hardware audio thread, so lock is needed. |
311 base::AutoLock auto_lock(lock_); | 311 base::AutoLock auto_lock(lock_); |
312 if (state_ != kPlaying) { | 312 if (state_ != kPlaying) { |
313 return 0; | 313 return 0; |
314 } | 314 } |
315 } | 315 } |
316 | 316 |
317 int frames = sync_reader_->Read(source, dest); | 317 int frames = sync_reader_->Read(source, dest); |
318 sync_reader_->UpdatePendingBytes( | 318 sync_reader_->UpdatePendingBytes( |
(...skipping 23 matching lines...) Expand all Loading... | |
342 // Handle error on the audio controller thread. | 342 // Handle error on the audio controller thread. |
343 message_loop_->PostTask(FROM_HERE, base::Bind( | 343 message_loop_->PostTask(FROM_HERE, base::Bind( |
344 &AudioOutputController::DoReportError, this, code)); | 344 &AudioOutputController::DoReportError, this, code)); |
345 } | 345 } |
346 | 346 |
347 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { | 347 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { |
348 DCHECK(message_loop_->BelongsToCurrentThread()); | 348 DCHECK(message_loop_->BelongsToCurrentThread()); |
349 | 349 |
350 // Allow calling unconditionally and bail if we don't have a stream_ to close. | 350 // Allow calling unconditionally and bail if we don't have a stream_ to close. |
351 if (stream_) { | 351 if (stream_) { |
352 audio_manager_->RemoveOutputDeviceChangeListener(this); | 352 // De-register from state change callbacks if stream_ was created via |
353 // AudioManager. | |
354 if (stream_ != diverting_to_stream_) | |
355 audio_manager_->RemoveOutputDeviceChangeListener(this); | |
353 | 356 |
354 stream_->Stop(); | 357 stream_->Stop(); |
355 stream_->Close(); | 358 stream_->Close(); |
359 if (stream_ == diverting_to_stream_) | |
360 diverting_to_stream_ = NULL; | |
356 stream_ = NULL; | 361 stream_ = NULL; |
357 | 362 |
358 weak_this_.InvalidateWeakPtrs(); | 363 weak_this_.InvalidateWeakPtrs(); |
359 } | 364 } |
360 | 365 |
361 // Should be last in the method, do not touch "this" from here on. | 366 // Should be last in the method, do not touch "this" from here on. |
362 if (done) | 367 if (done) |
363 done->Signal(); | 368 done->Signal(); |
364 } | 369 } |
365 | 370 |
366 void AudioOutputController::OnDeviceChange() { | 371 void AudioOutputController::OnDeviceChange() { |
367 DCHECK(message_loop_->BelongsToCurrentThread()); | 372 DCHECK(message_loop_->BelongsToCurrentThread()); |
368 | 373 |
369 // We should always have a stream by this point. | |
370 CHECK(stream_); | |
371 | |
372 // Recreate the stream (DoCreate() will first shut down an existing stream). | 374 // Recreate the stream (DoCreate() will first shut down an existing stream). |
373 // Exit if we ran into an error. | 375 // Exit if we ran into an error. |
374 const State original_state = state_; | 376 const State original_state = state_; |
375 state_ = kRecreating; | 377 state_ = kRecreating; |
376 DoCreate(); | 378 DoCreate(); |
377 if (!stream_ || state_ == kError) | 379 if (!stream_ || state_ == kError) |
378 return; | 380 return; |
379 | 381 |
380 // Get us back to the original state or an equivalent state. | 382 // Get us back to the original state or an equivalent state. |
381 switch (original_state) { | 383 switch (original_state) { |
382 case kStarting: | 384 case kStarting: |
383 case kPlaying: | 385 case kPlaying: |
384 DoPlay(); | 386 DoPlay(); |
385 return; | 387 return; |
386 case kCreated: | 388 case kCreated: |
387 case kPausedWhenStarting: | 389 case kPausedWhenStarting: |
388 case kPaused: | 390 case kPaused: |
389 // From the outside these three states are equivalent. | 391 // From the outside these three states are equivalent. |
390 return; | 392 return; |
391 default: | 393 default: |
392 NOTREACHED() << "Invalid original state."; | 394 NOTREACHED() << "Invalid original state."; |
393 } | 395 } |
394 } | 396 } |
395 | 397 |
398 const AudioParameters& AudioOutputController::GetAudioParameters() { | |
399 return params_; | |
400 } | |
401 | |
402 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) { | |
403 message_loop_->PostTask( | |
404 FROM_HERE, | |
405 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream)); | |
406 } | |
407 | |
408 void AudioOutputController::StopDiverting() { | |
409 message_loop_->PostTask( | |
410 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this)); | |
411 } | |
412 | |
413 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) { | |
414 DCHECK(message_loop_->BelongsToCurrentThread()); | |
415 | |
416 if (state_ == kClosed) | |
417 return; | |
418 | |
419 DCHECK(!diverting_to_stream_); | |
420 diverting_to_stream_ = to_stream; | |
421 // Note: OnDeviceChange() will engage the "re-create" process, which will | |
422 // detect and use the alternate AudioOutputStream rather than create a new one | |
423 // via AudioManager. | |
424 OnDeviceChange(); | |
425 } | |
426 | |
427 void AudioOutputController::DoStopDiverting() { | |
428 DCHECK(message_loop_->BelongsToCurrentThread()); | |
429 | |
430 if (state_ == kClosed) | |
431 return; | |
432 | |
433 // Note: OnDeviceChange() will cause the existing stream (the consumer of the | |
434 // diverted audio data) to be closed, and diverting_to_stream_ will be set | |
435 // back to NULL. | |
436 OnDeviceChange(); | |
437 DCHECK(!diverting_to_stream_); | |
438 } | |
439 | |
396 } // namespace media | 440 } // namespace media |
OLD | NEW |