Android实现声音采集回声与回声消除
作者:大飞飞鱼 发布时间:2022-09-28 12:13:17
本文实例为大家分享了Android实现声音采集回声与回声消除的具体代码,供大家参考,具体内容如下
一、回声产生的原因
回声(或称回音)是指障碍物对声音的反射。声波在遇到障碍物时,一部分声波会穿过障碍物,而另一部分声波会反射回来形成回声。若障碍物具有坚硬光滑的表面易产生回声;反之,具有柔软的表面则易吸收声音;另外,粗糙的表面易散射声音。回声相比那些直接传播的声音所经过的路程更长,所以会比直接传播的声音晚被听到。如果两列声波的时间间隔小于0.1秒,人耳边无法分辨,只能听到被延长的声音。因为室温(20℃)时空气中的声速是343米每秒,所以站在声源处的人要听到回声需要障碍物到声源的距离至少17米。
二、消除回声的原理
很多时候直播有连麦的需求,这时候就需要对采集的声音进行回声消除。当处在连麦的情况下,手机一边播放对方的声音,一边用麦克风进行采集,然后又将采集的声音传送给对方,这样的话对方就会听到自己的回声,由于这个循环回路一直进行,从而就会使得回声越来越多,最后出现嗡鸣声。
回声消除就是在麦克风录制外音的时候去除掉手机自身播放出来的声音,这样就将对方的声音从采集的声音中过滤出去,从而就避免了回声的产生。下面一张图片很好展示了回声消除的机制。
在近端,麦克风会采集到扬声器播放出来的远端声音,假设这路声音为y(n),当然由于需要将远端传来播放出来,我们当然能得到远端传来的声音信号,假设这路声音为x(n)。不难发现x(n)经过扬声器的播放,然后经过空气的传播,最后被麦克风采集,然后变为y(n),x(n)和y(n)具有明显的相关性。假设麦克风采集到的总声音信号为z(n),这时候需要通过自适应滤波器根据x(n)找出z(n)中的y(n),然后从z(n)中过滤掉y(n)。
三、Android 中的声音采集与回声消除
在Android中回声消除可以通过三种方式进行处理:
1、通过VOICE_COMMUNICATION模式进行录音,自动实现回声消除;
2、利用Android自身带的AcousticEchoCanceler进行回声消除处理;
3、使用第三方库(Speex、Webrtc)进行回声消除处理。
使用AudioRecord模式进行录音的时候,需要将AudioManager设置模式为MODE_IN_COMMUNICATION,还需要将麦克风打开。
有一点需要特别注意,音频采样率必须设置8000或者16000,通道数必须设为1个。
AudioManager audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setSpeakerphoneOn(true);
使用AcousticEchoCanceler过程比较简单,录制声音的时候可以通过AudioRecord得到AudioSessionId,在创建AudioTrack的时候也可以传入一个AudioSessionId,这时候将这个统一的AudioSessionId传入AcousticEchoCanceler,那么AcousticEchoCanceler将根据之前讲过的回声消除的原理进行回声消除。
private void initAec(int audioSessionId) {
if(!AudioAecUtils.isAcousticEchoCancelerApproved()) {
aecSwitch.setEnabled(false);
return;
}
aec = AcousticEchoCanceler.create(audioSessionId);
if (aec == null) {
Log.e(TAG, "AcousticEchoCanceler.create failed");
aecSwitch.setEnabled(false);
return;
}
}
private boolean setEnableAec(boolean enable) {
if (aec == null) {
return false;
}
int ret = aec.setEnabled(enable);
if (ret != AudioEffect.SUCCESS) {
Log.e(TAG, "AcousticEchoCanceler.setEnabled failed");
return false;
}
if(enable) {
Log.d(TAG, "Aec On");
} else {
Log.d(TAG, "Aec Off");
}
return true;
}
当使用Speex或者Webrtc第三方库进行回声消除的时候,需要将采集到的音频数据传入作为源数据,需要将此刻播放的音频数据传入作为参考数据,然后还需要传入一个延时间隔,这样第三方库就能工作,从而得到回声消除后的声音。因为播放的声音需要传播,而且麦克风采集声音还有相应的缓冲区,因此需要传入一个延时间隔。关于Speex和Webrtc在github上能找到相应的Android ndk库。
本人对三种方式都进行了尝试,发现第一种效果最好,兼容性也较好,因为手机免提通话的时候就进行了回声消除处理,所以基本上所有的手机是支持的。第二种方式支持的很少,Nexus 5支持第二种方式。理论上第三种方式兼容性最好,但是本人多次实验发现要设置合适的延时间隔很难,有些时候设置好了,但是通话一段时间效果又变差。
四、Android中的声音模式设置与回声消除
在Android系统中有着多种的声音模式,通过AudioManager.setMode()可以设置声音的模式。就像上面回声消除所描述的,通过设置声音模式为MODE_IN_COMMUNICATION,加上一些声音参数的设置可以启动Android自身的硬件回声消除(通话时候的回声消除)。
设置声音模式的时候需要权限“android.permission.MODIFY_AUDIO_SETTINGS”。不同的声音模式声音的输出行为不一样。
当设置为MODE_IN_COMMUNICATION模式时,声音默认是听筒出声,这时候如果是在连麦模式而且主播没有戴耳机的情况下显然这样不符合,这时候需要调用audioManager.setSpeakerphoneOn(true)切换成外放出声。当插上耳机后,声音不需要外放,需要从耳机出声,这样可以设置audioManager.setSpeakerphoneOn(false)。
当声音模式为MODE_NORMAL,没有插耳机的时候声音自动外放,插上耳机声音从耳机出声,不需要进行相应的设置。
来源:https://blog.csdn.net/ababab12345/article/details/119860746


猜你喜欢
- 首先我们先创建项目 注意:创建SpringBoot项目时一定要联网不然会报错项目创建好后我们首先对 application.yml 进行编译
- 案例说明:使用Java实现简单的斗地主洗牌发牌的操作;具体规则:共有54张牌,顺序打乱;三个玩家参与游戏,三人交替摸牌,每人17张牌,最后留
- 设计模式通常分为三个主要类别:创建型模式结构型模式行为型模式。这些模式是用于解决常见的对象导向设计问题的最佳实践。以下是23种常见的设计模式
- java 对象的克隆一、对象的浅克隆(1)需要克隆类需要重写Object类的clone方法,并且实现Cloneable接口(标识接口,无需实
- 在前面介绍的代码中有使用特性,这些特性都是Microsoft定义好的,作为.NET Framework类库的一部分,许多特性都得到了C#编译
- 利用Java,在控制台操作下,编写的五子棋,作为复习二维数组,面向对象等基础知识。w表示白棋,b表示黑棋import java.util.S
- 导入生成器需要的依赖坐标:<dependency> <groupId>com.baomidou</
- 一、面向对象的描述面向对象是一种现在最为流行的程序设计方法,几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的
- 每一个应用程序,其实都会有分享的需求,比如一键分享一篇文章或者一些活动到微博或者微信亦或者是twitter等社交平台,因为人类是社交动物,而
- 一:对象,JavaBean,SpringBean的区别1.什么是JavaBeanjavaBean要求所有属性为私有,该类必须有一个公共无参构
- 前言好几天没写了,工作有点忙,最近工作刚好做一个定时任务统计的,所以就将springboot 如何创建定时任务整理了一下。总的来说,spri
- 使用Android Studio 创建Android项目,分享给大家(1) 说明:还有一部分人在坚持使用 Eclipse ,建议抓紧换掉。使
- Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建
- 一、Bundle进行IPC介绍四大组件中的三大组件(Activity、Service、Receiver)都是支持在Intent中传递Bund
- 本文实例讲述了Android中AlertDialog显示简单和复杂列表的方法。分享给大家供大家参考,具体如下:AlertDialog 显示简
- 目录1 简介2 项目整合2.1 JWT整合2.1.1 JWT工具类2.1.2 Token处理的Filter2.1.3 JWT属性2.2 Sp
- 前情提要我们上节内容学习了如何创建\注册\读取bean我们发现bean对象操作十分的繁琐!所以我们这个章节,就带大家来了解更加简单的bean
- 前言 找工作的时候,曾经用C语言练习过一段时间的算法题目,也在几个还算出名的OJ平台有过还算靠谱的排名。
- 当app中打开了多个activity的时候,由于进入的比较深,所以,很多app不得不让用户一步一步退回到第一个界面(MainActivity
- java使用贪心算法解决电台覆盖问题代码实现/** * 贪心算法实现集合覆盖 */public class Demo { &n