作为一名重度依赖米家生态的打工人,在房间配置一个支持红外的中枢网关是刚需。出于生态融合和性价比的考量,我购入了小米智能音箱 Pro 作为终端输出设备。但如果只把它当作智能家居中枢,其音响硬件未免有些性能过剩。由于这款音箱原生并不支持我重度依赖的 AirPlay,为了满足高品质流媒体音频的播放需求,就有了这次的硬核改造计划。
经过一番硬件选型和底层折腾,我最终用闲置的 Cudy TR3000 (MT7981) 路由器,通过 OpenWrt / ImmortalWrt 成功实现了一套零成本、低延迟的 AirPlay 2 接收端。这篇文章记录了整个架构的选型思考、以及在 Linux ALSA 音频层和网络组播层踩过的各种深坑。

一、 动机:为什么非得是 AirPlay?
很多人会问,直接连蓝牙不香吗?在深度使用后,蓝牙音频的体验缺陷非常明显:
- 通知音混流的灾难:蓝牙本质上是系统全局音频输出。当你正在享受沉浸式音乐时,手机突然来一条微信提示音,或者你在刷 TikTok / Reels,声音会直接粗暴地打断音乐并从音箱外放,体验极差。
- 设备切换繁琐:在 MacBook、iPhone、iPad 之间切换蓝牙音箱的配对,永远是一个不够优雅的痛点。
- 音频压缩:常规蓝牙协议(SBC/AAC)在重采样过程中有不可忽视的音质损耗。
AirPlay 的优势在于它是基于网络层的流媒体投射协议(TCP/UDP)。它能做到媒体流与系统通知音彻底分离(音乐在音箱放,微信提示音只在手机响),且只要设备在同一个局域网(mDNS 发现),任何 Apple 设备都可以做到一键无缝切换投流,同时原生支持 ALAC 无损传输。
二、 硬件选型:为什么是小米智能音箱 Pro?
市面上有大把的无源/有源音箱,但我最终选择用这台小米音箱作为物理输出终端,主要基于以下作为“Smart Home Hub”的考量:
- 原生支持 USB-C 数字音频输入:这是折腾 Linux USB Audio (UAC) 的物理前提。
- 米家全家桶中枢:内置了蓝牙 Mesh 网关,方便接入家里的各类温湿度计和智能开关。
- 红外遥控核心:自带红外发射模块,可以直接把房间里老旧的非智能空调接入米家进行控制。
它是一个完美的智能家居 Node,唯一的缺点就是原生不支持 AirPlay。我们需要一个“外挂大脑”来帮它接收并解码 AirPlay 音频流。
三、 方案调研:外挂大脑怎么选?
在选型初期,我原本打算采用社区非常经典的 AirConnect 方案。其原理是在局域网中发现 DLNA 音箱,然后将其封装并广播为一个 AirPlay 设备。但我买来后才发现,新款的小米智能音箱已经彻底阉割了 DLNA 协议。此路不通,直接接收 AirPlay 协议并通过 USB Audio 数字输出给音箱,成了唯一的突围路径。
为了实现这个目标,我考察了目前主流的几种廉价硬件方案:
- 旧 Android 手机 + AeroPlay App:
- 优点:零门槛,App 生态成熟(部分支持 UAPP 绕过安卓 SRC)。
- 缺点:长期插电作为 Server 运行,电池有严重的鼓包/起火风险;即使 Root 后锁电也显得不够优雅。
- Raspberry Pi Zero 2 W + Shairport Sync:
- 优点:Linux 音频圈的“标准答案”,文档极多。
- 缺点:需要额外购买,且目前供应链有时不稳定,增加了系统冗余。
- ESP32-S3 DIY 魔改:
- 优点:极客最爱,成本极低,S3 原生支持 USB Host。
- 缺点:过于硬核。社区的 AirPlay 接收库大多只支持 AirPlay 1,且利用 TinyUSB 驱动特定 USB-C 音箱的 UAC 兼容性极差,需要大量底层的 C 语言 Debug。
- 闲置 OpenWrt 路由器(最终胜出):
- 硬件:手头闲置的 Cudy TR3000(搭载 MT7981 神 U,性能严重过剩)。
- 优势:原本就要插电运行,多跑一个后台 daemon 毫无压力;Linux (ImmortalWrt) 系统自带完整的 ALSA 架构和 USB 驱动,网络处理能力吊打 ESP32。
四、 踩坑实录:ImmortalWrt 的音频打通之旅
本以为在路由器上 make menuconfig 勾选几个包就能搞定,没想到一路遭遇了从底层驱动到网络架构的连环坑。
坑一:包名与依赖的“幻觉”
在编译 ImmortalWrt 时,寻找 USB 音频驱动耗费了一些时间。
- 误区:以为 USB 设备的驱动都在
Kernel modules > USB Support下。 - 正解:UAC 驱动实际上归属于
Sound Support。必须勾选kmod-usb-audio(核心驱动)和kmod-usb3(MT7981 的 DWC3 控制器)。服务端则直接选用shairport-sync-openssl,并搭配alsa-utils用于排障。
开源产物:整个项目的源码及编译配置已开源至我的 GitHub:
t0saki/openwrt-personal。如果你刚好也持有 Cudy TR3000 (v1),可以直接下载我编译好的 AirPlay 2 专版 Release 固件 免去编译折腾。
坑二:进程 Crash,TCP 7000 端口冲突
固件刷入,硬件通过 aplay -l 完美识别。但手动拉起 shairport-sync 时直接 Panic 退出。
- Debug:通过
shairport-sync -vvv抓取日志,发现unable to listen on IPv4 port 7000. The error is: "Address in use". - Root Cause:AirPlay 2 强依赖 TCP 7000 端口进行 RTSP 握手。而我路由器上跑的
frps(内网穿透服务端)默认也监听了 7000 端口。 - Fix:修改
frps.ini绑定端口,让出 7000。
坑三:OpenWrt 的 UID/GID 幽灵 Bug (Avahi Daemon Crash)
端口让出后,iPhone 依然搜不到设备。查日志发现 shairport-sync 找不到 mDNS backend,而底层的 avahi-daemon 在疯狂 Crash Loop。
- Root Cause:ImmortalWrt 引入
apk包管理器后,部分包的postinst脚本存在 Bug,系统安装dbus和avahi时没有自动创建对应的系统用户和用户组。出于安全机制,这两个 daemon 拒绝以 Root 身份启动,直接挂掉。 - Fix:直接写入
/etc/passwd和/etc/group,手动注入用户并赋予 socket 权限:echo "dbus:x:81:" >> /etc/group echo "dbus:x:81:81:dbus:/var/run/dbus:/bin/false" >> /etc/passwd echo "avahi:x:84:" >> /etc/group echo "avahi:x:84:84:avahi:/var/run/avahi-daemon:/bin/false" >> /etc/passwd
坑四:有进度条没声音,ALSA 的直通与重采样悖论
手机终于搜到了设备并成功连接,进度条在走,但音箱死活没声音。
- Root Cause:最开始我在
/etc/shairport-sync.conf中指定输出设备为hw:0,0。在 ALSA 架构中,hw意味着 Bit-perfect 直通。AirPlay 丢过来的是严格的 44.1kHz / 16-bit 音频流,而小米音箱内置的廉价 DAC 接口物理上只接受 48kHz 的输入。底层握手失败,音频帧被静默丢弃。 - Fix:将设备从
hw:0,0改为plughw:0,0。plughw插件会自动接管重采样(Sample Rate Conversion),将 44.1kHz 动态转换为 DAC 兼容的 48kHz。重启服务,声音终于响起!
坑五:L3 NAT 导致的 mDNS 与组播黑洞
我在 TR3000 自己的子网下测试一切完美,但在主路由(父网)下,设备再次“失联”,或者点击后一直转圈。
- Root Cause:TR3000 是作为 Wireless Client 接入主路由的,存在 NAT 隔离。
- mDNS 无法跨网段:默认配置下,父网拿不到 TR3000 的
_raop._tcp广播。 - PTP 时钟同步失败:AirPlay 2 强制依赖 UDP 319/320 端口和
224.0.1.129组播地址进行时钟同步。防火墙默认 Drop 了来自 WAN 区的组播包。
- mDNS 无法跨网段:默认配置下,父网拿不到 TR3000 的
- Fix:与其写一堆复杂的 Firewall Rules 和 Avahi Reflector 规则,不如直接从网络架构上降维打击。在 LuCI 中修改防火墙区域,将
wwan(上行接口) 划入lan的绿名单,实现 L3 扁平化(废弃 NAT)。修改 Avahi 仅向phy1-sta0广播。网络彻底打通,秒连秒播。
五、 总结
这套方案最终达到了我的全部预期:
- 0 额外硬件成本:完全榨干了闲置路由器的剩余价值。
- 极高的稳定性:MT7981 的算力和 Linux 的网络栈处理 AirPlay 2 的 Jitter Buffer 游刃有余。
- 完美的生态融合:音箱依然是米家/红外中心,但同时拥有了 Apple 原生的流媒体投射体验。
作为工程师,折腾过程中的乐趣往往大过结果。从内核驱动、ALSA 架构,再到网络层的 mDNS 与组播抓包,解决这一连串问题的获得感,是直接买一个 HomePod 无法替代的。如果你手头刚好也有吃灰的 OpenWrt 路由和支持 USB 音频的音箱,强烈建议尝试这个方案。
当然,如果你手里有树莓派之类的开发板,那么上述 OpenWrt 的很多特有深坑(如防火墙、NAT 隔离、包管理器 Bug)都能轻松避免,但在 ALSA 音频层和网络层的软件栈配置上,依然可以参考本文的踩坑经验。