國內智能音箱的問世早於國外,但因爲國內對智能化概念普及程度較低,初期智能音箱並無受到不少關注。但近幾年國內智能音箱行業經歷了從百花齊放到三足鼎立的發展階段,來自RT-Thread的黃天翔將從佔據主流市場的三個廠商脫穎而出的祕訣開始,分享RT-Thread在智能音箱在音頻方面的內容。
文 / 黃天翔算法
整理 / LiveVideoStack緩存
2014年10月,Alexa一款名爲 Echo 的智能音箱出現,智能音箱行業開始火爆並受到極大關注。2015年年末,全球智能音箱銷量達到250萬臺。服務器
國內智能音箱的問世早於國外,但因爲國內對智能化概念普及程度較低,初期智能音箱並無受到不少關注。2015年京東叮咚系列音箱問世,2016年國內的美的、酷狗等多家公司涉足智能音箱行業,到2017年智能音箱市場全面爆發,2018年各大廠商已完成智能音箱的全面佈局。網絡
國內智能音箱行業經歷了從百花齊放到三足鼎立的發展階段,到2018年末,阿里、小米、百度三家獨佔鰲頭,佔據主流市場。框架
咱們分析了三個廠商能脫穎而出的祕訣:首先百度用低價爆款的策略,以輕量化、小巧的產品迅速衝擊市場。ide
其次,如上右側圖所示,在兩年內國內廠商推出了多款智能音箱產品。從這些產品能夠發現智能音箱大熱還有一個重要因素:使用高性能芯片以及使用Linux系統方案。智能音箱涉及多方面難點技術,選用成本較高的方案快速迭代是市場得以推動的重要緣由。佈局
上圖所示的是兩種主流智能音箱的方案。百度小度智能音箱選用了Amlogic A113X1.5G 芯片配套 Linux 方案。小米音箱則是選用了全志 R16 A7四核心芯片。性能
基於現有方案能夠預測,後續各廠商將會尋找低成本且同時也能知足快捷開發、穩定的方案替代,愈來愈多中端廠商在考慮可否使用RTOS方案代替Linux方案。測試
如上圖所示的兩種方案,當前方案中使用的是高端芯片,將來則會選擇一些中低端甚至ARM9芯片完成智能音箱系統的開發。咱們能夠看到,目前方案從外接WIFI、藍牙芯片轉爲使用內置芯片,包括芯片、MCU、DSP等都發生了變化。從封裝來看,它從BGA封裝變爲QFN封裝,生產成本明顯下降。RTOS主打實時系統,開機速度下降到一兩秒,此外,它還有功耗低等特性。RTOS在智能音箱領域有必定優點,例如在ACE回採時,咱們會作主動喚醒,有固定的時間窗口使回採算法更可靠,時間不固定時回採數據不及時,RTOS可對時間窗口作極大保證。優化
上圖是通用方案啓動速度對比。咱們能夠看出系統分爲Boot、OS、APP啓動三個層面。從三個層面總體來看,Linux系統啓動須要10秒左右,而使用RTOS方案啓動時間只有一兩秒。
如上圖,咱們從四個方面作了對比。如你們所知,Linux所需的RAM、Flash是比較高的。ARM cortex-A方案是主流高端方案須要32MB RAM 和64MB Flash 的消耗。據咱們統計,遷移 RTOS 方案 後可作到2MB RAM 和 4MB Flash 左右的消耗。因爲 RTOS 系統比較輕巧,咱們可使用更小的RAM、Flash 芯片。
除了以上優點,RTOS也有生態劣勢。智能音箱的操做系統更須要涉及到網絡、音頻相關的內容。Linux系統有成熟穩定的網絡框架、音頻子系統以及ffmpeg、Curl等開源軟件。RTOS調度器則更多的使用了輕量級網絡協議棧,在音頻方面比較空缺,公司各有私有的方案,成本比較高。
咱們使用RTOS研發音頻播放系統鑑於成本趨勢、系統資源問題和開發成本的綜合考慮,但願能完成一套比較完整成熟的音頻系統。
如上圖是咱們初版音頻播放器方案框架。早期設計這一款播放器,沒有考慮網絡播放的相關的功能。這版邏輯比較簡單:獲取音頻數據後直接作解碼,解碼過程是一個循環邏輯,單線程等待外部響應事件,包括seek事件、暫停恢復事件、中止事件完成播放器邏輯,最後將解析出的數據寫入底層音頻驅動。
因爲初版不知足網絡播放的市場需求,咱們將網絡組件、網絡功能添加到了系統中。如上圖中紅色邏輯處理部分。在這部分咱們對框架思路作了修改,將文件、網絡資源放到同一層,選擇本地或網絡下載音頻資源,總體呈單線程模式。不管打開的URL資源是本地資源仍是網絡資源,都是得到資源後作解碼播放 。
這版播放器隨着在項目中愈來愈多的使用,逐漸的出現了不少噪音卡頓拖慢等問題。如上圖是咱們PCM項目回採得出的數據分析結果。咱們在播放音頻出現了短暫噪音以後繼續播放的狀況,後期多方面分析發現,這是因爲網絡狀況不穩定,解碼器短暫接收不到數據形成的。
如上圖所示網絡不可靠的緣由有多種,不少網絡不穩定是網絡硬件形成的波動,軟件層面是沒法徹底避免的,咱們只能經過軟件算法和思路減小這些問題形成的影響。
如上圖是咱們第三版改進後的播放器框架圖。左側是同樣的,依然是獲取數據進行解碼,惟一不一樣的是我會從網絡緩存區獲取數據。啓動播放後,咱們會啓動一個新線程將本地數據或網絡音頻寫入緩存區,將下載與解碼器分離。只要緩存區有數據,解碼播放便不會出現卡頓。
咱們採用了帶RTOS 喚醒調度機制且具備水位線管理的 pipe 做爲第三版的音頻緩衝區 。例如咱們設置了一個512KB的緩存區,經過HTTP鏈接下載數據。若是緩存區中沒有數據,咱們能夠簡單認爲下載與解碼同時進行的。解碼時緩存區沒有數據時會等待直到音頻數據高於水位線。水位線便可開始解碼的最低緩存數據量。咱們作了一個可動態調節的水位線機制。
改進事後,咱們作了一個測試。如上圖左側是咱們的測試環境數據。V2版本中,理論上音樂碼率大於1411kbps時才支持播放。而V3版本中,當下載速度大於播放速度時會致使水位上漲,必定會出現高於水位線狀況。當網絡出現卡頓時,緩存數據是高於水位線的,解碼器依然能夠拿到數據。
在另外一種測試環境時,當下載速度一直低於播放速度。這是一種極端狀況,下載達不到規定碼率,不管如何播放都絕對不會流暢。V2版本中音頻會一直間隔卡頓致使用戶沒法聽清內容。在水位線機制中,當碼率較低,緩存不夠時是不會發出聲音的,會有一秒的緩存時間,緩存事後播放的聲音是較長時間連續的。,這樣咱們可以提高必定會卡頓狀況下的用戶體驗,讓在很是卡頓的網絡狀況下音頻再也不發出刺耳的噪音。
有時咱們會播放一些相聲、新聞等實時音頻電臺流內容。和音樂文件有一些不一樣,這時會出現推送流碼率和播放流碼率相同的狀況。
這種狀況的解決涉及到變速不變調算法的使用,即咱們會改變語音播放速度而不改變語義語調,改變較小時人耳不會聽到差異。如上圖咱們作了測試。當下載碼率與播放碼率相同時,咱們經過變速不變調算法下降音頻的播放碼率,下載速度會始終大於播放速度。如圖中所示,雖然咱們會進行緩存,可是因爲下載速度較小,水位線漲不上去,依然會出現必定卡頓。經處理後,下載速度大於播放速度後,水位線會持續上漲,開始播放後即可以下降出現卡頓的狀況。
基於以上,咱們完成了第四版的改進。咱們在寫入底層播放驅動前作對每一幀作變速不變調算法處理,固然這是能夠選擇開啓的功能。
除了能夠作變速不變調處理,咱們還能夠在相同位置EQ算法均衡器等其它處理,實現流行音樂音效、超低音音效等效果。
因而咱們又作了一次改進。咱們將變速不變調作了剝離,以插件的形式動態選擇不一樣音效。
在智能音箱領域,客戶會使用多種容器、協議以及編碼格式。咱們須要支持多種組合。
咱們在原基礎上作了改進,改進點如上圖紅色部分所示。在以前版本中,咱們會將數據直接下載緩存到緩存區進行解碼。改進後,咱們將解碼和解容器進行分離,在下載中加入瞭解容器,播放過程當中解碼。解容器以插件形式接入系統,在播放過程當中探測它的格式,選用合適的容器解碼格式。在這個過程當中,不只能夠實現了多格式容器解碼,也實現了多協議解碼。咱們將下載線程進行分類,針對不一樣協議作下載邏輯。將容器、協議、解碼器剝離後,播放器框架可實現多種組合應用場景。
接下來我將介紹智能音箱設計過程當中遇到的另外一個重要問題。如上圖左側部分,音箱服務器推送了一個音頻,在播放過程當中忽然須要播放提示音,一般咱們須要將音頻暫停播放,插入提示音,播放完成後音頻恢復播放。在這種狀況下,設備須要維護播放狀態的。如圖中原始音頻是44K,採樣率是16K,中間有采樣率切換的過程。切換採樣率的過程當中,須要注意它的實時性,由於咱們控制內部芯片會產生必定時延。另外一個就是pop音問題,當還有音頻在播放時,切換採樣率會有噪音出現。對此,咱們作出了部分改進,採用混音的思路:將原音頻音量下降,再採用混音的方式將提示音混入,提示音播放完成後恢復音頻音量。這種思路不須要考慮播放器播放狀態的維護,並且兩路音頻徹底獨立,開發者邏輯代碼編寫也清晰簡單。
咱們在作這個方案時評估了Linux下的一個成熟算法。算法採用了線性重採樣算法。如上圖,它的庫裏有五種模式,默認使用最低模式。咱們使用ARM-CotexM4芯片作了測試,發現最多模式會佔用百分之八十CPU。
libsamplerate算法輸入的數據是浮點類型,使用此算法先將數據切爲單精度浮點數,內部使用雙精度浮點數作計算採樣以確保採樣效果。如圖中48K音頻採樣耗費了115%CPU,重採樣過程花費三百多秒。咱們對此作了改進。咱們對輸入參數使用整形定點算法,這時佔用CPU降到了79%。咱們又將內部雙精度浮點數強制降爲單精度後,CPU佔用率降到了49.5%。最終,咱們作成了全整形數,這時CPU佔用只有3.8%。另外,因爲重採樣算法由C語言寫成,咱們從彙編層面對它作了優化,以前的操做形成了採樣效果變差,經過彙編優化將32位整型數改成了64位,總體效果雖不及浮點數,但總體效果提高了不少。
市面上主流混音算法模型有幾種,第一種是兩個聲道數據直接加和,當某一通道的數據幅度較大時混音後任意出現音頻數據溢出,從而音頻失真。第二種是加和後再除以音道數防止溢出,這樣會形成音道內音量衰減,而且音軌越多衰減越多。還有一種是加和箝位,即相加超過最大值時進行限幅,這樣音頻也會失真。另外還有飽和處理、歸一化處理等。考慮到RTOS 方案應用場景是一個音軌音量高一個音量稍低,咱們並須要兩個聲音同時聽清,咱們只須要保證一個音軌的質量。最終咱們選擇了圖中第二種算法。雖然會產生一些衰減,可是在這個場景下只保證兩個音道中一個聲音清晰,衰減是能夠忽略的。可是其它算法可能會出現失真,這是不能接受的。這種方案在實際應用中效果很好的。
上圖是咱們測試結果。圖中是一幀數據、20毫秒的窗口,咱們作了重採樣混音算法。優化事後,主音軌重採樣耗了大概1.288毫秒,副音軌耗了1.296毫秒,混音用時1.281毫秒,在ARM9 120MHZ的系統中耗費了大概20%的CPU消耗。