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