Chromium Code Reviews| 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 |