speex 回聲消除的用法
speex的回聲訊息
就是speex_echo_cancellation函式的正確用法
回聲訊息的原理:
對參考聲音(解碼的對端原始語音包)做延遲(會有多個延遲,如麥克風直接採集到音箱的聲音,經牆壁反射後再次採集),衰減,
從聲卡里採集到的語音,做一個語音合成。
回聲產生的條件:
通話中,有一方使用音箱(或者雙方都用音箱)。
在實際中如何使用speex_echo_cancellation這個函式呢?錯誤的使用,將導致speex無法快速地收斂回聲濾波器的引數。
使用音箱的那一方,這裡我們稱之為"傳送方",呼叫speex_echo_cancellation,
這樣做就繞開了網路延遲,引起對演算法收斂的干撓。
這是第一點要注意的
(也可以在"接收方"呼叫speex_echo_cancellation,但網路出現抖動時,就會使演算法無法快速收斂,就無法消除回聲了)
這樣,我們的程式碼中,大概會是這樣的邏輯:
解碼網路語音包(記為 play)
寫入音效卡
採集麥克風的聲音(記為rec)
呼叫speex_echo_cancellation 參play與rec傳給這個函式
回想一下,應用層的程式可能會是這樣(當然您的程式也可能不是這樣,但情形類似):
一個接收執行緒,收包,放音
一個傳送執行緒,錄音,發包
我們自然會在錄音執行緒裡呼叫speex_echo_cancellation
但這有一個問題,錄音執行緒與放音執行緒因為系統的排程問題,也會造成抖動,導致speex的回聲消除演算法無法收斂。
以下的一個程式模形,讀者們可以參考
1 接收執行緒A,解碼網路語音包,接語音包推入一個訊息佇列A
2 放音錄音執行緒B,從佇列A中取出語音包,放音,錄音,錄音得到的語音包,通過speex_echo_cancellation處理後,存入佇列B
3 傳送執行緒C,從佇列B中取語音包,編碼,傳送
簡單地說,就是用一個執行緒放音,錄音,然後echo cancel,這樣就不存線上程排程引起的延遲抖動
採用這種方式,就避免了因為執行緒排程引起的抖動,避免了不確定的延遲對speex演算法收斂過程的干撓。
最後一個干撓因素:os提供的錄音放音介面也是非同步的。。。
這個干撓因素基本在應用層是無法排除的了。。。可能就是幾毫秒的誤差,但足以干撓回聲消除演算法了。
多路語音(會議)
選一個超級節點做合成語音,或者終端對語音進行合成,之後,處理就變成與單對單語音通話類似的情形了
直接上speex_echo_cancellation