| Index: media/audio/audio_output_controller.cc
|
| diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
|
| index f21da8fb75f429574aa11819d068c06b2a40adc2..e67afbd2ae7a00e7084a5f2f393bfe85c0e8a6f8 100644
|
| --- a/media/audio/audio_output_controller.cc
|
| +++ b/media/audio/audio_output_controller.cc
|
| @@ -137,10 +137,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);
|
|
|
| // We have successfully opened the stream. Set the initial volume.
|
| stream_->SetVolume(volume_);
|
| @@ -304,11 +303,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();
|
| }
|
| }
|
|
|
| @@ -361,16 +361,11 @@ 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.
|
| + // 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)
|
| @@ -392,4 +387,39 @@ void AudioOutputController::OnDeviceChange() {
|
| }
|
| }
|
|
|
| +AudioOutputStream::AudioSourceCallback* AudioOutputController::Divert() {
|
| + // Assumption: AudioRendererHost is calling this method on the IO
|
| + // BrowserThread.
|
| + DCHECK(!message_loop_->BelongsToCurrentThread());
|
| +
|
| + // 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();
|
| +
|
| + 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);
|
| +
|
| + // 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
|
|
|