LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_processing - echo_control_mobile_impl.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 197 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
      12             : 
      13             : #include <string.h>
      14             : 
      15             : #include "webrtc/base/constructormagic.h"
      16             : #include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h"
      17             : #include "webrtc/modules/audio_processing/audio_buffer.h"
      18             : #include "webrtc/system_wrappers/include/logging.h"
      19             : 
      20             : namespace webrtc {
      21             : 
      22             : namespace {
      23           0 : int16_t MapSetting(EchoControlMobile::RoutingMode mode) {
      24           0 :   switch (mode) {
      25             :     case EchoControlMobile::kQuietEarpieceOrHeadset:
      26           0 :       return 0;
      27             :     case EchoControlMobile::kEarpiece:
      28           0 :       return 1;
      29             :     case EchoControlMobile::kLoudEarpiece:
      30           0 :       return 2;
      31             :     case EchoControlMobile::kSpeakerphone:
      32           0 :       return 3;
      33             :     case EchoControlMobile::kLoudSpeakerphone:
      34           0 :       return 4;
      35             :   }
      36           0 :   RTC_NOTREACHED();
      37           0 :   return -1;
      38             : }
      39             : 
      40           0 : AudioProcessing::Error MapError(int err) {
      41           0 :   switch (err) {
      42             :     case AECM_UNSUPPORTED_FUNCTION_ERROR:
      43           0 :       return AudioProcessing::kUnsupportedFunctionError;
      44             :     case AECM_NULL_POINTER_ERROR:
      45           0 :       return AudioProcessing::kNullPointerError;
      46             :     case AECM_BAD_PARAMETER_ERROR:
      47           0 :       return AudioProcessing::kBadParameterError;
      48             :     case AECM_BAD_PARAMETER_WARNING:
      49           0 :       return AudioProcessing::kBadStreamParameterWarning;
      50             :     default:
      51             :       // AECM_UNSPECIFIED_ERROR
      52             :       // AECM_UNINITIALIZED_ERROR
      53           0 :       return AudioProcessing::kUnspecifiedError;
      54             :   }
      55             : }
      56             : }  // namespace
      57             : 
      58           0 : size_t EchoControlMobile::echo_path_size_bytes() {
      59           0 :   return WebRtcAecm_echo_path_size_bytes();
      60             : }
      61             : 
      62             : struct EchoControlMobileImpl::StreamProperties {
      63             :   StreamProperties() = delete;
      64           0 :   StreamProperties(int sample_rate_hz,
      65             :                    size_t num_reverse_channels,
      66             :                    size_t num_output_channels)
      67           0 :       : sample_rate_hz(sample_rate_hz),
      68             :         num_reverse_channels(num_reverse_channels),
      69           0 :         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:
      78           0 :   Canceller() {
      79           0 :     state_ = WebRtcAecm_Create();
      80           0 :     RTC_CHECK(state_);
      81           0 :   }
      82             : 
      83           0 :   ~Canceller() {
      84           0 :     RTC_DCHECK(state_);
      85           0 :     WebRtcAecm_Free(state_);
      86           0 :   }
      87             : 
      88           0 :   void* state() {
      89           0 :     RTC_DCHECK(state_);
      90           0 :     return state_;
      91             :   }
      92             : 
      93           0 :   void Initialize(int sample_rate_hz,
      94             :                   unsigned char* external_echo_path,
      95             :                   size_t echo_path_size_bytes) {
      96           0 :     RTC_DCHECK(state_);
      97           0 :     int error = WebRtcAecm_Init(state_, sample_rate_hz);
      98           0 :     RTC_DCHECK_EQ(AudioProcessing::kNoError, error);
      99           0 :     if (external_echo_path != NULL) {
     100           0 :       error = WebRtcAecm_InitEchoPath(state_, external_echo_path,
     101             :                                       echo_path_size_bytes);
     102           0 :       RTC_DCHECK_EQ(AudioProcessing::kNoError, error);
     103             :     }
     104           0 :   }
     105             : 
     106             :  private:
     107             :   void* state_;
     108             :   RTC_DISALLOW_COPY_AND_ASSIGN(Canceller);
     109             : };
     110             : 
     111           0 : EchoControlMobileImpl::EchoControlMobileImpl(rtc::CriticalSection* crit_render,
     112           0 :                                              rtc::CriticalSection* crit_capture)
     113             :     : crit_render_(crit_render),
     114             :       crit_capture_(crit_capture),
     115             :       routing_mode_(kSpeakerphone),
     116             :       comfort_noise_enabled_(true),
     117           0 :       external_echo_path_(NULL) {
     118           0 :   RTC_DCHECK(crit_render);
     119           0 :   RTC_DCHECK(crit_capture);
     120           0 : }
     121             : 
     122           0 : EchoControlMobileImpl::~EchoControlMobileImpl() {
     123           0 :     if (external_echo_path_ != NULL) {
     124           0 :       delete [] external_echo_path_;
     125           0 :       external_echo_path_ = NULL;
     126             :     }
     127           0 : }
     128             : 
     129           0 : void EchoControlMobileImpl::ProcessRenderAudio(
     130             :     rtc::ArrayView<const int16_t> packed_render_audio) {
     131           0 :   rtc::CritScope cs_capture(crit_capture_);
     132           0 :   if (!enabled_) {
     133           0 :     return;
     134             :   }
     135             : 
     136           0 :   RTC_DCHECK(stream_properties_);
     137             : 
     138           0 :   size_t buffer_index = 0;
     139             :   size_t num_frames_per_band =
     140           0 :       packed_render_audio.size() / (stream_properties_->num_output_channels *
     141           0 :                                     stream_properties_->num_reverse_channels);
     142             : 
     143           0 :   for (auto& canceller : cancellers_) {
     144           0 :     WebRtcAecm_BufferFarend(canceller->state(),
     145           0 :                             &packed_render_audio[buffer_index],
     146           0 :                             num_frames_per_band);
     147             : 
     148           0 :     buffer_index += num_frames_per_band;
     149             :   }
     150             : }
     151             : 
     152           0 : void EchoControlMobileImpl::PackRenderAudioBuffer(
     153             :     const AudioBuffer* audio,
     154             :     size_t num_output_channels,
     155             :     size_t num_channels,
     156             :     std::vector<int16_t>* packed_buffer) {
     157           0 :   RTC_DCHECK_GE(160, audio->num_frames_per_band());
     158           0 :   RTC_DCHECK_EQ(num_channels, audio->num_channels());
     159             : 
     160             :   // The ordering convention must be followed to pass to the correct AECM.
     161           0 :   packed_buffer->clear();
     162           0 :   int render_channel = 0;
     163           0 :   for (size_t i = 0; i < num_output_channels; i++) {
     164           0 :     for (size_t j = 0; j < audio->num_channels(); j++) {
     165             :       // Buffer the samples in the render queue.
     166             :       packed_buffer->insert(
     167           0 :           packed_buffer->end(),
     168           0 :           audio->split_bands_const(render_channel)[kBand0To8kHz],
     169           0 :           (audio->split_bands_const(render_channel)[kBand0To8kHz] +
     170           0 :            audio->num_frames_per_band()));
     171           0 :       render_channel = (render_channel + 1) % audio->num_channels();
     172             :     }
     173             :   }
     174           0 : }
     175             : 
     176           0 : size_t EchoControlMobileImpl::NumCancellersRequired(
     177             :     size_t num_output_channels,
     178             :     size_t num_reverse_channels) {
     179           0 :   return num_output_channels * num_reverse_channels;
     180             : }
     181             : 
     182           0 : int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio,
     183             :                                                int stream_delay_ms) {
     184           0 :   rtc::CritScope cs_capture(crit_capture_);
     185           0 :   if (!enabled_) {
     186           0 :     return AudioProcessing::kNoError;
     187             :   }
     188             : 
     189           0 :   RTC_DCHECK(stream_properties_);
     190           0 :   RTC_DCHECK_GE(160, audio->num_frames_per_band());
     191           0 :   RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels);
     192           0 :   RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels *
     193           0 :                                         audio->num_channels());
     194             : 
     195           0 :   int err = AudioProcessing::kNoError;
     196             : 
     197             :   // The ordering convention must be followed to pass to the correct AECM.
     198           0 :   size_t handle_index = 0;
     199           0 :   for (size_t capture = 0; capture < audio->num_channels(); ++capture) {
     200             :     // TODO(ajm): improve how this works, possibly inside AECM.
     201             :     //            This is kind of hacked up.
     202           0 :     const int16_t* noisy = audio->low_pass_reference(capture);
     203           0 :     const int16_t* clean = audio->split_bands_const(capture)[kBand0To8kHz];
     204           0 :     if (noisy == NULL) {
     205           0 :       noisy = clean;
     206           0 :       clean = NULL;
     207             :     }
     208           0 :     for (size_t render = 0; render < stream_properties_->num_reverse_channels;
     209             :          ++render) {
     210           0 :       err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean,
     211           0 :                                audio->split_bands(capture)[kBand0To8kHz],
     212           0 :                                audio->num_frames_per_band(), stream_delay_ms);
     213             : 
     214           0 :       if (err != AudioProcessing::kNoError) {
     215           0 :         return MapError(err);
     216             :       }
     217             : 
     218           0 :       ++handle_index;
     219             :     }
     220           0 :     for (size_t band = 1u; band < audio->num_bands(); ++band) {
     221           0 :       memset(audio->split_bands(capture)[band],
     222             :              0,
     223           0 :              audio->num_frames_per_band() *
     224           0 :                  sizeof(audio->split_bands(capture)[band][0]));
     225             :     }
     226             :   }
     227           0 :   return AudioProcessing::kNoError;
     228             : }
     229             : 
     230           0 : int EchoControlMobileImpl::Enable(bool enable) {
     231             :   // Ensure AEC and AECM are not both enabled.
     232           0 :   rtc::CritScope cs_render(crit_render_);
     233           0 :   rtc::CritScope cs_capture(crit_capture_);
     234           0 :   RTC_DCHECK(stream_properties_);
     235             : 
     236           0 :   if (enable &&
     237           0 :       stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
     238           0 :     return AudioProcessing::kBadSampleRateError;
     239             :   }
     240             : 
     241           0 :   if (enable && !enabled_) {
     242           0 :     enabled_ = enable;  // Must be set before Initialize() is called.
     243             : 
     244             :     // TODO(peah): Simplify once the Enable function has been removed from
     245             :     // the public APM API.
     246           0 :     Initialize(stream_properties_->sample_rate_hz,
     247           0 :                stream_properties_->num_reverse_channels,
     248           0 :                stream_properties_->num_output_channels);
     249             :   } else {
     250           0 :     enabled_ = enable;
     251             :   }
     252           0 :   return AudioProcessing::kNoError;
     253             : }
     254             : 
     255           0 : bool EchoControlMobileImpl::is_enabled() const {
     256           0 :   rtc::CritScope cs(crit_capture_);
     257           0 :   return enabled_;
     258             : }
     259             : 
     260           0 : int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
     261           0 :   if (MapSetting(mode) == -1) {
     262           0 :     return AudioProcessing::kBadParameterError;
     263             :   }
     264             : 
     265             :   {
     266           0 :     rtc::CritScope cs(crit_capture_);
     267           0 :     routing_mode_ = mode;
     268             :   }
     269           0 :   return Configure();
     270             : }
     271             : 
     272           0 : EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
     273             :     const {
     274           0 :   rtc::CritScope cs(crit_capture_);
     275           0 :   return routing_mode_;
     276             : }
     277             : 
     278           0 : int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
     279             :   {
     280           0 :     rtc::CritScope cs(crit_capture_);
     281           0 :     comfort_noise_enabled_ = enable;
     282             :   }
     283           0 :   return Configure();
     284             : }
     285             : 
     286           0 : bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
     287           0 :   rtc::CritScope cs(crit_capture_);
     288           0 :   return comfort_noise_enabled_;
     289             : }
     290             : 
     291           0 : int EchoControlMobileImpl::SetEchoPath(const void* echo_path,
     292             :                                        size_t size_bytes) {
     293             :   {
     294           0 :     rtc::CritScope cs_render(crit_render_);
     295           0 :     rtc::CritScope cs_capture(crit_capture_);
     296           0 :     if (echo_path == NULL) {
     297           0 :       return AudioProcessing::kNullPointerError;
     298             :     }
     299           0 :     if (size_bytes != echo_path_size_bytes()) {
     300             :       // Size mismatch
     301           0 :       return AudioProcessing::kBadParameterError;
     302             :     }
     303             : 
     304           0 :     if (external_echo_path_ == NULL) {
     305           0 :       external_echo_path_ = new unsigned char[size_bytes];
     306             :     }
     307           0 :     memcpy(external_echo_path_, echo_path, size_bytes);
     308             :   }
     309             : 
     310             :   // TODO(peah): Simplify once the Enable function has been removed from
     311             :   // the public APM API.
     312           0 :   RTC_DCHECK(stream_properties_);
     313           0 :   Initialize(stream_properties_->sample_rate_hz,
     314           0 :              stream_properties_->num_reverse_channels,
     315           0 :              stream_properties_->num_output_channels);
     316           0 :   return AudioProcessing::kNoError;
     317             : }
     318             : 
     319           0 : int EchoControlMobileImpl::GetEchoPath(void* echo_path,
     320             :                                        size_t size_bytes) const {
     321           0 :   rtc::CritScope cs(crit_capture_);
     322           0 :   if (echo_path == NULL) {
     323           0 :     return AudioProcessing::kNullPointerError;
     324             :   }
     325           0 :   if (size_bytes != echo_path_size_bytes()) {
     326             :     // Size mismatch
     327           0 :     return AudioProcessing::kBadParameterError;
     328             :   }
     329           0 :   if (!enabled_) {
     330           0 :     return AudioProcessing::kNotEnabledError;
     331             :   }
     332             : 
     333             :   // Get the echo path from the first channel
     334             :   int32_t err =
     335           0 :       WebRtcAecm_GetEchoPath(cancellers_[0]->state(), echo_path, size_bytes);
     336           0 :   if (err != 0) {
     337           0 :     return MapError(err);
     338             :   }
     339             : 
     340           0 :   return AudioProcessing::kNoError;
     341             : }
     342             : 
     343           0 : void EchoControlMobileImpl::Initialize(int sample_rate_hz,
     344             :                                        size_t num_reverse_channels,
     345             :                                        size_t num_output_channels) {
     346           0 :   rtc::CritScope cs_render(crit_render_);
     347           0 :   rtc::CritScope cs_capture(crit_capture_);
     348             : 
     349           0 :   stream_properties_.reset(new StreamProperties(
     350           0 :       sample_rate_hz, num_reverse_channels, num_output_channels));
     351             : 
     352           0 :   if (!enabled_) {
     353           0 :     return;
     354             :   }
     355             : 
     356           0 :   if (stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
     357           0 :     LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
     358             :   }
     359             : 
     360           0 :   cancellers_.resize(
     361           0 :       NumCancellersRequired(stream_properties_->num_output_channels,
     362           0 :                             stream_properties_->num_reverse_channels));
     363             : 
     364           0 :   for (auto& canceller : cancellers_) {
     365           0 :     if (!canceller) {
     366           0 :       canceller.reset(new Canceller());
     367             :     }
     368           0 :     canceller->Initialize(sample_rate_hz, external_echo_path_,
     369           0 :                           echo_path_size_bytes());
     370             :   }
     371             : 
     372           0 :   Configure();
     373             : }
     374             : 
     375           0 : int EchoControlMobileImpl::Configure() {
     376           0 :   rtc::CritScope cs_render(crit_render_);
     377           0 :   rtc::CritScope cs_capture(crit_capture_);
     378             :   AecmConfig config;
     379           0 :   config.cngMode = comfort_noise_enabled_;
     380           0 :   config.echoMode = MapSetting(routing_mode_);
     381           0 :   int error = AudioProcessing::kNoError;
     382           0 :   for (auto& canceller : cancellers_) {
     383           0 :     int handle_error = WebRtcAecm_set_config(canceller->state(), config);
     384           0 :     if (handle_error != AudioProcessing::kNoError) {
     385           0 :       error = handle_error;
     386             :     }
     387             :   }
     388           0 :   return error;
     389             : }
     390             : 
     391             : }  // namespace webrtc

Generated by: LCOV version 1.13