劉曉暉 秦子實
摘要:近年來,5G技術(shù)的發(fā)展帶動物聯(lián)網(wǎng)設(shè)備快速普及,以樹莓派為代表的卡片計算機大量出現(xiàn)在工程應(yīng)用的各個方面。而在音頻采集處理方面,基于樹莓派的麥陣列聲源采集具有高算力、高精度、低功率的特點。本文介紹基于sounddevice的采集、分發(fā)、播放音頻流的方法,該方法可以對音頻數(shù)字信號進行自定義預(yù)處理,支持多種數(shù)據(jù)分發(fā)方式,系統(tǒng)依賴少,代碼簡單且方便部署。
關(guān)鍵詞:物聯(lián)網(wǎng)設(shè)備;樹莓派;音頻采集
中圖分類號:TP393? ? ? 文獻標(biāo)識碼:A
文章編號:1009-3044(2021)17-0036-02
開放科學(xué)(資源服務(wù))標(biāo)識碼(OSID):
1 概述
樹莓派是一種尺寸極小的計算設(shè)備,具有包括處理器、內(nèi)存、外村在內(nèi)完整的計算機硬件要素,通常運行基于Debian的Linux系統(tǒng),功率約5W,具有豐富的外部接口。由于通用性強且已被市場廣泛應(yīng)用,目前具有大量適配的高質(zhì)量、低成本傳感器。
本文介紹基于樹莓派3B+平臺及SeeedReSpeaker6麥陣列,運行Raspbian buster系統(tǒng),使用sounddevice庫(以下簡稱sd)的聲源采集方案的設(shè)計與實現(xiàn)。該環(huán)形麥陣列精度較高、價格較低,適合在聲源定位、音頻采集項目中低成本部署。
2音頻采集
2.1 硬件識別
通過sounddevice庫進行音頻數(shù)據(jù)相關(guān)操作,首先需要識別聲卡并確定麥陣列聲卡的系統(tǒng)ID??梢酝ㄟ^sd.query_devices()函數(shù)確認(rèn)系統(tǒng)識別的音頻設(shè)備列表,返回示例如下:
“seeed-8mic-voicecard”即為麥陣列聲源采集設(shè)備(序號為2),具有8路輸入,即2顆AC108 ADC芯片,每芯4路輸入其中1路為playback,則實際采集為6路。麥陣列自帶聲卡輸出,即AC101 DAC芯片(序號為6),2路輸入2路輸出,占用樹莓派3.5mm耳機監(jiān)聽接口。因此,sounddevice庫主要使用序號2及序號6設(shè)備進行音頻數(shù)據(jù)的輸入輸出。通過以下代碼獲取輸入輸出設(shè)備ID:
2.2 音頻采集及監(jiān)聽
sounddevice庫支持兩種數(shù)據(jù)封裝格式,RawStream將數(shù)字信號轉(zhuǎn)為buffer對象進行傳輸,而Stream將RawStream再次封裝為numpy數(shù)組進行傳輸,需要numpy支持,更方便數(shù)據(jù)操作,本文選用Stream方式,發(fā)送numpy數(shù)組。
數(shù)據(jù)流發(fā)送有兩種方式:阻塞方式的和非阻塞回調(diào)方式,為方便調(diào)試,本文選用非阻塞回調(diào)方式,即音頻數(shù)據(jù)流發(fā)送開始后立即返回,這樣可以繼續(xù)在解釋器中繼續(xù)執(zhí)行其他作業(yè)。啟動音頻流的方法如下:
[rs = sd.Stream(samplerate=48000, device=iodevs, channels=[8, 2], callback=cb, finished_callback=fcb) ]
其中最主要的參數(shù)為回調(diào)callback,該函數(shù)將輸入輸出聯(lián)系起來,這個回調(diào)所要求的函數(shù)簽名為:
[callback(indata: ndarray, outdata: ndarray, frames: int, time, CData, status: CallbackFlags) -> None ]
其中indata參數(shù)時輸入設(shè)備傳入的數(shù)據(jù),即序號2的麥陣列,通常采用48Khz采樣率,每次回調(diào)傳入的numpy數(shù)組維度均為(512, 8),約為10ms的音頻數(shù)據(jù),延遲較低。outdata是傳給輸出設(shè)備的數(shù)據(jù),傳給輸出設(shè)備的數(shù)據(jù),在sd.Stream的聲道配置為[8, 2]即8路輸入2路輸出,因此需要將indata的8列數(shù)據(jù)轉(zhuǎn)為2列賦給outdata(如每4路求平均),此時3.5mm監(jiān)聽接口由于channels參數(shù)輸出設(shè)備的選擇,將有麥陣列采集的音頻信號輸出?;卣{(diào)函數(shù)示例,本文使用簡單的求平均法,將每4聲道數(shù)據(jù)求平均,使得原8列數(shù)據(jù)轉(zhuǎn)為2列數(shù)據(jù):
剩余的參數(shù)中,frames為幀數(shù),本文中即512;time是一個CFFI的C結(jié)構(gòu)體,包括輸入開始時間inputBufferAdcTime、輸出開始時間outputBufferDacTime、本次callback被調(diào)用的時間currentTime三個成員;status為本次回調(diào)狀態(tài),可以在此發(fā)送終止指令。
使用sounddevice將輸入處理后直接賦給輸出,經(jīng)實測延時極低,采集效率較高。
3 音頻數(shù)據(jù)分發(fā)
3.1 數(shù)據(jù)收發(fā)
由于在48000kHz采用率下,未經(jīng)壓縮是數(shù)據(jù)量較大(理論值約1.465MB/s),因此本文選用ZeroMQ分發(fā)numpy數(shù)組。ZeroMQ支持包括推送模式、拉取模式、MapReduce模式等多種分發(fā)方式,高效靈活,可以按照實際應(yīng)用場景靈活選擇。
ZeroMQ在Python下的支持庫名為pyzmq,在發(fā)送numpy數(shù)組時需要注意,pyzmq直接發(fā)送numpy數(shù)組時,ZeroMQ會使用Python的memoryview直接將數(shù)組轉(zhuǎn)換為字節(jié)發(fā)送,由于轉(zhuǎn)換過程僅保留數(shù)據(jù),數(shù)組的dtype類型信息和shape維度信息將丟失。因此,在發(fā)送數(shù)組時,需要使用ZeroMQ的SNDMORE標(biāo)識,先發(fā)送數(shù)組屬性,再發(fā)送數(shù)組內(nèi)容,如此即可在接收端重建完整數(shù)組。發(fā)送端的函數(shù)示例:
可以在分發(fā)時在md字典中添加其他屬性,如幀序列等信息,以輔助分發(fā)、重建及顯示,并不影響numpy數(shù)組重建。
3.2 數(shù)據(jù)重建及播放
在數(shù)據(jù)接收設(shè)備上,同樣按照2.1節(jié)的方法找出本地音頻輸入輸出設(shè)備(若是對數(shù)據(jù)進行重建并播放,則主要使用輸出設(shè)備)。鑒于發(fā)送端采用48000KHz采樣率,接收設(shè)備若希望能夠正常還原并播放音頻數(shù)據(jù),同樣需要調(diào)整設(shè)備聲卡采樣率至48000KHz,否則重組數(shù)據(jù)播放將有明顯的滯后。
接收設(shè)備收到的numpy數(shù)組每幀同樣為(512, 8)的維度,若接收設(shè)備播放為雙聲道,同樣需要進行調(diào)整輸出維度,安裝2.2節(jié)的回調(diào)函數(shù)進行按列求平均合并。
3.3 未來的改進
本文實例為最簡單的原理展示,若進行工程應(yīng)用需要注意,ZeroMQ與目前流行的其他消息隊列相比,具有極小極快可嵌入的優(yōu)點,但缺點也較為明顯——未配備持久化模塊。本文經(jīng)測試,在網(wǎng)絡(luò)狀況一般的環(huán)境中(如某些無線網(wǎng)絡(luò)),若網(wǎng)絡(luò)承受不住過大的數(shù)據(jù)流量,ZeroMQ發(fā)送端將出現(xiàn)消息堆積現(xiàn)象,并在緩存滿后直接丟棄數(shù)據(jù),在接收端的現(xiàn)象為數(shù)據(jù)滯后越來越大,在一定時間后重新同步至最新數(shù)據(jù),滯后未收到的數(shù)據(jù)將丟失。ZeroMQ因庫應(yīng)用場景及大小考慮,雖不提供官方持久化方案,但支持用戶自定義持久化,在工程應(yīng)用中,應(yīng)自行定義持久化模塊,以防數(shù)據(jù)丟失。
4 結(jié)束語
本文介紹了基于樹莓派的物聯(lián)網(wǎng)設(shè)備進行音頻數(shù)據(jù)采集,并使用ZeroMQ進行實時數(shù)據(jù)分發(fā)的方法,系統(tǒng)依賴少且部署簡便。該方法基于物聯(lián)網(wǎng)設(shè)備,在保證一定的數(shù)據(jù)處理能力的情況下維持低功耗。數(shù)據(jù)分發(fā)僅基于TCP socket,對網(wǎng)絡(luò)拓?fù)浼皡f(xié)議沒有特殊要求,兼容性良好且分發(fā)效率高,同時兼顧了多種的數(shù)據(jù)分發(fā)模式,可以在不同的場景中進行靈活應(yīng)用。
【通聯(lián)編輯:梁書】