浅谈回声消除中的回声抑制(echo suppress)
翻看pjproject中的源码,发现它实现了一个回声消除的例子aectest.c,它主要依赖三种算法(1=speex, 2=echo suppress, 3=WebRtc),这是可选的,实际使用时选择其中的一种。
它调用的一个命令行为:aectest -d 100 -a 1 ../bin/orig8.wav ../bin/echo8.wav ../bin/result8.wav
-d选项是延迟,因为远端进来的参考声音信号被扬声器播放出来,再到麦克风拾取后读出来,存在一定的延时。
-a选项是选择算法类型,其中echo suppress是pjproject自己实现的,在源码echo_suppress.c中。而speex和WebRtc是从开源项目中搬过来的,放在了third_party目录下面。
这个例子对于学习和研究回声消除是比较有用的。
这里的echo suppress是回声抑制算法,这个依赖于双端发生检测(这是一个对二者电平进行不断统计的过程),就是将远端传过来的声音的电平与近端录制的声音的电平相比较,如果远端在发声,则将近端录制的声音进行抑制,抑制的过程也是一个平滑过渡的过程。
这种抑制的方法是非线性的,有时候会造成扬声器的播放断断续续,但也简单实用。
一份较老的代码echo_suppress.c实现:
- /* $Id: echo_suppress.c 1417 2007-08-16 10:11:44Z bennylp $ */
- /*
- * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <pjmedia/types.h>
- #include <pjmedia/errno.h>
- #include <pjmedia/silencedet.h>
- #include <pj/assert.h>
- #include <pj/lock.h>
- #include <pj/log.h>
- #include <pj/os.h>
- #include <pj/pool.h>
- #include "echo_internal.h"
- #define THIS_FILE "echo_suppress.c"
- /*
- * Simple echo suppresor
- */
- typedef struct echo_supp
- {
- pj_bool_t suppressing;
- pjmedia_silence_det *sd;
- pj_time_val last_signal;
- unsigned samples_per_frame;
- unsigned tail_ms;
- } echo_supp;
- /*
- * Create.
- */
- PJ_DEF(pj_status_t) echo_supp_create( pj_pool_t *pool,
- unsigned clock_rate,
- unsigned samples_per_frame,
- unsigned tail_ms,
- unsigned latency_ms,
- unsigned options,
- void **p_state )
- {
- echo_supp *ec;
- pj_status_t status;
- PJ_UNUSED_ARG(clock_rate);
- PJ_UNUSED_ARG(options);
- PJ_UNUSED_ARG(latency_ms);
- ec = PJ_POOL_ZALLOC_T(pool, struct echo_supp);
- ec->samples_per_frame = samples_per_frame;
- ec->tail_ms = tail_ms;
- status = pjmedia_silence_det_create(pool, clock_rate, samples_per_frame,
- &ec->sd);
- if (status != PJ_SUCCESS)
- return status;
- pjmedia_silence_det_set_name(ec->sd, "ecsu%p");
- pjmedia_silence_det_set_adaptive(ec->sd, PJMEDIA_ECHO_SUPPRESS_THRESHOLD);
- pjmedia_silence_det_set_params(ec->sd, 100, 500, 3000);
- *p_state = ec;
- return PJ_SUCCESS;
- }
- /*
- * Destroy.
- */
- PJ_DEF(pj_status_t) echo_supp_destroy(void *state)
- {
- PJ_UNUSED_ARG(state);
- return PJ_SUCCESS;
- }
- /*
- * Let the AEC knows that a frame has been played to the speaker.
- */
- PJ_DEF(pj_status_t) echo_supp_playback( void *state,
- pj_int16_t *play_frm )
- {
- echo_supp *ec = (echo_supp*) state;
- pj_bool_t silence;
- pj_bool_t last_suppressing = ec->suppressing;
- silence = pjmedia_silence_det_detect(ec->sd, play_frm,
- ec->samples_per_frame, NULL);
- ec->suppressing = !silence;
- if (ec->suppressing) {
- pj_gettimeofday(&ec->last_signal);
- }
- if (ec->suppressing!=0 && last_suppressing==0) {
- PJ_LOG(5,(THIS_FILE, "Start suppressing.."));
- } else if (ec->suppressing==0 && last_suppressing!=0) {
- PJ_LOG(5,(THIS_FILE, "Stop suppressing.."));
- }
- return PJ_SUCCESS;
- }
- /*
- * Let the AEC knows that a frame has been captured from the microphone.
- */
- PJ_DEF(pj_status_t) echo_supp_capture( void *state,
- pj_int16_t *rec_frm,
- unsigned options )
- {
- echo_supp *ec = (echo_supp*) state;
- pj_time_val now;
- unsigned delay_ms;
- PJ_UNUSED_ARG(options);
- pj_gettimeofday(&now);
- PJ_TIME_VAL_SUB(now, ec->last_signal);
- delay_ms = PJ_TIME_VAL_MSEC(now);
- if (delay_ms < ec->tail_ms) {
- #if defined(PJMEDIA_ECHO_SUPPRESS_FACTOR) && PJMEDIA_ECHO_SUPPRESS_FACTOR!=0
- unsigned i;
- for (i=0; i<ec->samples_per_frame; ++i) {
- rec_frm[i] = (pj_int16_t)(rec_frm[i] >>
- PJMEDIA_ECHO_SUPPRESS_FACTOR);
- }
- #else
- pjmedia_zero_samples(rec_frm, ec->samples_per_frame);
- #endif
- }
- return PJ_SUCCESS;
- }
- /*
- * Perform echo cancellation.
- */
- PJ_DEF(pj_status_t) echo_supp_cancel_echo( void *state,
- pj_int16_t *rec_frm,
- const pj_int16_t *play_frm,
- unsigned options,
- void *reserved )
- {
- echo_supp *ec = (echo_supp*) state;
- pj_bool_t silence;
- PJ_UNUSED_ARG(options);
- PJ_UNUSED_ARG(reserved);
- silence = pjmedia_silence_det_detect(ec->sd, play_frm,
- ec->samples_per_frame, NULL);
- if (!silence) {
- #if defined(PJMEDIA_ECHO_SUPPRESS_FACTOR) && PJMEDIA_ECHO_SUPPRESS_FACTOR!=0
- unsigned i;
- for (i=0; i<ec->samples_per_frame; ++i) {
- rec_frm[i] = (pj_int16_t)(rec_frm[i] >>
- PJMEDIA_ECHO_SUPPRESS_FACTOR);
- }
- #else
- pjmedia_zero_samples(rec_frm, ec->samples_per_frame);
- #endif
- }
- return PJ_SUCCESS;
- }
可供初学者一睹其原貌,但最新的pjproject中的实现就比较复杂。
浅谈回声消除中的回声抑制(echo suppress)相关推荐
- 回声消除中的自适应滤波算法综述
作者:凌逆战 博客园地址:https://www.cnblogs.com/LXP-Never/p/11773190.html 自适应回声消除原理 声学回声是指扬声器播出的声音在接受者听到的同时,也通过 ...
- 运用计算机优化教学的方法,浅谈计算机教学中多种教学方法优化运用.doc
浅谈计算机教学中多种教学方法优化运用 浅谈计算机教学中多种教学方法优化运用 摘 要:每一种教学方法各有其优越性,也各有其局限性,正如一把钥匙不能打开所有的锁一样,所以对于不同特点的学生群体,不同特点的 ...
- mysql declare与set的区别_浅谈MySQL存储过程中declare和set定义变量的区别
在存储过程中常看到declare定义的变量和@set定义的变量.简单的来说,declare定义的类似是局部变量,@set定义的类似全局变量. 1.declare定义的变量类似java类中的局部变量,仅 ...
- 浅谈单片机程序设计中的“分层思想”!
浅谈单片机程序设计中的"分层思想",并不是什么神秘的东西,事实上很多做项目的工程师本身自己也会在用.看了不少帖子都发现没有提及这个东西,然而分层结构确是很有用的东西,参透后会有一种 ...
- 浅谈网络爬虫中广度优先算法和代码实现
前几天给大家分享了网络爬虫中深度优先算法的介绍及其代码实现过程,没来得及上车的小伙伴们可以戳这篇文章--浅谈网络爬虫中深度优先算法和简单代码实现.今天小编给大家分享网络爬虫中广度优先算法的介绍及其代码 ...
- 浅谈软件性能测试中关键指标的监控与分析(转)
浅谈软件性能测试中关键指标的监控与分析 一.软件性能测试需要监控哪些关键指标? 软件性能测试的目的主要有以下三点: Ø 评价系统当前性能,判断系统是否满足预期的性能需求. Ø 寻找软件系统可能存在 ...
- php hasmany,浅谈laravel orm 中的一对多关系 hasMany
个人对于laravel orm 中对于一对多关系的理解 文章表 article,文章自然可以评论,表 comment 记录文章的评论,文章和评论的关系就是一对多,一篇文章可以有多个评论. 在 comm ...
- mysql key_len_浅谈mysql explain中key_len的计算方法
mysql的explain命令可以分析sql的性能,其中有一项是key_len(索引的长度)的统计.本文将分析mysql explain中key_len的计算方法. 1.创建测试表及数据 CREATE ...
- 事物日志恢复 mysql_浅谈SQL Server中的事务日志(五)----日志在高可用和灾难恢复中的作用...
本篇文章是系列文章中的第五篇,是对前一个日志系列的补充篇.如果您对日志的基本概念还没有一个比较系统的了解,可以参看本系列之前的文章: 浅谈SQL Server中的事务日志(一)----事务日志的物理和 ...
最新文章
- ELK 搭建 TB 级海量日志监控系统,这个太强了!
- 合并果子(NOIP2004)
- 【Python】编程笔记6
- linux 系统安装mongodb数据库---方法2
- leetcode 480. 滑动窗口中位数(堆+滑动窗口)
- [react-router] 在history模式中push和replace有什么区别?
- 41%的网络保险理赔和勒索软件有关
- NYOJ455 - 黑色帽子
- 8.确保0对于值类型是有效的
- 《编写可维护的 JavaScript》读书笔记第7章:事件处理
- 【Gym-100889 H】Hitting Points【凸包三分】
- openGauss企业级开源数据库获第十届中国电子信息博览会金奖
- Java面向对象通讯录程序
- Java Wbe开发快速入门
- 贝叶斯公式:通俗的理解
- 海量数据处理技巧-转载
- 硬件知识:固态硬盘和机械硬盘区别
- matlab的数字图像处理,基于MATLAB的数字图像处理分析及应用.pdf
- MarkdownPad2行内公式如何用`$$`替代`\\(\\)`---MathJax风格化配置
- 基于python机票预定系统_机票预订系统课程设计.doc