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; |