On the echo suppression echo cancellation (echo suppress)

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/qiuchangyong/article/details/90439000

When look pjproject of source, found that it implements an echo cancellation aectest.c example, it mainly relies Three algorithms (1 = speex, 2 = echo suppress, 3 = WebRtc), which is optional, the actual select one of them.

It calls a command line: aectest -d 100 -a 1 ../bin/orig8.wav ../bin/echo8.wav ../bin/result8.wav

Options -d delay, because the distal end of the incoming reference speech signal is played out of a speaker, the microphone picks up and then read out, there is a delay.

-a option is to select the type of algorithm, which is pjproject echo suppress their own to achieve, in the source echo_suppress.c in. The speex and WebRtc from open source projects move over, placed third_party directory.

This example is useful for learning and research echo cancellation.

Here is the echo suppress echo suppression algorithm, which relies on detecting the occurrence of double-ended (which is a level for continuous to both of the statistical process) is the level of the proximal end of the recording of the sound from the remote end of the sound level comparison, if the utterance distal end, the proximal end of the recorded sound will be inhibited by the process is a process of smooth transition.

This method of inhibition is non-linear, sometimes cause the player to the speakers on and off, but also simple and practical.

A echo_suppress.c realize the older code:

  1. /* $Id: echo_suppress.c 1417 2007-08-16 10:11:44Z bennylp $ */   
  2. /*   
  3.  * Copyright (C) 2003-2007 Benny Prijono <[email protected]>  
  4.  *  
  5.  * This program is free software; you can redistribute it and/or modify  
  6.  * it under the terms of the GNU General Public License as published by  
  7.  * the Free Software Foundation; either version 2 of the License, or  
  8.  * (at your option) any later version.  
  9.  *  
  10.  * This program is distributed in the hope that it will be useful,  
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  13.  * GNU General Public License for more details.  
  14.  *  
  15.  * You should have received a copy of the GNU General Public License  
  16.  * along with this program; if not, write to the Free Software  
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   
  18.  */   
  19. #include <pjmedia/types.h>   
  20. #include <pjmedia/errno.h>   
  21. #include <pjmedia/silencedet.h>   
  22. #include <pj/assert.h>   
  23. #include <pj/lock.h>   
  24. #include <pj/log.h>   
  25. #include <pj/os.h>   
  26. #include <pj/pool.h>   
  27.    
  28. #include "echo_internal.h"   
  29.    
  30. #define THIS_FILE               "echo_suppress.c"   
  31.    
  32.    
  33. /*  
  34.  * Simple echo suppresor  
  35.  */   
  36. typedef struct echo_supp   
  37. {   
  38.     pj_bool_t        suppressing;   
  39.     pjmedia_silence_det * sd;   
  40.     pj_time_val      last_signal;   
  41.     unsigned         samples_per_frame;   
  42.     unsigned         tail_ms;   
  43. } echo_supp;   
  44.    
  45.    
  46.    
  47. /*  
  48.  * Create.   
  49.  */   
  50. PJ_DEF(pj_status_t) echo_supp_create( pj_pool_t *pool,   
  51.                       unsigned clock_rate,   
  52.                       unsigned samples_per_frame,   
  53.                       unsigned tail_ms,   
  54.                       unsigned latency_ms,   
  55.                       unsigned options,   
  56.                       void **p_state )   
  57. {   
  58.     echo_supp *ec;   
  59.     pj_status_t status;   
  60.    
  61.     PJ_UNUSED_ARG(clock_rate);   
  62.     PJ_UNUSED_ARG(options);   
  63.     PJ_UNUSED_ARG(latency_ms);   
  64.    
  65.     ec = PJ_POOL_ZALLOC_T(pool, struct echo_supp);   
  66.     ec->samples_per_frame = samples_per_frame;   
  67.     ec->tail_ms = tail_ms;   
  68.    
  69.     status = pjmedia_silence_det_create(pool, clock_rate, samples_per_frame,   
  70.                     &ec->sd);   
  71.     if (status != PJ_SUCCESS)   
  72.     return status;   
  73.    
  74.     pjmedia_silence_det_set_name(ec->sd, "ecsu%p");   
  75.     pjmedia_silence_det_set_adaptive(ec->sd, PJMEDIA_ECHO_SUPPRESS_THRESHOLD);   
  76.     pjmedia_silence_det_set_params(ec->sd, 100, 500, 3000);   
  77.    
  78.     *p_state = ec;   
  79.     return PJ_SUCCESS;   
  80. }   
  81.    
  82.    
  83. /*  
  84.  * Destroy.   
  85.  */   
  86. PJ_DEF(pj_status_t) echo_supp_destroy(void *state)   
  87. {   
  88.     PJ_UNUSED_ARG(state);   
  89.     return PJ_SUCCESS;   
  90. }   
  91.    
  92.    
  93. /*  
  94.  * Let the AEC knows that a frame has been played to the speaker.  
  95.  */   
  96. PJ_DEF(pj_status_t) echo_supp_playback( void *state,   
  97.                     pj_int16_t *play_frm )   
  98. {   
  99.     echo_supp *ec = (echo_supp*) state;   
  100.     pj_bool_t silence;   
  101.     pj_bool_t last_suppressing = ec->suppressing;   
  102.    
  103.     silence = pjmedia_silence_det_detect(ec->sd, play_frm,   
  104.                      ec->samples_per_frame, NULL);   
  105.    
  106.     ec->suppressing = !silence;   
  107.    
  108.     if (ec->suppressing) {   
  109.     pj_gettimeofday(&ec->last_signal);   
  110.     }   
  111.    
  112.     if (ec->suppressing!=0 && last_suppressing==0) {   
  113.     PJ_LOG(5,(THIS_FILE, "Start suppressing.."));   
  114.     } else if (ec->suppressing==0 && last_suppressing!=0) {   
  115.     PJ_LOG(5,(THIS_FILE, "Stop suppressing.."));   
  116.     }   
  117.    
  118.     return PJ_SUCCESS;   
  119. }   
  120.    
  121.    
  122. /*  
  123.  * Let the AEC knows that a frame has been captured from the microphone.  
  124.  */   
  125. PJ_DEF(pj_status_t) echo_supp_capture( void *state,   
  126.                        pj_int16_t *rec_frm,   
  127.                        unsigned options )   
  128. {   
  129.     echo_supp *ec = (echo_supp*) state;   
  130.     pj_time_val now;   
  131.     unsigned delay_ms;   
  132.    
  133.     PJ_UNUSED_ARG(options);   
  134.    
  135.     pj_gettimeofday(&now);   
  136.    
  137.     PJ_TIME_VAL_SUB(now, ec->last_signal);   
  138.     delay_ms = PJ_TIME_VAL_MSEC(now);   
  139.    
  140.     if (delay_ms < ec->tail_ms) {   
  141. #if defined(PJMEDIA_ECHO_SUPPRESS_FACTOR) && PJMEDIA_ECHO_SUPPRESS_FACTOR!=0   
  142.     unsigned i;   
  143.     for (i=0; i<ec->samples_per_frame; ++i) {   
  144.         rec_frm[i] = (pj_int16_t)(rec_frm[i] >>    
  145.                       PJMEDIA_ECHO_SUPPRESS_FACTOR);   
  146.     }   
  147. #else   
  148.     pjmedia_zero_samples(rec_frm, ec->samples_per_frame);   
  149. #endif   
  150.     }   
  151.    
  152.     return PJ_SUCCESS;   
  153. }   
  154.    
  155.    
  156. /*  
  157.  * Perform echo cancellation.  
  158.  */   
  159. PJ_DEF(pj_status_t) echo_supp_cancel_echo( void *state,   
  160.                        pj_int16_t *rec_frm,   
  161.                        const pj_int16_t *play_frm,   
  162.                        unsigned options,   
  163.                        void *reserved )   
  164. {   
  165.     echo_supp *ec = (echo_supp*) state;   
  166.     pj_bool_t silence;   
  167.    
  168.     PJ_UNUSED_ARG(options);   
  169.     PJ_UNUSED_ARG(reserved);   
  170.    
  171.     silence = pjmedia_silence_det_detect(ec->sd, play_frm,    
  172.                      ec->samples_per_frame, NULL);   
  173.    
  174.     if (!silence) {   
  175. #if defined(PJMEDIA_ECHO_SUPPRESS_FACTOR) && PJMEDIA_ECHO_SUPPRESS_FACTOR!=0   
  176.     unsigned i;   
  177.     for (i=0; i<ec->samples_per_frame; ++i) {   
  178.         rec_frm[i] = (pj_int16_t)(rec_frm[i] >>    
  179.                       PJMEDIA_ECHO_SUPPRESS_FACTOR);   
  180.     }   
  181. #else   
  182.     pjmedia_zero_samples(rec_frm, ec->samples_per_frame);   
  183. #endif   
  184.     }   
  185.    
  186.     return PJ_SUCCESS;   
  187. }   
  188.  

For beginners to see its original appearance, but the implementation of the latest pjproject more complicated.

 

Guess you like

Origin blog.csdn.net/qiuchangyong/article/details/90439000