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

 更新时间:2021年08月25日 10:21:08   作者:大飞飞鱼  
这篇文章主要为大家详细介绍了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,没有插耳机的时候声音自动外放,插上耳机声音从耳机出声,不需要进行相应的设置。

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

相关文章

  • Android自定义滚动选择器实例代码

    Android自定义滚动选择器实例代码

    本篇文章主要介绍了Android自定义滚动选择器实例代码,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • 详解Android UI更新的几种方法

    详解Android UI更新的几种方法

    本篇文章主要介绍了Android UI更新的几种方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Android WebView的使用方法及与JS 相互调用

    Android WebView的使用方法及与JS 相互调用

    这篇文章主要介绍了Android WebView的使用方法及与JS 相互调用的相关资料,WebView 是 Android 中一个非常实用的组​件, WebView 可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用,需要的朋友可以参考下
    2017-07-07
  • 安卓开发之mqtt协议实例代码

    安卓开发之mqtt协议实例代码

    下面小编就为大家分享一篇安卓开发之mqtt协议实例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • flutter 常见圆角处理示例详解

    flutter 常见圆角处理示例详解

    这篇文章主要介绍了flutter 常见圆角处理示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 详解Android更改APP语言模式的实现过程

    详解Android更改APP语言模式的实现过程

    本文详细介绍如何更改Android中APP的语言模式,这个功能对于大家开发Android APP很有帮助,本文运用文字介绍和代码示例把过程写的很详细,有需要的可以参考借鉴。
    2016-08-08
  • android textview设置字体的行距和字间距

    android textview设置字体的行距和字间距

    这篇文章主要介绍了android textview设置字体的行距和字间距的方法,非常简单实用,有需要的小伙伴可以参考下
    2016-05-05
  • android LabelView实现标签云效果

    android LabelView实现标签云效果

    这篇文章主要为大家详细介绍了android LabelView实现标签云效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Android NDK开发之:配置环境的详解

    Android NDK开发之:配置环境的详解

    本篇文章是对Android中的配置环境进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Android实现简易计算器(可以实现连续计算)

    Android实现简易计算器(可以实现连续计算)

    这篇文章主要为大家详细介绍了Android实现简易计算器,可以实现连续计算,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03

最新评论