<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E4%B8%80%E7%AE%80%E4%BB%8B">一簡介</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E4%BA%8C%E5%B1%80%E5%9F%9F%E7%BD%91%E8%AF%AD%E9%9F%B3%E9%85%8D%E7%BD%AE">二區域網路語音配置</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E4%B8%89speex">三Speex</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#31-%E7%AE%80%E4%BB%8B">1 簡介</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#32-%E6%8A%80%E6%9C%AF%E7%89%B9%E7%82%B9">2 技術特點</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#33-%E5%BC%80%E5%8F%91-%E8%AF%AD%E9%9F%B3%E5%8E%8B%E7%BC%A9">3 開發-語音壓縮</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#34-%E7%9B%B8%E5%85%B3%E8%AE%A1%E7%AE%97">4 相關計算</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E5%9B%9Bopus-%E9%9F%B3%E9%A2%91%E7%BC%96%E8%A7%A3%E7%A0%81%E5%99%A8%E4%B8%AD%E7%9A%84%E7%91%9E%E5%A3%AB%E5%86%9B%E5%88%80">四Opus - 音頻編解碼器中的瑞士軍刀</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#41-%E7%AE%80%E4%BB%8B">1 簡介</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#42-%E6%8A%80%E6%9C%AF">2 技術</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#43-%E5%BC%80%E5%8F%91%E6%8F%92%E4%BB%B6">3 開發插件</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#44-%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF">4 版本資訊</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#libopus-113%E7%A8%B3%E5%AE%9A%E5%8F%91%E8%A1%8C%E7%89%88">libopus 113穩定發行版</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#45-%E5%AF%B9%E6%AF%94">5 對比</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#46-%E6%A8%A1%E5%9D%97api%E6%96%87%E6%A1%A3">6 子產品API文檔</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#461-opus-encoder">61 Opus Encoder</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89">類型定義</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E6%96%B9%E6%B3%95">方法</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E8%AF%A6%E7%BB%86%E6%8F%8F%E8%BF%B0">較長的描述</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89%E6%96%87%E6%A1%A3">類型定義文檔</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E6%96%B9%E6%B3%95%E6%96%87%E6%A1%A3">方法文檔</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#462-opus-decoder">62 Opus Decoder</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E4%BA%94%E5%B0%8F%E7%BB%93">五小結</a>
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221#%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F">聯系方式</a>
現在有個需求,在區域網路内實作實時語音,傳輸層協定使用UDP協定,如果直接使用AudioRecord進行錄制音頻流并發送到另一端進行播放,音質會非常差,而且斷斷續續,原因如下:
采樣頻率: fm = 44.1KHz
量化位數:16bit
聲道配置:2(雙聲道)
那麼,碼率 V = 44.1K * 16 *2 = 1411.2 Kbps = 176.4KBps,即每秒傳輸速率大概176.4KB,
若音頻幀時間為20ms,每個音頻資料包大小為 size = 176.4KBps * 0.02s = 3.528KB,
一般情況下,我們每次讀取一個音頻幀的資料,可以取整為3600Byte,
是以 每秒大概發送 176.4/3.6=49 個資料包,每個資料包大小為3.6KB。
如果再考慮到資料報頭,實測每秒發送約45個資料包,每秒傳輸速率大概180KB。
如果傳輸的僅僅是語音資訊,那麼不需要很高的采樣頻率,可以使用8KHz進行采樣,單通道即可。
采樣頻率:8KHz,可以采集比較完整的語音資訊。當然,對于高頻的資訊無能為力;
資料格式:16bit,可以較為詳細的表示聲音的幅度;
聲道配置:單聲道輸入和輸出,能夠适配所有的機型,少部分手機不支援雙聲道(立體聲),如果設定立體聲會隻出現左耳機有聲音的情況;
音頻類型:音樂流
輸出模式:音頻流
音頻來源:麥克風
<a href="http://www.speex.org/" target="_blank">官方網址</a>
Speex是一套主要針對語音的開源免費,無專利保護的音頻壓縮格式。Speex工程着力于通過提供一個可以替代高性能語音編解碼來降低語音應用輸入門檻 。另外,相對于其它編解碼器,Speex也很适合網絡應用,在網絡應用上有着自己獨特的優勢。同時,Speex還是GNU工程的一部分,在改版的BSD協定中得到了很好的支援。
Speex是基于CELP并且專門為碼率在2-44kbps的語音壓縮而設計的。它的特點有:
窄帶(8kHz),寬帶(16kHz)和超寬帶(32kHz)壓縮于同一位流。
強化立體編碼
資料包丢失隐蔽
可變比特率(VBR)
語音捕捉(VAD)
非連續傳輸(DTX)
定點運算
感官回聲消除(AEC)
噪音屏蔽
<a href="https://github.com/KevinDGK/MyAudioDemo" target="_blank">本項目GitHub位址</a>
将代碼內建到自己的項目中的步驟:
第一步:将Demo的整個jni目錄複制到自己的main目錄下;
第二步:修改複制過來的jni檔案夾中的speex_jni.cpp中的方法名
第三步:添加gradle配置
将紅色框圈住的地方複制到自己的項目中即可。

第四步:編譯項目生成.so檔案
選擇Build->Make Project,然後找到.so庫複制到自己的libs下即可:
第五步:在程式中使用
将Speex這個編解碼工具類複制到自己的項目中,就可以正常使用了,具體使用方式詳見Demo。
采樣頻率: fm = 8KHz
聲道配置:1
那麼,碼率 V = 8K * 16 * 1 = 128Kbps = 16KBps,即每秒傳輸速率大概16KB,
若音頻幀時間為20ms,每幀音頻資料大小為 size = 16KBps * 0.02s = 320KB,即160 Short,
設定壓縮品質為4,每幀音頻資料壓縮完後隻有20Byte,壓縮比為 320:20,即 16:1,每秒發送1/0.02=50個資料包,即單單傳遞音頻資料占用的帶寬為 1 KBps,如果需要添加一些資料報頭,基本上也能維持在5KBps左右!
将176.4KBps變成16KBps,然後再壓縮成1KBps,好了,現在可以滿足基本的區域網路内的語音傳輸需求了。如果帶上耳機的話,基本上能夠很完美的語音通話了。如果不帶耳機,随着通話,麥克風或者環境的回聲會越來越強,将會嚴重降低通話品質,我們之後需要做的就是做回聲處理了。這個在之後的部落格中專門介紹。
盡管Speex也十分的優秀,但是還是被新的技術給踢下了寶座,連它的官網上都寫明了該技術已經被Opus給替代,并且宣稱Opus的各項性能都将比Speex優秀的多。接下來小編将為大家初步介紹一下Opus的特點和API~
Opus是一個完全開放的、免費的、多功能的音頻編解碼器。 它在互動式的語音和音樂在網際網路中的傳輸方面有着無與倫比的優勢,但是同樣緻力于存儲和流媒體應用程式。它是由網際網路工程任務組(IETF)制定的标準,标準格式為RFC 6716,由Skype的SILK編解碼器和Xiph.Org的CELT編解碼器合并發展而來,号稱音頻編解碼器中的瑞士軍刀(來自官方視訊)。
Opus可以處理廣泛的音頻應用程式,包括IP電話、視訊會議、遊戲内聊天、甚至遠端現場音樂表演。從低比特率窄帶語音到非常高品質的立體聲音樂,它都可以适用。技術特點:
6 kb /s到510 kb / s的比特率
采樣率從8 kHz(窄帶)到48 kHz(全頻)
幀大小從2.5毫秒到60毫秒
支援恒定比特率(CBR)和可變比特率(VBR)
從窄帶到全頻段的音頻帶寬
支援語音和音樂
支援單聲道和立體聲
支援多達255個頻道(多資料流的幀)
可動态調節比特率,音頻帶寬和幀大小
良好的魯棒性丢失率和資料包丢失隐藏(PLC)
浮點和定點實作
Libopus是Opus編解碼器的參考實作,我們可以參考該代碼進行開發。
為了能在Firefox中支援Opus,Mozilla提供了專門的Opus工具。Opus-tools提供指令行程式來進行編碼、檢查和解碼.opus檔案。在HTML中語音相關的可以使用,原來不是Android的,需要用的自己去官方首頁下載下傳即可。
小編翻譯到這裡還沒有找到和Android相關的,藍瘦,香菇!
<a href="http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz" target="_blank">opus-1.1.3.tar.gz</a>
小編曾說過,沒有對比,就沒有傷害。
品質和比特率
下圖說明了不同的編解碼器的品質和比特率直接的函數關系。
narrowband - 窄頻
wideband - 寬頻
super-wideband - 超寬頻
fullband - 全頻段
fullband stereo - 全頻段立體聲
從圖上可以看出,Opus的優勢十分明顯。尤其是較之前的Speex,具有更大的比特率範圍以及帶寬。
比特率/延遲比較
從圖中可以看出,Opus在任何比特率下都具有較少的延遲。
聽力測試
<a href="https://opus-codec.org/comparison/" target="_blank">測試結果</a>
<a href="https://opus-codec.org/examples/" target="_blank">音頻測試用例</a>
截止到目前位置,最新的版本是1.13穩定發行版,是以在這裡翻譯的都是該版本的API。
Opus 編碼器
1
2
因為Opus是有狀态編碼,編碼過程始于建立一個編碼器狀态:
從這一點開來,enc可以用來編碼一個音頻流。一個編碼器在同一時刻僅僅隻能用于一個音頻流編碼,并且對于每一種音頻格式初始化的編碼器狀态,不可以再次初始化。
當執行 opus_encoder_create() 為編碼器配置設定了記憶體之後,就可以初始化這個預配置設定的記憶體:
opus_encoder_get_size() 傳回編碼器對象所需要的記憶體大小,注意,該代碼在未來的版本中可能會變成改變記憶體大小,是以不要根據這個代碼有任何假定,即不要根據擷取記憶體大小這個方法來有一些邏輯上的處理,因為之後的版本變動有可能會影響你的代碼。
編碼器的狀态會一直儲存在記憶體中,并且隻有淺複制才能有效的複制該狀态,例如:memcpy()。
使用 opus_encoder_ctl() 接口可以改變一些編碼器的設定。所有的設定已經被預設設定成推薦值,是以隻有在必要的時候才去改變它們。最常見的想要改變的設定如下:
bitrate:比特率,b/s
complexity:複雜度,1-10,1最低,10最高
signal_type:信号類型,可以為OPUS_AUTO(預設)、OPUS_SIGNAL_VOICE、OPUS_SIGNAL_MUSIC
檢視CTLS相關編碼來擷取完整的設定參數清單,大部分參數可以在一個音頻流的任何時候設定和改變。
為了對一幀資料編碼, opus_encode() 或者 opus_encode_float() 在調用的時候必須使用的是恰好的一幀(2.5,5,10,20,40,60毫秒)音頻資料。
audio_frame:opus_int16格式的音頻資料
frame_size:抽樣的每一幀的時間大小(每個通道)
packet:壓縮後的編碼寫入的位元組數組
max_packet:位元組數組中可以寫入的最大位元組數,推薦大小為4000位元組,不要使用 max_packet 去控制可變比特率,而是使用 OPUS_SET_BITRATE 的CTL指令。
opus_encode() 和 opus_encode_float() 傳回實際接入到packet中的編碼後的音頻資料的位元組數。傳回值也許是無效的,表明編碼錯誤。如果傳回值小于2位元組或者更小,那麼這個packet不需要發送出去。
一旦這個編碼器對象不需要,可以銷毀掉:
如果編碼器對象是使用opus_encoder_init() 而不是 opus_encoder_create() 方法建立的,那麼除了可能需要釋放我們手動配置設定的記憶體之外,不需要其他的動作。
參數:
參數
參數類型
入參或出參
解釋
st
OpusEncoder∗
in
編碼器對象
pcm
const opus_int16*
輸入信号(雙聲道則為交錯模式),長度為frame_size × channels × sizeof(opus_int16),即采樣個數 × 聲道數 × 16。
frame_size
int
輸入的音頻信号的每個聲道的采樣數量,這一定是一個Opus架構編碼器采樣率的大小。例如,當采樣率為48KHz的時候,采樣數量允許的數值為120、240、480、960、1920和2880。傳遞一個持續時間少于10 ms的音頻資料(480個樣本48 kHz),編碼器将不會使用LPC或混合模式。
data
unsigned char∗
out
輸出編碼結果,至少包含max_data_bytes個位元組數。
max_data_bytes
opus_int32
為了輸出編碼結果配置設定的記憶體,它可能用于控制一個即時比特率的上線,但是不應該作為唯一的比特率控制。
關于采樣率和采樣數量的關系,上文已經提到過,opus_encode() 或者 opus_encode_float() 在調用的時候必須使用的是恰好的一幀(2.5,5,10,20,40,60毫秒)音頻資料,如果采樣頻率為48KHz,那麼:
∵ 采樣頻率 Fm = 48KHz
∴ 采樣間隔 T = 1/Fm = 1/48000 s = 1/48 ms
∴ 當T0 = 2.5 ms 時,N = T0/T = 2.5/(1/48) = 120,
當T0 = 5.0 ms 時,N = T0/T = 2.5/(1/48) = 240,
當T0 = 10 ms 時,N = T0/T = 2.5/(1/48) = 480,
當T0 = 20 ms 時,N = T0/T = 2.5/(1/48) = 960,
當T0 = 40 ms 時,N = T0/T = 2.5/(1/48) = 1920,
當T0 = 60 ms 時,N = T0/T = 2.5/(1/48) = 2880,
即,當Fm = 48KHz時:
采樣時間(ms)
2.5
5
10
20
40
60
采樣個數
120
240
480
960
1920
2880
實在是翻譯不動了。。。
其實有了上面的介紹,看官們應該能有個大概的認知,下面貼出一個中文版的翻譯文檔,大家自己浏覽,因為目前我也差不多看了一般,是以小編對該文檔的後面章節正确性與否并不負責~
<a href="http://blog.csdn.net/KevinDGK/article/details/52934221" target="_blank">Opus-官方文檔中文版</a>
如果對比一下Speex和Opus,會發現從內建和使用的角度來看,十分的相似,API的時候方式也差不多,隻不過Opus的功能更加的強大,API也更加豐富,但是也變相的增加了我們的開發難度,需要對C語言有相當好的功底,才可以定制實作自己的需求。
程式設計之路,任重而道遠。先是為了生活而程式設計,後是為了超越而程式設計!