不推薦單獨編譯 WebRTC 中的各個子產品出來使用。
昨天有幸在 Google 論壇裡詢問到 AECM 子產品的延遲計算一事,Project member 說搗騰這個延遲實際上對 AECM 的效果沒有幫助,這個延遲值僅在 AECM 啟動時加快内置延遲估算器的收斂,如果更新的延遲有誤,甚至會使 AECM 内置的延遲估算器出現錯誤的偏移,他建議我使用一個理論上的定值,Chrome 中他們用了 100ms。我之前也在 AECM 裡看到了它對内置的 delay_estimator 二進制延遲估算器有很大的依賴,近端與遠端資料比對與否,幾乎全部仰仗這個延遲估算器的結果。是以,對于 AECM 的使用,是否還需要花時間去計算這個系統延遲,bill 不再置評,個中效果大家自己實踐和把握。
其次,AECM 産生的唧唧聲 Project member 澄清這不是 bug,而是 AECM 算法本來就有此表現,屬正常現象。
本文已有一年之久,随着自己在學習過程中認識的加深,以及期間和各位在文後的讨論,擔心後來者照着這一年前的文章走彎路,bill 覺得有必要對文章做一個更新,點出自己走的彎路,以免誤導後來者。
1. 自己最開始是把 AECM、NS、VAD、AGC 各個子產品單獨提取出來使用,現在看來實屬麻煩,且效果也不甚理想。如果大家的項目沒有特殊的要求,大可将整個語音引擎 VoiceEngine 編譯出來使用。就我個人而言,目前的解決方案是獨立編譯使用音頻處理單元 AudioProcessingModule,因為 APM 是一個純淨的音頻處理單元,其接口僅與音頻處理有關,APM的使用加上上層代碼的優化,可以保證基本的通話效果(離完美還很遠),回聲基本是沒有的。主要會存在兩個問題,一是AECM出來的效果會有唧唧聲,這個聲音可以通過對延遲計算的不斷優化而得到改善,最終可以做到說幾句話之後有1~2次唧唧聲。二是通話過程中聲音會忽大忽小,目前我是懷疑由AECM的double talk處理引起的,具體的還要自己去倒騰。
2. 關于回聲消除濾波器延遲的計算,之前自己一直認為隻要這個延遲計算準确,就能得到理想的回聲消除效果,現在發現這個想法太幼稚,一是AECM算法本身有一定局限性,二是Android上的采集延遲沒有系統API支援,很難計算準确,而播放端的API又不能保證其準确性。目前我的能力隻能做到盡量優化上層的延遲計算,盡量減少由Android音頻API對延遲造成的影響。
3. 在 Android 上層優化計算系統音頻延遲的代碼達到一定瓶頸後,可以将優化目标轉向 1)AECM 算法。 2)優化AEC(PC)(使其能在手機上正常運作,目前AEC-PC預設濾波器長度為12塊,每塊64個點,(12*64=768采樣)即AEC-PC僅能處理48ms的單聲道16kHz延遲的資料,而Android的音頻系統延遲大多在100ms以上,是以既要增加AEC-PC濾波器長度又要保證其運作效率是優化的重點) 3)其他子產品的優化(比如抖動緩沖區等)。
4. 文後的源碼清單已經過時,由于我目前不再支援單獨編譯這些子產品,恕我不再更新該清單,如确有獨立編譯需求的,可自行在WebRTC項目對應目錄中找到需要的檔案。
前言
最近一直在搗騰如何在android和iOS上使用Google的WebRTC——一個無疑大力推動了網際網路即時通信以及VoIP發展的開源項目。(elesos注:連谷歌都通路不了的國家,活該落後!)
WebRTC提供一套音頻處理引擎VOE,但VOE在 android 和 iOS 上的整體編譯一直是一個比較繁瑣且惱火的問題,于是單獨提取了VOE中的NS(Noise Suppression 噪聲抑制)、VAD(Voice Activity Detection 靜音檢測)、AECM(Acoustic Echo Canceller for Mobile 聲學回聲消除)以及 AGC(Auto Gain Control 自動增益控制)等子產品進行編譯并搗鼓其使用方法。
經過自己兩月有餘的搗騰和測試,終于在 android 和 iOS 上成功編譯出各子產品并在項目中使用了NS/VAD/AECM三大子產品,效果比較不錯。
回過頭來看看,這幾大子產品的編譯其實非常簡單,不過兩月前的自己也着實為這個花了一番力氣。
正文
由于幾大子產品的編譯方式相同,故本文僅以 NS 子產品為例,其餘子產品請讀者自行摸索和實驗。
Step 1 - 下載下傳 google WebRTC 源碼
WebRTC目前的開發版主線版本已經到了 r4152 - 3.32,但這幾大子產品并未有大的修改,故本文依舊按bill當時的版本 3.31 進行講解,請自行使用SVN同步以下目錄(至于同步的方法,請自行google):
http://webrtc.googlecode.com/svn/branches/3.31/ 可通路
Step 2 - 提取WebRTC - NS子產品代碼
同步源碼後,進入目錄 \webrtc\modules\audio_processing\ns ,将NS子產品的源碼拷貝出來,下面是單獨編譯NS時的參考源碼清單(部分頭檔案在WebRTC項目其他目錄下,請自行搜尋提取):
defines.h
signal_procession_library.h
spl_inl.h
typdefs.h
windows_private.h
fft4g.h / fft4g.c
noise_suppression.h / noise_suppression/c
ns_core.h / ns_core.c
除了上述WebRTC源碼外,如果要在android的Java代碼中使用,還需自行編寫JNI包裝檔案:
ns_jni_wrapper.c(此為自定義的 jni 包裝檔案,詳情請見 此文)
ADDED(billhoo - 2013-6-14)
鑒于有朋友詢問JNI Wrapper的編寫,下面提供NS子產品create以及initialize函數(這兩個函數足以說明問題)的wrapper源碼及注釋,希望對大家有所幫助。更詳細的編寫步驟請參考 Oracle官方文檔 或 此文或 此文。
WebRtcNs_Create 包裝函數及注釋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
WebRtcNs_Initiate 包裝函數及注釋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
[END OF ADDED]
Step 3 - 編譯WebRTC - NS子產品
此步請參照 bill之前的文章将剛才提取的NS代碼添加進eclipse工程進行編譯即可。以下為NS子產品的Android.mk檔案:
1 2 3 4 5 6 7 8 9 | |
編譯完成後,将項目中的 webrtc_ns.so 動态庫拷貝出來以備後續使用。
Step 4 - 加載編譯好的NS子產品動态庫
接下來隻需要按照 此文 的描述在 android 的JAVA代碼中使用剛才編譯好的 webrtc_ns.so 動态庫便大功告成。
Step 5 - 幾大子產品的使用及注意事項
前四步已經完成了幾大音頻處理子產品在android上的單獨編譯過程,并分别生成了 webrtc_ns.so、webrtc_vad.so、webrtc_aecm.so 以及 webrtc_agc.so 四個動态庫,下面bill簡要介紹對NS、VAD以及AECM三個庫的函數使用方法及注意事項:
5.1 - NS庫函數的使用及注意事項
這個很簡單,參照 noise_suppression.h 頭檔案中對各API的描述即可,首先使用 WebRtcNs_Create 建立NS實體,然後 WebRtcNs_Init 初始化該實體,WebRtcNs_set_policy 設定噪聲抑制的級别(bill使用的是***别 2,效果比較理想),設定完成後便可調用 WebRtcNs_Process循環對10ms(8000Hz、16000Hz)音頻幀進行NS處理,注意最後别忘了調用 WebRtcNs_Free 将NS實體銷毀。
5.2 - VAD庫函數的使用及注意事項
VAD的使用和NS差別不大,唯一需要注意的是VAD僅僅隻是檢測,傳回結果1表示VAD檢測此幀為活動幀,0表示此幀為靜音幀,至于判斷為靜音後該進行何種處理,就和你自己的項目相關了。
5.3 - AECM庫函數的使用及注意事項
AECM實體的建立、初始化和銷毀工作與上述相同,之後需要在遠端和近端分别調用WebRtcAecm_BufferFarend (注:farend遠端)以及 WebRtcAecm_Process,對于AECM的使用,需要注意的重點在于Process函數的參數msInSndCardBuf,該參數在audio_procession.h頭檔案中以名為delay的變量呈現,該延遲的計算确為一難點(對于單獨使用AECM子產品來說),不過隻要嚴格按照delay的描述進行操作即可。
附:
其他幾大子產品單獨編譯時需要的源檔案清單(所有依賴頭檔案略,請自行根據報錯添加):
WebRTC - VAD 子產品源檔案清單
注意:VAD的編譯需要宏 WEBRTC_POSIX 的支援,而該宏是否有實作,由 WEBRTC_ANDROID 等宏是否被定義決定,若你在編譯時提示 once 函數未定義等錯誤, 請自行添加對 WEBRTC_ANDROID宏的定義。
webrtc_vad.c
vad_core.c
vad_filterbank.c
vad_gmm.c
vad_sp.c
real_fft.c
division_operations.c
complex_bit_reverse.c
cross_correlation.c
complex_fft.c
downsample_fast.c
vector_scaling_operations.c
get_scaling_square.c
energy.c
min_max_operations.c
spl_init.c
WebRTC - AECM 子產品源檔案清單
randomization_functions.c
spl_sqrt_floor.c
division_operations.c
min_max_operations.c
ring_buffer.c
delay_estimator.c
delay_estimator_wrapper.c
complex_bit_reverse.c
complex_fft.c
aecm_core.c
echo_control_mobile.c
WebRTC - AGC 子產品源檔案清單
spl_sqrt.c
copy_set_operations.c
division_operations.c
dot_product_with_scale.c
resample_by_2.c
analog_agc.c
digital_agc.c
下面是elesos從評論中摘抄的部分資訊:
使用
WebRtcAecm_Process
nearendNoisy 表示帶有噪聲的buf
nearendClean 表示經過降噪處理的 buf
建議首先使用NS将采集到的buf降噪,然後将原buf傳給nearendNoisy ,降噪後的buf傳給
nearendClean,如果不降噪,直接将buf傳給nearendNoisy ,nearendClean置為NULL即可。
NS每次處理10ms的資料
都處理10ms數據(8000HZ的sample是80, 16000HZ的sample是160)、謝謝!
先消回聲再降噪效果比先降噪再消回聲好。建議參考WebRTC AudioPreprocessing 子產品裡面的 ProcessStream 的實作順序。
WebRtcAecm_Init( &aecm , 8000 );
While ( aecProcessing )
{
WebRtcAecm_BufferFarend( speakerBuffer );
WebRtcAecm_Process( aecm , micBuffer , NULL , aecBuffer , 160 , 200 );
}
上面的200ms最好不要用常量,需要this delay is always changes, you should estimate it every
1 second or shorter.
在audio_processing.h中有描述
// Sets the |delay| in ms between AnalyzeReverseStream() receiving a far-end
// frame and ProcessStream() receiving a near-end frame containing the
// corresponding echo. On the client-side this can be expressed as
// delay = (t_render - t_analyze) + (t_process - t_capture)
// where,
// - t_analyze is the time a frame is passed to AnalyzeReverseStream() and
// t_render is the time the first sample of the same frame is rendered by
// the audio hardware.
// - t_capture is the time the first sample of a frame is captured by the
// audio hardware and t_pull is the time the same frame is passed to
// ProcessStream().
virtual int set_stream_delay_ms(int delay) = 0;
延遲你隻能根據自己的buffer實作進行計算。
四個時間點均在調用之前得到即可。
的第一個采樣被播放的時間,總感覺取不到,我們能取到的隻有播放完整個語音幀的時間點吧:我們确
實不能直接得到第一個采樣點的時間,但你可以根據自己上層的 buffer 大小以及底層的硬體 buffer
大小估算出緩沖區中總共緩沖了多少幀,這樣一來便可計算出第一個采樣點的時間。
請教一下你在android上層設計buffer并計算出delay時間的解決辦法。
盡量不要在java層做AECM,如果非要在java層做,delay的計算隻有根據你自己的buffer設計來,總體
思路就是系統底層硬體延遲 + 你的buffer延遲。
每發送一幀就更新延遲值。
可以采用OpenSE等JNI層的采集庫,而不是android上層的AudioRecord以及AudioTrack。
目前采用一半底層buffer大小作為采集的固定延遲。
T1(系統的播放延遲) = 幀A被硬體播放出來的時刻 - 幀A被放進 farend 的時刻;
T2(系統的采集延遲) = 幀B被放進 process 的時刻 - 幀B被硬體采集的時刻;
total delay = T1 + T2;
這個延遲的計算方法可以參考WebRTC主線版本目錄 webrtc\modules\audio_device\android\java\src\org\webrtc\voiceengine\
下的WebRTCAudioTrack和WebRTCAudioRecord
對于AECM的測試,首先可以使用同一個PCM檔案,分别放入FAREND和PROCESS,如果出來的結果接近全零
,則驗證你提取的AECM子產品工作正常。
在驗證AECM子產品能夠正常工作的前提下,你需要兩台裝置,每台裝置兩個線程,線程一用來采集和
PROCESS,線程二用來播放和FAREND。
“從手機SD卡中讀取一個pcm檔案,送入到揚聲器,同時調用WebRtcAecm_BufferFarend(), 然後讀取麥
克風采集到的資料,調用Process。再将out寫入到aec.pcm檔案。分析這個aec.pcm檔案。”
遠端資料就是網絡傳過來的資料,近端就是本機采集到的資料。
farend是遠端資料,即VoIP通信中接收到的對端的、即将被本地揚聲器播放的音頻A。
nearend是本地資料,即剛剛被本地麥克風采集到的音頻B,而音頻B可能包含上述音頻A(麥克風采集到了揚聲器播放的A),于是 A和B 一起發送給遠端,緻使遠端又聽到了自己剛才發送的A,也就産生了所謂的回聲。
發現你這裡面根本不存在“原聲”,何來原聲被消除呢?
你使用固定檔案作為聲音來源,我們假設輸入PCM資料為“A”,那麼你送到揚聲器的聲音就為“A”,
而麥克風采集到的聲音為揚聲器的“A”再加上背景噪聲“B”(現在的B才是實際意義上的“原聲”,
假設你沒說話),AECM的處理結果就是從“A+B”中找到被揚聲器播放出去的“A”并進行消除,留下
了“B”,而背景噪聲也許比較小,結果也就仍然接近全零了,繞了一圈,你做的這個流程和我用同一
個PCM檔案分别放入farend和process是一個道理。
應該在運作時說話,而不是放音樂。
VAD檢測出是靜音,你可以采取以下兩種方式:1.不發送這一段靜音的音頻 2.将這一段VAD認為靜音的
音頻全部置零然後發送。
出處http://billhoo.blog.51cto.com/2337751/1213801
[3樓]
wanglimingyin 回複
2013-06-14 17:18:33
回複 Bill_Hoo:[2樓]
謝謝你,bill。主要是我對c不熟悉,好久沒用了。現在有個需求就是需要拿到pcm音頻資料然後進行降噪,可是不知到怎麼使用裡面的方法
[4樓]
[匿名]WebRtc_Aecm 回複
2013-06-26 19:54:24
BillHoo你好, 我是從***追到這裡來的。有一個問題不知道樓主有沒有遇到過: WebRtcAecm_Process在去掉回聲的同時把與回聲重疊的那部分的原聲也去掉了。
還有一個問題啊,麥克風采集的PCM的buffer是作為WebRtcAecm_Process的第二個參數嗎?不勝感激。
[5樓]樓主
Bill_Hoo 回複
2013-06-26 21:07:14
回複 WebRtc_Aecm:[4樓]
你好,很高興你能追到這裡來 1)我沒有弄懂你說的回聲和原聲重疊是什麼意思。消回聲把原聲消掉了,這種情況我僅在回環路徑測試時遇到過,兩台裝置進行測試不會有此問題。
2)process函數原型如下 int32_t WebRtcAecm_Process(void* aecmInst,
const int16_t* nearendNoisy,
const int16_t* nearendClean,
int16_t* out,
int16_t nrOfSamples,
int16_t msInSndCardBuf);
其中 nearendNoisy 表示帶有噪聲的buf,nearendClean 表示經過降噪處理的 buf,建議首先使用NS将采集到的buf降噪,然後将原buf傳給nearendNoisy ,降噪後的buf傳給 nearendClean,如果不降噪,直接将buf傳給nearendNoisy ,nearendClean置為NULL即可。
[6樓]
[匿名]WebRtc_Aecm 回複
2013-06-27 09:54:30
回複 Bill_Hoo:[5樓]
多謝你的回複!
回聲和原聲重疊的意思是回聲和原聲同一時刻進入到麥克風,我将它稱之為“重疊”
回環路徑測試是怎樣的場景和配置呢?
我現在的測試環境是這樣搭的: 從手機SD卡中以80位元組為機關順序讀取一個pcm檔案,送入到揚聲器,同時調用WebRtcAecm_BufferFarend(), 然後讀取麥克風采集到的資料的80位元組,調用Process。再将out寫入到aec.pcm檔案。分析這個aec.pcm檔案時,發現回聲是被消除了,但是與回聲處于同一時刻的原聲也被消除了。
我這種測試思路有問題嗎?
還有一個問題,降噪與否對回聲抑制的效果影響大嗎?
多謝 :)
[7樓]樓主
Bill_Hoo 回複
2013-06-27 11:47:35
回複 WebRtc_Aecm:[6樓]
1.首先,我在***裡看到你調用時傳的是8000Hz的采樣率,也就是說你每次應該傳入80個采樣點,(編者注:10ms資料需要傳80,1000ms即1s為8000,是以10ms對應80*2=160位元組)一個采樣點是2個位元組,你應該采集160位元組/次才對。
注: http://***.com/questions/17319574/audio-is-also-be-cancelled-which-overlap-with-acoustic-echo-when-using-webrtc-ae/17333797#17333797
2.對于AECM的測試,首先可以使用同一個PCM檔案,分别放入FAREND和PROCESS,如果出來的結果接近全零,則驗證你提取的AECM子產品工作正常。
3.在驗證AECM子產品能夠正常工作的前提下,你需要兩台裝置,每台裝置兩個線程,線程一用來采集和PROCESS,線程二用來播放和FAREND。
4.降噪與否對回聲消除的效果:我的實驗結果為:先消回聲再降噪效果比先降噪再消回聲好。
[8樓]樓主
Bill_Hoo 回複
2013-06-27 12:47:50
回複 WebRtc_Aecm:[6樓]
還有個問題看掉了,我說的回環路徑就是 127.0.0.1 的本機測試。
[9樓]
[匿名]WebRtcAecm 回複
2013-06-27 13:17:45
回複 Bill_Hoo:[8樓]
對于第1點,我也測試過傳160位元組,效果和80位元組是差不多的。
對于第2點,結果會接近全零,但是在本地也有聲音進入麥克風的情況下,與回聲重疊的那部分原聲也會被消掉(預期應該是不會被消掉的,這和你的回環路徑測試不一樣,因為進入麥克風的"Normal Voice"沒有再次進入揚聲器,也就算不上是回聲,而我猜你的回環路徑測試是會再次被揚聲器播放出來吧?)。
這就是我遇到的最主要問題。AECM是可以工作的,但是結果沒有達到預期。我看了你的***的回複,這一點應該是和時延沒有關系的。
[10樓]樓主
Bill_Hoo 回複
2013-06-27 14:05:17
回複 WebRtcAecm:[9樓]
你好,我仔細看了下你的思路
“從手機SD卡中讀取一個pcm檔案,送入到揚聲器,同時調用WebRtcAecm_BufferFarend(), 然後讀取麥克風采集到的資料,調用Process。再将out寫入到aec.pcm檔案。分析這個aec.pcm檔案。”
發現你這裡面根本不存在“原聲”,何來原聲被消除呢?
你使用固定檔案作為聲音來源,我們假設輸入PCM資料為“A”,那麼你送到揚聲器的聲音就為“A”,而麥克風采集到的聲音為揚聲器的“A”再加上背景噪聲“B”(現在的B才是實際意義上的“原聲”,假設你沒說話),AECM的處理結果就是從“A+B”中找到被揚聲器播放出去的“A”并進行消除,留下了“B”,而背景噪聲也許比較小,結果也就仍然接近全零了,繞了一圈,你做的這個流程和我用同一個PCM檔案分别放入farend和process是一個道理。
如果需要做回聲測試,你需要兩台裝置,如我上一個回複所說。
希望對你有所幫助。
[11樓]
[匿名]WebRtcAecm 回複
2013-06-27 14:40:17
回複 Bill_Hoo:[10樓]
是啊是啊,就是你說的這個意思。唯一不同的是我放音樂了,也就是說“B”裡面有音樂,現在這段音樂與A重疊的部分就被消掉了 :(
[12樓]樓主
Bill_Hoo 回複
2013-06-27 14:54:04
回複 WebRtcAecm:[11樓]
也就是說你的問題不在AECM這個子產品上,而是你的測試思路。
你的問題就在于 —— 你的測試方法測出來本來就應該是這個結果,而你的預期卻錯誤地認為會是另外一個結果。
搞清什麼是“原聲”,什麼是“回聲”就OK了。
Elesos.com注:他的音樂其實還是送到揚聲器的聲音A吧,是回聲。是需要消除的。
[13樓]
[匿名]WebRtcAecm 回複
2013-06-27 14:59:41
回複 Bill_Hoo:[12樓]
預期:"AECM的處理結果就是從“A+B”中找到被揚聲器播放出去的“A”并進行消除,留下了“B”"
現在的結果是: B沒有被完全留下,有一部分被消掉了。你假設我沒有說話,實際我放了音樂并且被麥克風采集到了啊,這個音樂不是從揚聲器出來的,這不算回聲嗎?我覺得這個音樂應該是被保留的吧?現在被部分消掉了。
[14樓]樓主
Bill_Hoo 回複
2013-06-27 15:11:10
音樂是連續的音源,和人聲是有很大差別的,連續樂音中很可能某一段的資料被認為是和A中的資料比對進而導緻被消除,如果你非要這樣測,應該在運作時說話,而不是放音樂。
[15樓]樓主
Bill_Hoo 回複
2013-06-27 15:14:19
回複 WebRtcAecm:[13樓]
可以參考一下 http://www.net130.com/netbass/voip/20040008009.htm
回複 Bill_Hoo:[15樓]
注:http://***.com/questions/15302339/webrtc-aec-algorithm/16182942#16182942
多謝你的回複 :)
最後一個問題,那個時延是怎麼計算的? 我看了你在***上的發言,根據AudioProcessing.h的描述來計算,但是我的英文真是爛,那段話看了好久都沒有看懂...
Sets the |delay| in ms between AnalyzeReverseStream() receiving a far-end frame and ProcessStream() receiving a near-end frame containing the corresponding echo. On the client-side this can be expressed as delay = (t_render - t_analyze) + (t_process - t_capture)
where,
- t_analyze is the time a frame is passed to AnalyzeReverseStream() and
t_render is the time the first sample of the same frame is rendered by
the audio hardware.
- t_capture is the time the first sample of a frame is captured by the
audio hardware and t_pull is the time the same frame is passed to
ProcessStream().
1). 你是根據這個公式來計算的嗎?
2). 這4個值都是什麼意思啊?這段話我看了很多次了,總是看不懂。
[17樓]樓主
Bill_Hoo 回複
2013-06-27 22:13:30
回複 WebRtcAecm:[16樓]
你好,是根據這個來計算,而且需要嚴格根據這個的描述來
t_analyze 表示你對音頻幀A調用 farend 的時刻,t_render 表示[硬體]真正播放出幀A的時刻。
t_capture 表示[硬體]采集到音頻幀B(注意跟A沒關系了)的時刻,t_pull 表示幀B被傳入 Process的時刻。
其實就是計算系統硬體buffer + 軟體 buffer 的總延遲。
這個延遲在android系統中比較大,有100~200左右不等,需要你根據自己的buffer進行計算。計算方法就跟你android上層的buffer設計相關了。
[21樓]
[匿名]cstriker1407 回複
2013-07-01 14:30:12
問下樓主,
我參照樓主的做法,第二步中AECM已經可以了。
2.對于AECM的測試,首先可以使用同一個PCM檔案,分别放入FAREND和PROCESS,如果出來的結果接近全零,則驗證你提取的AECM子產品工作正常。
現在我的項目遇到的問題是,本機測試是可以的,但是雙機通訊下,會有非常大的噪聲,是不是AECM的msInSndCardBuf的參數錯了。這個到底該怎麼計算呢?
順便問個小白的問題,在雙機通信中,我認為從網絡上接收的音頻為遠端音頻,用WebRtcAecm_BufferFarend,本地錄音的音頻為近端,用process。這個沒錯吧。還有,我并沒有用NS,AGC和其他子產品,自用了AECM。這樣可以嗎?請樓主點播下,多謝。我的QQ:553270954
[22樓]樓主
Bill_Hoo 回複
2013-07-01 18:08:35
回複 cstriker1407:[21樓]
你好:
1.非常大的噪聲:你确定那是噪聲而不是嘯叫麼? 我這邊AECM區域網路通信沒有你說的很大的噪聲,隻是之前由于delay計算錯誤會産生很大的嘯叫。delay的計算公式在audio_procession.h裡面說的很清楚,那個延遲你隻能根據自己的buffer實作進行計算。
2.遠端資料就是網絡傳過來的資料,近端就是本機采集到的資料。
3.隻用AECM子產品是可以的。
[23樓]
[匿名]51CTO遊客 回複
2013-07-03 14:31:59
Bill_Hoo:
你好:
我現在在做回音消除這塊,但是不能準備計算delay的時間,雖然audio_precession.h頭檔案中的公式說得很清楚,但是對于android平台的java層始終不能很好的計算出delay的時間,是以想請教一下你在android上層設計buffer并計算出delay時間的解決辦法。
[24樓]
[匿名]cstriker1407 回複
2013-07-03 14:39:21
回複 Bill_Hoo:[22樓]
多謝樓主回複,問題(注:雙機通訊下,會有非常大的噪聲)我已經發現并解決了。不是webrtc的問題。
[25樓]樓主
Bill_Hoo 回複
2013-07-03 21:08:27
回複 51CTO遊客:[23樓]
你好,如果可能,盡量不要在java層做AECM,java到android底層中間還夾着jni,據說還有一個AudioFlinger的延遲,這個我也沒有深入,是以不敢亂講。如果你的項目不是必須在java層做音頻的采集和播放,那麼AECM還是放在底層做的好。
如果非要在java層做,delay的計算隻有根據你自己的buffer設計來,這個我沒辦法幫上忙,總體思路就是系統底層硬體延遲 + 你的buffer延遲。
[26樓]
w33222885 回複
2013-08-01 14:25:30
您好 我也在做webrtc的AEC 請問AudioRecord和AudioTrack如何的阻塞時間如何計算
long timestamp = System.nanoTime();
mAudioTrack.write(data, 0, data.length);
long renderTime = System.nanoTime() - timestamp;
native_set_audioRenderBlockTime(renderTime);
請問這樣做能得到準确的阻塞時間嘛
[27樓]
hsfhzkd 回複
2013-08-02 15:14:00
請問樓上,AECM、VAD、AGC三個子產品使用的順序是怎樣?如果VAD檢測出是靜音子產品,那麼AECM該如何調用啊?
[28樓]樓主
Bill_Hoo 回複
2013-08-02 15:33:47
回複 hsfhzkd:[27樓]
VAD檢測出是靜音,你可以采取以下兩種方式:1.不發送這一段靜音的音頻 2.将這一段VAD認為靜音的音頻全部置零然後發送。
[29樓]樓主
Bill_Hoo 回複
2013-08-02 15:34:46
回複 w33222885:[26樓]
你好,你這樣做可以得到 write 的阻塞時間,但這個時間并不是 renderTime(如果你的這個變量表示渲染延遲的話)。
[30樓]
w33222885 回複
2013-08-05 10:01:54
回複 Bill_Hoo:[29樓]
您好 請問渲染時間是一個固定的延遲嗎,是否跟audioflinger的lantency有關。
[31樓]樓主
Bill_Hoo 回複
2013-08-05 13:28:25
回複 w33222885:[30樓]
據我的實驗結果,該延遲并不是固定的,需要周期性更新。我當時看源碼時,AudioFlinger層的latency沒有辦法在上層擷取,是以沒有考慮這個。不過不知道現在4.1、4.2的源碼發生了怎樣的變化,是否有類似iOS的直接擷取底層硬體延遲的接口我也不清楚。
[32樓]
w33222885 回複
2013-08-05 13:47:52
回複 Bill_Hoo:[31樓]
現在aecm已經可以工作,但是最後的效果始終有嘶嘶的雜音,不知道您最終的效果如何~
[33樓]樓主
Bill_Hoo 回複
2013-08-06 13:14:27
回複 w33222885:[32樓]
單獨提取的AECM子產品達不到完美的效果,但也不會始終存在嘶嘶聲。也許你可以配合NS和VAD子產品一起使用。
[34樓]
[匿名]51CTO遊客 回複
2013-08-21 02:21:29
你好Bill Hoo,我對NS 子產品的 WebRtcNs_Process 這個函數有點疑問。int WebRtcNs_Process(NsHandle* NS_inst, short* spframe, short* spframe_H,short* outframe, short* outframe_H)。 最後面四個參數 是指什麼?我不太懂. noise_suppresion.h 裡面說 buffer for L band, buffer for H band。 L band 和 H band 是什麼?? 多謝了。
[35樓]樓主
Bill_Hoo 回複
2013-08-21 10:15:18
回複 51CTO遊客:[34樓]
可以參考下 http://what-when-how.com/voip/wideband-voice-voip/。
以及維基 http://en.wikipedia.org/wiki/H_band
http://en.wikipedia.org/wiki/L_band
L band, is the 1 to 2 GHz range of the radio spectrum.
[36樓]
[匿名]51CTO遊客 回複
2013-08-21 22:51:03
回複 Bill_Hoo:[35樓]
多謝,樓主。我的audio input format 是
PCM signed (wav file format)
16 bit encoding
8000 Hz sample rate
Mono (1 channel)
Big endian format
但是參考資料都是說把16khz 的audio 用qmf 分成2個8khz的audio。 那我要怎麼去用 WebRtcNs_Process 這個函數呢??隻把audio 放進spframe, buffer for L band 麼,不管buffer for H band?
[37樓]樓主
Bill_Hoo 回複
2013-08-22 08:59:28
回複 51CTO遊客:[36樓]
早上好, 8KHz sample 直接入 L band 就OK了,我目前最高用到 16KHz,均隻入的L band,至于 H band 對于話音的噪聲消除個人覺得應該沒有用處。 不過對于 32000 Hz 的sample就說不好了,一般單聲道的應用可能都不會觸及到 Hband,如果你發現在某個環境下會用到 H Band,還請回來告知一聲哦。
[38樓]
[匿名]51CTO遊客 回複
2013-08-22 17:23:51
Bill_Hoo你好,我又來了。之前一個月在做voip的其他功能,現在又開始做AEC了。現在遇到的問題是怎麼計算系統硬體buffer的延遲,這個Android有什麼接口嗎?
[39樓]樓主
Bill_Hoo 回複
2013-08-22 18:05:12
回複 51CTO遊客:[38樓]
你好,iOS有API直接提供硬體層的采集和播放延遲,但據我的實踐和了解,android目前并沒有提供直接的硬體延遲。是以你需要根據自己的上層工作buffer對底層buffer進行估算,進而得到一個較為精确的硬體延遲。但該延遲始終不精确,因為經過了幾處buffer的緩沖。 如果要更精确,可以采用OpenSE等JNI層的采集庫,而不是android上層的AudioRecord以及AudioTrack。不知道這樣回答是否解決了你的問題。
[40樓]
[匿名]51CTO遊客 回複
2013-08-23 02:10:14
回複 Bill_Hoo:[37樓]
恩, 謝拉。 L band 和 H band 估計跟壞境噪音的頻率有關吧。 我想問問你是怎麼wrap WebRtcNs_Process? 我成功把 .so build出來。 然後放到另一個app應用的時候出現了這個錯誤 Fatal signal 11 (SIGSEGV) at 0x1e90001d (code = 1). 我估計是我wrapper 寫錯了。 我的是這樣的
JNIEXPORT jint JNICALL
Java_research_webrtc_NoiseSuppression_process(JNIEnv *env, jclass jclazz,
jint nsHandler, jshortArray spframe, jshortArray spframe_H,
jshortArray outframe, jshortArray outframe_H) {
NsHandle *hNS = (NsHandle*) nsHandler;
// Step 1: Convert the incoming JNI jintarray to C\'s jint[]
jshort *inCArrayIn = (*env)->GetShortArrayElements(env, spframe, NULL );
jshort *inCArrayOut = (*env)->GetShortArrayElements(env, outframe, NULL );
//dummy variable for buffer for H band, contains no content
jshort *inCArrayIn_H = (*env)->GetShortArrayElements(env, spframe_H, NULL );
jshort *inCArrayOut_H = (*env)->GetShortArrayElements(env, outframe_H,
NULL );
if (NULL == inCArrayIn || NULL == inCArrayOut || NULL == inCArrayIn_H
|| NULL == inCArrayOut_H)
return -1;
jsize length = (*env)->GetArrayLength(env, spframe);
// Step 2: Perform its intended operations
jint result = 0;
result = WebRtcNs_Process(hNS, spframe, spframe_H, outframe, outframe_H);
// Step 3: Copy the content of C\'s Native jshort[] to JNI jshortarray, and release resources
(*env)->ReleaseShortArrayElements(env, spframe, inCArrayIn, 0);
(*env)->ReleaseShortArrayElements(env, outframe, inCArrayOut, 0);
(*env)->ReleaseShortArrayElements(env, spframe_H, inCArrayIn_H, 0);
(*env)->ReleaseShortArrayElements(env, outframe_H, inCArrayOut_H, 0);
return result;
}
[41樓]
[匿名]51CTO遊客 回複
2013-08-23 22:34:41
回複 Bill_Hoo:[37樓]
原來是WebRtcNs_Process的input放錯了。 問題已解決。
[42樓]樓主
Bill_Hoo 回複
2013-08-23 22:37:50
回複 51CTO遊客:[40樓]
你好,如果按照我的調用方式,H band的兩個參數我都會傳遞 NULL 指針,而你的
if (NULL == inCArrayIn || NULL == inCArrayOut || NULL == inCArrayIn_H
|| NULL == inCArrayOut_H)
就直接 return -1了;
再者,題外話,如果沒有這句if判斷,那麼錯誤會發生在
(*env)->ReleaseShortArrayElements(env, spframe_H, inCArrayIn_H, 0);
Release要求傳遞進去的指針不能為NULL,對NULL指針進行記憶體釋放是非法操作。
不知有沒有找到你的bug呢。
[43樓]樓主
Bill_Hoo 回複
2013-08-23 22:49:02
回複 51CTO遊客:[41樓]
哦哈哈,看來我在打字的時候你也在打字..................... 恭喜、
[44樓]
[匿名]51CTO遊客 回複
2013-09-02 15:22:24
回複 Bill_Hoo:[17樓]
"
你好,是根據這個來計算,而且需要嚴格根據這個的描述來
t_analyze 表示你對音頻幀A調用 farend 的時刻,t_render 表示[硬體]真正播放出幀A的時刻。
t_capture 表示[硬體]采集到音頻幀B(注意跟A沒關系了)的時刻,t_pull 表示幀B被傳入 Process的時刻。
其實就是計算系統硬體buffer + 軟體 buffer 的總延遲。
這個延遲在android系統中比較大,有100~200左右不等,需要你根據自己的buffer進行計算。計算方法就跟你android上層的buffer設計相關了。
"
Bill, 對于這個回複我還是有幾個問題弄不明白:
1. 幀B裡面是不是包含幀A的聲音( 幀A從speaker出來進入mic時就是幀B )?
2. 假如t_render < t_analyze呢? 我的了解是WebRtcAecm_BufFarend( Frame A )隻要在WebRtcAecm_Process( Frame B )之前調用進行了。這種了解對嗎?
3. 怎麼能夠找到幀A和幀B的對應關系呢(我感覺這是最困難的)?
3. 我又仔細讀了你在***的發言, 對于這兩點:
2.AudioRecord.read() and AudioTrack.write() sometimes block(due to minimized buffer size), so when you calc the delay, don\'t forget adding blocking time to it.
3.the buffer of AudioRecord and AudioTrack also increases the total delay. so add it.
你是怎麼知道blocking time和buffer of AudioRecord and AudioTrack的大小的呢?
問題有點多, 被AEC困擾挺久了。不勝感謝~
[45樓]
aaronlibra 回複
2013-09-02 19:07:20
Hi,Bill!
我最近在做一個Android的通過藍牙傳遞語音資料的項目,用了WebRTC的NS後聲音變得沙啞了。
我的實作過程很簡單,先用AudioRecord錄音,取出pcm資料,然後傳給ns_process,最好編碼後發出去,我為了排除其它影響,特地在ns_process後将資料寫入檔案播放,跟傳送到遠端後類似,都是變沙啞了。
另外,不加NS,整個通話聲音都是正常的,加上AECM也沒有問題。
你有沒有碰到類似的問題,NS需要什麼特殊設定嗎,還是我這個使用過程有問題?
麻煩你有空幫忙看看,謝謝!
[46樓]
[匿名]51CTO遊客 回複
2013-09-03 11:32:59
樓上可以試下nsx, ns是浮點運算, nsx是定點運算。我用nsx效果挺好的。
[47樓]
aaronlibra 回複
2013-09-03 16:03:50
回複 51CTO遊客:[46樓]
謝謝!找到原因了,不過不是因為浮點的原因。
我的參數:
16 bit encoding
8000 Hz sample rate
Mono (1 channel)
20ms一幀,故每幀為160位元組,之前将160位元組直接傳給NS,而NS每次處理10ms的資料,現在我分成兩次,每次傳80位元組就沒有問題了。
[48樓]樓主
Bill_Hoo 回複
2013-09-03 17:50:04
回複 51CTO遊客:[44樓]
你好:
A1、幀A和幀B沒有直接聯系,我們隻需要知道總延遲,至于這兩幀是否為互相包含的音頻沒有關系。
A2、根據你的描述,感覺你的思路是這樣的:記錄幀A放進farend buffer的時刻,然後要讓該時刻去比對幀B傳入 process 的時刻。如果你是這樣想的,是因為你覺得幀A和幀B是有關聯的。實際上這兩幀并沒有直接聯系。如A1所述,我們需要知道的僅僅是兩個時間:
T1(系統的播放延遲) = 幀A被硬體播放出來的時刻 - 幀A被放進 farend 的時刻;
T2(系統的采集延遲) = 幀B被放進 process 的時刻 - 幀B被硬體采集的時刻;
total delay = T1 + T2;
A3、AudioRecord.rad() and AudioTrack.write() 會阻塞,阻塞時間可以在調用前和調用後粗略計時即可。 AudioRecord buffer的最小大小可使用其提供的API擷取。詳情請參見 http://developer.android.com/reference/android/media/AudioRecord.html#getMinBufferSize(int, int, int)
希望以上闡述能解答你的疑惑。
[50樓]樓主
Bill_Hoo 回複
2013-09-03 17:53:05
回複 51CTO遊客:[46樓]
這段時間都沒接觸WebRTC音頻部分了,NS子產品都有定點了 - -+
[53樓]
emuman 回複
2013-09-22 11:33:59
回複 Bill_Hoo:[17樓]
你好部落客,請教一下您在17樓關于aecm延遲的計算說明:
“t_analyze 表示你對音頻幀A調用 farend 的時刻,t_render 表示[硬體]真正播放出幀A的時刻。
t_capture 表示[硬體]采集到音頻幀B(注意跟A沒關系了)的時刻,t_pull 表示幀B被傳入 Process的時刻。”
我看了echo_control_mobile.h裡的方法,關于四個時刻的點怎麼确定不是很清楚,比如t_analyze的時間,應該是在調用WebRtcAecm_BufferFarend()前計時還是調用後計時呢?看英文原意四個時刻應該是之後吧?可是如果t_pull是在調用WebRtcAecm_Process()之後才計時的話,WebRtcAecm_Process()它本身就需要使用延遲參數(也就是說調用它時這參數還沒計算出來呢),感覺又沖突了,請部落客指點迷津。
而關于render的時間,“t_render is the time the first sample of the same frame is rendered”,一個語音幀(80或160個采樣)的第一個采樣被播放的時間,總感覺取不到,我們能取到的隻有播放完整個語音幀的時間點吧,t_capture同理,您是怎麼處理這兩個時間點的呢?
[54樓]樓主
Bill_Hoo 回複
2013-09-23 14:04:58
回複 emuman:[53樓]
你好emuman,
A1:四個時間點均在調用之前得到即可。
A2:我們确實不能直接得到第一個采樣點的時間,但你可以根據自己上層的 buffer 大小以及底層的硬體 buffer 大小估算出緩沖區中總共緩沖了多少幀,這樣一來便可計算出第一個采樣點的時間。
[55樓]
emuman 回複
2013-09-25 15:02:09
回複 Bill_Hoo:[54樓]
首先多謝部落客答複,然後繼續咨詢一下。
這幾天我在android上試驗,用jni+opensles來錄音、放音,發現理論和實際情況大有不同。
參數是8khz、mono、16bit錄音和放音,每個語音幀80個sample(10ms)。
1、首先單個延遲很小,t_render - t_analyze大約在25-55ms區間内,t_pull - t_capture對我來說約等于0,因為我采集後馬上就進行process了;和部落客說的大約100--200ms差距比較大。此外我是不斷重新計算延遲值的,部落客您是計算出一個值就固定使用還是也不斷計算?
2、opensles的錄音放音情況是:某個時間段内得到m個錄音的語音幀,然後下一個時間段播放n個語音幀,如此反複。是以如果不變通,就會變成調用m次WebRtcAecm_BufferFarend()後再調用n次WebRtcAecm_Process,4個時間點怎麼确定就很暧昧了:因為延遲值其實是給錄音後的process用的,是以屬于錄音的t_capture和t_pull的時間點是明确的,但是放音的t_analyze和t_render用m個語音幀裡的哪個呢?第一個、最後一個、平均值?我試驗了最後一個(距離錄音動作最近的上個播放延遲),發現出來的結果不對;直覺上第一個、平均值也應該不對。
最後,從多次統計結果發現,m和n是同一個數量級,差距不大(這是顯然的)。
3、從我這段時間的測試資料看,android機系統有自己的opensles緩沖區,比如錄音,我設定錄音緩沖區是80個sample,系統會先錄制一段時間,資料充滿它自己的緩沖區(系統緩沖區)後再調用回調函數拷貝到我設定的緩沖區(使用者緩沖區),放音也同理(提供資料足夠快的情況下),這就解釋了上面第二點的情況:先提供m個錄音語音幀,再消費n個放音語音幀。
這裡有個問題,我翻遍開發文檔發現系統沒提供接口來得到系統内置緩沖區大小,我甚至在google play上找到個audio buffer size的app,它用自己的算法來計算系統opensles的内置緩沖區和采樣率大小,但我的測試機算出來的結果和我的測試資料又沒法對上。java層的AudioRecord.getMinBufferSize()以及api17後倒有個相關的AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER,這兩個試驗過發現也不對。
4、針對2和3的情況,我設想過能不能把m個錄音幀當一個大幀、n個放音幀當一個大幀來處理。WebRtcAecm_BufferFarend()好像可以累積資料,隻要長度不超過它的緩沖區最大值就好;但WebRtcAecm_Process()隻能傳進80或160個sample,這就沖突了。
5、好像蘋果機的機制是錄一個幀再放一個幀,非常符合webrtc aecm的理論,甚至它都提供内置的回音處理了。android在4.0後雖說也提供内置的回音處理,但效果很多時候等于沒有。這點是我的牢騷了,android還有很多地方要完善。
對opensles的這種情況,部落客有沒有什麼經驗?甚至提供個思考的方向都可以,我現在束手無策了
[56樓]樓主
Bill_Hoo 回複
2013-09-26 10:02:34
回複 emuman:[55樓]
emuman你好:
A1:100~200ms延遲是在 Java 層使用AudioRecord/AudioTrack得到的,你使用的opensles在JNI層了,延遲在25-55ms正常。t_pull - t_capture不一定為0,你雖然采集之後馬上就調用 process,但是t_captrue是硬體采集到某幀的時刻,該幀從硬體進入底層buffer,然後你的 opensles 從底層buffer讀取是有延遲的,這個延遲要算,在JNI層可能很小,但是也要算。最後延遲值的确需要不斷更新。WebRTC源碼裡我看了下好像是每一秒更新一次,我自己的實驗結果1秒太久了,我是每發送一幀就更新延遲值。
A2:當初選型的時候我沒用OpenslES,是以我不清楚他的工作流程。從你對他的描述中發現問題在于其錄音、放音流程導緻四個時間點不好捕捉,他自己緩存了錄音幀和播放幀,但我們又沒辦法求得緩存大小以最終求得緩存延遲。個人暫時沒想到好的直接可行的解決辦法,因為如果我們沒辦法得知他緩存了多少資料,那如何求得對應的延遲?不過我隐約有個思路是我們需要自己設計buffer來統一緩存資料,這樣便可計算,但實作方案我沒有思路。
A3:據你的描述,“我設定錄音緩沖區是80個sample,系統會先錄制一段時間,資料充滿它自己的緩沖區(系統緩沖區)後再調用回調函數拷貝到我設定的緩沖區(使用者緩沖區),放音也同理”。既然你可以設定緩沖區大小,為何不能計算出延遲呢?這點需要你再加以闡釋。其次,AudioRecord.getMinBufferSize()所獲得的大小是系統最小錄制緩沖區大小(如果你沒有其他設定的話),這個值你需要在構造AudioRecord執行個體時傳入,這樣該執行個體對應的底層buffer才會是這麼大,之後根據這個大小是可以估算出底層buffer所造成的延遲的。AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER我沒有研究過,不敢亂講。
A4:“當成一個大幀”這種思路其實和我第二點提到的思路異曲同工了,我們的核心思想都是希望将小的、不可知的opensles底層buffer延遲中和起來,得到一個整體的、可計算的延遲,我直覺可行,但需要實踐。 WebRtcAecm_BufferFarend()的确有自己的buffer,好像是用來做比對算法的,回聲處理的算法圖可以在 CSDN 裡找到。但該buffer大小不足以容納太多的資料。
A5:iOS音頻系統本身的延遲就很小,并且其具有直接擷取硬體延遲的API,WebRTC源碼裡就是直接調用的該API。 VoiceProcessionUnit 也自帶有回聲消除選項,不過我沒有使用過。至于 android 的 ES,我用過,效果不堪。android的的确确需要繼續完善,尤其是音頻API,不過 android 畢竟開源,個人覺得其生命力和活力都很不錯,而且 Google 也在統一 android 市場了,跑題了- -、
希望以上回答能幫助你打開思路,我還有哪裡沒講清楚的請留言。
[57樓]
emuman 回複
2013-09-26 10:36:29
你好部落客,感謝你的回複。
關于3,“既然你可以設定緩沖區大小,為何不能計算出延遲呢”,這裡沒講清楚,opensles裡初始化錄音器和播放器時必須指定緩沖區大小以及個數,自己設定的緩沖區指的是這個使用者緩沖區,它的延遲是可以計算的,但系統還有個緩沖區,那個現在看來無法直接取到它的大小(也就是延遲),問題是在這裡。
opensles的工作方式裡可以設定成給錄音/放音提供多個一樣大小的緩沖區(估計是為了資料處理連續性),這個緩沖區隻是使用者緩沖區而非系統緩沖區,然後指定錄音/放音回調函數,每次回調就提供/消費一個使用者緩沖區資料。
昨晚我有了新思路,這兩天繼續試驗,有什麼進展再過來讨論。
[58樓]
Suitjune 回複
2013-09-26 19:46:52
你好,BillHoo!
我從***追到這裡,我最近在做基于ARM Linux闆子的媒體通信項目,碰到回聲問題,想用WebRtc的AEC,但有些問題看代碼和網上資料沒看懂,想跟你請教以下幾個問題:
1.WebRtcAec_BufferFarend函數前面有注釋:
Only Buffer L band for farend
是什麼意思?隻能放L Band資料還是放了W Band他也轉換為L Band?我看了裡面代碼,就是時域轉頻域,然後寫緩存;
另外,L Band和W Band是指的采樣率的高低嗎?
2.WebRtcAecc_Process函數中的最後一個參數skew是幹什麼用的?怎麼設定?我沒看明白。
3.AEC和AECM都有注釋Not recommended to be enabled on the server-side.在aec_processing.h中,為什麼?伺服器端指的是什麼?多點通信中負責混音的類似H.323中的MCU嗎?超級節點?
4.AEC可以修改為44.1K采樣率嗎?Echo Tail Length想要修改的話要動哪裡?
不好意思,一口氣問了這麼多,還望部落客給予指點。
多謝!
[59樓]樓主
Bill_Hoo 回複
2013-09-29 15:01:55
回複 emuman:[57樓]
好的,祝你成功。
[60樓]樓主
Bill_Hoo 回複
2013-09-29 17:09:05
回複 Suitjune:[58樓]
你好 Suitjune, 我最近很忙,是以沒辦法詳細回複你,抱歉。
[62樓]
it206 回複
2013-10-17 11:29:47
能再分析下neteq子產品嗎,貌似對音頻品質有一定的提高
[63樓]樓主
Bill_Hoo 回複
2013-10-18 08:52:14
回複 it206:[62樓]
it206 你好,neteq子產品我還沒有涉及,如果有可能涉及到,我會分享在這裡的。謝謝你的建議 :)
[64樓]
Suitjune 回複
2013-10-20 15:22:04
Bill Ho,還是要請教你相關問題:
1.我用WebRtc的AEC提取出來,在ARM-Linux的闆子上運作,現在我做測試:
1.32K單聲道的人聲檔案A,1次160采樣點做BufferFarend,同時将這個檔案去做Process,Output出來的檔案幾乎沒有聲音,都去掉了;
2.如果我是A去做BufferFarend,同時A+B,兩個人聲去做Process,則輸出聲音劣化嚴重,聲音嗡嗡的;
3.如果我錄制了一段很安靜的聲音,幾乎沒有聲音的檔案C去做BufferFarend,然後A+B人聲做Process,那輸出也是嗡嗡的;
這可能是什麼問題導緻的呢?謝謝!
[65樓]
Suitjune 回複
2013-10-20 16:23:42
上面的問題應該是我自己弄粗了。
[66樓]
Jack6690 回複
2013-10-21 21:33:39
樓主,您好,最近項目中要用到AECM,我在按照樓主提供的AECM子產品源檔案進行編譯的時候(頭檔案都已添加),出現函數缺失的錯誤,具體的錯誤提示為“undefined reference to \'WebRtcSpl_MaxAbsValueW16\'”...“undefined reference to \'WebRtcSpl_RealForwardFFT\'“等等錯誤。我的解決方法是找到這些函數所在的源檔案并添加到工程中,生成的庫之後,編寫Demo按照樓主方法進行檢測,讀取相同音頻檔案時依然有原聲。樓主能否給個生成AECM庫的完整檔案,QQ 893077446,萬分感謝。
[67樓]
米牛牛 回複
2013-10-23 23:35:04
謝謝您的文章!我正在使用webRTC中的AEC模塊、我想問一次WebRtcAec_BufferFarend和WebRtcAec_Process中的音頻信號的格式(就是nearend.pcm和farend.pam的格式):我現在是用:
8000HZ採樣、Signed-16 PCM、LITTLE_ENDIAN
我用audacity錄的farend.pcm、然後(僅為測試)我把farend.pcm直接拷貝生成nearend.pcm、這樣我希望AEC處理後生成的output.pcm應該不含有聲音信號(全部過濾)、但是我得到的output.pcm是很大的噪聲、是以我懷疑是我爸音頻格式設錯了。
請問:
輸入的farend.pcm和nearend.pcm的格式是8000HZ採樣、Signed-16 PCM、LITTLE_ENDIAN嗎?
AEC處理後輸出的output.pcm的格式也是8000HZ採樣、Signed-16 PCM、LITTLE_ENDIAN嗎?
另外附上我的測試代碼(從sample中拷貝的)、麻煩您幫我看一下問題在哪裡、謝謝!
。。。
void * haec = NULL;
if( 0!=WebRtcAec_Create(&haec) )
printf("create error\n");
if( 0!=WebRtcAec_Init(haec,8000,8000) )
printf("init error\n");
short farend[160],nearend[160],output[160];
FILE *ffar, *fnear,*foutput;
ffar = fopen("farend.pcm","r");
fnear = fopen("nearend.pcm","r");
foutput = fopen("realoutput.pcm","w");
for(int i=0;i<500;i++)
{
fread(farend,2,160,ffar);
fread(nearend,2,160,fnear);
if( 0!=WebRtcAec_BufferFarend(haec,farend,160) )
printf("bufferfarend error\n");
if( 0!=WebRtcAec_Process(haec,nearend,NULL,output,NULL,160,0,0) )
printf("process error\n");
fwrite(output,2,160,foutput);
}
if( 0!=WebRtcAec_Free(haec) )
printf("free error\n");
fclose(ffar);
fclose(fnear);
fclose(foutput);
。。。
[68樓]
米牛牛 回複
2013-10-24 02:34:44
問題已經找到了(粗心大意忘記用2進制來讀寫測試檔案了)。現在把farend.pcm中的語音以100ms延遲混入nearend.pcm中,再用WebRtcAec_Process(haec,nearend,NULL,output,NULL,160,100,0)來處理,基本可以去掉原來farend.pcm中的語音(迴聲),再次感謝您的文章!
[70樓]
米牛牛 回複
2013-10-24 22:16:42
謝謝!我還想問您一個問題:在昨天的測試中,我剛開始使用8000HZ/Signed-16-PCM/LITTLE_Endian的語音數據、當延遲100ms的時候,迴聲基本可以消除;但是後來改為我們現在實際使用的16000HZ/Signed-16-PCM/LITTLE_Endian的語音數據時,發現迴聲殘留明顯比8000HZ的時候大很多。我在處理8000HZ數據的時候調用WebRtcAec_Process的參數是這樣的:
WebRtcAec_Process(haec, nearend, NULL, output, NULL, 160, 100, 0)
我覺的160應該是20ms的8000HZ/Signed-16數據,是以當處理16000HZ/Signed-16數據的時候,應該改成320,即這樣調用:
WebRtcAec_Init(haec,16000, 16000)
WebRtcAec_BufferFarend(haec, farend, 320)//20ms的16000HZ/Signed-16數據
WebRtcAec_Process(haec, nearend, NULL, output, NULL, 320, 100, 0)//100ms延時
但是當改成320的時候、WebRtcAec_BufferFarend和WebRtcAec_Process都報錯(傳回值不為0),我想問一下:是否這2個函數能夠處理的sample數目最大就是160?您在處理16000HZ/Signed-16數據的時候、每次處理的是10ms(160)還是20ms(320),請問這個sample數目和消除迴聲的效果有關係嗎?謝謝!
[71樓]
米牛牛 回複
2013-10-25 03:21:13
剛才看見WebRtcAec_Process的源碼(echo_cancellation.c)中:
。。。
// number of samples == 160 for SWB input
if (nrOfSamples != 80 && nrOfSamples != 160) {
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
return -1;
}
。。。
是以可能是都處理10ms數據(8000HZ的sample是80, 16000HZ的sample是160)、謝謝!
[72樓]樓主
Bill_Hoo 回複
2013-10-25 08:53:35
回複 米牛牛:[71樓]
您好米牛牛,16000Hz,10ms就是 160 個 sample,您最後是算對了的。
[73樓]
icebery425 回複
2013-10-29 21:07:14
hi, bill
最近也在研究webRTC中的AEC子產品,有個問題請教下
WebRtcAec_BufferFarend和WebRtcAec_Process中的參數farend和nearend是不是分别表示揚聲器要發出的原始音頻資料和麥克風錄制的原始音頻資料(這個有可能包括揚聲器的回聲)?另外參數 nrOfSamples是不是表示這兩個函數一次最大處理的資料塊?即隻有80和160這兩個
[74樓]
米牛牛 回複
2013-10-29 21:57:08
您好!我還想問一下關於drift compensation的問題:WebRtcAec_Process最後的那個skew參數、我現在一般都設為0、請問這個參數需要根據硬體的情況進行調整嗎?還是說都設為0?謝謝!
[75樓]
米牛牛 回複
2013-10-29 22:12:10
這裡有一個skew參數的討論:
https://groups.google.com/forum/#!searchin/discuss-webrtc/skew|sort:relevance/discuss-webrtc/T8j0CT_NBvs/aLmJ3YwEiYAJ
其中有一段:
。。。but we\'re really just compensating for a mismatch
between 44.1 and 44 kHz sampling rates.。。。
這是不是說對於8000HZ和16000HZ來說、skew參數都可以設為0?還是說依然要設法計算當前硬體的drift?謝謝!
[76樓]
icebery425 回複
2013-10-30 09:28:28
回複 米牛牛:[75樓]
這個應該是對于不同平台的時鐘補償吧,因為不同平台的時鐘不一樣,會導緻同頻率有差異
[77樓]樓主
Bill_Hoo 回複
2013-10-30 17:40:27
回複 icebery425:[73樓]
您好icebery,
farend是遠端資料,即VoIP通信中接收到的對端的、即将被本地揚聲器播放的音頻A。
nearend是本地資料,即剛剛被本地麥克風采集到的音頻B,而音頻B可能包含上述音頻A(麥克風采集到了揚聲器播放的A),于是 A和B 一起發送給遠端,緻使遠端又聽到了自己剛才發送的A,也就産生了所謂的回聲。
nrOfSamples 可以這麼了解,具體的含義WebRTC源碼裡有說明的 :)
[78樓]樓主
Bill_Hoo 回複
2013-10-30 17:43:46
回複 米牛牛:[74樓]
您好米牛牛,該參數在理想情況下的確為0,但硬體不同,對音頻進行渲染和播放的延遲就有所差異,這個差異在我之前的android設備上達到了100~200ms不等,如果始終保持為0,僅根據我的實踐結果,將得不到好的回聲消除效果。以我個人的經驗來說,該參數是需要實時更新的。 :)
注:部落客用繁體回複,真是很好的一個人啊
[79樓]
icebery425 回複
2013-10-30 19:56:18
hi, bill
最近我在研究一個消除超音波回聲的項目,用WebRTC中的AEC時,發現在調用WebRtcAec_Init時,參數有一個需要傳遞采樣資料頻率隻有8000, 16000,32000hz這幾種頻率,我這邊需要用到的采樣資料頻率為44100,當傳這個值是就出錯,應該是表示不能傳其它頻率的值,或更高的值,想問下,你有沒碰到過這樣的問題,或者類似的情況,需要消除超音波的回聲?
[80樓]
米牛牛 回複
2013-10-30 23:19:41
回複 Bill_Hoo:[78樓]
謝謝您的回複!您說的要實時更新的100~200ms的參數是下面的哪一個?是msInSndCardBuf還是skew?
WebRtcAec_Process(void *aecInst,
const WebRtc_Word16 *nearend,
const WebRtc_Word16 *nearendH,
WebRtc_Word16 *out,
WebRtc_Word16 *outH,
WebRtc_Word16 nrOfSamples,
WebRtc_Word16 msInSndCardBuf,
WebRtc_Word32 skew)
msInSndCardBuf是用來適應延遲的、您說的要在100~200ms內實時更新的是指msInSndCardBuf嗎?請問是否skew也需要實時更新?是否skew目前隻用於對於44100hz的漂移補償?能介紹一下如何實時更新skew參數的步驟嗎?謝謝!
[81樓]
icebery425 回複
2013-10-31 09:08:55
回複 米牛牛:[80樓]
hi, 米牛牛,你有沒償試做過對44.1KHz采樣資料的消回聲事情?
見96樓
[82樓]樓主
Bill_Hoo 回複
2013-10-31 09:16:50
回複 米牛牛:[80樓]
您好米牛牛:
我很抱歉的發現我們討論的不是一個模塊。我說的是手機上進行AEC處理的模塊“AECM”,而你使用的是PC端的“AEC”模塊。手機上的AECM模塊是沒有skew參數的,我想這也是手機CPU瓶頸所緻。而PC端的接口會有skew參數。這個參數我沒有研究。隻是當初在手機上使用PC端模塊AEC時,該參數被我設置為0。之後就沒有對這個參數做任何學習了。
[86樓]
米牛牛 回複
2013-11-01 02:03:13
回複 米牛牛:[84樓]
但是我發現一個情況:就是當我把AEC初始化為16K的時候、依然可以處理8K的數據(這時每次處理的數據依然是160個samples、即變為20ms的8K數據)、不知是否對您的44K項目有用
[87樓]
lzg9099 回複
2013-11-01 10:59:40
Bill_Hoo,請教你一下,我在android上應用了那個aecm子產品,回音消除的效果不錯,但是,如果一個語音過長的話,比如說一次說七八個字,經過回音消除後,出現了語音丢失的情況,即第四五個字會丢失或者無法聽清楚,不知道這個是什麼原因呢,是和參數的設定有關嗎?我的msInSndCardBuff設為240左右?這個問題困擾了好久了,最近一直在看源代碼也沒啥頭緒。
[88樓]樓主
Bill_Hoo 回複
2013-11-01 11:21:14
回複 lzg9099:[87樓]
您好lzg9099:
我在想,你是一直使用240這個定值麼?再者,回聲消除的級别是否開到了最大?降一個級别試試。如果你能提供更明确的資訊,也許我們可以找到問題所在。
[89樓]樓主
Bill_Hoo 回複
2013-11-01 11:50:49
回複 lzg9099:[87樓]
還有一個問題我突然想到,你是不是在做本機的回環(127.0.0.1)測試? 如果是的話,吞字是正常的。
[90樓]
lzg9099 回複
2013-11-01 13:23:24
回複 Bill_Hoo:[89樓]
感謝你的回複:
1,我是一直使用的240這個定值,我換了幾個手機測試時都是用的240,效果都很好,要是将該值設為其他的話,聲音要麼有雜音,要麼就聽不到聲音了;2,關于回音消除的級别,我沒有去設定,那應該是預設的級别吧,這個級别我也沒弄太清楚;3,關于測試,我隻是寫了一個demo,通過将AudioRecord采集的聲音,傳給aecProcess()方法進行回音消除,然後利用AudioTrack将處理過後的聲音播放出來,播放以後調用aecmBufferFarend()方法将處理後的聲音處理一下。這樣測試時,播放出來的聲音是沒有回音的,但是出現了吞字狀況。
[91樓]
AudioAEC 回複
2013-11-02 07:43:28
Bill_Hoo 高手,你好,我按照你的思想把aecm抽取出來編譯成so,通過jni給Android調用,回音消除效果如下:如果是前置喇叭(聽筒)效果完美,如果是後置喇叭(播放音樂用的)效果不如前置喇叭,總體來說還不錯。但是現在出現一個問題就是 當選擇後置喇叭作為輸出時,如果在一個很安靜的房間,靜靜的幾分鐘不說話,就會産生嘯叫,如果出現嘯叫後就說話,這嘯叫就立刻消失。想請教一下,這個嘯叫怎麼産生的,還有怎麼樣可以解決,你的軟體會産生這樣情況嗎? 恭候QQ上讨論 扣扣 1281200395
[92樓]樓主
Bill_Hoo 回複
2013-11-02 21:06:13
回複 AudioAEC:[91樓]
你好,首先,聽筒放音是不會存在聲學回聲的。聲學回聲之是以産生,是因為揚聲器播放出來的聲音又被麥克風采集回去。而聽筒播放的聲音麥克風是采不到的。
其次,嘯叫的問題需要借助 VAD 來進行靜音檢測,在靜音的環境下就不需要向揚聲器傳遞音頻進行播放了。
[95樓]
Jack6690 回複
2013-11-04 19:20:42
您好,我的AECM子產品讀檔案測試正常。在開雙線程測試時,一個線程用AudioTrack讀檔案播放,并調用bufferFarend;另一個線程中,用AudioRecord錄取音頻資料,并調用process将錄取的資料進行處理,處理後的資料存入到pcm檔案中。用Audition播放處理後的音頻資料,為能完全消除掉回聲,但是出現吞音的現象,且經常出現。用setConfig方法設定回音消除等級後,吞音現象微有減弱,但依然存在。
調試了很多,依然無法解決上面的問題,我懷疑是延時計算有問題,我的延時計算為:
硬體延時t1: bufferSize1 = AudioRecord.getMinBufferSize(...)
t1 = bufferSize1 / frameLength * 10 ms
讀取資料阻塞延時t2:
startTime = System.currentTimeMillis()
audioRecord.read(...)
t2 = System.currentTimeMillis() - startTime
硬體延時t3: bufferSize2 = AudioTrack.getMinBufferSize(...)
t3 = bufferSize2 / frameLength * 10 ms
讀取資料阻塞延時t4 :
startTime = System.currentTimeMillis()
inStream.read(...)
t4 = System.currentTimeMillis() - startTime
總延時是上述四個延時之和,不知道上述延時計算是否存在問題,請多指教。
我是從pcm檔案讀取資料送到AudioTrack播放,同時錄音擷取的資料直接送到process中。
[96樓]樓主
Bill_Hoo 回複
2013-11-05 16:34:38
回複 icebery425:[81樓]
您好 icebery425:
我這段時間在往WebRTC音頻的上邊一層看,也就是APM(AudioProcessingModule),發現APM使用的抽象類型 AudioFrame 最高僅支援雙聲道 60ms 的 32KHz音頻。
/* This class holds up to 60 ms of super-wideband (32 kHz) stereo audio. It
* allows for adding and subtracting frames while keeping track of the resulting
* states.
你所說的44.1應該會被處理掉的,具體的我還在看。
[97樓]
it206 回複
2013-11-06 22:40:50
想問下,vad子產品的使用,為什麼我的WebRtcVad_Process總是傳回1,即使不說話時也是這樣
[98樓]樓主
Bill_Hoo 回複
2013-11-06 22:58:36
回複 Bill_Hoo:[96樓]
您好,delay的計算方法在之前的讨論中已經讨論過了。我看了下你的計算,應該還沒有計算底層 buffer 緩沖的資料。最近我在看 APM 了,建議您參考下 audio_device_jni_android.cc 中的實作。
[99樓]樓主
Bill_Hoo 回複
2013-11-06 22:59:42
回複 it206:[97樓]
您好,您給的條件好像少了點,我沒辦法判斷傳回值異常的原因。也許你的JNI實作有bug?也許VAD模式開到了***别?級别越高,傳回1的機率越大。
[100樓]
it206 回複
2013-11-07 10:52:45
我是8000采樣,pcm16,每次處理320 byte資料,區域網路自環或者2台手機udp互通,情況一樣,WebRtcVad_Create,VadApi_Init 都正常傳回0,vad模式設定0或者最高都試過,在編碼之前做靜音檢測,如下
for(int i = 0; i < 2; ++i)
{
result = vad.VadApiValidRateAndFrameLength(8000, 160);
System.out.println("VadApiValidRateAndFrameLength result = " + result);
System.arraycopy(bufferSpeech, i * 160, intmp, 0, 160);
result = vad.VadApiProcess(8000, intmp, 160);
System.out.println("VadApiProcess result = " + result);
}
VadApiValidRateAndFrameLength 傳回0
VadApiProcess每次都傳回1
感覺這樣使用沒有問題,但是無法檢測靜音
[101樓]
米牛牛 回複
2013-11-08 23:40:35
我還有個問題想問一下:我在實驗中想處理2種迴聲:
第一種是別人的聲音進來後我不把它發出去(由我的麥克風造成的)、這種迴聲延時較短
第二種是我的聲音發出去之後又被別人echo回來、我不想聽到自己的聲音、這種迴聲延時較長
我現在可以消除第一種迴聲,但是第二種基本無法消除:請問你們有用webRTC-GIPS的這個API可以成功消除第二種迴聲的嗎?謝謝!
我現在的思路是:隻要我能夠正確估算出延時、我就可以先buffer一段數據、然後在合適的時候再調用WebRtcAec_BufferFarend、如果這個思路可行的話、延時可能可以用某種算法(比如卡爾曼濾波)來自適應跟蹤、不知這種思路是否可行?謝謝!
[102樓]
米牛牛 回複
2013-11-09 03:09:53
另外請問一下:這篇論文討論的是不是我在前面說的第二種迴聲(就是我發出去的然後又傳回來)?謝謝!
http://wenku.baidu.com/view/403b6739376baf1ffc4fadfc.html
[103樓]樓主
Bill_Hoo 回複
2013-11-09 11:06:49
回複 米牛牛:[101樓]
您好米牛牛:
不知道你的實驗是基於PC的還是手機的?
首先我們討論的是VoIP中的聲學回聲的消除。WEBRTC的API足以保證聲學回聲的消除(隻是如果延遲處理的不好,會有部份正反饋嘯叫)。
就我目前的知識水準來說,我認為你說的第一種情況不會產生、至少不會影響到正常通話的聲學回聲。麥克風造成的應該是硬體回聲吧?這跟WebRTC討論的聲學回聲應該不是一個範疇。
第二種情況,是別人開了揚聲器外放,如果沒有做回聲消除,外放的聲音會被他的麥克風再次採集并發送給我們,這是聲學回聲的範疇,WebRTC是可以很好處理的。
如果你是基於PC的實驗,WebRTC上Windows端的回聲消除做得還是不錯的,他的延遲可以根據系統API直接計算出來,這個過程WebRTC - win 的Demo中已經有了,可以直接參考著做。
如果你是基於手機的VoIP應用,本文提供的方法可以消除90%的回聲,剩餘的10%是因為delay計算的不準確導緻的正反饋嘯叫。這一點我現在也正在努力,目前的思路是上升一個級別的API,使用WebRTC - APM 并使用底層的OpenSLES進行音頻的播放和採集,這樣最大限度的減小延遲的誤算。
[104樓]
LuoZH 回複
2013-11-10 16:08:07
Bill_Hoo,你好。
我現在也在做Aecm這塊,我這邊編譯後,在PC上測試,一點效果都沒有,用PCM檔案測試,聲音都變得很糟。是不是編譯的時候需要打開什麼宏啊?另外,你能提供一個Demo嗎?
謝謝。
[105樓]
Sea_biscuit 回複
2013-11-11 00:41:41
樓主你好,請問如何利用 web rtc的AEC子產品在本地采集音頻并播放,進而驗證消除回聲的功能。我在使用windows 下的directshow 音頻采集和 播放,在 Audio Capture 和 DSound renderer之間加入了自己寫的AEC filter(内部利用Webrtc AEC來實作), 在AEC Filter内部 設定緩沖區存放之前的幾個聲音buffer, 同時将新來的buffer和老的buffer做回聲消除。效果很差,仍然會出現回聲嘯叫。請問樓主這種方案可行麼?問題出在什麼地方?謝謝~
[106樓]
Sea_biscuit 回複
2013-11-11 00:44:58
樓主你好,請問使用webrtc 的回聲消除功能,隻需要使用它的 AEC 部分,編譯成庫檔案即可麼?還是需要整個了解設定 webrtc 的 Audio Processing 子產品來使用(我看網上好多這麼寫的,但都沒有執行個體)?希望樓主有時間解答一下,謝謝~
[107樓]
linux_aecm 回複
2013-11-11 12:03:08
樓主 你好!一直在關注你的回複,我現在在linux平台上測試webrtc的aecm子產品,現在苦于延時的計算,我用的是alsa的接口aplay和arecord來進行放音和錄音,很難計算出第一個幀從硬體放出來的時間和第一個幀被硬體采集到的時間,系統貌似沒有提供合适的函數來計算這些時間,請問樓主能否給一些建議,非常感謝!
[108樓]
米牛牛 回複
2013-11-12 02:27:53
回複 LuoZH:[104樓]
Bill_Hoo您好,
我在測試中發現2種迴聲都是存在的、具體如下:
第一種迴聲是我自己的設備產生的:即別人的聲音進到我的揚聲器後、又被我的麥克風捕獲後發給別人、這種迴聲延時較短。這時AEC的目的是不想讓別人(因為我的設別)而聽到他自己的聲音、這時farend是我收到的語音、nearend是我即將要發出的語音
第二種迴聲是別人的設備產生的:即我的聲音進到別人的揚聲器後、又被別人的麥克風捕獲後發給我、這種迴聲延時較長。這時AEC的目的是我自己不想因為別人的設備而聽到我自己的聲音、這時farend是我即將要發出的語音、nearend是我收到的語音
我發現因為第一種情況延時較短是以AEC效果較好;而第二種情況延時較短是以AEC效果相對較差;請問您處理的是哪一種情況?您計算出來的延時大概是多少毫秒?能否告訴我一下您通常處理的這個延時數?謝謝!
[109樓]樓主
Bill_Hoo 回複
2013-11-12 09:27:26
回複 米牛牛:[108樓]
您好米牛牛:
我懂到您的意思了,您對farend和nearend的了解和我的了解不太一樣。
首先說說我的了解:針對同一台設備,隻存在一個 farend 和一個 nearend,同一台設備上,從對方設備接收到的音頻數據為 farend(也即即將被本機播放的音頻);從本機採集到的音頻為 nearend (也即即將發送給對方的音頻)。而每一台設備僅針對自己設備上的farend和nearend進行AEC處理而無需考慮對方(因為對方也會在他的設備上做同樣的處理)。
綜上所述,是以我認為不存在您所說的具備兩種回聲。
不知道我這樣的了解是否有誤?您有什麽見解我們再一起討論。
其次,延遲參數在不同的設備上是不一樣的,這裡我僅有手機處理的經驗,是以就不談PC了。手機上,比如三星i9100延遲計算出來達到了150~230ms的樣子,而魅族MX延遲僅在80~120ms左右。當然i9100用的是android 2.3.1,而魅族MX是4.1.3,不過CPU處理能力也占一部份因素。延遲爲什麽會差距這麼大,就我目前的知識水品無法說清楚。
[110樓]樓主
Bill_Hoo 回複
2013-11-12 09:33:52
回複 linux_aecm:[107樓]
您好:
linux上的ALSA接口我沒有測試過,我這段時間在看APM,好像針對ALSA有單獨的編譯選項,具體的我沒有深究。這裡僅說一下android上延遲的計算。android上也沒有直接擷取延遲的API,不過可以通過得到底層緩沖區的大小和目前播放的位置進而估算出緩沖區造成的延遲,這一計算的具體細節我昨天剛在WebRTC源碼的android_test中找到。不知道linux上的接口是否有提供關于底層緩沖buffer大小的資訊?
[111樓]樓主
Bill_Hoo 回複
2013-11-12 09:37:57
回複 Sea_biscuit:[105樓]
您好Sea_biscuit:
PC上的AEC我沒有涉足,不敢亂講。不過PC上好像不用單獨把AEC提取出來,因為沒有CPU的限制,PC上是可以直接把WebRTC-WIN編譯出來跑的。
至于您的第二個問題,在手機上,AECM子產品是可以單獨使用的。如果延遲計算的好,效果是可以接受的、不會産生反感情緒,但不夠完美。是以近段時間我也一直在倒騰APM,現已經完成了APM整體子產品的編譯和測試,隻是如何調優我還在倒騰中,是以也不敢亂講。
[112樓]樓主
Bill_Hoo 回複
2013-11-12 09:42:25
回複 it206:[100樓]
您好,初步看了下代碼應該是沒有問題的。建議您進行底層的調試以求找到問題所在。調試方法部落格裡有寫。希望對您有所幫助。
[113樓]樓主
Bill_Hoo 回複
2013-11-12 09:44:14
回複 LuoZH:[104樓]
您好,AECM是用于手機等移動裝置的回聲消除子產品。PC您應該使用AEC才對。至于編譯選項,不知道您是在PC環境下(WIN32宏)還是在linux環境下(WEBRTC_ANDROID等宏)編譯的?
[114樓]
Sea_biscuit 回複
2013-11-12 12:07:10
回複 Bill_Hoo:[111樓]
樓主你好,謝謝你的回複。還有一些問題,就是你說的 PC上可以直接将 WebRTc-WIN編譯出來跑是什麼意思,是整個P2p的聊天系統麼? 還有就是樓主能否講一下如何将整個APM 編譯使用麼,是做成庫還是啥?謝謝~
[115樓]樓主
Bill_Hoo 回複
2013-11-12 18:18:24
回複 Sea_biscuit:[114樓]
您好,PC上WebRTC是有完整的DEMO的,隻要編譯出來就可以跑,然後你可以根據自己的需要進行提取。具體的我沒有親自實驗過是以就不亂講了。APM是可以直接編譯成庫進行使用的。
[116樓]
Sea_biscuit 回複
2013-11-12 20:36:11
回複 Bill_Hoo:[115樓]
樓主你好,謝謝你的回複。現在還有個問題麻煩你一下下,就是我編譯出來 audioprocessing.lib 在程式中結合 audio_processing.h 使用。其中 static AudioProcessing* AudioProcessing::Create(int id);函數顯示未定義還是啥
: error LNK2019: unresolved external symbol "public: static class webrtc::AudioProcessing * __stdcall webrtc::AudioProcessing::Create(int)" (?Create@AudioProcessing@webrtc@@SGPAV12@H@Z) referenced in function "public: __thiscall APM::APM(void)" (??0APM@@QAE@XZ)
就是這個。
請問樓主問題出在什麼地方? 是使用方法不對還是什麼,謝謝~
[117樓]樓主
Bill_Hoo 回複
2013-11-12 21:20:07
回複 Sea_biscuit:[116樓]
您好,我沒有編譯PC上的APM,不過這個問題您可以借助GOOGLE進行分析解決,直接GOOGLE:error LNK2019:http://www.cppblog.com/longshen/archive/2010/04/02/111418.html
[118樓]
Sea_biscuit 回複
2013-11-12 22:46:59
回複 Bill_Hoo:[117樓]
謝謝樓主,您真是太耐心了~謝謝,問題我自己解決了。使用APM子產品不光需要 audio_processing.lib還需要其他幾個lib.再次感謝!
需要以下的幾個lib
#pragma comment(lib, "webrtc\\audio_processing.lib")
#pragma comment(lib, "webrtc\\audio_processing_sse2.lib")
#pragma comment(lib, "webrtc\\system_wrappers.lib")
#pragma comment(lib, "webrtc\\protobuf_lite.lib")
#pragma comment(lib, "webrtc\\common_audio.lib")
#pragma comment(lib, "webrtc\\audioproc_debug_proto.lib")
[119樓]
米牛牛 回複
2013-11-12 23:02:27
回複 Bill_Hoo:[110樓]
Bill_Hoo您好!是的一般都是處理第一種迴聲(我自己的設備產生的)、並且如果每一個設備都把自己的迴聲消除之後、就不會存在第二種迴聲了。隻有當通話對方(或視頻會議中某一個或某幾個與會者)的設備沒有消除自己的迴聲時、別人才會聽到自己的迴聲(第二種)、正如您所說的這種情況比較少見、並且延時也較長不太容易處理(視不同的網絡情況、延時可能會超過1000ms)。
再次感謝您提供的手機延時數據!
[121樓]樓主
Bill_Hoo 回複
2013-11-13 09:10:15
回複 米牛牛:[119樓]
您好米牛牛,您所說的第二種回聲是我沒有考慮到的。我一直假設的是每個設備都能自己把回聲處理掉,也就是說我假設參與會畫的雙方或多方都已經開啟了AEC模塊。感謝您提出的新思路。預祝您的試驗成功。
[122樓]
LuoZH 回複
2013-11-14 10:49:31
回複 Bill_Hoo:[113樓]
Bill_Hoo你好!
你這篇文章幫我了大忙,我是在Linux下編譯的,按你的方法編譯了。之前播放和錄音是在兩個線程,然後沒有正确的計算延時,是以效果很差,現在播放和錄音放在一個線程。将buffer調整到盡量小,現在,消除效果很好。下下一步是在安卓和winCE上使用。
很感謝你們這些願意分享知識的人,如果Lz後續能夠繼續完善後續的研究結果,一定會幫助許多人的。
謝謝Bill_Hoo.
[123樓]樓主
Bill_Hoo 回複
2013-11-14 12:51:34
回複 LuoZH:[122樓]
您好,感謝您的回報。如果您願意,也可以将您在Linux上的經驗寫成博文分享給大家 :) 比如您提到的播放和錄音在同一個線程裡進行。我現在在android上仍然是兩個線程,并且為計算延遲也花了不少精力,如果您的方法更有效,我想這對大家後續的開發都有好處。
[124樓]
LuoZH 回複
2013-11-14 15:51:06
回複 Bill_Hoo:[123樓]
Bill_Hoo你好!
我這個因為場景特殊,是以才能在一個線程内播放和錄音。
編譯的AECM,使用了Linux的OSS接口,可以使用ioctl直接修改buffer(這個網上資料很豐富)。我是使用一個線程進行接收和發送。接收到資料後直接将資料放入一個隊列,然後到另一個隊列去取資料來發送。另一個線程處理錄音和播放,線程首先去接收隊列取資料,放入WebRtcAecm_Farend,并播放,然後立即錄音,将錄到的資料放入WebRtcAecm_Process進行處理,處理之後放入發送隊列。你提到adnroid_test裡面有對延遲的計算,但webRTC類太多層了,我找了很久也沒找到這個計算,不知你能否對這部分計算的相關源碼進行更多的講解。
[125樓]樓主
Bill_Hoo 回複
2013-11-14 16:20:46
回複 LuoZH:[124樓]
您好,android_test 中的延遲仍然使用的是2012年的版本,錄制延遲僅僅采用了一個粗略的固定值,播放延遲的計算方法我比較贊同,也是我自己使用的方法,就是通過android AudioTrack的API估算出底層buffer緩沖的資料延遲。總的來說,仍然是盡可能嚴格地按照前面所說的那個延遲計算公式進行計算,計算得越嚴格,效果越好。
[126樓]
LuoZH 回複
2013-11-14 18:00:48
回複 Bill_Hoo:[125樓]
你好,可否把你計算的這部分代碼發給我?我的Email是[email protected]
[127樓]樓主
Bill_Hoo 回複
2013-11-15 08:53:48
回複 LuoZH:[126樓]
您好,本文僅讨論實作的思路,代碼已經涉及實作細節,有所不便,都是技術人員,請諒解。 :)
[128樓]
huangqizhen 回複
2013-11-26 09:43:27
您好,看了您的博文很有啟發,是以自己也弄了幾個子產品,編譯成了.so檔案。aec我也使用起來了,但現在我被兩個問題所困擾:
1,我是在linux下的alsa環境下作的,是以測延時用了snd_pcm_delay函數。計算出來總共有60多毫秒,去回聲效果還行,但是我把其中一台的delay設成0之後去回聲效果反而還更好了些。這個就有點納悶了,難道delay計算有錯?
2,另一個問題是我在通話的過程當中偶爾會有聲音忽然變小的現象出現,甚至小到聽不到。然後又會恢複。我感覺有點像是回聲消除的太多,把我說話的原音也消除了些。但是我把回音消除的級别降低後現象反而還更不好(我用的是aec,不是aecm,即對nlpMode調節)。
[129樓]樓主
Bill_Hoo 回複
2013-12-04 20:15:39
回複 huangqizhen:[128樓]
您好 huangqizhen:
這段時間很忙沒能及時回複。
A1:linux上的接口我沒有使用過,不過根據 http://mailman.alsa-project.org/pipermail/alsa-devel/2008-June/008421.html 中的回複所說 —— In the driver implementation level, snd_pcm_delay() simply returns the
difference between appl_ptr and hw_ptr. It means how many samples are
ahead on the buffer from the point currently being played. 看樣子 snd_pcm_delay 能夠得到播放緩沖的延遲,但還差采集緩沖的所造成的延遲。至于你把delay置為0之後進行測試效果更好,我覺得這個屬于硬體個别現象,固定的delay不能達到穩定的回聲消除效果。
A2:忽然變小甚至小到聽不到,但是聲音仍然存在?如果聲音存在,隻是變小聲了,是否是你使用了 AGC 且參數設定除了問題。
[130樓]樓主
Bill_Hoo 回複
2013-12-04 20:18:05
回複 huangqizhen:[128樓]
這裡的一些零星資訊也許可以幫到你
http://www.wavecn.com/content.php?id=198
[131樓]樓主
Bill_Hoo 回複
2013-12-04 20:21:29
回複 huangqizhen:[128樓]
上文中提到“不要使用 snd_pcm_delay() 來查詢播放緩沖區的填充情況。它隻能用來作同步用途。”。也許這個才是你延遲計算的罪魁禍首。對于該API我沒有話語權,你可以試着在網絡上查找更多的資訊。
[132樓]
huangqizhen 回複
2013-12-05 10:14:52
回複 Bill_Hoo:[130樓]
您好,Bill
我現在是直接使用WebRtcAec_GetDelayMetrics來擷取目前延時偏差。并根據這個偏差來進行微調,效果在聲音不大的時候還是比較穩定的。但是,聲音一旦想要大起來就出現回音嘯叫了(PS:使用電視與高靈敏度麥克風)。現在也沒有使用snd_pcm_delay了。webrtc的最佳效果不知是否是這樣的,我不太相信隻是這樣。我想是我沒調節好。但是我現在也感覺沒什麼想法與路子了。
請教請教啊,呵呵。
[133樓]
huangqizhen 回複
2013-12-05 11:09:03
聲音忽大忽小的現象現在倒是沒那麼明顯了,我是把ns放到aec前面了。之前是ns放在aec的後面。
[134樓]
huangqizhen 回複
2013-12-05 11:12:02
另外我在audio_device_alsa_linux.cc中找到這個:
// calculate delay
_playoutDelay = 0;
_recordingDelay = 0;
if (_handlePlayout)
{
err = LATE(snd_pcm_delay)(_handlePlayout,
&_playoutDelay); // returned delay in frames
if (err < 0)
{
// TODO(xians): Shall we call ErrorRecovery() here?
_playoutDelay = 0;
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
"playout snd_pcm_delay: %s",
LATE(snd_strerror)(err));
}
}
err = LATE(snd_pcm_delay)(_handleRecord,
&_recordingDelay); // returned delay in frames
if (err < 0)
{
// TODO(xians): Shall we call ErrorRecovery() here?
_recordingDelay = 0;
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
"capture snd_pcm_delay: %s",
LATE(snd_strerror)(err));
}
是以說snd_pcm_delay也可以對錄音計算延時才對的啊?
[137樓]
習慣在這裡 回複
2013-12-19 19:19:11
你好,我的大學畢業設計是android webrtc的實時視訊通訊系統,您能給我點思路嗎,我現在不知道要先做什麼
[138樓]樓主
Bill_Hoo 回複
2013-12-19 21:04:07
回複 習慣在這裡:[137樓]
您好,不清楚你們的畢設要求是什麼,如果隻是視訊通訊,你隻需要把WebRTC在android上整個兒編譯出來就OK了。WebRTC的Demo本身就是一個視訊通訊系統。已經編譯好的Demo你可以在網上搜尋得到。
[139樓]
huangqizhen 回複
2013-12-24 17:10:59
回複 Bill_Hoo:[129樓]
bill您好!
現在有個比較急的問題,就是那個聲音有的時候會變小,甚至有點失真的現象。我沒有使用AGC子產品。現在一直找不到問題所在,基本上20個字有1個字聲音會變小。很影響體驗。求教大俠啊!!!
[140樓]樓主
Bill_Hoo 回複
2014-01-09 11:24:24
回複 huangqizhen:[139樓]
您好,這幾天沒有關注部落格,您提到的聲音有時候會變小,是不是AEC的等級過高導緻自己的聲音被當做回聲一并消掉了?
我最近也遇到一個問題,為了适配各種手機,我找了一個折中的算法進行延遲的計算,但最後的效果就是折中了,雙方通話時卻能聽到令人很不爽的唧唧聲,不知你遇到這種問題沒有,如何解決的呢?
[141樓]
huangqizhen 回複
2014-02-08 18:06:14
您好,bill,年前去做别的事情了,呵呵,是以沒能及時關注。
1、聲音變小應該是能量過低,比如說站在4米外講話,造成語音狀态檢測的誤判(然而檢測閥值又不能太低),把較低能量的語音給消除掉了。現在經過調整好很多了,用手機的話應該是沒有我這個問題的。
2、您說的唧唧聲音是否身處的環境有各種機器的叫聲?比如列印機,或着是在工廠裡?如果是的話,我也不知道,這是一個難題,目前我也在為這個苦惱。使用低通濾波器,比如4K頻率以下的通過,可以降低唧唧叫的幾率。(我的采樣率是16000)。
如果環境不是的話,那麼我覺得還是延時的計算不對了。建議使用WebRtcAec_GetDelayMetrics去估計延時偏差。
[142樓]樓主
Bill_Hoo 回複
2014-02-09 20:07:18
回複 huangqizhen:[141樓]
您好huangqizhen,我這邊聲音忽然變小的問題應該和能量沒有關系,我都是距離手機十五公分左右測試的,這個距離比正常的視訊、語音通話距離還近。這個問題我還要繼續觀察。
至于唧唧聲,我的測試環境除了環境噪聲、周圍人聲就沒有别的異常聲音了,這個唧唧聲應該是AECM算法收斂失敗造成的。
我會繼續關注這幾個問題的。希望大家都能早日解決。
[143樓]
lee_fat 回複
2014-02-13 13:10:26
Bill_Hoo大神你好
我在做linphone上移植NetEQ功能,我想問您一下NetEQ是包括了解碼麽?
[144樓]樓主
Bill_Hoo 回複
2014-02-14 20:41:06
回複 lee_fat:[143樓]
您好lee_fat
由于項目的安排我沒能接觸到NetEQ子產品,是以不敢妄言。
[145樓]
nicholashz 回複
2014-02-21 14:54:17
您好!
看了你的文章,也想玩一玩WebRTC,不過死活卡在第一步下載下傳源碼...我這裡網絡環境不穩定,用gclient同步兩天了總是會中斷。你能幫忙把android上的所有源碼打包發給我一下麼?我的郵箱是[email protected],如果太大的話網盤什麼的也可以,多謝了
[146樓]樓主
Bill_Hoo 回複
2014-02-26 13:13:16
回複 nicholashz:[145樓]
您好 nicholashz,直接 svn 同步 http://webrtc.googlecode.com/svn/trunk/ 主線即可。我沒有花時間去同步整 android 的整體工程。
[147樓]
lzg9099 回複
2014-02-28 10:49:10
Bill,
您好,還是關于msInSndCardBuff這個參數的計算。
請問,您在Android中是采取何種方式去擷取到音頻硬體采集到幀A的時間以及播放出幀B的時間的。Android中好像沒有這樣的API呢,之前您說在WebRtc 源碼中的android-test有那樣的處理方法,恕我愚昧,找了很久也就理出個頭緒來,故來向您取經求教,謝謝。
[148樓]樓主
Bill_Hoo 回複
2014-03-01 14:37:41
回複 lzg9099:[147樓]
您好,這個延遲的計算方法可以參考WebRTC主線版本目錄 webrtc\modules\audio_device\android\java\src\org\webrtc\voiceengine\
下的WebRTCAudioTrack和WebRTCAudioRecord
具體如何在程式中展現,還需要你自己進行程式結構的調優和測試。
[149樓]
appleZYY 回複
2014-03-18 16:22:09
hello,Bill,我認真的看了前面的所有評論,還是有幾個問題想要請教您
1.采集的時候audioRecord.read(tempBuf, 0, buffer_frame_size),tempBuf用short類型和byte類型有差別嗎?80HZ 采集,如果用byte類型,buffer_frame_size是傳遞160吧?如果是short類型,是傳遞320?
因為我看到前面的很多人都是用short傳遞到process中的,是以有點蒙,不懂該怎麼做才是合适的
2.jni層,aecm process函數像下面這樣寫有錯嗎?AudioRecode采集的時候是用byte類型存儲的,我直接傳遞給nearendNoisy,WebRtcAecm_Process需要傳遞的類型是short*,是以我把jbyte*類型轉換成short*,不知道有沒有錯?還有nrOfSamples傳遞的是160(80HZ的)?
jint....Process(JNIEnv *env,
jclass jclazz, jint aecmInst,jbyteArray nearendNoisy,jbyteArray nearendClean,jbyteArray out,jint nrOfSamples,jint msInSndCardBuf) {
void* handle = (void*) aecmInst;
jbyte* nn = (*env)->GetByteArrayElements(env, nearendNoisy, NULL);
jbyte* nc = (*env)->GetByteArrayElements(env, nearendClean, NULL);
jbyte* sout = (*env)->GetByteArrayElements(env, out, NULL);
jint result = 0;
if(nearendClean==NULL)
result= WebRtcAecm_Process(handle,(short *)nn,NULL,(short *)sout,nrOfSamples,msInSndCardBuf);
else
result= WebRtcAecm_Process(handle,(short *)nn,(short *)nc,(short *)sout,nrOfSamples,msInSndCardBuf);
if (nn != NULL)
(*env)->ReleaseByteArrayElements(env, nearendNoisy, nn, 0);
if (nc != NULL)
(*env)->ReleaseByteArrayElements(env, nearendClean, nc, 0);
if (sout != NULL)
(*env)->ReleaseByteArrayElements(env, out , sout, 0);
return result;
}
3.關于降噪,如果是80HZ,160位元組采集的話是要分成兩次降噪嗎,每次傳遞80byte?
4.目前我播放和采集都在一個線程中執行,發送和接收在另一個線程,播放的時候去接收隊列中取出資料,執行bufferFarend,然後采集,降噪,process,再靜音檢測,不知道這樣的流程是否可行?
初次接觸音頻部分研究,還望多指點,感謝
[150樓]
lzg9099 回複
2014-03-18 16:53:30
bill,您好:
關于那個延遲的計算,根據您的提示,我這邊測試了一下,發現達不了預期的效果呢。我是将采集和播放放在一個線程裡面來測試的,代碼入下,不知道這樣處理是不是正确的:
while(iswork){
long timeRecBegin = System.currentTimeMillis();
rcdLen = rcdAudio.read(rcdBuff, 0, AUDIO_SAMPLE_LEN);
long timeRecEnds = System.currentTimeMillis();
Log.i(TAG, "Read one audio frame " + rcdLen);
if(AudioRecord.ERROR_INVALID_OPERATION == rcdLen) {
Log.i(TAG, "Read wrong audio data.");
continue;
}
//對采集到的音頻進行噪音消除。
m_audioNs.audioNsProcess(nsHandlerAddress, rcdBuff, null, ns_processed_out, null);
//對噪音消除後的音頻進行回音消除
timeRecDelay = (short) (System.currentTimeMillis() -( timeRecBegin + ((timeRecEnds - timeRecBegin) * bufferedRecSamples)/80));
processed_out = m_aecm.aecProcess(ns_processed_out, out, nrOfSamples, (short) (timeRecDelay+timePlayDelay));
Log.i("TEST", "aecmProgress msInSndCardBuff is " + (timeRecDelay + timePlayDelay));
int written = 0;
long timePlayBegin = System.currentTimeMillis();
written = trkAudio.write(processed_out, 0, processed_out.length);
long timePlayEnds = System.currentTimeMillis();
Log.i(TAG, "write one audio frame.....");
if (processed_out.length != written){
Log.i(TAG, "write wrong audio data.");
continue ;
}
bufferedPlaySamples = countBufferedPlaySamples(written);
Log.i("TEST","bufferedPlaySamples is " + bufferedPlaySamples);
timePlayDelay = (short) (System.currentTimeMillis() - (timePlayBegin + ((timePlayEnds - timePlayBegin)* bufferedPlaySamples)/80));
m_aecm.aecmBufferFarend(processed_out, nrOfSamples);
Log.i("TEST","timePlayDelay is " + timePlayDelay);
}
countBufferedPlaySamples這個函數是我用來計算播放時的延遲的:
public int countBufferedPlaySamples(int written){
bufferedPlaySamples += (written >> 1);
int pos = trkAudio.getPlaybackHeadPosition();
if (pos < playPosition){
playPosition = 0;
}
bufferedPlaySamples -= (pos - playPosition);
playPosition = pos;
return bufferedPlaySamples;
希望您有空時候,能再給點建議,不勝感激。
[151樓]
appleZYY 回複
2014-03-19 12:35:36
hello,Bill,我現在回聲是消除了,但是聲音開到最大聲有時候還是有噪聲和嘯叫,我是80HZ,160byte采集的,執行順序是:回聲消除-->噪音消除-->靜音檢測(如果是靜音,就不發送),請問這樣的流程對嗎?
代碼執行個體如下:
//frame_size : 160
short[] nsout=new short[frame_size];
short[] aecmout=new short[frame_size];
short[] temp1=new short[frame_size/2];
short[] temp2=new short[frame_size/2];
//recData 為接收到的資料,結構short[160]
WebrtcAECM.Process(recData, null, aecmout, frame_size, 200); //回聲消除
//噪聲消除分成兩段,一次80個位元組
System.arraycopy(aecmout, 0, temp1, 0, frame_size/2);
WebrtcNs.NSProcess(temp1, null, temp2, null); //噪音消除
System.arraycopy(temp2, 0, nsout, 0, frame_size/2);
System.arraycopy(aecmout, frame_size/2, temp1, 0, frame_size/2);
WebrtcNs.NSProcess(temp1, null, temp2, null); //噪音消除
System.arraycopy(temp2, 0, nsout, frame_size/2, frame_size/2);
int vadFlag=WebrtcVAD.process(sampleRate, nsout, frame_size); //靜音檢測,如果是靜音就不發送
延遲時間目前暫時用固定值200,會影響到噪聲消除嗎?
感謝~
[152樓]樓主
Bill_Hoo 回複
2014-03-20 11:18:52
回複 lzg9099:[150樓]
您好lzg9099,AudioRecord 以及 AudioTrack 的接口是阻塞式的,很可能影響了延遲的計算。
對于最終的效果,我從釋出這篇文章到目前為止基本上都在做優化,雖然相比最初的版本有較大改善,但不論是單獨使用AECM還是使用內建APM以及其他WebRTC元件,均達不到我預期的100%滿意的效果。目前正在等待Google進一步的優化。之前看了下WebRTC的計劃,貌似會廢棄AECM子產品,改用其他實作方式。
[153樓]樓主
Bill_Hoo 回複
2014-03-20 11:29:50
回複 appleZYY:[151樓]
您好appleZYY,您說的采樣率應該是8000Hz單聲道吧。對應為160位元組是沒錯的。執行順序是可以自己調優的。建議參考WebRTC AudioPreprocessing 子產品裡面的 ProcessStream 的實作順序。不過,有時間可以直接把APM用起來。
固定的延遲得不到較好的效果,對于同一台手機,可能由于線程排程、Audio API 阻塞等不可控因素導緻延遲發生變化。對于不同手機,延遲基本上是不同的。
關于嘯叫:回聲消除算法未收斂成功,會導緻最後一個尾音産生回報嘯叫。這種嘯叫可以通過優化程式結構和延遲計算算法盡量的壓制,但無法100%消除。
[154樓]
appleZYY 回複
2014-03-20 12:27:19
回複 Bill_Hoo:[153樓]
hello,bill,感謝您的回複
我在***裡面有看到您的回複:
”2.AudioRecord.read() and AudioTrack.write() sometimes block(due to minimized buffer size), so when you calc the delay, don\'t forget adding blocking time to it.
3.the buffer of AudioRecord and AudioTrack also increases the total delay. so add it.“
read和write的block time是算調用read前後的時間差嗎?我有測試過,采集160byte, 是0~60ms不等;
the buffer of AudioRecord and AudioTrack 這個我不知道該怎麼算,可否指點一二?
我感覺好像都得不到真正的read和write第一幀的時間
[155樓]樓主
Bill_Hoo 回複
2014-03-20 12:35:53
回複 appleZYY:[154樓]
您好,根據目前 android 的音頻API确實得不到精确的底層第一幀的時間,但是AudioTrack有API可以估算底層還有多少資料沒有播放,這個可以參考下樓上lzg9099的代碼。至于AudioRecord,目前隻能想辦法少讓它阻塞。
SO上面的回複已經是很早的事情了,該描述現在看來不甚準确,可以忽略。
[156樓]
lzg9099 回複
2014-03-20 14:56:21
回複 Bill_Hoo:[152樓]
Bill,感謝您的回複。
按照我之前的估算延遲方法,我測試的時候有時候會發現延遲竟然是負數,這個問題真心困擾我了,怎麼會是負數呢?而關于播放端的bufferedPlaySamples,在小米3上經常是在1千多,而在華為的手機上就隻有六七百左右;另外,關于audioRecord的AudioSource參數,我發現如果是設為VOICE_COMMUNICATION的話,有的手機剛開始時根本不用我們這個aecm也能夠消除回音,但也會有嘯叫聲,這個時候是用到了手機自帶的回音消除功能嗎?而當設為MIC的話,我們的這個aecm顯然是起作用了的,但是效果在不同手機上差别很大,而且即使消除了回音的手機上依然會存在唧唧唧唧的聲音。
[157樓]樓主
Bill_Hoo 回複
2014-03-20 16:09:14
回複 lzg9099:[156樓]
您好 lzg9099
A1:關于延遲是負數的情況,問題很有可能出在播放端延遲的計算上,因為你的 bufferedPlaySamples -= (pos - playPosition); 很有可能越界。這隻是猜測,因為我之前自己也犯過這個毛病。
A2:bufferedPlaySamples 是随硬體實作而變的,底層buffer有多大,不同機型有很大差别。我在一台華為上,通過API得到的底層最小buffer盡然達到了7000+位元組。
A3:VOICE_COMMUNICATION 是 Android API Level 11 之後才加入的新特性,它要求硬體廠商在API 11之後,對這個采集流實作硬體回聲消除。這幾種模式的詳細情況可以參照 CSipSimple 的開源代碼。更換模式不失為一種有效的解決辦法,但是不同的硬體廠商對該标準的支援很不一樣,尤其是三星系列,很多機型根本沒有對API進行支援,甚至有選擇該模式後直接卡死的情況。
A4:“唧唧”聲也是我目前覺得比較棘手的問題。之前一直在對系統延遲的計算以及程式結構進行優化,能夠不斷減少這種聲音的發生。但仍然無法完全消除。主要有兩點原因:1)要在各種android機型上找到一個普遍适用的系統延遲算法确實比較困難,就WebRTC自身而言,其延遲計算也是估算的。2)即使系統延遲估算準确,手機上的回聲消除子產品本身存在其局限性,最終導緻“唧唧”聲的出現。
針對原因1,可以對您自己的算法不斷的調優,對程式結構和線程排程不斷調優,确實可以達到一定效果,甚至和QQ語音相差無幾,但是QQ語音實際上也做得不是很好,相差YY語音很大一截。而我們希望要達到YY語音的效果,光從AECM子產品入手恐怕是不行的,這個願景在目前看來有點牽強。
針對原因2,我目前也卡在這裡,時刻關注Google對AECM子產品的優化或者方案變更。AECM算法簡介可以參考 http://blog.csdn.net/u012931018/article/details/17045077
[158樓]
lzg9099 回複
2014-03-20 16:55:07
回複 Bill_Hoo:[157樓]
Bill,太感謝您的寶貴建議了。
再請教您一個問題,關于語音采集那兒一塊兒的延遲,即bufferedRecSamples,您那邊也是按照WebRtcAudioRecord裡面的粗略估計值嗎,即sampleRate / 200 ?
[159樓]樓主
Bill_Hoo 回複
2014-03-20 17:00:06
回複 lzg9099:[158樓]
采集延遲這一塊我目前也沒有定下來,之前嘗試了很多方法,始終不盡人意,目前采用一半底層buffer大小作為采集的固定延遲。如果您有新的發現,還請來此回報。感謝。
[160樓]
lzg9099 回複
2014-03-25 17:22:01
回複 Bill_Hoo:[159樓]
bill,我這邊采集延遲也是用的固定的buffer = SAMPLERATE / 200 ; 看了一下算出來的msInSndCardBuff 在100左右到300左右,偶爾會高出500,大部分是在200 到 300 之間。
測試發現:當說話時,是不會聽到自己的回音了,但是呢,随着時間的增長有一個“唧唧”聲音,從很小很小變得越來越大,這種現象是每次都會出現的,運作一會兒就出現了,這是因為回音消除算法沒有收斂成功嗎?不知道您那邊遇到過這種問題沒有,如果遇到了,您處理的思路是如何的呢?感謝。
[161樓]樓主
Bill_Hoo 回複
2014-03-25 21:22:24
回複 lzg9099:[160樓]
您好lzg9099,這個延遲算出來基本是穩定的,我沒有遇到過超出500的情況。也許你的結構設計上哪裡還有些問題。至于唧唧聲,我這邊也有,目前正在解決。不過,如果延遲計算準确,唧唧聲不會每次都出現。總體來說,在一個準确的延遲範圍内,AECM的效果會趨于平穩,這種狀态下仍然可能出現唧唧聲。這個聲音應該是爆破音,你google一下 pop/clicking sound 應該有所收獲,如何以程式的方式去除這個 clicking sound,還要再仔細研究。
[162樓]
lzg9099 回複
2014-03-26 11:50:47
回複 Bill_Hoo:[161樓]
Bill,感謝您的回複,問一下您那邊穩定後的範圍是多少呢,我剛調試了一下,不會出現500以上的了,但是一直在40左右到200左右直接波動。
[163樓]
lzg9099 回複
2014-03-26 18:10:29
回複 Bill_Hoo:[161樓]
Bill,采集延遲如果通過底層buffer大小的一半作為固定延遲的話,可能會有問題,我小米2s和小米3的手機的這個底層buffer是在1000多左右,這個時候算出來的msInSndBuffer會穩定下來,在200左右,但是當我換成一個華為的榮耀3後,這個buffer竟然為7680,如果根據這個來算出采集端的延遲的話,msInSndBuffer穩定在900多左右,而webRtc源碼裡面,msInSndCardBuffer隻适用于0--500之間,大于了500就無法處理了。我這邊目前先暫時設定了一個值240,當msInSndCardBuffer大于500就直接設為240,但是這個時候的效果就沒動态算出來的效果好。
[164樓]樓主
Bill_Hoo 回複
2014-03-27 10:10:12
回複 lzg9099:[163樓]
您好,我這邊華為底層buffer也是7000+,但是根據你算出來的延遲900多,我猜測你是否使用了雙聲道32KHz的采樣率?如果是單聲道16KHz的話,7000bytes對應的延遲也才200多毫秒。是否哪裡計算錯了呢?
[165樓]
lzg9099 回複
2014-03-27 10:35:54
回複 Bill_Hoo:[164樓]
bill,您好,我這邊是使用的8k,單聲道。底層buffer 7000+ 的話,recBuffer 固定為 3500+ 個Samples,我是這樣了解的,8個samples采集需1ms,那麼3500 / 8 = 400+ ,這樣的話光是采集就400多的延遲。按照這種算法,我在另外兩個手機上測試的時候,即小米2s和小米3上測試,底層buffer為1200左右,算出來msInSndBuff就穩定在200左右,效果很好,唧唧的聲音很小很小了。不知道您那邊采集端是如何根據這個buffer計算延遲的。
[166樓]樓主
Bill_Hoo 回複
2014-03-31 16:51:43
回複 lzg9099:[165樓]
您好,計算方法都是一樣的。我使用的16KHz資料,是以延遲是你的一半左右。
[167樓]
wendel1983 回複
2014-04-03 17:53:20
回複 Bill_Hoo:[166樓]
bill,你好,不知道你有沒有解決唧唧的聲音,還有音質也不太好
[168樓]
controler2013 回複
2014-04-10 15:10:00
hi, 請問 windows phone 是否也可以單獨提取出來編譯呢
或者說有沒有試過編譯webrtc給 win phone 使用
剛開始接觸webrtc,發現和win ph 相關的資訊太少了
[169樓]
HulkChen 回複
2014-05-08 15:58:34
hi,bill,首先感謝你這片部落格。我按照你的提示,單獨提取出來AECM子產品。目前在驗證AECM的正常工作有點問題:
我是在Android上層做錄音播放工作:
初始化:
int aecmHandler;
aecmHandler = mWebrtc.createAecm();
int initAecmResult = mWebrtc.initAecm(aecmHandler, sampleRateInHz);
驗證:
int frame_size=160;
int sampleRateInHz=8000;
private short[] recordedShorts = new short[frame_size];
shortsRead = audioRecord.read(recordedShorts, 0,frame_size);
mWebrtc.bufferFarend(aecmHandler, recordedShorts,sampleRateInHz);
mWebrtc.processAecm(aecmHandler, recordedShorts, null,aecmOutFrame, frame_size, 0);
audioTrack.write(aecmOutFrame, 0, frame_size);
如果AECM是正常的,這樣驗證,是不是應該沒有聲音?我是采用死循環,可是會出現很大噪音,應該是嘯叫。AECM是沒正常?還是我的驗證有問題?謝謝指教
[171樓]樓主
Bill_Hoo 回複
2014-05-08 19:49:05
回複 controler2013:[168樓]
您好,抱歉很久沒回部落格。
WinPhone我沒有接觸過,是說一下我了解的資訊吧,WebRTC底層是C/C++的實作,Android上也是要用JNI去調用底層實作的。如果WinPhone沒有這個能力調用C/C++實作,那這個事情可能就沒辦法。
[172樓]樓主
Bill_Hoo 回複
2014-05-08 19:50:47
回複 HulkChen:[169樓]
理論上講,将同一音頻放入Farend和Process,輸出就是全零的。你覺得你最好記錄音頻檔案看一下問題出在哪裡。
[173樓]
LuoZH 回複
2014-05-09 18:10:08
回複 Bill_Hoo:[171樓]
謝謝bloger的解答,我單獨編譯AEC等幾個子產品,WINCE下面效果非常理想,Android下面我用OpenSLES接口,一直存在偶爾串回音,效果很差,後來我發現Android已經自帶libwebrtc_audio_preprocessing.so,使用這個so,效果非常好,但是OpenSLES的延遲達450ms,十分可怕.
[174樓]
shifu0803 回複
2014-05-10 16:47:20
bill你好,最近我也在搞webrtc的回聲消除,看到你的文章對我的幫助很大。在看代碼的過程中我有一些問題想請教一下你
1.aecm_core.c代碼過程中屢次提到的Q-domain是什麼意思?隻是一種定點表示規範?
例:// @param aecm [i/o] Handle of the AECM instance.
// @param far_spectrum [in] Pointer to farend spectrum.
// @param far_q [in] Q-domain of farend spectrum.
// @param nearEner [in] Near end energy for current block in
// Q(aecm->dfaQDomain).
// @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
//
void WebRtcAecm_CalcEnergies(AecmCore_t * aecm,const WebRtc_UWord16* far_spectrum,const WebRtc_Word16 far_q,const WebRtc_UWord32 nearEner,WebRtc_Word32 * echoEst)
這當中的Pointer to farend spectrum.和 Q-domain of farend spectrum都是與遠端有關的,怎麼讀都讀不懂?
2.是不是加上噪聲抑制一定會對噪聲處理産生良好效果,我對此也進行了測試,感覺加在後面效果比在前面好,這是為什麼呢?按照aecm中process函數的了解,當中既然為ns後的語音流留了接口,難道不是應該放在前面效果更好嗎?
3.你對完成以後的唧唧聲或嘯叫聲是怎樣了解的呢?從理論上分析,當輸入為小的噪聲時,webrtc本身代碼處理過程有可能自激産生嘯叫嗎?亦或是時延精度對這一現象造成的影響?webrtc中是否隻有遠近端對齊時的這一種時延要求,是否裡面仍有不同類型的時延計算需求,時延一面看的糊裡糊塗的。
問題問的有點多,麻煩你了,最近被這些問題困擾很久,非常感謝!
[175樓]樓主
Bill_Hoo 回複
2014-05-12 09:15:05
回複 LuoZH:[173樓]
你好LuoZH,很高興你能來此回報,有幾個問題向你請教一下:
Q1 不知道你提到的效果非常好是怎麼個好法,還存在唧唧聲嗎?
Q2 libwebrtc_audio_preprocessing.so 是你用WebRTC編譯出來的,還是其他什麼地方得來的?
Q3 上述庫的接口有頭檔案可以參考麼?
[176樓]樓主
Bill_Hoo 回複
2014-05-12 10:10:32
回複 shifu0803:[174樓]
您好shifu0803:
A1:對于 Q-domain 我也沒能很好的了解,不過看 AECM 的頭檔案,應該用了一個叫做 DYNAMIC-Q 的優化算法。
A2:這幾個獨立子產品的順序可以參照 APM 裡面的實作,如果沒有特别的要求需要單獨編譯各個子產品,其實可以直接把APM子產品編譯出來使用,參數的配置,接口的統一都友善很多。
A3:嘯叫聲應該是延遲沒有計算準确導緻的,最開始我也以為是AECM自己有問題,後來不斷優化延遲的計算,嘯叫聲是不存在的。唧唧聲按我現有的知識沒法作出理論上的描述,我隻能說一下我的感受,我覺得這個唧唧聲很像本次回聲消除後殘留的一點點聲音,這個聲音沒被AECM抵消掉,被播放了出來。
A4:隻是按我的了解,這裡的延遲有兩個。我用 sys_delay 和 filter_delay 加以區分。sys_delay 是我們上層計算出來傳給AECM接口的系統延遲,表示音頻在android系統上的延遲值,一般為100~200ms。sys_delay 主要用于AECM裡遠端buffer 偏移量的計算,它被AECM拿去以20%的權重(另80%為舊值,以求延遲穩定)重新計算新的遠端曆史buffer偏移量。 filter_delay 用于表示AECM的濾波器偏移量,這個偏移量通過 delay_estimator 得到計算。最後拿去給濾波算法使用的是 filter_delay,但如果我們的 sys_delay 計算失誤,會導緻 delay_estimator 始終得不到一個正确的 filter_delay,是以上層計算延遲是需要注意和優化的。
針對AECM延遲的計算,更加詳細的解釋請參考這位部落客的文章:
http://blog.csdn.net/u012931018/article/details/17045077
打開源碼對比着了解就很容易了。
我音頻專業知識不足,說錯的地方還希望大家幫我指出來,謝謝。
[177樓]
HulkChen 回複
2014-05-15 18:29:35
回複 Bill_Hoo:[172樓]
非常感謝Bill的回答。将同一音頻放入Farend和Process,講話或者放歌的聲音都沒有了,但不是完全靜音狀态,還是有平靜的小小的嗡嗡聲,我是單獨提取AECM及NS子產品處理的,這代表AECM子產品工作正常?
另外想問下Bill,單獨用了AECM,NS子產品,如果嚴格計算延時參數,能達到的效果會是怎樣的?我這邊确實沒有了沒用AECM前,雙向通話一打開,直接嘯叫的現象。但是雙方聽到的聲音都是有失真,斷續的感覺,而且失真有點嚴重。我是一個線程将接收遠的資料存入隊列,另一個線程取隊列資料播放及采集麥克風資料壓縮傳輸。這是延時參數計算不是非常準确引起的還是我在AECM子產品的提取存在問題?
AGC子產品利用上,對音質效果會有提示?AGC子產品是利用gain_control.h裡面的函數?因為對一些類似WebRtcAgc_Process函數參數利用存在一些疑惑。
[178樓]樓主
Bill_Hoo 回複
2014-05-15 20:08:24
回複 HulkChen:[177樓]
您好 HulkChen,
A1:AECM在相同檔案作為NearEnd和Farend輸入時,基本全零就可以了,這隻是拿檔案來驗證你的JNI是否有誤。
A2:我不清楚你說的聲音失真是什麼,被削掉了一半,還是忽大忽小。
A3:延遲值計算準确的話,在每一台機型上都該是一個針對該機型的穩定值(上下波動不大),比如我這邊魅族MX延遲穩定在90~100ms,三星9100延遲穩定在134ms上下,你可以記錄你的延遲,如果不穩定,說明是有問題的,具體問題需要結合你的代碼和設計自己查找。更多關于這個延遲的說明,請參見文前更新内容。
A4:斷斷續續的感覺可能跟你的隊列設計有很大關系,你的隊列由于在兩個線程間共享,可能需要上鎖,或者使用自帶同步的隊列資料結構,很可能會導緻播放線程不能及時播放。這個需要你自己去确認。
A5:AGC子產品我沒有單獨使用,在寫此文後不久,我就整體編譯APM出來跑了,AGC是在APM裡寫好的,是以單獨對AGC的使用我沒有經驗,不敢亂說。
另,建議大家講APM整體編譯出來使用,條件允許的,請直接使用VOE,獨立編譯各個子產品出來使用是我很早之前的做法了,不再推薦。
[179樓]
LuoZH 回複
2014-05-23 13:24:32
回複 Bill_Hoo:[176樓]
Q1,效果已經達到産品級别,沒有唧唧聲,偶爾串一點回音
Q2,so在Android自帶,在/system/lib/目錄下
Q3,這個庫 == audio_process,跟手動編譯的使用是相同接口.頭檔案也是使用手動編譯時的
[180樓]樓主
Bill_Hoo 回複
2014-05-23 15:28:22
回複 LuoZH:[179樓]
恭喜恭喜,沒有唧唧聲是很不錯的表現了。
你們測試了哪些機型呢?在沒有開啟android硬體回聲消除的前提下也是這個效果嗎?
[181樓]樓主
Bill_Hoo 回複
2014-05-23 15:36:23
回複 LuoZH:[179樓]
對了LZY,你提及的動态庫是從哪個版本的Android裡導出的? 我現在的軟體結構沒辦法直接用這個庫了,不過我想自己建個工程去試試看。
[182樓]
LuoZH 回複
2014-05-26 10:19:48
回複 Bill_Hoo:[181樓]
4.0.2
[183樓]
DarkEnergy 回複
2014-05-30 17:45:28
解決延時問題,把aecm_defines.h裡面的MAX_DELAY調大一點。嘯叫問題嘗試把CNG關掉試試看還有沒有嘯叫。msInSndCardBuf這個參數不要亂設。和AGC配合時特别要注意AGC别把殘餘回聲給放大了。
[184樓]樓主
Bill_Hoo 回複
2014-05-30 20:17:11
回複 DarkEnergy:[183樓]
您好DarkEnergy,感謝,
MAX_DELAY 是底層曆史遠端資料的buffer大小,我之前有試着調大,但沒有發現明顯的改善。
CNG我在測試時發現它會出異常,AECM可能出現異常的噪聲,很大聲。是以一直關了的。
msInSndCardBuf 這個參數我嘗試過定值,定值的時候,一旦出現殘餘回聲(應該是AECM收斂失敗)就很難再次收斂(或收斂速度慢),但如果我每次都更新一個計算後的值,在出現殘餘回聲後,能夠很快的将濾波器偏移修正回來。是以我自己覺得,這個值還是要算。
最後,我很感興趣您提到的AGC将殘餘回聲放大的問題。因為這是一個客觀事實,殘餘回聲會和正常語音一起被AGC放大。目前我的拙劣的解決辦法是降低AGC的增益級别,進而降低其對殘餘回聲的影響。
是以很想請教您,如何避免AGC将殘餘回聲放大?調整AGC在APM裡面的執行順序麼?希望能得到您的指點。
[185樓]
xubingnihao 回複
2014-05-31 15:12:10
樓主,你好
最新剛剛一個項目需要,需要做回音消除。
1.目前子產品都已編譯工作,我在同一個線程裡先将遠端資料設為全0,結果發現Aecm process後的聲音聽起來有些問題,沒有以前清楚,而且感覺上有變聲?
2.另外雖說是8000HZ的,但我這邊是512 short的長度來發送接收的。現在隻有切開80 short長度的。
想問下,在一個線程連續調用WebRtcAecm_BufferFarend之後,再另外一個線程連續調用幾次WebRtcAecm_Process,這樣是不是就沒有效果了?是不是一次BufferFarend,隻對下一次的_Process有效?
3.因為在一個線程裡做WebRtcAecm_BufferFarend,另外一個線程中做WebRtcAecm_Process,是否需要加什麼鎖之類的啊?
[186樓]
DarkEnergy 回複
2014-06-03 09:53:52
回複 Bill_Hoo:[184樓]
AGC的問題需要修改代碼,最好把AECM裡面回聲抵消的VAD判決拿幾個參數出來,加入到你的AGC裡面,相當于AGC要判斷遠端是否有聲音,遠端單端有聲音的話就不作放大,但是這一塊還是要和延時結合起來,因為回聲是滞後的。這個也不難弄,因為你近端是有VAD的,而且AECM裡面是能夠判斷出雙端的。MAX_DELAY這個參數很重要,AECM是在MAX_DELAY這個長度範圍内去尋找遠端與近端最比對的位置來做延時估計。要是做移動端的應用,參考和回聲有時延時很大的。比如三星的某些手機可以達到600ms,如果MAX_DELAY小于延時,AECM做延時估計就永遠傳回錯誤的值了。AECM非常依賴延時檢測,因為它做回聲抵消的方法是将遠端參考和回聲對齊,然後計算HNL通過維納濾波器抑制回聲。還有一種可能情況是,MAX_DELAY剛好超過延時,但超過得不多,當延時出現抖動時(延時邊長且超過MAX_DELAY),這個時候就沒法再次收斂了,是以你修改msInSndCardBuf是能夠解決問題的,但是是不是解決了根本,還得再研究研究,看是不是這種可能性
[188樓]樓主
Bill_Hoo 回複
2014-06-03 11:00:23
回複 DarkEnergy:[187樓]
嗯,謝謝您花時間來此指點,AGC的問題我會參考您的建議自己下去試驗的。
另,我看了下您說的關于MAX_DELAY和msInSndCardBuf的問題,這個就真得再研究研究了,說明我底層源碼還沒有吃透,還要花時間。
[189樓]樓主
Bill_Hoo 回複
2014-06-03 21:06:17
回複 xubingnihao:[185樓]
您好 xubingnihao:
A1:不好意思我沒有看懂這個問題,還請再組織一下語言。
A2:這兩個API是可以異步調用的,你可以在兩個線程裡分别調用兩個API,沒有問題。
A3:鎖隻是在有資源競争的情況下加,我不清楚你的程式結構。光從這兩個API來看,上層沒有加鎖的必要。
[190樓]
xdwanmei 回複
2014-06-04 11:21:21
您好Bill_Hoo:
我也遇到186樓朋友的類似問題:
1、我單獨編譯了aec子產品,并封裝提供了兩個接口:1、添加遠端資料,2、添加近端資料。然而把遠端資料添加進去後做了混音處理後變成了異步資料,我想問下:把混音後的遠端資料添加到WebRtcAecm_BufferFarend函數的操作是否一定要先于把近端資料添加到WebRtcAecm_Process函數的操作。
[191樓]樓主
Bill_Hoo 回複
2014-06-04 14:31:49
回複 xdwanmei:[190樓]
您好,請參見 #190 的回複。兩API的較長的描述請參見 audio_processing.h 頭檔案中的官方說明,兩接口沒有強制的先後順序。
另,本文開頭已不再建議獨立編譯各個子子產品出來使用,請知曉。
[192樓]
xdwanmei 回複
2014-06-04 16:45:24
回複 Bill_Hoo:[191樓]
您好Bill_Hoo:
由于某些原因,暫時隻能單獨使用所有,還有些問題想請教下你:
在使用WebRtcAecm_BufferFarend函數時,遠端資料是否要進行軟體混音(注:遠端的資料是采集到的資料)?
[193樓]樓主
Bill_Hoo 回複
2014-06-04 17:56:23
回複 xdwanmei:[192樓]
您好,farend 資料指你從網絡接收到的對端音頻,nearend 才是指你本地采集到的音頻資料。
[194樓]
Jason_Old_Woo 回複
2014-06-29 11:52:54
這樣好麻煩啊,有沒有整理出來的aecm子產品?
[195樓]
wangyaliss 回複
2014-07-01 17:45:04
回複 huangqizhen:[132樓]
你好,我現在也在linux上用aec,也有你說的那個聲音忽大忽小的問題,很苦惱,請問你是怎麼調整的,盼指點,還有aec子產品效率很低,在arm9上處理一幀10ms的音頻需要4ms,不知道你遇到過這個問題沒,是做彙編優化了嗎
[196樓]
wangyaliss 回複
2014-07-03 11:22:40
bill你好,我現在在linux上用aec子產品,遇到的問題就是算法效率很低,處理一幀10ms的音頻16k采樣率的話需要将近10ms,不知道你遇到這個問題沒,是否需要做彙編優化或者浮點轉定點?
[197樓]樓主
Bill_Hoo 回複
2014-07-03 19:22:27
回複 wangyaliss:[196樓]
Linux上我沒有使用經驗,不過Android上如果使用原始的AEC(PC),處理效率就是你這個樣子。正常。
[198樓]
wangyaliss 回複
2014-07-04 15:48:42
回複 Bill_Hoo:[197樓]
bill謝謝你的回複,另外我還遇到另外一個問題,就是處理後的聲音忽大忽小。像是去回聲的時候過于敏感,把遠端聲音去除的同時把近端聲音也去除了一部分,你遇到過這個問題嗎
[199樓]
wangyaliss 回複
2014-07-04 16:15:56
回複 Bill_Hoo:[197樓]
我用aec子產品和aecm子產品都有上面說的那個聲音忽大忽小的問題
[200樓]樓主
Bill_Hoo 回複
2014-07-08 16:42:55
回複 wangyaliss:[198樓]
一般不會存在忽大的問題,僅有忽小的問題。忽小是因為AECM不支援雙邊通話,一旦出現雙邊通話的情況,AECM就會進行強制壓制,導緻本地處理出來的聲音變形,減弱,對方聽上去就忽小了。
至于AEC,我沒有在android上使用,PC上不存在這個問題。
[201樓]
shifu0803 回複
2014-07-10 17:07:46
bill你好,現在我在研究安卓的回聲消除部分,不知道你對安卓4.1版本後自帶的回聲消除子產品有沒有研究,就是把webrtc的回聲消除部分加進了安卓系統。
我現在遇到的問題是加載完該子產品後在開始的一段時間回聲消除會起作用,但是在過幾分鐘後感覺回聲消除的功能失效了,回聲變的很清晰,而且無法恢複原有的無回聲狀态,
不知道你對此是否有研究?或者你認為會引起該狀況的原因會是什麼呢?
謝謝。
[202樓]樓主
Bill_Hoo 回複
2014-07-14 19:19:35
回複 shifu0803:[201樓]
您好 shifu0803:
我沒有使用自帶的回聲消除器的經驗,僅僅在之前測試時開啟過一次,效果很糟,之後就沒有使用過。
你提到的回聲特别清晰,是否是一個回聲之後就沒有了?因為如果回聲消除不起作用的話,你的通話會産生無限的回聲回報,到最後除了嘯叫聲,其他是聽不清的。
還有一個,你的測試環境是怎樣的?是否兩台手機在兩個房間(保證本地說話不會被另一方的麥克風直接采集到)?
[203樓]
shifu0803 回複
2014-07-18 17:19:54
回複 Bill_Hoo:[202樓]
bill謝謝你的回複~
我提到的回聲很糟的意思的确是一個回聲之後就沒有了,回聲很清晰,但是并沒有出現無限的回聲回報這種情況。
主要讓我特别不了解的是開始的一段時間并沒有這種情況,但是打了一會電話後就會出現清晰的回聲。
我的測試環境可以保證一方說話不會被另一方采集到,一個在屋内一個在屋外。
不知道bill你覺得引起這種現象的原因大概會是什麼的?
再次感謝~
[204樓]樓主
Bill_Hoo 回複
2014-07-23 08:55:08
回複 shifu0803:[203樓]
如果沒有出現無限的回聲回報,隻是偶然出現一個清晰的回聲,這個現象是可以存在的。
我聽其他朋友說自帶的EC底層也是WebRTC裡的AECM算法。AECM出現偶爾的回聲是正常的。
[205樓]
xdwanmei 回複
2014-08-14 10:28:47
你好 Bill:
我想問下aec的那個delay該怎麼算,我看了下提供的那個公司,這幾個時間點都是什麼時候标記出來,我是用了aec後回聲變小了,是不是因為我delay設定的原因(我給了一個常值50ms)。
[206樓]
xdwanmei 回複
2014-08-14 16:12:32
你好 Bill:
我把問題又梳理了下:
A1:我想問下aec的那個delay該怎麼算,我看了下提供的那個公式,這幾個時間點都是什麼時候标記出來,apm處理近端和遠端資料函數每次隻能接收一定的資料,t_pull 和t_analyze是每次調用函數前更新一次嗎?
A2:如果使用了aec,過一會對方就聽不到自己說話了,不使用aec對方就可以聽到自己說話,這中現象有碰到過嗎,有人說是delay的問題(delay我設了一個常值)?
[207樓]樓主
Bill_Hoo 回複
2014-08-15 09:20:45
回複 xdwanmei:[206樓]
您好 xdwanmei:
A1:這幾個時間點的含義源碼注釋已經寫得比較清楚了,評論清單裡也有好多網友提及過,你可以再看看。确實需要每次都更新。
A2:我沒有實際測試過AEC(PC),我隻使用過AECM,對于過一會就聽不到說話了,那那個時候是什麼聲音?持續嘯叫還是完全無聲音?delay在AEC(PC)裡面是需要動态更新的,常量值僅适用于AECM。
還有問題我們再讨論。
[208樓]
xdwanmei 回複
2014-08-15 10:47:58
Bill 你好:
A1:我看了下你們的讨論,但是實際的操作讓我有點困惑,比如:我采集的一幀資料9600個,但是apm每次處理的資料是遠遠小于一幀資料量的,我在采集這幀資料是記錄一個時間,在每次調用process時都記錄一個process時間點,去跟我這一幀采集時間點作比較嗎?注:我看了下webrtc自帶的一套音頻引擎,看了下它裡面隻設定了播放和采集的delay,沒有計算加入AnalyzeReverseStream 和ProcessStream的時間,是不是采集後或者播放前不做其他處理直接調用函數,這兩個時間可以忽略。
A2:是沒有任何聲音了,感覺要是把所有聲音都消掉了。
麻煩您了。
[209樓]
xdwanmei 回複
2014-09-02 17:46:50
Bill 你好:
可以郵件溝通下,[email protected]
[210樓]樓主
Bill_Hoo 回複
2014-09-09 09:22:10
回複 xdwanmei:[208樓]
您好 xdwanmei,
這段時間較忙沒來看部落格,不好意思。
A1:如果在 Android 上,不使用OpenSLES的話,一般用API AudioRecord,一次讀取10ms對應采樣率的采樣點數,如8kHz 80個Sample,16kHz 160個sample。由于Android的音頻采集API沒有提供能夠精确計算延遲的資訊,是以可參照WebRTC的粗略實作,使用一個固定值作為采集延遲。播放延遲可以通過 AudioTrack 的API getPlaybackHeadPosition[http://developer.android.com/reference/android/media/AudioTrack.html#getPlaybackHeadPosition()] 進行估算,估算目前底層播放緩沖中還有多少采樣點沒有被硬體渲染,這些采樣點就造成了主要的播放延遲。
A2:這個問題你光這麼說我也不是很清楚,你可以說一下細節之類的。不過,我看你采集出來的一幀9600,不知道你這個一幀是指什麼,10ms?AECM最高支援16kHz的回聲壓制,AEC我不熟悉,好像是48kHZ,超過了都會被重采樣的。
[213樓]
keke274233971 回複
2014-10-09 15:00:50
你好,Bill_Hoo.我有些問題想請教你的。
我在做aecm時,延時時間msInSndCardBuf都是給個固定值的(如100ms,250ms,490ms等等)。效果是可以消除回音了,但是手機一直都有雜音(不知道是不是你說的唧唧音,不說話也一直有,而msInSndCardBuf都從0到490作為固定值一個一個的測還是一直有哪些唧唧音)。
1.msInSndCardBuf是不是一定時間要改變,才會減小唧唧音。但我看你說msInSndCardBuf是一個比較穩定值,那設為一個固定值應該也可以消除部分的唧唧音,但是我做的aecm一直都是開啟就有唧唧音了。
[214樓]
keke274233971 回複
2014-10-09 15:17:02
hi,Bill_Hoo.在185樓說的CNG關掉的CNG是什麼來的。是WebRtcAecm_set_config函數參數的AecmConfig的echoMode嗎
[215樓]
keke274233971 回複
2014-10-09 16:48:26
hi,Bill_Hoo.我在做aecm計算的msInSndCardBuf時,做
long time = System.currentTimeMillis();
mHead.BufferFarend(outBytes, AudioRecordThread.SAMPLE);
mAudoiTrack.write(outBytes, 0, outBytes.length);
int playtime = System.currentTimeMillis()-time;
得到的playtime在0到2ms之間,我怎麼都覺得不對啊!這播放延時間一般是多少?
[216樓]
keke274233971 回複
2014-10-09 18:06:06
hi,Bill_Hoo.我是做aecm的用了2個線程,一個是播放線程一個是采集線程。這2個線程要不要什麼同步的條件。現在這2個線程是播放線程WebRtcAecm_BufferFarend()m個,再到采集線程WebRtcAecm_Process()n個,每次m和n都不同的。這樣是對的嗎
[217樓]樓主
Bill_Hoo 回複
2014-10-10 21:46:59
回複 keke274233971:[215樓]
您好,關于這個延遲值,AECM 子產品使用定值是标準的做法,因為 AECM 内部有自己的延遲估算機制。
如果一定要計算這個 delay 值,其計算方法在 audio_processing.h 頭檔案中有詳細的描述,仔細閱讀便可 :)
[218樓]
keke274233971 回複
2014-10-11 15:32:00
回複 Bill_Hoo:[217樓]
感謝Bill_Hoo,我是用了定值做的,隻是運作時一直有唧唧聲(音量開得大時)。我隻用了噪音處理,沒有用靜音處理。是不是靜音沒有處理産生的?說話時唧唧聲會變小或者消失。請求幫我分析原因,謝謝
[219樓]
642759382 回複
2014-10-14 17:44:40
部落客你好,謝謝分享。我現在也在用aecm來降噪讀取的buffer大小是320(char數組),在一些手機比如小米2s上面效果很好,但是其他手機比如Nexus5上面效果很差,後來發現錄音的回掉不均勻,不管是用opensles還是java的錄音回掉的周期都不均勻,N5的Native Buffer 大小是960,我現在讀取的是320,傳回不均勻,但是小米的Natvie Bufer是320回掉就很均勻。
我看你在之前在googlecode上面也問過類似問題 https://code.google.com/p/android/issues/detail?id=53996
後來你是怎麼解決的?
我自己在代碼中加了定時器強制均勻時間但是效果扔沒有改善。
這種情況要如何處理,謝謝!
[220樓]
zylthinking 回複
2014-10-18 01:30:30
Hi, 我看webrtc 源碼, 發現 msInSndCardBuf 似乎與所謂二進制延遲估算器無關, 而是用來計算 acem->knowndelay 用的, 這個 knowndelay 用來從 aecm->farbuf 定位具體位元組偏移;具體來說, 就是沒調用一次 process, 則從 farendbuf 緩沖區讀對應的若幹幀到 acem->farbuf, 這個不由任何 delay 控制, 就是順序讀;這個 farbuf 的最大大小是 PART_LEN4, 即 4 個 PART_LEN 大小, 或者說 256 位元組, 而後, 再從這個 farbuf 裡面讀一個一個 part 來做信号處理;
aecm 跟蹤一個名為 farBufReadPos 的變量, 其含義就是上次已經從 farbuf 裡面讀到了哪個位元組; 經 msInSndCardBuf 計算出來的 knwndelay 即在這裡發生作用, 具體來說, 就是 farBufReadPos - kowndelay 作為新的 farBufReadPos; 而二進制延遲估算器是在處理 part 時計算的, 這部分代碼還沒看, 但該 part 是 間接由 msInSndCardBuf 標明的;即msInSndCardBuf決定那部分資料作為參考幀, 選取完畢後進行的一系列計算, 包括二進制延遲估算器, 基本沒msInSndCardBuf什麼事情了;但我還沒搞明白那個估算器是幹什麼用的,
整體來看, 似乎是如下模型: webrtc 認為硬體足夠可信, 即 8000 采樣率的 8000 個點硬體一定是在 1 秒内播放或者捕獲完畢;是以隻要資料始終供應充足, 那麼理論上。 若保持 farendbuf 大小正好是 api 頭檔案說明的那個值, 則每捕獲一幀資料, 則farend 中的參考幀必然是 farendbuf 中 readpos 指向的那一幀; 即在一切理想的情況下, kowndelay 應該始終為 0;
但這個函數卻給我莫名其妙的感覺了:
static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf)
{
short delayNew, nSampSndCard;
short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
short diff;
nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
delayNew = nSampSndCard - nSampFar;
if (delayNew < FRAME_LEN)
{
WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
delayNew += FRAME_LEN;
}
aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
diff = aecm->filtDelay - aecm->knownDelay;
if (diff > 224)
{
if (aecm->lastDelayDiff < 96)
{
aecm->timeForDelayChange = 0;
} else
{
aecm->timeForDelayChange++;
}
} else if (diff < 96 && aecm->knownDelay > 0)
{
if (aecm->lastDelayDiff > 224)
{
aecm->timeForDelayChange = 0;
} else
{
aecm->timeForDelayChange++;
}
} else
{
aecm->timeForDelayChange = 0;
}
aecm->lastDelayDiff = diff;
if (aecm->timeForDelayChange > 25)
{
aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
}
return 0;
}
按我了解, delayNew = nSampSndCard - nSampFar; 若 nSampFar == nSampSndCard, 則是我所說的最理想情況, 此時計算出的 delayNew 為 0,
若 沒有
if (delayNew < FRAME_LEN)
{
WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
delayNew += FRAME_LEN;
}
那麼, 一切還是很完美, knowndelay 最終計算出 0, 然後把剩下的全交給硬體;
但 這個判斷是什麼意思呢, 為何要加上 FRAME_LEN, 若這麼搞, 則最終意味者 farBufReadPos 将減去某個值, 而這個值初始化為 0, 減去的結果就是 0 + 256 - kowndelay, 那麼, 第一個被分析的 part 的參考則可能根本就不是 farendbuf 中, 而是初始化時 memset 的 0;
另外, nSampFar 也不等于 nSampSndCard, webrtc 啟動階段在 farendbuf 填充到 nSampSndCard * 3 / 4 時就結束了, 那麼, nSampFar 小于 nSampSndCard 的可能性很大;
最終的效果, 就是這個算法弄了一系列無法摸清規律的因子進去, 實在搞不懂那是為什麼。
[221樓]
阿弱德一号 回複
2014-10-20 22:07:52
一直在跟看樓主的文章,樓主好人。一直回答超過1年了。
我們現在也在用AECM做回音消除,現在發現幾款手機的表現不一緻。華為和小米表現較好,三星和Nexus表現不行,對比檔案一直有一些尾音消不掉。
請教了一些人,有人說可能是時延和抖動不穩定的問題,好像類似220樓的兄弟問的那樣?
也有說還是參數的配置問題?
樓主和各位兄弟有沒有見過這種現象?多謝了。
急需一條明路。。。
[222樓]樓主
Bill_Hoo 回複
2014-10-28 11:34:11
回複 keke274233971:[218樓]
Re[219]: 你好,近段時間沒有跟進WebRTC的進度了,是以僅根據以前的經驗回答,叽叽聲應當是 AECM 算法本身的表現,靜音檢測打開,在靜音時發送全零資料,可以減少些許能量較弱的唧唧聲。
[223樓]樓主
Bill_Hoo 回複
2014-10-28 11:35:46
回複 642759382:[219樓]
您好,據我所知目前 Google 的該音頻回調 API 是存在 bug 的,你不能依靠這個回調去保證你的采集時間。我采用的是 AudioRecord.read() 這個阻塞 API。
[224樓]樓主
Bill_Hoo 回複
2014-10-28 11:38:00
回複 zylthinking:[220樓]
您好,這個函數我也看了很久,最後我以為,它僅僅作為穩定延遲,防止延遲突變的工具函數。僅個人了解。
[225樓]樓主
Bill_Hoo 回複
2014-10-28 11:43:31
回複 阿弱德一号:[221樓]
您好,不同 Android 機型的表現不一是正常現象,這取決于其音頻底層實作。
如果使用的是 AECM 子產品,有些許尾音消不掉(或者出現扭曲的唧唧聲)是正常現象,據我所知 Google 前日已經關閉 [issue 1067][https://code.google.com/p/webrtc/issues/detail?id=1067],表示不對此進行修複。
[226樓]
lance7 回複
2014-11-12 14:21:36
可以請問一下AGC的使用方法嗎?
int32_t mic_level_out = 0;
int32_t mic_level_in = 0;
uint8_t sat;
WebRtcAgc_VirtualMic(iAGC, (int16_t*)pcm, NULL, 160, 0, &mic_level_in);
if(WebRtcAgc_Process(iAGC, (const int16_t*)pcm, NULL, 160, (int16_t*)agc_buffer, NULL, mic_level_in, &mic_level_out, 0, &sat) == -1)
QLOGE("webRTC_audio::PinIn AGC process ERR");
用這種寫法是正確的嗎?每個frame得到的mic_level_in和mic_level_out都是相同的
[227樓]樓主
Bill_Hoo 回複
2014-11-14 08:58:26
回複 lance7:[226樓]
您好 lance7,AGC我之前單獨提取出來使用過,效果不好,最後使用的是整體的 APM 子產品,它自己已經架設好了這些獨立子產品之間的銜接。本文開頭已經提到過,不再提倡單獨編譯AGC、NS等子產品進行處理。
[228樓]
guowei19862006 回複
2014-11-14 10:40:22
回複 Bill_Hoo:[22樓]
你好,就是用webrtc測試時,兩個用戶端嘯叫的很厲害,這個怎麼解決?有沒有好的方法
[229樓]樓主
Bill_Hoo 回複
2014-11-18 10:16:13
回複 guowei19862006:[228樓]
你好,兩個用戶端嘯叫的很厲害,首先應當排除距離問題,兩個用戶端是否靠得太近導緻雙方均能直接采集到對方發出的聲音?
[230樓]
zhu4272 回複
2014-11-21 19:29:12
Bill,你好。我最近在做手機和網頁視訊通話的項目。在我目前在android手機端的語音子產品用了webrtc,PC端沒有加webrtc。通過實驗,ns去噪現在效果顯著,但是aecm去回聲沒有效果。我在PC端用耳機說話,可以聽到自己的回聲。這個回聲應該是到達手機端,喇叭放出後再通過麥克風錄入傳回來的。我把手機端的喇叭靜音,PC端再講話就聽不到自己聲音了。aecm我嘗試了各種delay值,沒有通過計算。看到不少人在這裡評論,寫死數值也應該有一點效果的。webrtc去回音去的是那一部分,是不是我在PC端也要加上webrtc的消回音,這樣我PC端才不會聽到自己講話的回聲?期待你的幫助。
[231樓]
zhu4272 回複
2014-11-25 15:50:51
Bill,你好。
我在github上看到了你共享出來的關于aecm的工程(https://github.com/lhc180/webrtc-based-android-aecm),我把他加入到了我的工程中,但是消回音幾部手機測試下來普遍不理想,回應還在。我測試的方式是PC端講話,通過流媒體發往手機端。如果我在PC端聽不到自己的回聲,那麼就是去回聲成功了。以三星S5為例,我采集的是8KHZ單聲道,播放延遲和采集延遲總和是50ms以内,AudioTrack和AudioRecord通過getMinBufferSize()得到的buffer大小之和是1920,算下來延遲是120ms,msInSndCardBuf在120-170之間波動,但是回音還在,看到前面好多人評論說回音消掉了,可我卻沒消掉,希望Bill能幫助一下
[232樓]樓主
Bill_Hoo 回複
2014-11-25 18:13:19
回複 zhu4272:[231樓]
你好,GitHub上的工程我已經移除了,你看到的應該是别人fork的分支,文章開頭已經提到,不再建議單獨使用AECM等子產品,請使用APM或者VOE,它們能使底層的獨立音頻子產品更好的協作。
看到你說回聲消除沒有效果,我看你的測試環境估計沒有問題。AECM的兩大接口是否有用對?在其頭檔案中有對接口的詳細說明。
[233樓]
S風繼續吹S 回複
2014-12-08 15:53:38
樓主,您好。我想問你一下,webrtc中的自動增益控制(agc)是用來幹什麼的?
[234樓]
liuliu886 回複
2014-12-17 16:26:38
回複 Bill_Hoo:[17樓]
t_analyze 表示你對音頻幀A調用 farend 的時刻,t_render 表示[硬體]真正播放出幀A的時刻。
t_capture 表示[硬體]采集到音頻幀B(注意跟A沒關系了)的時刻,t_pull 表示幀B被傳入 Process的時刻。
----------
看了以上讨論受益匪淺,有幾點疑惑,希望能指點一下。
t_analyze 表示你對音頻幀A調用 farend 的時刻:
這裡是指調用WebRtcAecm_BufferFarend()的時刻嗎,還是請求系統播放(AudioTrack.write)的時刻?
----------
t_render 表示[硬體]真正播放出幀A的時刻:
這裡是指硬體開始播放幀A的時刻還是播放完幀A的時刻?如何得到這個時間?
如果是用AudioTrack的話,使用那個setMarkerPosition嗎?
----------
t_capture 表示[硬體]采集到音頻幀B(注意跟A沒關系了)的時刻:
這個應該是AudioRecord.read傳回時的時刻吧?還是用這個時刻減去所讀buffer的size對應的時間?
----------
t_pull 表示幀B被傳入 Process的時刻:
此處t_pull是指公式中的t_process吧
----------
另外AECM可以直接用多路進來的聲音進行去回聲嗎 還是必須要先把多路合為一路以作為參考 ?
不勝感激
[235樓]
fingerplay 回複
2015-02-12 19:35:33
樓主,我參照你的方法編譯了agc子產品,但是在調用agc的WebRtcAgc_Process函數時 有點疑問,
int WMWebRtcAgc_Process(void* agcInst,
const int16_t* const* inNear,
int16_t num_bands,
int16_t samples,
int16_t* const* out,
int32_t inMicLevel,
int32_t* outMicLevel,
int16_t echo,
uint8_t* saturationWarning);
不知道inNear要傳入怎樣的參數,看源碼似乎要調用AudioBuffer的函數去擷取按頻率分段的一個數組,我現在隻有一個buffer,單聲道的,怎麼去轉換成這樣一個數組
[236樓]樓主
Bill_Hoo 回複
2015-02-15 13:05:24
回複 fingerplay:[235樓]
您好,前面已經說過,不再建議單獨使用各種子產品去進行音頻處理,本文目前參考價值較小。
[237樓]
dttlg 回複
2015-04-11 16:20:02
樓主,您好。
非常感謝你的文章。我編譯了單獨的ns, 确實可以去掉一些背景噪音。但是同時說話的聲音也變低了,這個可以了解。但是說話的聲音也模糊不清楚了,還需要什麼處理麼。
多謝回複。
[238樓]
zengwh513 回複
2015-04-24 21:26:59
Bill_Hoo,你好,我近期把webrtc的音頻子產品單獨拿出來編譯,是在ARM+LINUX平台下,音頻驅動是OSS,揚聲器那端我是接了個耳機, 當我說話的時候 我把耳機放到麥克風旁 産生很強的嘯叫,這是延遲計算錯誤的原因嗎?
[239樓]
dttlg 回複
2015-04-27 15:09:49
回複 Bill_Hoo:[17樓]
你說的(注意跟A沒關系了)是什麼意思?難道是不需要包含音頻a, 可以是播放a之前就錄好的音頻幀嗎?
[240樓]
dttlg 回複
2015-04-28 20:17:40
回複 Bill_Hoo:[236樓]
我先在回音消除, 發現有時候能夠消除一些,比如連續說話,有些回音是可以消除的。但是不能夠完全消除,大牛,有啥高見沒?
[241樓]樓主
Bill_Hoo 回複
2015-04-29 08:37:26
回複 zengwh513:[238樓]
沒有明白你說的把耳機放到麥克風旁什麼意思,讓麥克風再次采集耳機裡播放出來的聲音?
[242樓]
zengwh513 回複
2015-04-29 09:15:53
回複 Bill_Hoo:[241樓]
是的,這樣是不是一定會産生嘯叫
[243樓]
wutongluxjtu 回複
2015-07-13 17:23:59
"t_analyze 表示你對音頻幀A調用 farend 的時刻,t_render 表示[硬體]真正播放出幀A的時刻。
t_capture 表示[硬體]采集到音頻幀B(注意跟A沒關系了)的時刻,t_pull 表示幀B被傳入 Process的時刻。"
樓主可否将這4個值進行量化?我是指這幾個值在具體實作時的數學表達式。
ps: 例如Android中 t_render 和t_capture 時怎麼得到的?貌似上層不能擷取到硬體的播放/錄音時刻吧?