树莓派麦阵列数据采集分发的设计与实现

    刘晓晖 秦子实

    

    

    

    摘要:近年来,5G技术的发展带动物联网设备快速普及,以树莓派为代表的卡片计算机大量出现在工程应用的各个方面。而在音频采集处理方面,基于树莓派的麦阵列声源采集具有高算力、高精度、低功率的特点。本文介绍基于sounddevice的采集、分发、播放音频流的方法,该方法可以对音频数字信号进行自定义预处理,支持多种数据分发方式,系统依赖少,代码简单且方便部署。

    关键词:物联网设备;树莓派;音频采集

    中图分类号:TP393? ? ? 文献标识码:A

    文章编号:1009-3044(2021)17-0036-02

    开放科学(资源服务)标识码(OSID):

    1 概述

    树莓派是一种尺寸极小的计算设备,具有包括处理器、内存、外村在内完整的计算机硬件要素,通常运行基于Debian的Linux系统,功率约5W,具有丰富的外部接口。由于通用性强且已被市场广泛应用,目前具有大量适配的高质量、低成本传感器。

    本文介绍基于树莓派3B+平台及SeeedReSpeaker6麦阵列,运行Raspbian buster系统,使用sounddevice库(以下简称sd)的声源采集方案的设计与实现。该环形麦阵列精度较高、价格较低,适合在声源定位、音频采集项目中低成本部署。

    2音频采集

    2.1 硬件识别

    通过sounddevice库进行音频数据相关操作,首先需要识别声卡并确定麦阵列声卡的系统ID。可以通过sd.query_devices()函数确认系统识别的音频设备列表,返回示例如下:

    “seeed-8mic-voicecard”即为麦阵列声源采集设备(序号为2),具有8路输入,即2颗AC108 ADC芯片,每芯4路输入其中1路为playback,则实际采集为6路。麦阵列自带声卡输出,即AC101 DAC芯片(序号为6),2路输入2路输出,占用树莓派3.5mm耳机监听接口。因此,sounddevice库主要使用序号2及序号6设备进行音频数据的输入输出。通过以下代码获取输入输出设备ID:

    2.2 音频采集及监听

    sounddevice库支持两种数据封装格式,RawStream将数字信号转为buffer对象进行传输,而Stream将RawStream再次封装为numpy数组进行传输,需要numpy支持,更方便数据操作,本文选用Stream方式,发送numpy数组。

    数据流发送有两种方式:阻塞方式的和非阻塞回调方式,为方便调试,本文选用非阻塞回调方式,即音频数据流发送开始后立即返回,这样可以继续在解释器中继续执行其他作业。启动音频流的方法如下:

    [rs = sd.Stream(samplerate=48000, device=iodevs, channels=[8, 2], callback=cb, finished_callback=fcb) ]

    其中最主要的参数为回调callback,该函数将输入输出联系起来,这个回调所要求的函数签名为:

    [callback(indata: ndarray, outdata: ndarray, frames: int, time, CData, status: CallbackFlags) -> None ]

    其中indata參数时输入设备传入的数据,即序号2的麦阵列,通常采用48Khz采样率,每次回调传入的numpy数组维度均为(512, 8),约为10ms的音频数据,延迟较低。outdata是传给输出设备的数据,传给输出设备的数据,在sd.Stream的声道配置为[8, 2]即8路输入2路输出,因此需要将indata的8列数据转为2列赋给outdata(如每4路求平均),此时3.5mm监听接口由于channels参数输出设备的选择,将有麦阵列采集的音频信号输出。回调函数示例,本文使用简单的求平均法,将每4声道数据求平均,使得原8列数据转为2列数据:

    剩余的参数中,frames为帧数,本文中即512;time是一个CFFI的C结构体,包括输入开始时间inputBufferAdcTime、输出开始时间outputBufferDacTime、本次callback被调用的时间currentTime三个成员;status为本次回调状态,可以在此发送终止指令。

    使用sounddevice将输入处理后直接赋给输出,经实测延时极低,采集效率较高。

    3 音频数据分发

    3.1 数据收发

    由于在48000kHz采用率下,未经压缩是数据量较大(理论值约1.465MB/s),因此本文选用ZeroMQ分发numpy数组。ZeroMQ支持包括推送模式、拉取模式、MapReduce模式等多种分发方式,高效灵活,可以按照实际应用场景灵活选择。

    ZeroMQ在Python下的支持库名为pyzmq,在发送numpy数组时需要注意,pyzmq直接发送numpy数组时,ZeroMQ会使用Python的memoryview直接将数组转换为字节发送,由于转换过程仅保留数据,数组的dtype类型信息和shape维度信息将丢失。因此,在发送数组时,需要使用ZeroMQ的SNDMORE标识,先发送数组属性,再发送数组内容,如此即可在接收端重建完整数组。发送端的函数示例:

    可以在分发时在md字典中添加其他属性,如帧序列等信息,以辅助分发、重建及显示,并不影响numpy数组重建。

    3.2 数据重建及播放

    在数据接收设备上,同样按照2.1节的方法找出本地音频输入输出设备(若是对数据进行重建并播放,则主要使用输出设备)。鉴于发送端采用48000KHz采样率,接收设备若希望能够正常还原并播放音频数据,同样需要调整设备声卡采样率至48000KHz,否则重组数据播放将有明显的滞后。

    接收设备收到的numpy数组每帧同样为(512, 8)的维度,若接收设备播放为双声道,同样需要进行调整输出维度,安装2.2节的回调函数进行按列求平均合并。

    3.3 未来的改进

    本文实例为最简单的原理展示,若进行工程应用需要注意,ZeroMQ与目前流行的其他消息队列相比,具有极小极快可嵌入的优点,但缺点也较为明显——未配备持久化模块。本文经测试,在网络状况一般的环境中(如某些无线网络),若网络承受不住过大的数据流量,ZeroMQ发送端将出现消息堆积现象,并在缓存满后直接丢弃数据,在接收端的现象为数据滞后越来越大,在一定时间后重新同步至最新数据,滞后未收到的数据将丢失。ZeroMQ因库应用场景及大小考虑,虽不提供官方持久化方案,但支持用户自定义持久化,在工程应用中,应自行定义持久化模块,以防数据丢失。

    4 结束语

    本文介绍了基于树莓派的物联网设备进行音频数据采集,并使用ZeroMQ进行实时数据分发的方法,系统依赖少且部署简便。该方法基于物联网设备,在保证一定的数据处理能力的情况下维持低功耗。数据分发仅基于TCP socket,对网络拓扑及协议没有特殊要求,兼容性良好且分发效率高,同时兼顾了多种的数据分发模式,可以在不同的场景中进行灵活应用。

    【通联编辑:梁书】