tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gain_control_impl.cc (12299B)


      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 "modules/audio_processing/gain_control_impl.h"
     12 
     13 #include <algorithm>
     14 #include <array>
     15 #include <cstddef>
     16 #include <cstdint>
     17 #include <optional>
     18 #include <vector>
     19 
     20 #include "api/array_view.h"
     21 #include "api/audio/audio_processing.h"
     22 #include "common_audio/include/audio_util.h"
     23 #include "modules/audio_processing/agc/gain_control.h"
     24 #include "modules/audio_processing/agc/legacy/gain_control.h"
     25 #include "modules/audio_processing/audio_buffer.h"
     26 #include "modules/audio_processing/logging/apm_data_dumper.h"
     27 #include "rtc_base/checks.h"
     28 #include "rtc_base/logging.h"
     29 
     30 namespace webrtc {
     31 
     32 typedef void Handle;
     33 
     34 namespace {
     35 int16_t MapSetting(GainControl::Mode mode) {
     36  switch (mode) {
     37    case GainControl::kAdaptiveAnalog:
     38      return kAgcModeAdaptiveAnalog;
     39    case GainControl::kAdaptiveDigital:
     40      return kAgcModeAdaptiveDigital;
     41    case GainControl::kFixedDigital:
     42      return kAgcModeFixedDigital;
     43  }
     44  RTC_DCHECK_NOTREACHED();
     45  return -1;
     46 }
     47 
     48 // Applies the sub-frame `gains` to all the bands in `out` and clamps the output
     49 // in the signed 16 bit range.
     50 void ApplyDigitalGain(const int32_t gains[11],
     51                      size_t num_bands,
     52                      float* const* out) {
     53  constexpr float kScaling = 1.f / 65536.f;
     54  constexpr int kNumSubSections = 16;
     55  constexpr float kOneByNumSubSections = 1.f / kNumSubSections;
     56 
     57  float gains_scaled[11];
     58  for (int k = 0; k < 11; ++k) {
     59    gains_scaled[k] = gains[k] * kScaling;
     60  }
     61 
     62  for (size_t b = 0; b < num_bands; ++b) {
     63    float* out_band = out[b];
     64    for (int k = 0, sample = 0; k < 10; ++k) {
     65      const float delta =
     66          (gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections;
     67      float gain = gains_scaled[k];
     68      for (int n = 0; n < kNumSubSections; ++n, ++sample) {
     69        RTC_DCHECK_EQ(k * kNumSubSections + n, sample);
     70        out_band[sample] *= gain;
     71        out_band[sample] =
     72            std::min(32767.f, std::max(-32768.f, out_band[sample]));
     73        gain += delta;
     74      }
     75    }
     76  }
     77 }
     78 
     79 }  // namespace
     80 
     81 struct GainControlImpl::MonoAgcState {
     82  MonoAgcState() {
     83    state = WebRtcAgc_Create();
     84    RTC_CHECK(state);
     85  }
     86 
     87  ~MonoAgcState() {
     88    RTC_DCHECK(state);
     89    WebRtcAgc_Free(state);
     90  }
     91 
     92  MonoAgcState(const MonoAgcState&) = delete;
     93  MonoAgcState& operator=(const MonoAgcState&) = delete;
     94  int32_t gains[11];
     95  Handle* state;
     96 };
     97 
     98 int GainControlImpl::instance_counter_ = 0;
     99 
    100 GainControlImpl::GainControlImpl()
    101    : data_dumper_(new ApmDataDumper(instance_counter_)),
    102      mode_(kAdaptiveAnalog),
    103      minimum_capture_level_(0),
    104      maximum_capture_level_(255),
    105      limiter_enabled_(true),
    106      target_level_dbfs_(3),
    107      compression_gain_db_(9),
    108      analog_capture_level_(0),
    109      was_analog_level_set_(false),
    110      stream_is_saturated_(false) {}
    111 
    112 GainControlImpl::~GainControlImpl() = default;
    113 
    114 void GainControlImpl::ProcessRenderAudio(
    115    ArrayView<const int16_t> packed_render_audio) {
    116  for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    117    WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
    118                        packed_render_audio.size());
    119  }
    120 }
    121 
    122 void GainControlImpl::PackRenderAudioBuffer(
    123    const AudioBuffer& audio,
    124    std::vector<int16_t>* packed_buffer) {
    125  RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
    126  std::array<int16_t, AudioBuffer::kMaxSplitFrameLength>
    127      mixed_16_kHz_render_data;
    128  ArrayView<const int16_t> mixed_16_kHz_render(mixed_16_kHz_render_data.data(),
    129                                               audio.num_frames_per_band());
    130  if (audio.num_channels() == 1) {
    131    FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
    132                  audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
    133  } else {
    134    const int num_channels = static_cast<int>(audio.num_channels());
    135    for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
    136      int32_t sum = 0;
    137      for (int ch = 0; ch < num_channels; ++ch) {
    138        sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
    139      }
    140      mixed_16_kHz_render_data[i] = sum / num_channels;
    141    }
    142  }
    143 
    144  packed_buffer->clear();
    145  packed_buffer->insert(
    146      packed_buffer->end(), mixed_16_kHz_render.data(),
    147      (mixed_16_kHz_render.data() + audio.num_frames_per_band()));
    148 }
    149 
    150 int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
    151  RTC_DCHECK(num_proc_channels_);
    152  RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
    153  RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
    154  RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
    155 
    156  int16_t split_band_data[AudioBuffer::kMaxNumBands]
    157                         [AudioBuffer::kMaxSplitFrameLength];
    158  int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
    159      split_band_data[0], split_band_data[1], split_band_data[2]};
    160 
    161  if (mode_ == kAdaptiveAnalog) {
    162    for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    163      capture_levels_[ch] = analog_capture_level_;
    164 
    165      audio.ExportSplitChannelData(ch, split_bands);
    166 
    167      int err =
    168          WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
    169                           audio.num_bands(), audio.num_frames_per_band());
    170 
    171      if (err != AudioProcessing::kNoError) {
    172        return AudioProcessing::kUnspecifiedError;
    173      }
    174    }
    175  } else if (mode_ == kAdaptiveDigital) {
    176    for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    177      int32_t capture_level_out = 0;
    178 
    179      audio.ExportSplitChannelData(ch, split_bands);
    180 
    181      int err =
    182          WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
    183                               audio.num_bands(), audio.num_frames_per_band(),
    184                               analog_capture_level_, &capture_level_out);
    185 
    186      capture_levels_[ch] = capture_level_out;
    187 
    188      if (err != AudioProcessing::kNoError) {
    189        return AudioProcessing::kUnspecifiedError;
    190      }
    191    }
    192  }
    193 
    194  return AudioProcessing::kNoError;
    195 }
    196 
    197 int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
    198                                         bool stream_has_echo) {
    199  if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
    200    return AudioProcessing::kStreamParameterNotSetError;
    201  }
    202 
    203  RTC_DCHECK(num_proc_channels_);
    204  RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
    205                audio->num_frames_per_band());
    206  RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
    207 
    208  stream_is_saturated_ = false;
    209  bool error_reported = false;
    210  for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    211    int16_t split_band_data[AudioBuffer::kMaxNumBands]
    212                           [AudioBuffer::kMaxSplitFrameLength];
    213    int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
    214        split_band_data[0], split_band_data[1], split_band_data[2]};
    215    audio->ExportSplitChannelData(ch, split_bands);
    216 
    217    // The call to stream_has_echo() is ok from a deadlock perspective
    218    // as the capture lock is allready held.
    219    int32_t new_capture_level = 0;
    220    uint8_t saturation_warning = 0;
    221    int err_analyze = WebRtcAgc_Analyze(
    222        mono_agcs_[ch]->state, split_bands, audio->num_bands(),
    223        audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level,
    224        stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains);
    225    capture_levels_[ch] = new_capture_level;
    226 
    227    error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
    228 
    229    stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1;
    230  }
    231 
    232  // Choose the minimun gain for application
    233  size_t index_to_apply = 0;
    234  for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
    235    if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) {
    236      index_to_apply = ch;
    237    }
    238  }
    239 
    240  for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    241    ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(),
    242                     audio->split_bands(ch));
    243  }
    244 
    245  RTC_DCHECK_LT(0ul, *num_proc_channels_);
    246  if (mode_ == kAdaptiveAnalog) {
    247    // Take the analog level to be the minimum accross all channels.
    248    analog_capture_level_ = capture_levels_[0];
    249    for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
    250      analog_capture_level_ =
    251          std::min(analog_capture_level_, capture_levels_[ch]);
    252    }
    253  }
    254 
    255  if (error_reported) {
    256    return AudioProcessing::kUnspecifiedError;
    257  }
    258 
    259  was_analog_level_set_ = false;
    260 
    261  return AudioProcessing::kNoError;
    262 }
    263 
    264 // TODO(ajm): ensure this is called under kAdaptiveAnalog.
    265 int GainControlImpl::set_stream_analog_level(int level) {
    266  data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
    267 
    268  was_analog_level_set_ = true;
    269  if (level < minimum_capture_level_ || level > maximum_capture_level_) {
    270    return AudioProcessing::kBadParameterError;
    271  }
    272  analog_capture_level_ = level;
    273 
    274  return AudioProcessing::kNoError;
    275 }
    276 
    277 int GainControlImpl::stream_analog_level() const {
    278  data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
    279                        &analog_capture_level_);
    280  return analog_capture_level_;
    281 }
    282 
    283 int GainControlImpl::set_mode(Mode mode) {
    284  if (MapSetting(mode) == -1) {
    285    return AudioProcessing::kBadParameterError;
    286  }
    287 
    288  mode_ = mode;
    289  RTC_DCHECK(num_proc_channels_);
    290  RTC_DCHECK(sample_rate_hz_);
    291  Initialize(*num_proc_channels_, *sample_rate_hz_);
    292  return AudioProcessing::kNoError;
    293 }
    294 
    295 int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
    296  if (minimum < 0 || maximum > 65535 || maximum < minimum) {
    297    return AudioProcessing::kBadParameterError;
    298  }
    299 
    300  minimum_capture_level_ = minimum;
    301  maximum_capture_level_ = maximum;
    302 
    303  RTC_DCHECK(num_proc_channels_);
    304  RTC_DCHECK(sample_rate_hz_);
    305  Initialize(*num_proc_channels_, *sample_rate_hz_);
    306  return AudioProcessing::kNoError;
    307 }
    308 
    309 int GainControlImpl::set_target_level_dbfs(int level) {
    310  if (level > 31 || level < 0) {
    311    return AudioProcessing::kBadParameterError;
    312  }
    313  target_level_dbfs_ = level;
    314  return Configure();
    315 }
    316 
    317 int GainControlImpl::set_compression_gain_db(int gain) {
    318  if (gain < 0 || gain > 90) {
    319    RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
    320    return AudioProcessing::kBadParameterError;
    321  }
    322  compression_gain_db_ = gain;
    323  return Configure();
    324 }
    325 
    326 int GainControlImpl::enable_limiter(bool enable) {
    327  limiter_enabled_ = enable;
    328  return Configure();
    329 }
    330 
    331 void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
    332  data_dumper_->InitiateNewSetOfRecordings();
    333 
    334  RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
    335             sample_rate_hz == 48000);
    336 
    337  num_proc_channels_ = num_proc_channels;
    338  sample_rate_hz_ = sample_rate_hz;
    339 
    340  mono_agcs_.resize(*num_proc_channels_);
    341  capture_levels_.resize(*num_proc_channels_);
    342  for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    343    if (!mono_agcs_[ch]) {
    344      mono_agcs_[ch].reset(new MonoAgcState());
    345    }
    346 
    347    int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
    348                               maximum_capture_level_, MapSetting(mode_),
    349                               *sample_rate_hz_);
    350    RTC_DCHECK_EQ(error, 0);
    351    capture_levels_[ch] = analog_capture_level_;
    352  }
    353 
    354  Configure();
    355 }
    356 
    357 int GainControlImpl::Configure() {
    358  WebRtcAgcConfig config;
    359  // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
    360  //            change the interface.
    361  // RTC_DCHECK_LE(target_level_dbfs_, 0);
    362  // config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
    363  config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
    364  config.compressionGaindB = static_cast<int16_t>(compression_gain_db_);
    365  config.limiterEnable = limiter_enabled_;
    366 
    367  int error = AudioProcessing::kNoError;
    368  for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
    369    int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
    370    if (error_ch != AudioProcessing::kNoError) {
    371      error = error_ch;
    372    }
    373  }
    374  return error;
    375 }
    376 }  // namespace webrtc