diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-16 01:13:53 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-16 01:13:53 +0000 |
commit | fa71f6840afff9f846471d4eb2e9461c636b0c21 (patch) | |
tree | 6f18ed7c375f5badfc6652a3ee93936aa9317cdc /media/audio/audio_output_controller.cc | |
parent | 2055d3fde0b4ac33bbde4f020bd64d7cd047b3d7 (diff) | |
download | chromium_src-fa71f6840afff9f846471d4eb2e9461c636b0c21.zip chromium_src-fa71f6840afff9f846471d4eb2e9461c636b0c21.tar.gz chromium_src-fa71f6840afff9f846471d4eb2e9461c636b0c21.tar.bz2 |
Make AudioOutputController.Close() truly asynchronous.
Added closed_task parameter in this method. This parameter is used to
notify the caller when the stream is actually closed. Callbacks may
be called until closed_task is executed.
BUG=55755
TEST=Unittests, audio still works, doesn't crash
Review URL: http://codereview.chromium.org/3415007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59600 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/audio_output_controller.cc')
-rw-r--r-- | media/audio/audio_output_controller.cc | 106 |
1 files changed, 46 insertions, 60 deletions
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index 6ff02aa..b3a42e9 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -115,18 +115,12 @@ void AudioOutputController::Flush() { NewRunnableMethod(this, &AudioOutputController::DoFlush)); } -void AudioOutputController::Close() { - { - AutoLock auto_lock(lock_); - // Don't do anything if the stream is already closed. - if (state_ == kClosed) - return; - state_ = kClosed; - } - +void AudioOutputController::Close(Task* closed_task) { + DCHECK(closed_task); + DCHECK(message_loop_); message_loop_->PostTask( FROM_HERE, - NewRunnableMethod(this, &AudioOutputController::DoClose)); + NewRunnableMethod(this, &AudioOutputController::DoClose, closed_task)); } void AudioOutputController::SetVolume(double volume) { @@ -147,8 +141,6 @@ void AudioOutputController::DoCreate(AudioParameters params, uint32 hardware_buffer_size) { DCHECK_EQ(message_loop_, MessageLoop::current()); - AutoLock auto_lock(lock_); - // Close() can be called before DoCreate() is executed. if (state_ == kClosed) return; @@ -180,6 +172,7 @@ void AudioOutputController::DoCreate(AudioParameters params, // If in normal latency mode then start buffering. if (!LowLatencyMode()) { + AutoLock auto_lock(lock_); SubmitOnMoreData_Locked(); } } @@ -187,35 +180,25 @@ void AudioOutputController::DoCreate(AudioParameters params, void AudioOutputController::DoPlay() { DCHECK_EQ(message_loop_, MessageLoop::current()); - { - AutoLock auto_lock(lock_); - // We can start from created or paused state. - if (state_ != kCreated && state_ != kPaused) - return; - state_ = kPlaying; - } + // We can start from created or paused state. + if (state_ != kCreated && state_ != kPaused) + return; + state_ = kPlaying; // We start the AudioOutputStream lazily. stream_->Start(this); - { - AutoLock auto_lock(lock_); - // Tell the event handler that we are now playing. - if (state_ != kClosed) - handler_->OnPlaying(this); - } + // Tell the event handler that we are now playing. + handler_->OnPlaying(this); } void AudioOutputController::DoPause() { DCHECK_EQ(message_loop_, MessageLoop::current()); - { - AutoLock auto_lock(lock_); - // We can pause from started state. - if (state_ != kPlaying) - return; - state_ = kPaused; - } + // We can pause from started state. + if (state_ != kPlaying) + return; + state_ = kPaused; // Then we stop the audio device. This is not the perfect solution because // it discards all the internal buffer in the audio device. @@ -227,11 +210,7 @@ void AudioOutputController::DoPause() { sync_reader_->UpdatePendingBytes(kPauseMark); } - { - AutoLock auto_lock(lock_); - if (state_ != kClosed) - handler_->OnPaused(this); - } + handler_->OnPaused(this); } void AudioOutputController::DoFlush() { @@ -241,23 +220,30 @@ void AudioOutputController::DoFlush() { // If we are in the regular latency mode then flush the push source. if (!sync_reader_) { - AutoLock auto_lock(lock_); if (state_ != kPaused) return; push_source_.ClearAll(); } } -void AudioOutputController::DoClose() { +void AudioOutputController::DoClose(Task* closed_task) { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(kClosed, state_); - // |stream_| can be null if creating the device failed in DoCreate(). - if (stream_) { - stream_->Stop(); - stream_->Close(); - // After stream is closed it is destroyed, so don't keep a reference to it. - stream_ = NULL; + + if (state_ != kClosed) { + // |stream_| can be null if creating the device failed in DoCreate(). + if (stream_) { + stream_->Stop(); + stream_->Close(); + // After stream is closed it is destroyed, so don't keep a reference to + // it. + stream_ = NULL; + } + + state_ = kClosed; } + + closed_task->Run(); + delete closed_task; } void AudioOutputController::DoSetVolume(double volume) { @@ -267,22 +253,16 @@ void AudioOutputController::DoSetVolume(double volume) { // right away but when the stream is created we'll set the volume. volume_ = volume; - { - AutoLock auto_lock(lock_); - if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) - return; - } + if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) + return; stream_->SetVolume(volume_); } void AudioOutputController::DoReportError(int code) { DCHECK_EQ(message_loop_, MessageLoop::current()); - { - AutoLock auto_lock(lock_); - if (state_ != kClosed) - handler_->OnError(this, code); - } + if (state_ != kClosed) + handler_->OnError(this, code); } uint32 AudioOutputController::OnMoreData(AudioOutputStream* stream, @@ -291,8 +271,6 @@ uint32 AudioOutputController::OnMoreData(AudioOutputStream* stream, uint32 pending_bytes) { // If regular latency mode is used. if (!sync_reader_) { - AutoLock auto_lock(lock_); - // Record the callback time. last_callback_time_ = base::Time::Now(); @@ -302,8 +280,10 @@ uint32 AudioOutputController::OnMoreData(AudioOutputStream* stream, return 0; } - // Push source doesn't need to know the stream and number of pending bytes. - // So just pass in NULL and 0. + AutoLock auto_lock(lock_); + + // Push source doesn't need to know the stream and number of pending + // bytes. So just pass in NULL and 0. uint32 size = push_source_.OnMoreData(NULL, dest, max_size, 0); hardware_pending_bytes_ = pending_bytes + size; SubmitOnMoreData_Locked(); @@ -317,6 +297,8 @@ uint32 AudioOutputController::OnMoreData(AudioOutputStream* stream, } void AudioOutputController::OnClose(AudioOutputStream* stream) { + DCHECK_EQ(message_loop_, MessageLoop::current()); + // Push source doesn't need to know the stream so just pass in NULL. if (LowLatencyMode()) { sync_reader_->Close(); @@ -343,6 +325,10 @@ void AudioOutputController::SubmitOnMoreData_Locked() { uint32 pending_bytes = hardware_pending_bytes_ + push_source_.UnProcessedBytes(); + // If we need more data then call the event handler to ask for more data. + // It is okay that we don't lock in this block because the parameters are + // correct and in the worst case we are just asking more data than needed. + AutoUnlock auto_unlock(lock_); handler_->OnMoreData(this, timestamp, pending_bytes); } |