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