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