1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11f1de5e9f51647f96ef28b50779574f39ac7d678dandrew@webrtc.org#include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
133f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <assert.h>
143f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <string.h>
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16f1de5e9f51647f96ef28b50779574f39ac7d678dandrew@webrtc.org#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
17f1de5e9f51647f96ef28b50779574f39ac7d678dandrew@webrtc.org#include "webrtc/modules/audio_processing/audio_buffer.h"
18f1de5e9f51647f96ef28b50779574f39ac7d678dandrew@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19f1de5e9f51647f96ef28b50779574f39ac7d678dandrew@webrtc.org#include "webrtc/system_wrappers/interface/logging.h"
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgtypedef void Handle;
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace {
263f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.orgint16_t MapSetting(EchoControlMobile::RoutingMode mode) {
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  switch (mode) {
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoControlMobile::kQuietEarpieceOrHeadset:
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return 0;
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoControlMobile::kEarpiece:
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return 1;
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoControlMobile::kLoudEarpiece:
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return 2;
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoControlMobile::kSpeakerphone:
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return 3;
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoControlMobile::kLoudSpeakerphone:
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return 4;
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(false);
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return -1;
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioProcessing::Error MapError(int err) {
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  switch (err) {
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AECM_UNSUPPORTED_FUNCTION_ERROR:
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kUnsupportedFunctionError;
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AECM_NULL_POINTER_ERROR:
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kNullPointerError;
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AECM_BAD_PARAMETER_ERROR:
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kBadParameterError;
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AECM_BAD_PARAMETER_WARNING:
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kBadStreamParameterWarning;
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    default:
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // AECM_UNSPECIFIED_ERROR
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // AECM_UNINITIALIZED_ERROR
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kUnspecifiedError;
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgsize_t EchoControlMobile::echo_path_size_bytes() {
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return WebRtcAecm_echo_path_size_bytes();
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
65a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.orgEchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm,
66a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org                                             CriticalSectionWrapper* crit)
67a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  : ProcessingComponent(),
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    apm_(apm),
69a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org    crit_(crit),
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    routing_mode_(kSpeakerphone),
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    comfort_noise_enabled_(true),
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    external_echo_path_(NULL) {}
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgEchoControlMobileImpl::~EchoControlMobileImpl() {
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (external_echo_path_ != NULL) {
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      delete [] external_echo_path_;
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      external_echo_path_ = NULL;
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled()) {
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNoError;
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->samples_per_split_channel() <= 160);
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->num_channels() == apm_->num_reverse_channels());
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int err = apm_->kNoError;
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The ordering convention must be followed to pass to the correct AECM.
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  size_t handle_index = 0;
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  for (int i = 0; i < apm_->num_output_channels(); i++) {
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (int j = 0; j < audio->num_channels(); j++) {
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      Handle* my_handle = static_cast<Handle*>(handle(handle_index));
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      err = WebRtcAecm_BufferFarend(
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          my_handle,
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          audio->low_pass_split_data(j),
993f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org          static_cast<int16_t>(audio->samples_per_split_channel()));
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (err != apm_->kNoError) {
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return GetHandleError(my_handle);  // TODO(ajm): warning possible?
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      handle_index++;
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled()) {
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNoError;
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!apm_->was_stream_delay_set()) {
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kStreamParameterNotSetError;
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->samples_per_split_channel() <= 160);
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->num_channels() == apm_->num_output_channels());
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int err = apm_->kNoError;
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The ordering convention must be followed to pass to the correct AECM.
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  size_t handle_index = 0;
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  for (int i = 0; i < audio->num_channels(); i++) {
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // TODO(ajm): improve how this works, possibly inside AECM.
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //            This is kind of hacked up.
131785c2fdd22c9ad2d172c0976d1224bbe44073bc7andrew@webrtc.org    const int16_t* noisy = audio->low_pass_reference(i);
1323f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org    int16_t* clean = audio->low_pass_split_data(i);
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (noisy == NULL) {
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      noisy = clean;
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      clean = NULL;
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (int j = 0; j < apm_->num_reverse_channels(); j++) {
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      Handle* my_handle = static_cast<Handle*>(handle(handle_index));
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      err = WebRtcAecm_Process(
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          my_handle,
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          noisy,
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          clean,
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          audio->low_pass_split_data(i),
1443f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org          static_cast<int16_t>(audio->samples_per_split_channel()),
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          apm_->stream_delay_ms());
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (err != apm_->kNoError) {
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return GetHandleError(my_handle);  // TODO(ajm): warning possible?
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      handle_index++;
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::Enable(bool enable) {
159a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Ensure AEC and AECM are not both enabled.
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (enable && apm_->echo_cancellation()->is_enabled()) {
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadParameterError;
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return EnableComponent(enable);
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoControlMobileImpl::is_enabled() const {
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return is_component_enabled();
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
173a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (MapSetting(mode) == -1) {
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadParameterError;
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  routing_mode_ = mode;
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Configure();
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgEchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const {
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return routing_mode_;
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::enable_comfort_noise(bool enable) {
188a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  comfort_noise_enabled_ = enable;
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Configure();
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoControlMobileImpl::is_comfort_noise_enabled() const {
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return comfort_noise_enabled_;
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::SetEchoPath(const void* echo_path,
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       size_t size_bytes) {
199a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (echo_path == NULL) {
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNullPointerError;
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (size_bytes != echo_path_size_bytes()) {
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Size mismatch
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadParameterError;
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (external_echo_path_ == NULL) {
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    external_echo_path_ = new unsigned char[size_bytes];
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memcpy(external_echo_path_, echo_path, size_bytes);
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Initialize();
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::GetEchoPath(void* echo_path,
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       size_t size_bytes) const {
218a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (echo_path == NULL) {
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNullPointerError;
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (size_bytes != echo_path_size_bytes()) {
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Size mismatch
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadParameterError;
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled()) {
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNotEnabledError;
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Get the echo path from the first channel
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  Handle* my_handle = static_cast<Handle*>(handle(0));
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes) != 0) {
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return GetHandleError(my_handle);
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::Initialize() {
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled()) {
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNoError;
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
244467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  if (apm_->proc_sample_rate_hz() > apm_->kSampleRate16kHz) {
245f1de5e9f51647f96ef28b50779574f39ac7d678dandrew@webrtc.org    LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadSampleRateError;
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return ProcessingComponent::Initialize();
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid* EchoControlMobileImpl::CreateHandle() const {
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  Handle* handle = NULL;
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    handle = NULL;
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  } else {
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(handle != NULL);
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return handle;
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
263ffc2de0133683fb103eef61f21134f469bc099dbbjornv@webrtc.orgvoid EchoControlMobileImpl::DestroyHandle(void* handle) const {
264ffc2de0133683fb103eef61f21134f469bc099dbbjornv@webrtc.org  WebRtcAecm_Free(static_cast<Handle*>(handle));
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::InitializeHandle(void* handle) const {
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(handle != NULL);
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  Handle* my_handle = static_cast<Handle*>(handle);
270467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  if (WebRtcAecm_Init(my_handle, apm_->proc_sample_rate_hz()) != 0) {
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return GetHandleError(my_handle);
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (external_echo_path_ != NULL) {
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (WebRtcAecm_InitEchoPath(my_handle,
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                external_echo_path_,
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                echo_path_size_bytes()) != 0) {
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return GetHandleError(my_handle);
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::ConfigureHandle(void* handle) const {
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  AecmConfig config;
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  config.cngMode = comfort_noise_enabled_;
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  config.echoMode = MapSetting(routing_mode_);
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::num_handles_required() const {
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->num_output_channels() *
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         apm_->num_reverse_channels();
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoControlMobileImpl::GetHandleError(void* handle) const {
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(handle != NULL);
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
302