近期研究WEBRTC語音如何在IOS下運行,發現WEBRTC的voice_engine中已實現相關IOS的類,但在具體應用中卻遇到一系列問題,經過連續幾天的艱苦奮鬥後,終於解決一系列問題,成功在模擬器中實現錄音、播放本地迴環。
在編寫測試程式的過程中,打算利用libjingle這個庫作為WEBRTC的外層封裝庫,解決語音的傳輸控制方面的介面問題,方便以後擴充,最終卻發現libjingle似乎未考慮IOS下的應用,於是乎,漫漫征程踏上了第一步。
一、分析libjingle,抽取部分類編譯出一個for ios版本
這部分工作不太難,只是將用到的一些類引用進來,編譯成一個靜態庫,幸好這裡沒有用到平台相關的代碼,解決一大麻煩。但在過程也也遇到的兩個問題,其實和語音無關,是視頻(voice_engin)方面的,但我又想把視頻部分代碼先編譯進來,便於後期視頻方面的工作。
第一個就是libjingle沒有實現for ios的內部視頻捕捉(include_internal_video_capture)與渲染(include_internal_video_render)類,OK,屏蔽它,在gyp的設定檔中去掉
第二個yasm這個項目了,這個項目是用來編譯彙編的東東,通過gyp產生的項目這個yasm是編譯不了的,為什麼呢,因為ios不支援編譯目標為命令列程式的項目。可這個項目是用來編譯jpeg和libvpx的呀,缺少了還不行,看來只有繞路了。經過研究,發現用到的libjpeg_turbo在網上有現在編譯版本(for ios模擬器和裝置版),於是乎果斷下載,在gyp設定檔中加入ios的OS判斷,是ios就去掉原libjpeg_turbo,引用編譯好的版本。
第三個就是libvpx項目了,這個我現在都沒有完全解決,原因在於這個項目也需要用yasm來編譯,通過gyp產生的項目編譯不了的。經過一翻研究,發現gyp產生的mac版的項目中,libvpx編譯出來的靜態庫是面向i386和x86兩個架構的。看來這裡,不經猜想,這裡的i386是乎可以用到ios 模擬器下?引用進去,果然編譯通過,不過,不知是否可運行 ,不管了,反正現在我只用到音頻,還用不到視頻。能否運行和iphone版的靜態庫後面再研究吧。
到這裡,測試程式終於寫好了,編譯通過,開始測試。
二、痛苦的測試之路
怎麼就沒有聲音呢?怎麼就能沒有聲音呢?從頭到尾仔細檢查,設定編譯條件為_DEBUG,設定WEBRTC voice_engine的trace回調,列印所有日誌資訊,沒錯呀,所有函數都調用成功,能看到採集的語音資料通過libjingle介面發送,從介面接收到的語音資料也正確傳入voice_engine,但就是沒聲音呀!
這裡好像進入了瓶頸,工作陷入了停滯中。
三天后,還是沒解決。
為什麼已有採集的資料了,並且資料已傳入引擎了,沒聲音呢。到底是測試程式、voice_engin、還是libjingle的問題呢。
反向推算一下,看下最後一步的播放有問題嗎?找到測試程式接收到語音資料的代碼,打下斷點。咦,為什麼語音資料一直是0呢,全是0?難道傳輸有問題?先不管,手動把這個資料全設定為隨機數。測試,終於有聲音了,雜音,全是雜音,但畢竟也是聲音呀,熱淚.....雜音,你堅定了我繼續下去的決心。
再打斷點到語音資料轉送前,還是0,看來是採集有問題了。
沒辦法,讀與分析代碼吧,最原始的方法。找到ios語音採集代碼(audio_device_ios.cc),讀吧,仔細讀吧。
從頭到尾分析一次,似乎沒什麼問題呀,可為什麼呢,採集到資料全是0。
痛苦,真的痛苦,語音的初始化、緩衝區管理、資料擷取、發送,都正確的吧,是吧?!從goolge的SVN上checkout的代碼應該是經過測試的吧,不會有什麼問題吧?本著懷疑一切的精神,開始小心的求證。
從apple開發網站上下了一個audiounit的sample(aurioTouch),編譯、運行,可以呀,能錄音、能播放呀。OK,一行行對比代碼,好像初始化、採集、緩衝管理差不多,只是採樣率等參數不一樣,不過這個不影響吧,事實證明,的確不影響。
等等,是乎AudioComponentDescription的componentSubType這個參數有點不一樣,sample中是設定的是kAudioUnitSubType_RemoteIO,而WEBRTC中用的是kAudioUnitSubType_VoiceProcessingIO,這個有問題嗎,事實證明,問題就在這裡!修改,將WEBRTC的參數值設定了kAudioUnitSubType_RemoteIO!啊,終於聽到本地迴環聲音了,幸福!
這兩個參數有何不同呢?二者分別應該用在什麼地方呢?到底是什麼原因WEBRTC中要用kAudioUnitSubType_VoiceProcessingIO呢,我不知!
有人能解答一下嗎?