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 915ca35f400fd7a3efe7e8392332731fc4e441e1..329d3212d50a6db65c7f0843228b8a526a2c0b66 100644 |
| --- a/media/audio/audio_output_controller.cc |
| +++ b/media/audio/audio_output_controller.cc |
| @@ -11,9 +11,10 @@ |
| #include "base/threading/platform_thread.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| -#include "media/audio/audio_silence_detector.h" |
| +#include "media/audio/audio_power_monitor.h" |
| #include "media/audio/audio_util.h" |
| #include "media/audio/shared_memory_util.h" |
| +#include "media/base/bind_to_loop.h" |
| #include "media/base/scoped_histogram_timer.h" |
| using base::Time; |
| @@ -21,16 +22,13 @@ using base::TimeDelta; |
| namespace media { |
| -// Amount of contiguous time where all audio is silent before considering the |
| -// stream to have transitioned and EventHandler::OnAudible() should be called. |
| -static const int kQuestionableSilencePeriodMillis = 50; |
| +// Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for |
| +// semantics. This value was arbitrarily chosen, but seems to work well. |
| +static const int kPowerMeasurementTimeConstantMillis = 10; |
| -// Sample value range below which audio is considered indistinguishably silent. |
| -// |
| -// TODO(miu): This value should be specified in dbFS units rather than full |
| -// scale. See TODO in audio_silence_detector.h. |
| -static const float kIndistinguishableSilenceThreshold = |
| - 1.0f / 4096.0f; // Note: This is approximately -72 dbFS. |
| +// Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting |
| +// power levels in the audio signal. |
| +static const int kPowerMeasurementsPerSecond = 30; |
| // Polling-related constants. |
| const int AudioOutputController::kPollNumAttempts = 3; |
| @@ -95,8 +93,10 @@ void AudioOutputController::Pause() { |
| void AudioOutputController::Close(const base::Closure& closed_task) { |
| DCHECK(!closed_task.is_null()); |
| - message_loop_->PostTaskAndReply(FROM_HERE, base::Bind( |
| - &AudioOutputController::DoClose, this), closed_task); |
| + // See comment in DoClose(), which explains why this can't be a simple |
| + // PostTaskAndReply() operation. |
| + message_loop_->PostTask(FROM_HERE, base::Bind( |
| + &AudioOutputController::DoClose, this, BindToCurrentLoop(closed_task))); |
| } |
| void AudioOutputController::SetVolume(double volume) { |
| @@ -158,20 +158,22 @@ void AudioOutputController::DoPlay() { |
| sync_reader_->UpdatePendingBytes(0); |
| state_ = kPlaying; |
| - silence_detector_.reset(new AudioSilenceDetector( |
| + |
| + // Start monitoring power levels and send an initial notification that we're |
| + // starting in silence. |
| + handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false); |
| + power_monitor_.reset(new AudioPowerMonitor( |
| params_.sample_rate(), |
| - TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis), |
| - kIndistinguishableSilenceThreshold)); |
| + TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis), |
| + TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond, |
| + base::MessageLoop::current(), |
| + base::Bind(&EventHandler::OnPowerMeasured, base::Unretained(handler_)))); |
| // We start the AudioOutputStream lazily. |
| AllowEntryToOnMoreIOData(); |
| stream_->Start(this); |
| - // Tell the event handler that we are now playing, and also start the silence |
| - // detection notifications. |
| handler_->OnPlaying(); |
| - silence_detector_->Start( |
| - base::Bind(&EventHandler::OnAudible, base::Unretained(handler_))); |
| } |
| void AudioOutputController::StopStream() { |
| @@ -180,8 +182,9 @@ void AudioOutputController::StopStream() { |
| if (state_ == kPlaying) { |
| stream_->Stop(); |
| DisallowEntryToOnMoreIOData(); |
| - silence_detector_->Stop(true); |
| - silence_detector_.reset(); |
| + power_monitor_.reset(); |
| + // Send a final notification that we're ending in silence. |
| + handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false); |
| state_ = kPaused; |
| } |
| } |
| @@ -201,7 +204,7 @@ void AudioOutputController::DoPause() { |
| handler_->OnPaused(); |
| } |
| -void AudioOutputController::DoClose() { |
| +void AudioOutputController::DoClose(const base::Closure& done_callback) { |
| DCHECK(message_loop_->BelongsToCurrentThread()); |
| SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); |
| @@ -210,6 +213,13 @@ void AudioOutputController::DoClose() { |
| sync_reader_->Close(); |
| state_ = kClosed; |
| } |
| + |
| + // The AudioOutputController is now closed. Until a playing stream was fully |
|
DaleCurtis
2013/07/22 17:27:21
Is it really necessary to send a zero during close
miu
2013/07/22 21:10:48
You're right, this is unnecessary since the final
|
| + // stopped, however, there may have been additional tasks posted to |
| + // |message_loop_| (e.g., by the AudioPowerMonitor). Such tasks may attempt |
| + // to invoke EventHandler methods. Therefore, ensure that |done_callback| is |
| + // run *after* those tasks to guarantee EventHandler remains alive for them. |
| + message_loop_->PostTask(FROM_HERE, done_callback); |
| } |
| void AudioOutputController::DoSetVolume(double volume) { |
| @@ -270,7 +280,7 @@ int AudioOutputController::OnMoreIOData(AudioBus* source, |
| sync_reader_->UpdatePendingBytes( |
| buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); |
| - silence_detector_->Scan(dest, frames); |
| + power_monitor_->Scan(*dest, frames); |
| AllowEntryToOnMoreIOData(); |
| return frames; |