Home | History | Annotate | Download | only in agc
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/audio_processing/agc/agc.h"
     12 
     13 #include <cmath>
     14 #include <cstdlib>
     15 
     16 #include <algorithm>
     17 #include <vector>
     18 
     19 #include "webrtc/base/checks.h"
     20 #include "webrtc/modules/audio_processing/agc/histogram.h"
     21 #include "webrtc/modules/audio_processing/agc/utility.h"
     22 #include "webrtc/modules/include/module_common_types.h"
     23 
     24 namespace webrtc {
     25 namespace {
     26 
     27 const int kDefaultLevelDbfs = -18;
     28 const int kNumAnalysisFrames = 100;
     29 const double kActivityThreshold = 0.3;
     30 
     31 }  // namespace
     32 
     33 Agc::Agc()
     34     : target_level_loudness_(Dbfs2Loudness(kDefaultLevelDbfs)),
     35       target_level_dbfs_(kDefaultLevelDbfs),
     36       histogram_(Histogram::Create(kNumAnalysisFrames)),
     37       inactive_histogram_(Histogram::Create()) {
     38   }
     39 
     40 Agc::~Agc() {}
     41 
     42 float Agc::AnalyzePreproc(const int16_t* audio, size_t length) {
     43   assert(length > 0);
     44   size_t num_clipped = 0;
     45   for (size_t i = 0; i < length; ++i) {
     46     if (audio[i] == 32767 || audio[i] == -32768)
     47       ++num_clipped;
     48   }
     49   return 1.0f * num_clipped / length;
     50 }
     51 
     52 int Agc::Process(const int16_t* audio, size_t length, int sample_rate_hz) {
     53   vad_.ProcessChunk(audio, length, sample_rate_hz);
     54   const std::vector<double>& rms = vad_.chunkwise_rms();
     55   const std::vector<double>& probabilities =
     56       vad_.chunkwise_voice_probabilities();
     57   RTC_DCHECK_EQ(rms.size(), probabilities.size());
     58   for (size_t i = 0; i < rms.size(); ++i) {
     59     histogram_->Update(rms[i], probabilities[i]);
     60   }
     61   return 0;
     62 }
     63 
     64 bool Agc::GetRmsErrorDb(int* error) {
     65   if (!error) {
     66     assert(false);
     67     return false;
     68   }
     69 
     70   if (histogram_->num_updates() < kNumAnalysisFrames) {
     71     // We haven't yet received enough frames.
     72     return false;
     73   }
     74 
     75   if (histogram_->AudioContent() < kNumAnalysisFrames * kActivityThreshold) {
     76     // We are likely in an inactive segment.
     77     return false;
     78   }
     79 
     80   double loudness = Linear2Loudness(histogram_->CurrentRms());
     81   *error = std::floor(Loudness2Db(target_level_loudness_ - loudness) + 0.5);
     82   histogram_->Reset();
     83   return true;
     84 }
     85 
     86 void Agc::Reset() {
     87   histogram_->Reset();
     88 }
     89 
     90 int Agc::set_target_level_dbfs(int level) {
     91   // TODO(turajs): just some arbitrary sanity check. We can come up with better
     92   // limits. The upper limit should be chosen such that the risk of clipping is
     93   // low. The lower limit should not result in a too quiet signal.
     94   if (level >= 0 || level <= -100)
     95     return -1;
     96   target_level_dbfs_ = level;
     97   target_level_loudness_ = Dbfs2Loudness(level);
     98   return 0;
     99 }
    100 
    101 }  // namespace webrtc
    102