Index: media/audio/audio_power_monitor.cc |
diff --git a/media/audio/audio_power_monitor.cc b/media/audio/audio_power_monitor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a9dce8e256841dcd96d05d7fdca95b15bd717bb3 |
--- /dev/null |
+++ b/media/audio/audio_power_monitor.cc |
@@ -0,0 +1,95 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/audio/audio_power_monitor.h" |
+ |
+#include <cmath> |
+#include <limits> |
+ |
+#include "base/bind.h" |
+#include "base/float_util.h" |
+#include "base/message_loop.h" |
+#include "base/time.h" |
+#include "media/base/audio_bus.h" |
+ |
+namespace media { |
+ |
+// dBFS reference level is 1.0f (the maximum possible value of a sample). |
+static const float kReferenceLevel = 1.0f; |
DaleCurtis
2013/05/16 18:24:45
AudioBus doesn't guarantee 1.0 is maximum. See au
miu
2013/05/16 21:44:11
This is the way dBFS units are defined, not a rest
|
+ |
+const float AudioPowerMonitor::kZeroPowerDBFS = |
+ -std::numeric_limits<float>::infinity(); |
+ |
+const float AudioPowerMonitor::kMaxPowerDBFS = 0.0f; |
+ |
+AudioPowerMonitor::AudioPowerMonitor( |
+ int sample_rate, |
+ const base::TimeDelta& measurement_period, |
+ base::MessageLoop* message_loop, |
+ const PowerMeasurementCallback& callback) |
+ : num_frames_per_callback_(sample_rate * measurement_period.InSecondsF()), |
+ message_loop_(message_loop), |
+ notify_power_level_(callback) { |
+ DCHECK(message_loop_); |
+ DCHECK(!notify_power_level_.is_null()); |
+ ResetScanAccumulations(); |
+} |
+ |
+AudioPowerMonitor::~AudioPowerMonitor() { |
+} |
+ |
+void AudioPowerMonitor::Scan(const AudioBus* buffer, int num_frames) { |
+ if (!buffer) |
DaleCurtis
2013/05/16 18:24:45
Is this ever true?
miu
2013/05/16 21:44:11
Good point. (Left over from AudioSilenceDetector
|
+ return; |
+ DCHECK_LE(num_frames, buffer->frames()); |
+ const int num_channels = buffer->channels(); |
+ if (num_frames <= 0 || num_channels <= 0) |
+ return; |
+ |
+ // The overall goal here is to compute the RMS of the amplitudes over all |
DaleCurtis
2013/05/16 18:24:45
You say RMS, but I see no sqrt() below :)
miu
2013/05/16 21:44:11
The subtlety: RMS is root-mean-square amplitude.
|
+ // channels. An accumulation of sum-of-squares is maintained over one or more |
+ // calls to this method. Then, once a sufficient number of frames have been |
+ // scanned, the accumulated values are converted into dBFS units and a |
+ // callback is attempted. |
+ |
+ // Compute the sum of squared amplitudes for the audio signal in |buffer|. |
+ // |
+ // TODO(miu): Implement optimized SSE/NEON to efficiently calculate |
+ // sum-of-squares (or dot product, for more general-purpose use?) in |
+ // media/base/vector_math. |
+ float sum_of_squares = 0.0f; |
+ for (int i = 0; i < num_channels; ++i) { |
+ const float* p = buffer->channel(i); |
+ const float* const end_of_samples = p + num_frames; |
+ for (; p < end_of_samples; ++p) |
+ sum_of_squares += (*p) * (*p); |
+ } |
+ DCHECK(base::IsFinite(sum_of_squares)); |
+ |
+ // Accumulate with existing values. |
+ sum_of_squares_so_far_ += sum_of_squares / num_channels; |
+ frames_so_far_ += num_frames; |
+ |
+ // Once enough frames have been scanned, try to post a task to run the |
+ // callback with the dBFS result. The posting of the task is guaranteed to be |
+ // non-blocking, and therefore could fail. If that happens, the accumulated |
+ // values will be retained. |
+ if (frames_so_far_ >= num_frames_per_callback_) { |
DaleCurtis
2013/05/16 18:24:45
The way this is written you end up with a stretche
miu
2013/05/16 21:44:11
I put the answer to this in the form of comments i
|
+ const float average_power = sum_of_squares_so_far_ / frames_so_far_; |
+ const float measurement_in_dbfs = |
+ 10.0f * log10(average_power / (kReferenceLevel * kReferenceLevel)); |
DaleCurtis
2013/05/16 18:24:45
10.0? http://en.wikipedia.org/wiki/DBFS says 20.
miu
2013/05/16 21:44:11
20 is for amplitudes. 10 is for power (i.e., ampl
|
+ if (message_loop_->TryPostTask( |
+ FROM_HERE, |
+ base::Bind(notify_power_level_, measurement_in_dbfs))) { |
+ ResetScanAccumulations(); |
+ } |
+ } |
+} |
+ |
+void AudioPowerMonitor::ResetScanAccumulations() { |
+ sum_of_squares_so_far_ = 0.0f; |
+ frames_so_far_ = 0; |
+} |
+ |
+} // namespace media |