1. 项目背景与需求分析在智能语音交互和音视频监控领域多路麦克风采集与回声消除(AEC)是两项关键技术。全志V853作为一款面向智能视觉和语音处理的高性能SoC配合Tina Linux系统为这类应用提供了完整的解决方案。本次项目需要实现6路麦克风并行采集包含V853内部Audio Codec的2路模拟麦克风以及通过TP9930芯片接入的4路数字I2S麦克风实时回声消除其中1路内部麦克风与Lineout硬件直连专门用于采集回声参考信号多声道数据处理需要将6路音频数据分离处理并对特定声道实施AEC算法这种配置常见于智能会议系统、车载语音助手等场景其中多麦克风阵列可支持波束成形和噪声抑制回声消除能有效解决扬声器声音被麦克风二次采集导致的啸叫问题TP9930作为视频处理芯片其I2S接口复用为音频输入时需特别注意时序配置2. 硬件架构与接口配置2.1 硬件连接拓扑系统硬件连接关系如下[TP9930芯片] --I2S1-- [V853主控] ├── MIC1 ├── MIC2 ├── MIC3 └── MIC4 [V853内部Codec] --模拟音频总线-- ├── MIC5 (与Lineout直连) └── MIC62.2 I2S从机模式配置由于TP9930作为I2S主机V853需配置为从机模式。关键寄存器设置// 设备树配置片段 daudio1_plat { tdm-num 1; tx-pin 0; // 不使用发送功能 rx-pin 0; // 启用接收 pinctrl-used; pinctrl-names default,sleep; pinctrl-0 daudio1_pins_a; pinctrl-1 daudio1_pins_b; tx-hub-en; rx-sync-en; status okay; // 启用I2S1接口 }; daudio1_mach { soundcard-mach,format i2s; // 标准I2S模式 soundcard-mach,frame-master daudio1_codec; soundcard-mach,bitclock-master daudio1_codec; soundcard-mach,slot-num 16; // TP9930固定16slot soundcard-mach,slot-width 16; // 16bit位深 status okay; daudio1_cpu: soundcard-mach,cpu { sound-dai daudio1_plat; soundcard-mach,pll-fs 1; soundcard-mach,mclk-fs 0; // 从机模式无需MCLK }; };2.3 TP9930音频输出配置TP9930需要配置为I2S主机模式输出16bit/16slot数据static struct regval_list reg_audio_init[] { {0x40, 0x40}, // 音频模块使能 {0x00, 0x01}, // I2S输出使能 {0x01, 0x02}, // 主时钟分频 {0x17, 0x00 | (16 2)}, // 16bit数据宽度 {0x1B, 0x01 | (16 6)}, // I2S模式 {0x18, 0x80 | (0x0F)}, // 采样率设置 {0x3d, 0x01}, // 音频复位 {0x40, 0x00}, // 配置完成 };注意使用示波器验证BCLK、LRCLK和DATA信号时应确认BCLK频率 采样率 × 位宽 × 通道数LRCLK频率 采样率DATA信号在BCLK下降沿稳定3. 软件架构与音频通路搭建3.1 ALSA复合设备配置在/etc/asound.conf中创建虚拟声卡合并6路输入# 主控两路模拟MIC pcm.Capture2MicHard { type hooks slave.pcm hw:0,0 hooks.0 { type ctl_elems hook_args [ { name MIC1 Switch value 1 } { name MIC2 Switch value 1 } ] } } # TP9930四路数字MIC pcm.CaptureI2SRX { type hooks slave.pcm hw:snddaudio1,0 hooks.0 { type ctl_elems hook_args [ { name loopback debug value 0 } ] } } # 六路合并虚拟设备 pcm.Capture1MicPlusAec { type route slave.pcm { type multi slaves { a { pcm Capture2MicHard channels 2 } b { pcm CaptureI2SRX channels 4 } } bindings { 0 { slave a channel 0 } # MIC5 1 { slave a channel 1 } # MIC6 2 { slave b channel 0 } # MIC1 3 { slave b channel 1 } # MIC2 4 { slave b channel 2 } # MIC3 5 { slave b channel 3 } # MIC4 } } ttable.0.0 1 ttable.1.1 1 ttable.2.2 1 ttable.3.3 1 ttable.4.4 1 ttable.5.5 1 }3.2 音频采集测试使用ALSA工具验证采集功能# 录制6声道PCM数据 arecord -Dplug:Capture1MicPlusAec -f S16_LE -c 6 -r 8000 /tmp/multi_mic.wav # 单独测试TP9930输入 arecord -Dplug:CaptureI2SRX -f S16_LE -c 4 -r 8000 /tmp/i2s_mic.wav常见问题排查若只有部分声道有数据检查设备树slot-num和slot-width配置TP9930的声道映射寄存器出现噪声或失真确认I2S主从时钟同步检查硬件上拉电阻和滤波电路4. 回声消除实现细节4.1 信号流设计回声消除处理流程[扬声器信号] -- Lineout ─┬─ [MIC5] (参考信号) └─ 空间回声 ── [其他MIC] (含回声) [MIC5原始信号] ---- WebRTC AEC ---- [纯净语音] | | [其他MIC信号] --------------------4.2 WebRTC AEC集成使用WebRTC的AEC模块进行处理#include webrtc/modules/audio_processing/aec/echo_cancellation.h // 初始化参数 AecConfig config; config.nlpMode kAecNlpModerate; config.skewMode kAecFalse; config.metricsMode kAecFalse; config.delay_logging kAecFalse; // 创建实例 void* aecmInst WebRtcAec_Create(); WebRtcAec_Init(aecmInst, 8000, 8000); // 采样率8kHz // 处理流程 short far_frame[80]; // 10ms数据8kHz short near_frame[80]; short out_frame[80]; while(1) { // 获取参考信号(MIC5) get_audio_channel(5, far_frame, 80); // 获取待处理信号(如MIC1) get_audio_channel(1, near_frame, 80); // AEC处理 WebRtcAec_BufferFarend(aecmInst, far_frame, 80); WebRtcAec_Process(aecmInst, near_frame, NULL, out_frame, NULL, 80, 40, 0); // 输出处理结果 save_processed_data(out_frame, 80); }关键参数说明nlpMode非线性处理强度建议从kAecNlpModerate开始调试延迟控制WebRtcAec_Process的msInSndCardBuf参数需与实际硬件延迟匹配建议处理块大小设为10ms8kHz下80个样本过大导致延迟增加过小影响处理效果4.3 性能优化技巧延迟校准# 测量系统延迟 speaker-test -t sine -f 1000 arecord -D hw:0,0 -f dat -d 10 | sox -t raw -r 44100 -e signed -b 16 -c 2 - -n stat根据测量结果调整msInSndCardBuf参数双讲检测优化// 启用双讲检测 WebRtcAec_enable_delay_agnostic(aecmInst, 1);非线性处理// 调整抑制强度 WebRtcAec_SetConfig(aecmInst, config);5. 多声道数据处理与编码5.1 声道分离实现从6声道PCM中提取各麦克风数据// 16bit交错模式下的声道分离 void split_channels(short* input, short** outputs, int frames) { for(int i0; iframes; i) { for(int ch0; ch6; ch) { outputs[ch][i] input[i*6 ch]; } } } // 使用示例 short pcm_data[6*1024]; short* channels[6]; for(int i0; i6; i) channels[i] malloc(1024*2); split_channels(pcm_data, channels, 1024);5.2 AAC编码配置使用V853内置的AAC编码器#include aw_audio_codec.h // 初始化参数 AACENC_CONFIG aac_config; aac_config.sample_rate 8000; aac_config.channels 1; // 单声道独立编码 aac_config.bit_rate 24000; // 24kbps aac_config.adts_used 1; // 添加ADTS头 // 创建编码器 HANDLE aac_enc AACEncoderInit(aac_config); // 编码流程 short pcm_frame[1024]; unsigned char aac_data[2048]; int aac_len; while(get_pcm_data(pcm_frame)) { aac_len AACEncoderEncode(aac_enc, pcm_frame, aac_data); save_aac_frame(aac_data, aac_len); }5.3 多路编码优化为提升6路并行编码效率使用线程池处理各声道共享编码器实例但独立上下文采用零拷贝内存管理// 线程池实现示例 void* encode_thread(void* arg) { int ch (int)arg; while(1) { short* data get_channel_data(ch); int len AACEncoderEncode(encoders[ch], data, buffers[ch]); output_stream(ch, buffers[ch], len); } } // 创建6个编码线程 for(int i0; i6; i) { pthread_create(threads[i], NULL, encode_thread, (void*)i); }6. 系统集成与调试6.1 完整数据流验证系统级测试流程使用信号发生器向Lineout注入1kHz正弦波同时播放人声测试音频采集各麦克风原始数据验证MIC5应包含纯净参考信号其他MIC应包含人声泄漏的正弦波AEC输出应只保留人声6.2 常见问题解决方案现象可能原因解决方案AEC效果差参考信号与回声不同步调整msInSndCardBuf参数高频失真抗混叠滤波不足启用硬件滤波器或软件重采样断续杂音I2S时钟不稳定检查PCB布线缩短时钟走线声道错位slot配置错误确认设备树slot-width和slot-num6.3 性能监控指标通过/proc接口获取实时状态# 查看CPU负载 cat /proc/loadavg # 查看音频中断频率 cat /proc/interrupts | grep daudio # 查看内存使用 cat /proc/meminfo | grep MemAvailable建议优化方向当CPU负载70%时考虑降低AEC处理复杂度减少编码比特率出现音频中断丢失时检查DMA配置优化中断亲和性7. 实测效果与优化记录在实际车载环境测试中初始方案存在以下问题车辆加速时引擎噪声导致AEC失效解决方案增加噪声抑制模块调整AEC参数WebRtcAec_enable_extended_filter(aecmInst, 1); // 启用长尾消除多麦克风相位差影响波束成形解决方案增加硬件同步信号软件校准延迟# 延迟校准工具 ./audio_calibrate -m 1,2,3,4 -r 5低温环境下I2S时序异常解决方案调整TP9930时钟驱动能力// 修改寄存器0x1C值从0x15到0x17 {0x1C, 0x17} // 增强时钟驱动经过三轮迭代优化后在-20℃~85℃温度范围内系统达到回声衰减量30dB语音MOS分4.2端到端延迟80ms