Chromium Code Reviews| Index: media/audio/audio_output_controller.cc |
| diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc |
| index 50850c9265cdd2b0f503e97994a122b70167047d..1375c5d0d303b1028f833586ac6dff84b9b83c34 100644 |
| --- a/media/audio/audio_output_controller.cc |
| +++ b/media/audio/audio_output_controller.cc |
| @@ -29,15 +29,19 @@ AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
| const AudioParameters& params, |
| SyncReader* sync_reader) |
| : audio_manager_(audio_manager), |
| + params_(params), |
| handler_(handler), |
| stream_(NULL), |
| + diverting_to_stream_(NULL), |
| volume_(1.0), |
| state_(kEmpty), |
| sync_reader_(sync_reader), |
| message_loop_(audio_manager->GetMessageLoop()), |
| number_polling_attempts_left_(0), |
| - params_(params), |
| ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { |
| + // This thread-checker is only used to ensure calls to StartDiverting() and |
| + // StopDiverting() are made by the same single outside thread. |
| + divert_thread_checker_.DetachFromThread(); |
| } |
| AudioOutputController::~AudioOutputController() { |
| @@ -70,13 +74,10 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create( |
| if (!params.IsValid() || !audio_manager) |
| return NULL; |
| - // Starts the audio controller thread. |
| scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
| audio_manager, event_handler, params, sync_reader)); |
| - |
| controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
| &AudioOutputController::DoCreate, controller)); |
| - |
| return controller; |
| } |
| @@ -120,7 +121,8 @@ void AudioOutputController::DoCreate() { |
| DCHECK(state_ == kEmpty || state_ == kRecreating) << state_; |
| DoStopCloseAndClearStream(NULL); |
| - stream_ = audio_manager_->MakeAudioOutputStreamProxy(params_); |
| + stream_ = diverting_to_stream_ ? diverting_to_stream_ : |
| + audio_manager_->MakeAudioOutputStreamProxy(params_); |
| if (!stream_) { |
| state_ = kError; |
| @@ -138,9 +140,11 @@ void AudioOutputController::DoCreate() { |
| return; |
| } |
| - // Everything started okay, so register for state change callbacks if we have |
| - // not already done so. |
| - if (state_ != kRecreating) |
| + // Everything started okay, so re-register for state change callbacks if |
| + // stream_ was created via AudioManager. Note: The call to |
| + // DoStopCloseAndClearStream() above called |
| + // RemoveOutputDeviceChangeListener(). |
| + if (stream_ != diverting_to_stream_) |
| audio_manager_->AddOutputDeviceChangeListener(this); |
| // We have successfully opened the stream. Set the initial volume. |
| @@ -348,13 +352,17 @@ void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { |
| // Allow calling unconditionally and bail if we don't have a stream_ to close. |
| if (stream_) { |
| + // De-register from state change callbacks if stream_ was created via |
| + // AudioManager. |
| + if (stream_ != diverting_to_stream_) |
| + audio_manager_->RemoveOutputDeviceChangeListener(this); |
| + |
| stream_->Stop(); |
| stream_->Close(); |
| + if (stream_ == diverting_to_stream_) |
| + diverting_to_stream_ = NULL; |
| stream_ = NULL; |
| - audio_manager_->RemoveOutputDeviceChangeListener(this); |
| - audio_manager_ = NULL; |
| - |
| weak_this_.InvalidateWeakPtrs(); |
| } |
| @@ -366,16 +374,9 @@ void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { |
| void AudioOutputController::OnDeviceChange() { |
| DCHECK(message_loop_->BelongsToCurrentThread()); |
| - // We should always have a stream by this point. |
| - CHECK(stream_); |
| - |
| - // Preserve the original state and shutdown the stream. |
| - State original_state = state_; |
| - stream_->Stop(); |
| - stream_->Close(); |
| - stream_ = NULL; |
| - |
| - // Recreate the stream, exit if we ran into an error. |
| + // Recreate the stream (DoCreate() will first shut down an existing stream). |
| + // Exit if we ran into an error. |
| + const State original_state = state_; |
| state_ = kRecreating; |
| DoCreate(); |
| if (!stream_ || state_ == kError) |
| @@ -397,4 +398,33 @@ void AudioOutputController::OnDeviceChange() { |
| } |
| } |
| +void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) { |
| + if (!message_loop_->BelongsToCurrentThread()) { |
|
DaleCurtis
2013/01/02 21:56:44
This is still odd and inconsistent with the rest o
miu
2013/01/03 22:30:42
Done.
|
| + DCHECK(divert_thread_checker_.CalledOnValidThread()); |
| + message_loop_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&AudioOutputController::StartDiverting, this, to_stream)); |
| + return; |
| + } |
| + |
| + DCHECK(!diverting_to_stream_); |
| + diverting_to_stream_ = to_stream; |
| + DCHECK_NE(kClosed, state_); |
|
DaleCurtis
2013/01/02 21:56:44
Instead of a DHCECK_NE, shouldn't this be an if (s
miu
2013/01/03 22:30:42
Done.
|
| + OnDeviceChange(); |
| +} |
| + |
| +void AudioOutputController::StopDiverting() { |
|
DaleCurtis
2013/01/02 21:56:44
Ditto.
miu
2013/01/03 22:30:42
Done.
|
| + if (!message_loop_->BelongsToCurrentThread()) { |
| + DCHECK(divert_thread_checker_.CalledOnValidThread()); |
| + message_loop_->PostTask( |
| + FROM_HERE, base::Bind(&AudioOutputController::StopDiverting, this)); |
| + return; |
| + } |
| + |
| + if (state_ != kClosed) { |
| + OnDeviceChange(); |
|
DaleCurtis
2013/01/02 21:56:44
This needs a comment since it's subtle that OnDevi
miu
2013/01/03 22:30:42
Done.
|
| + DCHECK(!diverting_to_stream_); |
| + } |
| +} |
| + |
| } // namespace media |