[前言]
前言
今天跟王總聊天,他狠狠地(形容詞)叼了我,他說你為什么不寫一些比較牛逼的文章,為什么總是寫一些教別人如何安裝軟件,如何打開軟件的文章,你還妄想用這樣的文章拉攏人心,你是不是腦子進水,是不是腦子進水,是不是腦子進水,王總連續說了幾次腦子進水,我當時是羞愧萬分,我不知道如何去表達我當時的窘境,我只能默默的低頭跟王總說,我水平太差,我水平太差,我水平太差,然后王總又跟我說當時他在華為做開發,linux相關的問題從不過夜,一年升一個級別,我們在愉快的交談中結束了午飯時間,所以我想了很久,有必要結合AI音箱寫一下Android音頻方面的知識
最近音頻方面的開發非常火熱,也出現了一些非常牛逼的公司,訊飛占領老大位置,思必馳,云之聲都有非常完善的AI音箱方案
對應的產品有,小愛音箱,小度,叮咚,天貓精靈,斐訊,市場一片火熱,做好一個AI音箱,電聲方面的知識是必不可少的,我這篇文章主要也是從這個為入口講一些這方面的知識。
一、音頻基礎
(1)采樣率(samplerate)
采樣就是把模擬信號數字化的過程,不僅僅是音頻需要采樣,所有的模擬信號都需要通過采樣轉換為可以用0101來表示的數字信號,示意圖如下所示:
藍色代表模擬音頻信號,紅色的點代表采樣得到的量化數值。采樣頻率越高,紅色的間隔就越密集,記錄這一段音頻信號所用的數據量就越大,同時音頻質量也就越高。
根據奈奎斯特理論,采樣頻率只要不低于音頻信號最高頻率的兩倍,就可以無損失地還原原始的聲音。
通常人耳能聽到頻率范圍大約在20Hz~20kHz之間的聲音,為了保證聲音不失真,采樣頻率應在40kHz以上。常用的音頻采樣頻率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz等。
(2)量化精度(位寬)
上圖中,每一個紅色的采樣點,都需要用一個數值來表示大小,這個數值的數據類型大小可以是:4bit、8bit、16bit、32bit等等,位數越多,表示得就越精細,聲音質量自然就越好,當然,數據量也會成倍增大。
常見的位寬是:8bit 或者 16bit
(3)聲道數(channels)
由于音頻的采集和播放是可以疊加的,因此,可以同時從多個音頻源采集聲音,并分別輸出到不同的揚聲器,故聲道數一般表示聲音錄制時的音源數量或回放時相應的揚聲器數量。單聲道(Mono)和雙聲道(Stereo)比較常見,顧名思義,前者的聲道數為1,后者為2
二、Android Audio框架
Android用的是C/S的框架,就是一個client,一個service,中間是一個HAL作為統一的接口,HAL往下就會到tinyalsa,tinyalsa是alsa的裁剪版本,后面對應的就是驅動層了。
三、I2S接口介紹
I2S總線標準:I2S(Inter-IC Sound Bus)是飛利浦公司為數字音頻設備之間的音頻數據傳輸而制定的一種總線標準。在飛利浦公司的I2S標準中,既規定了硬件接口規范,也規定了數字音頻數據的格式。I2S有3個主要信號:
串行時鐘 SCLK:也叫做位時鐘BCLK,即對應數字音頻的每一位數據,SCLK的頻率=2×采樣頻率×采樣位數,現在問題來了,有人會問這些東西到底是什么意思呢?其實,I2S一般是傳輸立體聲,有兩個聲道channel,采樣頻率指得是采樣數率,多久去采集一個點,每個點是幾個bit組成。
幀時鐘LRCK:用于切換左右聲道的數據,LRCK為“0”表示正在傳輸的是左聲道的數據,為“1”表示正在傳輸的是右聲道的數據。LRCLK == FS,就是采樣頻率
串行數據SDATA:就是用二進制補碼表示的音頻數據,有時為了使系統間能夠更好的同步,還需要另外傳輸一個信號MCLK,稱為主時鐘,也叫系統時鐘(System Clock),是采樣頻率的256或384倍
I2S不同的標準介紹:I2S主要是針對ADC和主控,如果ADC設置的I2S標準和主控的不一致,那么錄音肯定是要出問題的,正常使用的時候,會涉及1bit delay,大家在量I2S波形的時候也可以看出來
BCLK計算:BCLK =LRCLKxbitsxch,Ch 默認是2,我們現在用的是8ch的數據,但是我們用的是4個數據線,這時候計算的時候ch還是用2來計算
BCLK =16K x 32bitsx2ch = 1.024M
注意:我們在使用CX20810 ADC芯片的時候,CX20810現在是市面上做AI音響用的主流芯片,像叮咚叮咚就是用這個,里面介紹一個TDM 模式,這個也是一個I2S的標準,不過這個標準是一個DATA線傳8ch的數據
四、TINYALSA子系統
(1)代碼介紹
目前linux中主流的音頻體系結構是ALSA(Advanced Linux Sound Architecture),ALSA在內核驅動層提供了alsa-driver,在應用層提供了alsa-lib,應用程序只需要調用alsa-lib(libtinyalsa.so)提供的API就可以完成對底層硬件的操作。說的這么好,但是Android中沒有使用標準的ALSA,而是一個ALSA的簡化版叫做tinyalsa。Android中使用tinyalsa控制管理所有模式的音頻通路,我們也可以使用tinyalsa提供的工具進行查看、調試。
tinycap.c 實現錄音相關代碼 tinycap
Tinyplay.c 實現放音相關代碼 tinyplay
Pcm.c 與驅動層alsa-driver調用接口,為audio_hw提供api接口
Tinymix 查看和設置混音器 tinymix
Tinypcminfo.c 查看聲卡信息tinypcminfo
(2)音頻幀(frame)
這個概念在應用開發中非常重要,網上很多文章都沒有專門介紹這個概念。
音頻跟視頻很不一樣,視頻每一幀就是一張圖像,而從上面的正玄波可以看出,音頻數據是流式的,本身沒有明確的一幀幀的概念,在實際的應用中,為了音頻算法處理/傳輸的方便,一般約定俗成取2.5ms~60ms為單位的數據量為一幀音頻。
這個時間被稱之為“采樣時間”,其長度沒有特別的標準,它是根據編解碼器和具體應用的需求來決定的,我們可以計算一下一幀音頻幀的大小:
假設某音頻信號是采樣率為8kHz、雙通道、位寬為16bit,20ms一幀,則一幀音頻數據的大小為:
int size = 8000 x 2 x 16bit x 0.02s = 5120bit = 640 byte
音頻幀總結
period(周期):硬件中斷間的間隔時間。它表示輸入延時。
聲卡接口中有一個指針來指示聲卡硬件緩存區中當前的讀寫位置。只要接口在運行,這個指針將循環地指向緩存區中的某個位置。
frame size=sizeof(one sample) * nChannels
alsa中配置的緩存(buffer)和周期(size)大小在runtime中是以幀(frames)形式存儲的。
period_bytes=pcm_format_to_bits 用來計算一個幀有多少bits,實際應用的時候經常用到
下面有個老外的講的音頻幀,很多解釋都是從這里翻譯來的,大家自行體味一下
五、CODEC介紹
(1)專用術語
ASLA- Advanced Sound Linux Architecture
OSS - 以前的Linux音頻體系結構,被ASLA取代并兼容
Codec - Coder/Decoder
I2S/PCM/AC97 - Codec與CPU間音頻的通信協議/接口/總線
DAI- Digital Audio Interface 其實就是I2S/PCM/AC97
DAC - Digit to Analog Conversion
ADC - Analog to Digit Conversion
DSP - Digital Signal Processor
Mixer - 混音器,將來自不同通道的幾種音頻模擬信號混合成一種模擬信號
Mute - 消音,屏蔽信號通道
PCM - Pulse Code Modulation 脈沖調制編碼,一種從音頻模擬信號轉換成數字信號的技術,區別于PCM音頻通信協議
SSI - Serial Sound Interface
DAPM - Dynamic Audio Power Management
(2)放音錄音框圖
(3) OSS和ALSA比較
a.OSS的優點(對用戶來說)
在內核空間(kernel space)里面包含了一個透明軟件混音器(vmix)。這樣多個程序就可以同時使用聲音設備而且沒有任何問題。
這個混音器可以讓你單獨調節各個程序的音量。
對某些老聲卡有著更好的支持比如創新(Creative)的X-Fi。
聲音程序的初始反應時間一般更好。
對使用OSS的應用程序接口(API)的程序有更好的支持,很多程序都支持OSS的API,而不需要ALSA的模擬。
b.OSS的優點(對開發者來說)
清晰的API文檔,更易于使用。
支持用戶空間的聲音驅動。
可移植性強,OSS也可以在BSDs和Solaris下運行。
本身可以跨平臺,可以更方便移植到新的操作系統。
c.ALSA的優點
ALSA對USB音頻設備支持更好,而OSS的輸出還在試驗中,輸入還未實現。
ALSA支持藍牙聲音設備。
ALSA支持AC'97和HDAudio dial-up soft-modems (比如Si3055)。
ALSA對MIDI支持得更好,但用OSS你只能通過軟件合成器(如timidity和fluidsynth)來使用MIDI。
ALSA對待機支持更好,而用OSS,你需要在待機前使用soundoff來停止OSS驅動,在恢復后使用soundon來啟動OSS。
OSS的jack檢測目前在某些HDAudio-powered主板上不能正常工作。也就是說在某些型號的主板上,你可能需要在插入耳機的時候手動關閉外置揚聲器。而ALSA沒這個問題。
d.調用接口
alsa是多了一個alsa-lib接口,但是OSS是直接操作設備文件的,這個差異還是很大的,不過幸運的是,alsa出來后為了兼容oss,也是做了一些修改。
(4)ASOC介紹
ASOC--ALSA System on Chip (即ALSA在片選系統上的應用),是建立在標準ALSA驅動層上,為了更好地支持嵌入式處理器和移動設備中的音頻Codec的一套軟件體系。在ASoc出現之前,內核對于SoC中的音頻已經有部分的支持,不過會有一些局限性
Codec類: Codec即編解碼芯片的驅動,此Codec驅動是和平臺無關,包含的功能有: 音頻的控制接口,音頻讀寫IO接口,以及DAPM的定義等。如果需要的話,此Codec類可以在BT,FM,MODEM模塊中不做修改的使用。因此Codec就是一個可重復使用的模塊,同一個Codec在不同的SOC中可以使用。對應ak7755.c
Platform類: 可以理解為某款SOC平臺,平臺驅動中包括音頻DMA引擎驅動,數字接口驅動(I2S, AC97, PCM)以及該平臺相關的任何音頻DSP驅動。同樣此Platform也可以重用,在不同的Machine中可以直接重復使用。
Machine類:Machine可以理解為是一個橋梁,用于在Codec和Platform之間建立聯系。此Machine指定了該機器使用那個Platform,那個Codec,最終會通過Machine建立兩者之間的聯系。
(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
六、音頻相關調試技巧
在調試錄音和放音的時候,我們先使用tinyalsa的調試命令來進行調試,比如tinycap、tinyplay、tinypcminfo
Proc下的音頻調試介紹:
#The_.2Fproc.2Fasound.2Foss.2F_directory
(1)通過命令確認聲卡是否注冊成功
rk3399_mid:/ $ ls /proc/asound/
card0 cards hwdep rockchipak7755c timers
card1 devices pcm rockchipi2sdmic version
$ ls /dev/snd/
(2)xrun debug
我們在調試音頻的時候,難免會遇到underrun或者overrun,出現此兩者情況時內核會打印log協助問題分析,Menuconfig中需要開啟如下選項:
[*] Advanced Linux Sound Architecture --->
[*] Debug [*] More verbose debug
[*] Enable PCM ring buffer overrun/underrun debugging
然后在對應聲卡/proc/asound/card0/xrun中寫入相應的值,值如下:
#define XRUN_DEBUG_BASIC (1 xrun
開啟所有debug信息檢測。
Xrun主要是讀寫速度不一致引起的音頻錄音播放異常,之前遇到一個這樣的問題是因為DMA引起的,在注冊聲卡設備時會申請一個period_size,這個size是不能隨意更改大小的,所以大家在寫代碼的時候要注意。
七、AI智能音響核心點
這部分講的每一點內容都是非常核心的,直接影響到AI音箱的整體效果,包括聲源定位,回聲消除,有很多人反饋為什么我的音箱聲源定位不好,為什么我的回聲消除效果很差,我們就要從下面幾個問題點去排查
(1)、音頻部分
1、做到有效采樣16bits 32bits,(失真、截幅)、軟件端對多通道數據可以編碼
多通道數據采樣同步,采樣率同步,采樣時鐘同步,比如不能出現錄音的時候出現失真情況。
2、錄音的采樣深度理論是越大是越好的,采樣頻率要跟算法部分確認好,訊飛要求的是16K的采樣音頻送給他們的算法
3、播放不能有失真,電聲部分一定要通過嚴格的測試要求,整個掃頻階段都不能出現問題,比如不能出現播放高頻的時候發現喇叭有低頻的聲音此類問題
(2)、結構部分
1、MIC開孔深度、孔徑、構型符合標準;
2、內部音腔隔離,密封性能;
3、結構震動隔離;震音非常關鍵,測試的時候會發現,裝上機構后的回聲消除比沒有結構時候差很多,大多是由于增加了結構,震音結構影響很大。
4、喇叭與MIC的距離,不能太近;
(3)、回聲消除注意
作用:
抑制產品(喇叭)本身發出的聲音,使得產品在播放音頻時依然可以進行語音交互;
注意點:
1、需要接參考信號,信號采樣需要符合要求;
做到有效采樣
使用硬采集方案
參考信號采樣盡量與mic采集到的回聲同步,至少不晚于回聲;
2、結構方面需要特別注意;
內部音腔隔離
震動隔離
喇叭與MIC的相對位置;
3、硬件選型方面需要注意;
4、整個采樣系統中的延時要穩定;
彩蛋:
?ASR(automaticspeech recognition)把語音轉換成文字,AI算法說的是自我學習算法,所以學習是一個非常復雜的過程,下面是一個鏈接,有開源的一些模型,感興趣的可以自己拿去學習
https://github.com/kaldi-asr/kaldi