tor-browser

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

echo_control_mobile_impl.cc (9228B)


      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/echo_control_mobile_impl.h"
     12 
     13 #include <array>
     14 #include <cstdint>
     15 #include <cstring>
     16 #include <vector>
     17 
     18 #include "api/array_view.h"
     19 #include "api/audio/audio_processing.h"
     20 #include "common_audio/include/audio_util.h"
     21 #include "modules/audio_processing/aecm/echo_control_mobile.h"
     22 #include "modules/audio_processing/audio_buffer.h"
     23 #include "rtc_base/checks.h"
     24 
     25 namespace webrtc {
     26 
     27 namespace {
     28 int16_t MapSetting(EchoControlMobileImpl::RoutingMode mode) {
     29  switch (mode) {
     30    case EchoControlMobileImpl::kQuietEarpieceOrHeadset:
     31      return 0;
     32    case EchoControlMobileImpl::kEarpiece:
     33      return 1;
     34    case EchoControlMobileImpl::kLoudEarpiece:
     35      return 2;
     36    case EchoControlMobileImpl::kSpeakerphone:
     37      return 3;
     38    case EchoControlMobileImpl::kLoudSpeakerphone:
     39      return 4;
     40  }
     41  RTC_DCHECK_NOTREACHED();
     42  return -1;
     43 }
     44 
     45 AudioProcessing::Error MapError(int err) {
     46  switch (err) {
     47    case AECM_UNSUPPORTED_FUNCTION_ERROR:
     48      return AudioProcessing::kUnsupportedFunctionError;
     49    case AECM_NULL_POINTER_ERROR:
     50      return AudioProcessing::kNullPointerError;
     51    case AECM_BAD_PARAMETER_ERROR:
     52      return AudioProcessing::kBadParameterError;
     53    case AECM_BAD_PARAMETER_WARNING:
     54      return AudioProcessing::kBadStreamParameterWarning;
     55    default:
     56      // AECM_UNSPECIFIED_ERROR
     57      // AECM_UNINITIALIZED_ERROR
     58      return AudioProcessing::kUnspecifiedError;
     59  }
     60 }
     61 
     62 }  // namespace
     63 
     64 struct EchoControlMobileImpl::StreamProperties {
     65  StreamProperties() = delete;
     66  StreamProperties(int sample_rate_hz,
     67                   size_t num_reverse_channels,
     68                   size_t num_output_channels)
     69      : sample_rate_hz(sample_rate_hz),
     70        num_reverse_channels(num_reverse_channels),
     71        num_output_channels(num_output_channels) {}
     72 
     73  int sample_rate_hz;
     74  size_t num_reverse_channels;
     75  size_t num_output_channels;
     76 };
     77 
     78 class EchoControlMobileImpl::Canceller {
     79 public:
     80  Canceller() {
     81    state_ = WebRtcAecm_Create();
     82    RTC_CHECK(state_);
     83  }
     84 
     85  ~Canceller() {
     86    RTC_DCHECK(state_);
     87    WebRtcAecm_Free(state_);
     88  }
     89 
     90  Canceller(const Canceller&) = delete;
     91  Canceller& operator=(const Canceller&) = delete;
     92 
     93  void* state() {
     94    RTC_DCHECK(state_);
     95    return state_;
     96  }
     97 
     98  void Initialize(int sample_rate_hz) {
     99    RTC_DCHECK(state_);
    100    int error = WebRtcAecm_Init(state_, sample_rate_hz);
    101    RTC_DCHECK_EQ(AudioProcessing::kNoError, error);
    102  }
    103 
    104 private:
    105  void* state_;
    106 };
    107 
    108 EchoControlMobileImpl::EchoControlMobileImpl()
    109    : routing_mode_(kSpeakerphone), comfort_noise_enabled_(false) {}
    110 
    111 EchoControlMobileImpl::~EchoControlMobileImpl() {}
    112 
    113 void EchoControlMobileImpl::ProcessRenderAudio(
    114    ArrayView<const int16_t> packed_render_audio) {
    115  RTC_DCHECK(stream_properties_);
    116 
    117  size_t buffer_index = 0;
    118  size_t num_frames_per_band =
    119      packed_render_audio.size() / (stream_properties_->num_output_channels *
    120                                    stream_properties_->num_reverse_channels);
    121 
    122  for (auto& canceller : cancellers_) {
    123    WebRtcAecm_BufferFarend(canceller->state(),
    124                            &packed_render_audio[buffer_index],
    125                            num_frames_per_band);
    126 
    127    buffer_index += num_frames_per_band;
    128  }
    129 }
    130 
    131 void EchoControlMobileImpl::PackRenderAudioBuffer(
    132    const AudioBuffer* audio,
    133    size_t num_output_channels,
    134    size_t num_channels,
    135    std::vector<int16_t>* packed_buffer) {
    136  RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
    137                audio->num_frames_per_band());
    138  RTC_DCHECK_EQ(num_channels, audio->num_channels());
    139 
    140  // The ordering convention must be followed to pass to the correct AECM.
    141  packed_buffer->clear();
    142  int render_channel = 0;
    143  for (size_t i = 0; i < num_output_channels; i++) {
    144    for (size_t j = 0; j < audio->num_channels(); j++) {
    145      std::array<int16_t, AudioBuffer::kMaxSplitFrameLength> data_to_buffer;
    146      FloatS16ToS16(audio->split_bands_const(render_channel)[kBand0To8kHz],
    147                    audio->num_frames_per_band(), data_to_buffer.data());
    148 
    149      // Buffer the samples in the render queue.
    150      packed_buffer->insert(
    151          packed_buffer->end(), data_to_buffer.data(),
    152          data_to_buffer.data() + audio->num_frames_per_band());
    153      render_channel = (render_channel + 1) % audio->num_channels();
    154    }
    155  }
    156 }
    157 
    158 size_t EchoControlMobileImpl::NumCancellersRequired(
    159    size_t num_output_channels,
    160    size_t num_reverse_channels) {
    161  return num_output_channels * num_reverse_channels;
    162 }
    163 
    164 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio,
    165                                               int stream_delay_ms) {
    166  RTC_DCHECK(stream_properties_);
    167  RTC_DCHECK_GE(160, audio->num_frames_per_band());
    168  RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels);
    169  RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels *
    170                                        audio->num_channels());
    171 
    172  int err = AudioProcessing::kNoError;
    173 
    174  // The ordering convention must be followed to pass to the correct AECM.
    175  size_t handle_index = 0;
    176  for (size_t capture = 0; capture < audio->num_channels(); ++capture) {
    177    // TODO(ajm): improve how this works, possibly inside AECM.
    178    //            This is kind of hacked up.
    179    RTC_DCHECK_LT(capture, low_pass_reference_.size());
    180    const int16_t* noisy =
    181        reference_copied_ ? low_pass_reference_[capture].data() : nullptr;
    182 
    183    RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
    184                  audio->num_frames_per_band());
    185 
    186    std::array<int16_t, AudioBuffer::kMaxSplitFrameLength> split_bands_data;
    187    int16_t* split_bands = split_bands_data.data();
    188    const int16_t* clean = split_bands_data.data();
    189    if (audio->split_bands(capture)[kBand0To8kHz]) {
    190      FloatS16ToS16(audio->split_bands(capture)[kBand0To8kHz],
    191                    audio->num_frames_per_band(), split_bands_data.data());
    192    } else {
    193      clean = nullptr;
    194      split_bands = nullptr;
    195    }
    196 
    197    if (noisy == nullptr) {
    198      noisy = clean;
    199      clean = nullptr;
    200    }
    201    for (size_t render = 0; render < stream_properties_->num_reverse_channels;
    202         ++render) {
    203      err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean,
    204                               split_bands, audio->num_frames_per_band(),
    205                               stream_delay_ms);
    206 
    207      if (split_bands) {
    208        S16ToFloatS16(split_bands, audio->num_frames_per_band(),
    209                      audio->split_bands(capture)[kBand0To8kHz]);
    210      }
    211 
    212      if (err != AudioProcessing::kNoError) {
    213        return MapError(err);
    214      }
    215 
    216      ++handle_index;
    217    }
    218    for (size_t band = 1u; band < audio->num_bands(); ++band) {
    219      memset(audio->split_bands_f(capture)[band], 0,
    220             audio->num_frames_per_band() *
    221                 sizeof(audio->split_bands_f(capture)[band][0]));
    222    }
    223  }
    224  return AudioProcessing::kNoError;
    225 }
    226 
    227 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
    228  if (MapSetting(mode) == -1) {
    229    return AudioProcessing::kBadParameterError;
    230  }
    231  routing_mode_ = mode;
    232  return Configure();
    233 }
    234 
    235 EchoControlMobileImpl::RoutingMode EchoControlMobileImpl::routing_mode() const {
    236  return routing_mode_;
    237 }
    238 
    239 int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
    240  comfort_noise_enabled_ = enable;
    241  return Configure();
    242 }
    243 
    244 bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
    245  return comfort_noise_enabled_;
    246 }
    247 
    248 void EchoControlMobileImpl::Initialize(int sample_rate_hz,
    249                                       size_t num_reverse_channels,
    250                                       size_t num_output_channels) {
    251  low_pass_reference_.resize(num_output_channels);
    252  for (auto& reference : low_pass_reference_) {
    253    reference.fill(0);
    254  }
    255 
    256  stream_properties_.reset(new StreamProperties(
    257      sample_rate_hz, num_reverse_channels, num_output_channels));
    258 
    259  // AECM only supports 16 kHz or lower sample rates.
    260  RTC_DCHECK_LE(stream_properties_->sample_rate_hz,
    261                AudioProcessing::kSampleRate16kHz);
    262 
    263  cancellers_.resize(
    264      NumCancellersRequired(stream_properties_->num_output_channels,
    265                            stream_properties_->num_reverse_channels));
    266 
    267  for (auto& canceller : cancellers_) {
    268    if (!canceller) {
    269      canceller.reset(new Canceller());
    270    }
    271    canceller->Initialize(sample_rate_hz);
    272  }
    273  Configure();
    274 }
    275 
    276 int EchoControlMobileImpl::Configure() {
    277  AecmConfig config;
    278  config.cngMode = comfort_noise_enabled_;
    279  config.echoMode = MapSetting(routing_mode_);
    280  int error = AudioProcessing::kNoError;
    281  for (auto& canceller : cancellers_) {
    282    int handle_error = WebRtcAecm_set_config(canceller->state(), config);
    283    if (handle_error != AudioProcessing::kNoError) {
    284      error = handle_error;
    285    }
    286  }
    287  return error;
    288 }
    289 
    290 }  // namespace webrtc