| 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()) {
|
| + 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_);
|
| + OnDeviceChange();
|
| +}
|
| +
|
| +void AudioOutputController::StopDiverting() {
|
| + if (!message_loop_->BelongsToCurrentThread()) {
|
| + DCHECK(divert_thread_checker_.CalledOnValidThread());
|
| + message_loop_->PostTask(
|
| + FROM_HERE, base::Bind(&AudioOutputController::StopDiverting, this));
|
| + return;
|
| + }
|
| +
|
| + if (state_ != kClosed) {
|
| + OnDeviceChange();
|
| + DCHECK(!diverting_to_stream_);
|
| + }
|
| +}
|
| +
|
| } // namespace media
|
|
|