Android實(shí)現(xiàn)聲音采集回聲與回聲消除
本文實(shí)例為大家分享了Android實(shí)現(xiàn)聲音采集回聲與回聲消除的具體代碼,供大家參考,具體內(nèi)容如下
一、回聲產(chǎn)生的原因
回聲(或稱回音)是指障礙物對(duì)聲音的反射。聲波在遇到障礙物時(shí),一部分聲波會(huì)穿過障礙物,而另一部分聲波會(huì)反射回來形成回聲。若障礙物具有堅(jiān)硬光滑的表面易產(chǎn)生回聲;反之,具有柔軟的表面則易吸收聲音;另外,粗糙的表面易散射聲音?;芈曄啾饶切┲苯觽鞑サ穆曇羲?jīng)過的路程更長,所以會(huì)比直接傳播的聲音晚被聽到。如果兩列聲波的時(shí)間間隔小于0.1秒,人耳邊無法分辨,只能聽到被延長的聲音。因?yàn)槭覝兀?0℃)時(shí)空氣中的聲速是343米每秒,所以站在聲源處的人要聽到回聲需要障礙物到聲源的距離至少17米。
二、消除回聲的原理
很多時(shí)候直播有連麥的需求,這時(shí)候就需要對(duì)采集的聲音進(jìn)行回聲消除。當(dāng)處在連麥的情況下,手機(jī)一邊播放對(duì)方的聲音,一邊用麥克風(fēng)進(jìn)行采集,然后又將采集的聲音傳送給對(duì)方,這樣的話對(duì)方就會(huì)聽到自己的回聲,由于這個(gè)循環(huán)回路一直進(jìn)行,從而就會(huì)使得回聲越來越多,最后出現(xiàn)嗡鳴聲。
回聲消除就是在麥克風(fēng)錄制外音的時(shí)候去除掉手機(jī)自身播放出來的聲音,這樣就將對(duì)方的聲音從采集的聲音中過濾出去,從而就避免了回聲的產(chǎn)生。下面一張圖片很好展示了回聲消除的機(jī)制。
在近端,麥克風(fēng)會(huì)采集到揚(yáng)聲器播放出來的遠(yuǎn)端聲音,假設(shè)這路聲音為y(n),當(dāng)然由于需要將遠(yuǎn)端傳來播放出來,我們當(dāng)然能得到遠(yuǎn)端傳來的聲音信號(hào),假設(shè)這路聲音為x(n)。不難發(fā)現(xiàn)x(n)經(jīng)過揚(yáng)聲器的播放,然后經(jīng)過空氣的傳播,最后被麥克風(fēng)采集,然后變?yōu)閥(n),x(n)和y(n)具有明顯的相關(guān)性。假設(shè)麥克風(fēng)采集到的總聲音信號(hào)為z(n),這時(shí)候需要通過自適應(yīng)濾波器根據(jù)x(n)找出z(n)中的y(n),然后從z(n)中過濾掉y(n)。
三、Android 中的聲音采集與回聲消除
在Android中回聲消除可以通過三種方式進(jìn)行處理:
1、通過VOICE_COMMUNICATION模式進(jìn)行錄音,自動(dòng)實(shí)現(xiàn)回聲消除;
2、利用Android自身帶的AcousticEchoCanceler進(jìn)行回聲消除處理;
3、使用第三方庫(Speex、Webrtc)進(jìn)行回聲消除處理。
使用AudioRecord模式進(jìn)行錄音的時(shí)候,需要將AudioManager設(shè)置模式為MODE_IN_COMMUNICATION,還需要將麥克風(fēng)打開。
有一點(diǎn)需要特別注意,音頻采樣率必須設(shè)置8000或者16000,通道數(shù)必須設(shè)為1個(gè)。
AudioManager audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); audioManager.setSpeakerphoneOn(true);
使用AcousticEchoCanceler過程比較簡單,錄制聲音的時(shí)候可以通過AudioRecord得到AudioSessionId,在創(chuàng)建AudioTrack的時(shí)候也可以傳入一個(gè)AudioSessionId,這時(shí)候?qū)⑦@個(gè)統(tǒng)一的AudioSessionId傳入AcousticEchoCanceler,那么AcousticEchoCanceler將根據(jù)之前講過的回聲消除的原理進(jìn)行回聲消除。
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; }
當(dāng)使用Speex或者Webrtc第三方庫進(jìn)行回聲消除的時(shí)候,需要將采集到的音頻數(shù)據(jù)傳入作為源數(shù)據(jù),需要將此刻播放的音頻數(shù)據(jù)傳入作為參考數(shù)據(jù),然后還需要傳入一個(gè)延時(shí)間隔,這樣第三方庫就能工作,從而得到回聲消除后的聲音。因?yàn)椴シ诺穆曇粜枰獋鞑?,而且麥克風(fēng)采集聲音還有相應(yīng)的緩沖區(qū),因此需要傳入一個(gè)延時(shí)間隔。關(guān)于Speex和Webrtc在github上能找到相應(yīng)的Android ndk庫。
本人對(duì)三種方式都進(jìn)行了嘗試,發(fā)現(xiàn)第一種效果最好,兼容性也較好,因?yàn)槭謾C(jī)免提通話的時(shí)候就進(jìn)行了回聲消除處理,所以基本上所有的手機(jī)是支持的。第二種方式支持的很少,Nexus 5支持第二種方式。理論上第三種方式兼容性最好,但是本人多次實(shí)驗(yàn)發(fā)現(xiàn)要設(shè)置合適的延時(shí)間隔很難,有些時(shí)候設(shè)置好了,但是通話一段時(shí)間效果又變差。
四、Android中的聲音模式設(shè)置與回聲消除
在Android系統(tǒng)中有著多種的聲音模式,通過AudioManager.setMode()可以設(shè)置聲音的模式。就像上面回聲消除所描述的,通過設(shè)置聲音模式為MODE_IN_COMMUNICATION,加上一些聲音參數(shù)的設(shè)置可以啟動(dòng)Android自身的硬件回聲消除(通話時(shí)候的回聲消除)。
設(shè)置聲音模式的時(shí)候需要權(quán)限“android.permission.MODIFY_AUDIO_SETTINGS”。不同的聲音模式聲音的輸出行為不一樣。
當(dāng)設(shè)置為MODE_IN_COMMUNICATION模式時(shí),聲音默認(rèn)是聽筒出聲,這時(shí)候如果是在連麥模式而且主播沒有戴耳機(jī)的情況下顯然這樣不符合,這時(shí)候需要調(diào)用audioManager.setSpeakerphoneOn(true)切換成外放出聲。當(dāng)插上耳機(jī)后,聲音不需要外放,需要從耳機(jī)出聲,這樣可以設(shè)置audioManager.setSpeakerphoneOn(false)。
當(dāng)聲音模式為MODE_NORMAL,沒有插耳機(jī)的時(shí)候聲音自動(dòng)外放,插上耳機(jī)聲音從耳機(jī)出聲,不需要進(jìn)行相應(yīng)的設(shè)置。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android Broadcast原理分析之registerReceiver詳解
- Android端權(quán)限隱私的合規(guī)化處理實(shí)戰(zhàn)記錄
- Android實(shí)現(xiàn)簡單點(diǎn)贊動(dòng)畫
- Android多返回棧技術(shù)
- Android Intent與IntentFilter案例詳解
- Android自定義view之利用drawArc方法實(shí)現(xiàn)動(dòng)態(tài)效果(思路詳解)
- Android ExpandableListView使用方法案例詳解
- Android 使用registerReceiver注冊BroadcastReceiver案例詳解
相關(guān)文章
Android自定義滾動(dòng)選擇器實(shí)例代碼
本篇文章主要介紹了Android自定義滾動(dòng)選擇器實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01Android WebView的使用方法及與JS 相互調(diào)用
這篇文章主要介紹了Android WebView的使用方法及與JS 相互調(diào)用的相關(guān)資料,WebView 是 Android 中一個(gè)非常實(shí)用的組​件, WebView 可以使得網(wǎng)頁輕松的內(nèi)嵌到app里,還可以直接跟js相互調(diào)用,需要的朋友可以參考下2017-07-07詳解Android更改APP語言模式的實(shí)現(xiàn)過程
本文詳細(xì)介紹如何更改Android中APP的語言模式,這個(gè)功能對(duì)于大家開發(fā)Android APP很有幫助,本文運(yùn)用文字介紹和代碼示例把過程寫的很詳細(xì),有需要的可以參考借鑒。2016-08-08android textview設(shè)置字體的行距和字間距
這篇文章主要介紹了android textview設(shè)置字體的行距和字間距的方法,非常簡單實(shí)用,有需要的小伙伴可以參考下2016-05-05android LabelView實(shí)現(xiàn)標(biāo)簽云效果
這篇文章主要為大家詳細(xì)介紹了android LabelView實(shí)現(xiàn)標(biāo)簽云效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android NDK開發(fā)之:配置環(huán)境的詳解
本篇文章是對(duì)Android中的配置環(huán)境進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Android實(shí)現(xiàn)簡易計(jì)算器(可以實(shí)現(xiàn)連續(xù)計(jì)算)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡易計(jì)算器,可以實(shí)現(xiàn)連續(xù)計(jì)算,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03