天天看點

【單獨編譯使用WebRTC的音頻處理子產品 - android】

更新

【2015年2月15日】

    Bill 這段時間沒有再關注 WebRTC 以及音頻處理的相關資訊,且我個人早已不再推薦單獨編譯 WebRTC 中的各個子產品出來使用。實際上本文的參考價值已經很小了,甚至可能會産生誤導。不删這篇文章的原因在于文後有很多讀者的讨論,其中的一些仍具備一定的價值,請大家務必以批判和審慎的态度閱讀文章。

【2014年5月14日】

   昨天有幸在 Google 論壇裡詢問到 AECM 子產品的延遲計算一事,Project member 說搗騰這個延遲實際上對 AECM 的效果沒有幫助,這個延遲值僅在 AECM 啟動時加快内置延遲估算器的收斂,如果更新的延遲有誤,甚至會使 AECM 内置的延遲估算器出現錯誤的偏移,他建議我使用一個理論上的定值,Chrome 中他們用了 100ms。我之前也在 AECM 裡看到了它對内置的 delay_estimator 二進制延遲估算器有很大的依賴,近端與遠端資料比對與否,幾乎全部仰仗這個延遲估算器的結果。是以,對于 AECM 的使用,是否還需要花時間去計算這個系統延遲,bill 不再置評,個中效果大家自己實踐和把握。

   其次,AECM 産生的唧唧聲 Project member 澄清這不是 bug,而是 AECM 算法本來就有此表現,屬正常現象。

   在這裡僅希望大家知道此事,以免被我一家之言誤導。

   【2014年5月8日】

   本文已有一年之久,随着自己在學習過程中認識的加深,以及期間和各位在文後的讨論,擔心後來者照着這一年前的文章走彎路,bill覺得有必要對文章做一個更新,點出自己走的彎路,以免誤導後來者。

   2. 關于回聲消除濾波器延遲的計算,之前自己一直認為隻要這個延遲計算準确,就能得到理想的回聲消除效果,現在發現這個想法太幼稚,一是AECM算法本身有一定局限性,二是Android上的采集延遲沒有系統API支援,很難計算準确,而播放端的API又不能保證其準确性。目前我的能力隻能做到盡量優化上層的延遲計算,盡量減少由Android音頻API對延遲造成的影響。

   3. 在 Android 上層優化計算系統音頻延遲的代碼達到一定瓶頸後,可以将優化目标轉向 1)AECM 算法。 2)優化AEC(PC)(使其能在手機上正常運作,目前AECPC預設濾波器長度為12塊,每塊64個點,即AECPC僅能處理48ms的單聲道16kHz延遲的資料,而Android的音頻系統延遲大多在100ms以上,是以既要增加AECPC濾波器長度又要保證其運作效率是優化的重點) 3)其他子產品的優化(比如抖動緩沖區等)。

   4. 文後的源碼清單已經過時,由于我目前不再支援單獨編譯這些子產品,恕我不再更新該清單,如确有獨立編譯需求的,可自行在WebRTC項目對應目錄中找到需要的檔案。

附言

   WebRTC是時下比較熱門的新技術,由于bill接觸時間尚短,對該項目的了解和認知定存在不足甚或偏差,文中有描述不當之處還望各位悉心指出,感激不盡。

前言

   雖然WebRTC主要目标是為網際網路提供高品質的富媒體即時通信,但其源碼為C/C++所寫,且其開發版中也包含對 android 和 iOS 等移動裝置的支援,是以對于如今飛速發展的移動網際網路,WebRTC也能推波助瀾大顯神通。

   WebRTC提供一套音頻處理引擎VOE(本文不涉及視訊處理引擎VIE),但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):

<a href="http://webrtc.googlecode.com/svn/branches/3.31/" target="_blank">http://webrtc.googlecode.com/svn/branches/3.31/</a>

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包裝檔案:

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

<code>/***</code>

<code> </code><code>* Summary</code>

<code> </code><code>* types:</code>

<code> </code><code>*   NSinst_t : the type of noise suppression instance structure.</code>

<code> </code><code>*   NsHandle : actually the same type of NSinst_t, defined in</code>

<code> </code><code>*              "noise_suppression.h" as a empty struct type named</code>

<code> </code><code>*              "NsHandleT".</code>

<code> </code><code>*</code>

<code> </code><code>*   Note:</code>

<code> </code><code>*    1.You have no need to pass env and jclazz to these functions,</code>

<code> </code><code>*      cus' JVM will does it for you.</code>

<code> </code><code>*    2.We only support 10ms frames, that means you can only input 320</code>

<code> </code><code>*      Bytes a time.</code>

<code> </code><code>**/</code>

<code>/**</code>

<code> </code><code>* This function wraps the "WebRtcNs_Create" function in "noise_suppression.c".</code>

<code> </code><code>* Input:</code>

<code> </code><code>*        none.</code>

<code> </code><code>* Output:</code>

<code> </code><code>*        the handler of created noise suppression instance.</code>

<code> </code><code>* Return value:</code>

<code> </code><code>*        -1 : error occurs.</code>

<code> </code><code>*        other value : available handler of created NS instance.</code>

<code> </code><code>* @author billhoo</code>

<code> </code><code>* @version 1.0 2013-1-29</code>

<code> </code><code>*/</code>

<code>JNIEXPORT jint JNICALL</code>

<code>Java_你的類限定名_createNSInstance(JNIEnv *env,</code>

<code>        </code><code>jclass jclazz) {</code>

<code>    </code><code>NsHandle *hNS = NULL; </code><code>//create a pointer to NsHandle on native stack.</code>

<code>    </code><code>if</code> <code>(WebRtcNs_Create(&amp;hNS) == -1) { </code><code>//allocate dynamic memory on native heap for NS instance pointed by hNS.</code>

<code>        </code><code>return</code> <code>-1;  </code><code>//error occurs</code>

<code>    </code><code>} </code><code>else</code> <code>{</code>

<code>        </code><code>return</code> <code>((</code><code>int</code><code>) (NSinst_t *) hNS); </code><code>//returns the address of NS instance on native heap.</code>

<code>    </code><code>}</code>

<code>}</code>

WebRtcNs_Initiate 包裝函數及注釋

<code> </code><code>* This function wraps the "WebRtcNs_Init" function in</code>

<code> </code><code>* "noise_suppression.c".</code>

<code> </code><code>* Initializes a NS instance and has to be called before any other</code>

<code> </code><code>* processing is made.</code>

<code> </code><code>*        - nsHandler   - Handler of NS instance that should be</code>

<code> </code><code>*                        initialized.</code>

<code> </code><code>*        - sf          - sampling frequency, only 8000, 16000, 32000</code>

<code> </code><code>*                        are available.</code>

<code> </code><code>*         nsHandler  - the handler of initialized instance.</code>

<code> </code><code>*         0                - OK</code>

<code> </code><code>*         -1               - Error</code>

<code>Java_你的類限定名_initiateNSInstance(JNIEnv *env,</code>

<code>        </code><code>jclass jclazz, jint nsHandler, jlong sf) {</code>

<code>    </code><code>NsHandle *hNS = (NsHandle*) nsHandler;</code>

<code>    </code><code>return</code> <code>WebRtcNs_Init(hNS, sf);</code>

[END OF ADDED]

Step 3 - 編譯WebRTC - NS子產品

<code>LOCAL_PATH := $(call my-dir)</code>

<code>include $(CLEAR_VARS)</code>

<code>LOCAL_MODULE    := webrtc_ns</code>

<code>LOCAL_SRC_FILES := \</code>

<code>        </code><code>noise_suppression.c \</code>

<code>        </code><code>ns_core.c \</code>

<code>        </code><code>fft4g.c \</code>

<code>        </code><code>ns_jni_wrapper.c</code>

<code>include $(BUILD_SHARED_LIBRARY)</code>

   編譯完成後,将項目中的 webrtc_ns.so 動态庫拷貝出來以備後續使用。

Step 4 - 加載編譯好的NS子產品動态庫

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 以及 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

       ring_buffer.c

       delay_estimator.c

       delay_estimator_wrapper.c

       aecm_core.c

       echo_control_mobile.c

WebRTC - AGC 子產品源檔案清單

       spl_sqrt.c

       copy_set_operations.c

       dot_product_with_scale.c

       resample_by_2.c

       analog_agc.c

       digital_agc.c

     本文轉自Bill_Hoo 51CTO部落格,原文連結:http://blog.51cto.com/billhoo/1213801,如需轉載請自行聯系原作者

繼續閱讀