大概是两年前的一个周末,我从朋友那儿顺回来一块TI的DM365开发板,当时他跟我说这玩意儿做视频处理挺厉害,但我满脑子想的就一件事——能不能用它把书房那套老音响改成无线的,那种感觉估计你也懂,就是手头有点空闲,刚好又有个小念头在脑子里转悠,不试试浑身不舒服。
先搞清楚DM365是个什么角色
说实话刚拿到板子的时候我也懵,后来查了不少资料才慢慢理清楚,DM365本质上是一颗ARM9内核加视频协处理器的SoC,它厉害的地方在于硬件编解码——H.264、MPEG-4这些格式它都能硬解,但问题是,我一开始完全跑偏了方向,老想着用它来直接处理WiFi音频流,后来才明白这事儿其实得分层看。
打个比方吧,DM365就像厨房里那个主厨,它擅长做大菜,但你现在让它去门口收快递,不是不行,只是有点浪费,WiFi模块负责把数据包收进来,这就是快递员干的活;DM365拿到数据之后解码、处理,这才是它该做的事。
| 模块 | 负责的事 | 像我生活中的什么 |
| WiFi芯片(比如RTL8188) | 接收网络音频数据包 | 门口取快递的人 |
| DM365的ARM核 | 跑Linux、管理任务调度 | 厨房里安排菜单的人 |
| DM365的音频接口(McASP) | 把解码后的数据送到DAC | 把菜端上桌的手 |
| 外部DAC(比如PCM5102A) | 数字信号转模拟,接功放 | 最后撒调料调整口感 |
你看,关键瓶颈其实不在DM365本身,而在于WiFi链路稳不稳、驱动有没有配好、缓冲够不够大,我第一次失败就是因为缓冲设太小,播30秒就断,后来改到8MB才稳下来。
WiFi音频传输这事儿,坑比想象的多
我一开始想得特别简单:板子连WiFi,接收手机发过来的音频流,解码,送到扬声器,完事,真正动手才发现每一步都有小坑等着你。
第一道坎:驱动
DM365跑的是MontaVista Linux(后来有人移植了OpenEmbedded),内核版本偏老,我手上那个USB WiFi网卡是Ralink RT73芯片的,驱动编译就搞了一下午。make menuconfig那一步永远会漏掉某个依赖,报错信息还特别不友好,后来学乖了,直接找了个确认适配的驱动源码包,版本号是rt73-k2wrlz-3.0.3,在DM365的2.6.32内核上勉强跑起来了。

第二道坎:数据传输方式
音频流走WiFi,可选的方式挺多,我试过三种:
- RTP直推——延迟低但丢包时会有明显爆音,适合局域网环境好时用
- HTTP拉流——缓冲多、稳当,但延迟偏高,听歌可以,实时播放就别想了
- 自定义UDP包——我自己写了个简单的发包程序,加了个序号方便接收端重排,效果意外还行
最后实装用的是第三种,配合一个环形缓冲区,代码写得挺糙的,但能用,有时候工程上就是这样,优雅的方案要打磨很久,不如先把东西跑通再说。
数据在板子里面走一圈,到底经历了什么
这个流程图我画在笔记本上了,大概是这样:

手机App编码 → PCM数据 → 压缩成低带宽格式 → WiFi发出 → DM365的WiFi模块接收 → 网络协议栈 → 用户态缓冲区 → 音频解码 → McASP接口 → 外部DAC → 功放 → 音箱出声
这里面有两个环节特别容易被忽略,一个是时钟同步问题——手机的时钟和DM365的时钟是两回事,跑久了会漂移,我加了自适应采样率转换才勉强稳住,另一个是DMA搬运——如果音频数据走CPU搬运,占用率高得吓人,开了EDMA之后才降到5%左右。
第二张图我后来搜文献的时候看到一篇挺有意思的,标题是"Design of Wi-Fi Audio Transmission System Based on DM365",里面有个硬件框图跟我实际搭的系统很像,McASP接I2S格式的DAC,DM365的GPIO还能顺带控制功放的静音引脚,这样没数据的时候自动静音,不会有底噪。
后来这套东西在我书桌上跑了两个月,每天下班回家点一下手机,书房音箱就接着前一天没听完的播客继续放,那种感觉挺奇妙的,就一块绿油油的板子,几根杜邦线,一个USB WiFi小网卡,居然真的把一堆零零碎碎的东西串起来干活了。
偶尔还会有爆音,WiFi信号不好时也会卡,但已经不影响日常用了,回头想想,当时要是买个成品无线音频接收器也就几十块钱的事,但自己从零搭出来的东西,每次听它出声都会忍不住笑一下,可能这就是瞎折腾的乐趣吧。


