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