Linux 上 Apple AirPods 3 头部追踪跑通

AirPods 3 已经在 Linux 上完成配对并连接,MousePods 却报告“设备缺席”,设备公告里也看不到 devmotion6、gyro 和 accel。此时先检查主机的 L2CAP 接收 MTU,而不是先改鼠标灵敏度或校准参数。

按 MousePods 项目的公开发现,测试环境默认接收 MTU 为 672 字节,设备公告中只有三项服务,运动传感器缺席;改为 2582 字节后,公告才增加 devmotion6、gyro、accel。直接原因之一是 devmotion6 的单条公告就有 833 字节,已经超过 672 字节的接收空间。 但 2582 是该项目测试环境中的有效值,不是所有 Linux、BlueZ 和耳机固件都必须采用的通用最小值。

项目仓库是 github.com/starman-tech/mousepods,其中包含源码、协议文档、十六进制抓包文件和本地控制界面。运行前提包括 Linux、BlueZ、已经配对并连接的 AirPods,以及当前用户对 /dev/uinput 的写权限;项目同时支持 Wayland 和 X11。 安装、启动以及 MTU 设置应以仓库当前 README 为准,现有资料没有提供可以跨发行版复用的完整命令和真实终端输出,因此不应把其他蓝牙教程里的 bluetoothctl、btmgmt 或 sysctl 命令拼成一套通用方案。

Apple 官方所说的头部追踪,是空间音频的一部分,用来配合设备营造沉浸式声音效果;MousePods 的目标则是读取 AirPods 3 的运动数据,计算姿态,再生成 Linux 鼠标、指向或滚动事件。 它不是用摄像头做人脸关键点检测,也不会把 Apple 的空间音频链路搬到 Linux 上。

故障可按以下层级定位:

症状 所在层级 优先检查
蓝牙显示已连接,但看不到 devmotion6、gyro、accel 设备公告 实际生效的 L2CAP 主机接收 MTU;对照 672 与 2582 字节
能发现设备,但启动后没有有效回复 协议握手 AirPods 3 的 RemoteHID、AACP RTBuddy 0x800 通道
已建立连接,却收不到 InputReport 报告配置 SetReport 是否发送,以及报告间隔是否设置成功
InputReport 已到达,但光标完全不动 输入输出 /dev/uinput 权限、姿态计算、控制模式和虚拟鼠标事件
鼠标模式可用,但指向位置不准 校准 指向模式的角点校准
转动方向相反或持续抖动 运动计算 坐标轴、陀螺仪偏置和校准状态

先确认主机接收 MTU,再确认运动服务是否出现在公告中,最后才进入传感器解码,这个顺序能避免把“服务不可见”误判为“姿态算法失效”。

这里说的 MTU 是 L2CAP 连接上的主机接收 MTU,也就是主机接收数据单元时允许使用的尺寸上限,不是 AirPods 一侧的发送参数。蓝牙连接成功只说明耳机和主机建立了连接,并不代表主机已经接收并解析了完整的运动服务公告。

如果当前公告仍然只有那三项服务,应先确认实际生效的接收 MTU,而不是只看配置文件里希望设置的数值。调整连接参数后,也要重新取得设备公告;若设置只对新建连接生效,还需要按项目文档重新建立相应连接。

MTU 的协商结果还可能受到 BlueZ 版本、适配器、连接建立方式和耳机固件影响。更换系统或蓝牙栈以后,正确做法仍是重新检查实际值和公告内容,而不是继续沿用另一台机器上的结论。

即使调大 MTU 后仍找不到运动服务,也不能据此判断 AirPods 3 的传感器一定坏了。此时需要把三个状态分开:蓝牙连接是否建立、运动服务是否进入设备公告、传感器是否持续产生报告。第一个状态正常,只能说明链路建立;第二个状态正常,才说明主机看得见 devmotion6 等服务;第三个状态正常,才轮到检查 InputReport 和姿态数据。

Claude Code 在这个项目中负责代码编写、资料检索和协议探索,作者负责操作耳机、进行硬件测试并判断方案是否成立。项目材料称整体研发耗时约一下午,但 README 同时记录了约 300 次失败尝试。 这两个数字放在一起看,更接近真实研发过程:模型可以缩短搜索和编码时间,最终决定协议分支是否成立的仍然是实机反馈,而不是一次对话里的推测。

AirPods 3 的运动传感器表现为虚拟 HID 设备,通信承载在 AACP 协议的 RTBuddy 0x800 通道。AirPods Pro 2 等设备使用 SensorDataWX,把相同启动方式直接套到 AirPods 3 上会缺少有效回复。 所以排查握手问题时,不能只确认“耳机连上了”,还要确认程序走的是 AirPods 3 对应的 RemoteHID 路径。

正常握手顺序是:

HostConnect → DeviceConnect → SetReport → InputReport

主机先发送 HostConnect,AirPods 返回包含设备信息的 DeviceConnect 公告;随后主机发送 SetReport 配置报告间隔,耳机才开始输出 InputReport。

这几个阶段应当分别判断。没有 DeviceConnect,先回到 MTU 和设备公告;能看到公告却没有有效回复,重点检查 RemoteHID、AACP 通道以及是否误用了其他型号的运动数据协议;连接已经建立却没有 InputReport,再检查 SetReport 和报告间隔设置;只有 InputReport 已经到达且数据格式合理,才进入姿态计算与鼠标事件这一段。

MousePods 仓库还提供了两份十六进制抓包,可以用来静态解码并核对文档中描述的协议结构。项目资料的核对结果显示,抓包内容与文档描述相符,但这种验证只能说明文件里的数据与协议说明能够对应,不能代替真实 AirPods 3 在当前 Linux 环境中的行为验证。 静态抓包正常而实机失败时,仍应回到公告、握手和输入输出三个阶段逐段检查。

收到 InputReport 后,程序还要解码运动数据块,提取旋转速度、重力和姿态信息。运动计算层负责坐标轴处理、校准与陀螺仪偏置,控制层再把结果转换成鼠标事件,最后由 /dev/uinput 创建并写入虚拟输入设备。 因此“已经收到运动数据”和“桌面上光标会动”之间仍有三段独立链路。

如果连虚拟输入设备都无法创建,应先查当前用户对 /dev/uinput 的访问权限,以及系统是否加载并开放了对应的 uinput 接口。不要通过长期放宽权限来掩盖权限错误;持久权限策略应按当前系统和项目文档配置。

如果虚拟设备存在、光标也有事件,但方向相反、漂移或抖动,应检查坐标轴映射、初始校准和陀螺仪偏置。鼠标模式与指向模式的判断也不同:鼠标模式把耳机转动转换为光标运动,指向模式依赖角点校准;鼠标模式看起来正常而指向位置不准时,不应先改鼠标速度,而应重新完成指向模式的角点校准。

项目共提供三种控制模式,其中还包含与耳机桌面位移相关的滚动映射。 现有资料没有完整给出这一模式的阈值和换算细节,因此这里不补写具体参数,实际定义应以仓库当前 README 和本地控制界面为准。无论选择哪种模式,如果 Wayland 与 X11 两个桌面会话中的表现不同,应分别在当前会话里验证,不能把某一桌面的输入行为直接推广到所有 Linux 环境。

最终验收要逐段检查,而不是只看某一个“connected”状态:设备公告中出现运动服务,握手后收到 InputReport,解码层得到旋转速度、重力和姿态,控制层生成鼠标事件,再由 /dev/uinput 写入,最后确认当前桌面中的光标确实响应。真实 AirPods 3、其他 Linux 环境、不同蓝牙栈和不同固件仍需要用实机复测。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容