Android实现声音采集回声与回声消除

本文实例为大家分享了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,没有插耳机的时候声音自动外放,插上耳机声音从耳机出声,不需要进行相应的设置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现直接播放麦克风采集到的声音

    本文实例讲述了Android实现直接播放麦克风采集到的声音.分享给大家供大家参考.具体如下: 这是一个直接播放麦克风采集到的声音线程类: class RecordThread extends Thread{ static final int frequency = 44100; static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; static final int audioEncoding

  • Android实现声音采集回声与回声消除

    本文实例为大家分享了Android实现声音采集回声与回声消除的具体代码,供大家参考,具体内容如下 一.回声产生的原因 回声(或称回音)是指障碍物对声音的反射.声波在遇到障碍物时,一部分声波会穿过障碍物,而另一部分声波会反射回来形成回声.若障碍物具有坚硬光滑的表面易产生回声:反之,具有柔软的表面则易吸收声音:另外,粗糙的表面易散射声音.回声相比那些直接传播的声音所经过的路程更长,所以会比直接传播的声音晚被听到.如果两列声波的时间间隔小于0.1秒,人耳边无法分辨,只能听到被延长的声音.因为室温(20

  • Android EasyPlayer声音自动停止、恢复,一键静音等功能

    Android EasyPlayer声音自动停止.恢复,一键静音等功能 我们在开发播放器时,可能会需要静音或者降低音量的功能.比如说某款音乐播放器,当在后台播放时,如果此时有另外的系统通知声音发出,可能播放器会把音量降低,系统声音结束后,再调高:如果有来电了,播放器可能会把音乐暂停,等通话结束后再继续播放.还有,比方说我们在某个场合放个视频,不料音量很大,会引来很多目光(很尴尬),这时候可能我们需要一键静音的功能.那这些功能我们应该如何实现呢? Android播放声音的类为AudioTrack,

  • Android RecyclerView曝光采集的实现方法

    本文实例为大家分享了Android RecyclerView曝光采集的具体代码,供大家参考,具体内容如下 一.背景 近期pm提出需要统计首页商品的曝光亮,由于我们的首页是用的recylerview实现的,这里就来讲下如何使用监听recylerview的滚动事件来实现子view的曝光量统计,我们这里说的view都是列表中的子item条目(子view) 二.监听recylerview的滚动事件OnScrollListener onScrollStateChanged:监听滚动状态onScrolled

  • Android录制声音文件(音频)并播放

    本文实例为大家分享了Android录制音频文件的具体代码,供大家参考,具体内容如下 1.这个demo中没有对多次点击同一个声音文件做详细处理,偶尔会有崩溃,用的时候需要注意. 2.按住录音按钮录音过程中,只对竖直方向处理了一下,水平方向没写: 3.没有做删除某个声音文件的操作,但是测试的时候实现了功能,需要用到的话,在MainActivity->onItemClick中的TODO中有详细说明: 4.这只是个demo,如果要在项目中使用,先写出demo,没问题了,再引入项目,在写成demo后,在真

  • Windows下VScode实现简单回声服务的方法

    目录 1. 相关知识 1.1 什么是回声服务 1.2 服务端.客户端如何交互 2. socket 编程 2.1 服务端 2.2 客户端 3. demo展示 3.1 服务端源代码 3.2 客户端源代码 3.3 运行结果 参考链接 1. 相关知识 1.1 什么是回声服务 回声服务端可以将客户端传来的信息,再原封不动地发送给客户端,因而得名 epoch 服务.服务端 server 和 客户端 client 基于 TCP 进行通信. 1.2 服务端.客户端如何交互 下图给出了基于 TCP 的服务器端和客

  • Android WebRTC 对 AudioRecord 的使用技术分享

    目录 一.创建和初始化 二.启动 三.读数据 四.停止和销毁 前言: AudioRecord 是 Android 基于原始PCM音频数据录制的类,WebRCT 对其封装的代码位置位于org/webrtc/audio/WebRtcAudioRecord.java,接下来我们学习一下 AudioRecord 是如何创建启动,读取音频采集数据以及销毁等功能的. 一.创建和初始化 private int initRecording(int sampleRate, int channels) {    

  • android编程实现电话录音的方法

    本文实例讲述了android编程实现电话录音的方法.分享给大家供大家参考.具体如下: 在清单文件AndroidManifest.xml中添加权限: <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- 在SDCard中创建与删除文件权限 --> <uses-permission android:name="android.permission.MOUN

  • Android提高之蓝牙传感应用实例

    前面文章介绍了Android利用麦克风采集并显示模拟信号的实现方法,这种采集手段适用于无IO控制.单纯读取信号的情况.如果传感器本身需要包含控制电路(例如采集血氧信号需要红外和红外线交替发射),那么传感器本身就需要带一片主控IC,片内采集并输出数字信号了.Android手机如何在不改硬件电路的前提下与这类数字传感器交互呢?可选的通信方式就有USB和蓝牙,两种方式各有好处:USB方式可以给传感器供电,蓝牙方式要自备电源:USB接口标准不一,蓝牙普遍支持SPP协议.本文就选择蓝牙方式做介绍,介绍An

  • Android使用SoundPool播放音效

    本文实例为大家分享了Android使用SoundPool播放音效的具体代码,供大家参考,具体内容如下 SoundPool(int maxStreams, int streamType, int srcQuality) 参数依次是: ①指定支持多少个声音,SoundPool对象中允许同时存在的最大流的数量. ②指定声音类型,流类型可以分为STREAM_VOICE_CALL(通话), STREAM_SYSTEM(系统), STREAM_RING(铃声),STREAM_MUSIC(媒体音量) 和STR

  • iOS视频添加背景音乐同时保留原音

    话不多说,请看代码: //抽取原视频的音频与需要的音乐混合 -(void)addmusic:(id)sender { [MBProgressHUDshowHUDAddedTo:self.viewanimated:YES]; AVMutableComposition *composition =[AVMutableCompositioncomposition]; audioMixParams =[[NSMutableArrayalloc]initWithObjects:nil]; //录制的视频

随机推荐