Home | History | Annotate | Download | only in audio
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/audio/audio_power_monitor.h"
      6 
      7 #include <algorithm>
      8 #include <cmath>
      9 
     10 #include "base/float_util.h"
     11 #include "base/logging.h"
     12 #include "base/time/time.h"
     13 #include "media/base/audio_bus.h"
     14 #include "media/base/vector_math.h"
     15 
     16 namespace media {
     17 
     18 AudioPowerMonitor::AudioPowerMonitor(
     19     int sample_rate, const base::TimeDelta& time_constant)
     20     : sample_weight_(
     21           1.0f - expf(-1.0f / (sample_rate * time_constant.InSecondsF()))) {
     22   Reset();
     23 }
     24 
     25 AudioPowerMonitor::~AudioPowerMonitor() {
     26 }
     27 
     28 void AudioPowerMonitor::Reset() {
     29   power_reading_ = average_power_ = 0.0f;
     30   clipped_reading_ = has_clipped_ = false;
     31 }
     32 
     33 void AudioPowerMonitor::Scan(const AudioBus& buffer, int num_frames) {
     34   DCHECK_LE(num_frames, buffer.frames());
     35   const int num_channels = buffer.channels();
     36   if (num_frames <= 0 || num_channels <= 0)
     37     return;
     38 
     39   // Calculate a new average power by applying a first-order low-pass filter
     40   // (a.k.a. an exponentially-weighted moving average) over the audio samples in
     41   // each channel in |buffer|.
     42   float sum_power = 0.0f;
     43   for (int i = 0; i < num_channels; ++i) {
     44     const std::pair<float, float> ewma_and_max = vector_math::EWMAAndMaxPower(
     45         average_power_, buffer.channel(i), num_frames, sample_weight_);
     46     // If data in audio buffer is garbage, ignore its effect on the result.
     47     if (!base::IsFinite(ewma_and_max.first)) {
     48       sum_power += average_power_;
     49     } else {
     50       sum_power += ewma_and_max.first;
     51       has_clipped_ |= (ewma_and_max.second > 1.0f);
     52     }
     53   }
     54 
     55   // Update accumulated results, with clamping for sanity.
     56   average_power_ = std::max(0.0f, std::min(1.0f, sum_power / num_channels));
     57 
     58   // Push results for reading by other threads, non-blocking.
     59   if (reading_lock_.Try()) {
     60     power_reading_ = average_power_;
     61     if (has_clipped_) {
     62       clipped_reading_ = true;
     63       has_clipped_ = false;
     64     }
     65     reading_lock_.Release();
     66   }
     67 }
     68 
     69 std::pair<float, bool> AudioPowerMonitor::ReadCurrentPowerAndClip() {
     70   base::AutoLock for_reading(reading_lock_);
     71 
     72   // Convert power level to dBFS units, and pin it down to zero if it is
     73   // insignificantly small.
     74   const float kInsignificantPower = 1.0e-10f;  // -100 dBFS
     75   const float power_dbfs = power_reading_ < kInsignificantPower ? zero_power() :
     76       10.0f * log10f(power_reading_);
     77 
     78   const bool clipped = clipped_reading_;
     79   clipped_reading_ = false;
     80 
     81   return std::make_pair(power_dbfs, clipped);
     82 }
     83 
     84 }  // namespace media
     85