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..ac1ca355eb0110da0becb6fd79b57fef080f1d50 100644 |
| --- a/media/audio/audio_output_controller.cc |
| +++ b/media/audio/audio_output_controller.cc |
| @@ -29,6 +29,7 @@ AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
| const AudioParameters& params, |
| SyncReader* sync_reader) |
| : audio_manager_(audio_manager), |
| + params_(params), |
| handler_(handler), |
| stream_(NULL), |
| volume_(1.0), |
| @@ -36,7 +37,6 @@ AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
| sync_reader_(sync_reader), |
| message_loop_(audio_manager->GetMessageLoop()), |
| number_polling_attempts_left_(0), |
| - params_(params), |
| ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { |
| } |
| @@ -70,13 +70,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; |
| } |
| @@ -138,10 +135,9 @@ void AudioOutputController::DoCreate() { |
| return; |
| } |
| - // Everything started okay, so register for state change callbacks if we have |
| - // not already done so. |
| - if (state_ != kRecreating) |
| - audio_manager_->AddOutputDeviceChangeListener(this); |
| + // Everything started okay, so re-register for state change callbacks (the |
| + // call to DoStopCloseAndClearStream() above de-registered this instance). |
| + audio_manager_->AddOutputDeviceChangeListener(this); |
|
DaleCurtis
2012/12/05 23:35:14
I don't see where you're removing the device chang
miu
2012/12/11 02:30:45
The call to DoStopCloseAndClearStream() above call
|
| // We have successfully opened the stream. Set the initial volume. |
| stream_->SetVolume(volume_); |
| @@ -215,7 +211,8 @@ void AudioOutputController::StartStream() { |
| state_ = kPlaying; |
| // We start the AudioOutputStream lazily. |
| - stream_->Start(this); |
| + if (stream_) |
|
DaleCurtis
2012/12/05 23:35:14
stream_ should always be valid here. why not check
miu
2012/12/11 02:30:45
I had changed the semantics so that stream_ is NUL
|
| + stream_->Start(this); |
| // Tell the event handler that we are now playing. |
| handler_->OnPlaying(this); |
| @@ -305,11 +302,12 @@ int AudioOutputController::OnMoreIOData(AudioBus* source, |
| TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); |
| { |
| - // Check state and do nothing if we are not playing. |
| + // Check state. When not playing, fill the destination with zeros. |
| // We are on the hardware audio thread, so lock is needed. |
| base::AutoLock auto_lock(lock_); |
| if (state_ != kPlaying) { |
| - return 0; |
| + dest->Zero(); |
| + return dest->frames(); |
| } |
| } |
| @@ -353,7 +351,6 @@ void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { |
| stream_ = NULL; |
| audio_manager_->RemoveOutputDeviceChangeListener(this); |
| - audio_manager_ = NULL; |
| weak_this_.InvalidateWeakPtrs(); |
| } |
| @@ -366,16 +363,11 @@ void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { |
| void AudioOutputController::OnDeviceChange() { |
| DCHECK(message_loop_->BelongsToCurrentThread()); |
| - // We should always have a stream by this point. |
|
DaleCurtis
2012/12/05 23:35:14
Is this not true anymore?
miu
2012/12/11 02:30:45
Done. (Reverted back to original behavior.)
|
| - CHECK(stream_); |
| - |
| - // Preserve the original state and shutdown the stream. |
| + // Preserve the original state. |
| 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. |
| state_ = kRecreating; |
| DoCreate(); |
| if (!stream_ || state_ == kError) |
| @@ -385,6 +377,7 @@ void AudioOutputController::OnDeviceChange() { |
| switch (original_state) { |
| case kStarting: |
| case kPlaying: |
| + DoSetVolume(volume_); |
| DoPlay(); |
| return; |
| case kCreated: |
| @@ -397,4 +390,39 @@ void AudioOutputController::OnDeviceChange() { |
| } |
| } |
| +AudioOutputStream::AudioSourceCallback* AudioOutputController::Divert() { |
| + // Assumption: AudioRendererHost is calling this method on the IO |
| + // BrowserThread. |
| + DCHECK(!message_loop_->BelongsToCurrentThread()); |
|
DaleCurtis
2012/12/05 23:35:14
Is this helpful? It doesn't really matter what thr
miu
2012/12/11 02:30:45
Done.
|
| + |
| + // Block until stream closure is complete because, otherwise, it's possible |
| + // for two entities to be pulling audio data at the same time. In addition, |
| + // a side effect of closing the stream is that this controller will be |
| + // de-registered from device change events (from AudioManager) during the |
| + // "divert." |
| + base::WaitableEvent blocker(true, false); |
| + message_loop_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&AudioOutputController::DoStopCloseAndClearStream, this, |
| + &blocker)); |
| + blocker.Wait(); |
|
DaleCurtis
2012/12/05 23:35:14
Hmmm, seems risky. You're blocking the IO thread w
miu
2012/12/11 02:30:45
I changed my approach, and came up with something
|
| + |
| + return this; |
| +} |
| + |
| +void AudioOutputController::Revert( |
| + AudioOutputStream::AudioSourceCallback* asc) { |
| + // Assumption: AudioRendererHost is calling this method on the IO |
| + // BrowserThread. |
| + DCHECK(!message_loop_->BelongsToCurrentThread()); |
| + |
| + DCHECK_EQ(this, asc); |
|
DaleCurtis
2012/12/05 23:35:14
Again seems odd.
miu
2012/12/11 02:30:45
Done.
|
| + |
| + // The following re-creates the normal audio output stream and places it in |
| + // the correct playback state. It also re-registers this controller for |
| + // device change events from AudioManager. |
| + message_loop_->PostTask( |
| + FROM_HERE, base::Bind(&AudioOutputController::OnDeviceChange, this)); |
| +} |
| + |
| } // namespace media |