返回发布列表
macOS + Android 工具 · USBLINKMIC

USBLinkMic,让 Android 手机变成 Mac 的麦克风和网卡

USBLinkMic 把 Android 手机麦克风和网络接到 Mac。这里记录它怎么把 ADB 流程收进图形应用,以及一次 DHCP 时序问题的排查过程。

有次线上开会,我发现 MacBook 自带麦克风在空一点的房间里容易录出回声,手边 Android 手机的麦克风反而更合适。

当时能用的方案不少,但通常要先装 Homebrew、Android SDK,把 adb 加进 PATH,再手动跑 adb reverse,最后还要自己配置音频路由。这些步骤我能照着做,但如果想把工具交给别人用,它们就成了额外门槛。

我开始做 USBLinkMic 时,想解决的就不只是传音频,而是把这些步骤收进一个图形应用里,让人先看到能做什么,再按界面一步步连起来。

USBLinkMic Mac 端主界面
Mac 端主界面把三条功能链路和音频状态放在一起。

1. 先把范围定下来

目前项目里有三条彼此独立的链路。

  • 手机麦克风 → Mac,通过 ADB 或局域网把 Android 麦克风音频送到 Mac,并输出到选定的 Mac 输出设备。
  • 手机网络 → Mac,通过 ADB 启动 USB CDC-NCM,把手机的移动网络共享给 Mac。
  • Mac 网络 → 手机,通过 ADB 反向中继加 Android VPN Service,把 Mac 的网络反向共享回手机。

第三条在 3.1.0 版本接入了 gnirehtet v2.5.1 的 Rust relay,手机端不需要再单独安装一款工具。

功能清单列出来不算太难,真正花时间的是怎么把它们做成别人也能走完的流程。

2. 把依赖收进 DMG

早期版本有个绕不开的门槛,adb 要从哪里来。它不随 macOS 提供,用户得自己安装 Homebrew 或 Android SDK。对熟悉命令行的人来说只是多一步,对其他人来说,这一步就足够劝退。

3.2.0 把独立的 Universal 架构 adb(37.0.1)和 Android APK 一起打进 Mac 端,再用首次使用向导带人检测连接、确认调试授权、安装手机端 App、选用途预设,最后做声音测试。装好 DMG 后,不必再单独装 Homebrew、Android SDK,也不用手动敲这些命令。

我还把几个容易出问题的地方放进界面里。

  • 音频路由和防啸叫提示,画出手机到会议软件的连接路径,说明 BlackHole 2ch 怎么安装,也提醒哪些设置可能产生啸叫。
  • 日志脱敏,复制日志时会抹掉设备序列号、敏感 IP 和主机用户名,方便排查时少暴露设备信息。
  • 设置草稿保护,标出哪些修改立即生效,哪些需要重启,并允许放弃还没保存的内容。

3. DHCP 为什么没赶上

有个问题我想把排查过程记下来。Android 已经通过 start-ethernet 回调报告启动成功,tethered 接口里也能看到 usb0,但 Mac 端还是报 USB 网卡没有拿到 IP。

这两个信号很关键,手机侧的 Tethering 已经起来了,出错的是 Mac 读取网络接口的时机。如果把注意力一直放在手机有没有启动上,就会往错误的方向查。

我沿着调用链往回找,最后看到的流程是这样。

startNcmTethering  (AppModel.swift:469)
  └─ 判断 network.ip != "-" → 为 false 则失败
       └─ network.ip 由 refreshNetworkWithRetry 更新
            └─ 3 轮 × 2s = 6s,每轮调用 networksetup -getinfo

当时的等待窗口只有 6 秒,每轮只读一次 IP,没有重新触发 detectnewhardware 或启用网络服务。DHCP 要是晚一点完成,App 就已经报错了。

我用实验脚本把等待改成 25 秒,并在每轮重新触发检测和 enable,问题就消失了。

修复前:3 × 2s,每轮只读 IP
修复后:25s 轮询,每轮重新触发 detectnewhardware + enable

后来我给这条链路补了诊断信息,也给清理流程加了超时限制。退出 App 时,ADB reverse、VPN 和网络配置都要按上限收尾,不能因为清理卡住就一直挂在那里。

这次排查让我记住一件很具体的事,跨设备的「启动成功」只说明对端接到了请求,不等于 Mac 上的状态已经准备好。中间那段等待,也得认真处理。

4. 我把 AI Agent 放在什么位置

这个项目同时碰到 macOS、Android、音频和系统网络配置。我用 AI Agent 做审查和查漏,尤其适合先把调用链整理清楚。

上面的 DHCP 问题,我让 Agent 只读检查「Android Tethering 成功之后,Mac 怎么拿到 IP」这一段。它给了带文件名、方法名和行号的调用链,包括 AppModel.swift:469 的判断、AppModel.swift:677 的 refreshNetworkWithRetry,以及 AppModel.swift:703 对 networksetup -getinfo 的调用。我当时要求它不要改代码,先把因果关系摆出来,确认方向后再决定修哪里。

它也帮我做横向检查。项目里留下了能耗、构建配置、代码质量,以及 Android Shell 和 Mac 端能力对齐的审查记录。涉及两端时,我自己很容易只盯着手上的那一侧;让 Agent 按清单扫一遍,能提醒我去看另一端。

不过审查报告和建议都得验证。3.1.0 的整数 PCM 波形问题,是结合实际波形观察和性能追踪确认的,不是因为读了几行代码就算修好。

Agent 对 ADB、Android 版本和 macOS 网络行为也可能说错。我遇到过不适用于当时系统版本的 networksetup 用法,最后还是本机测试和系统返回值更可靠。Agent 能帮我缩小排查范围,不能替我给结论盖章。

5. 成品与代码

  • macOS 原生应用 + Android 客户端,DMG / APK 双产物
  • 内建 adb 与 APK,零配置启动
  • 三条网络/音频链路,麦克风上行、USB NCM 共享、Mac 网络反向共享
  • 实时电平表、音频路由可视化、脱敏日志导出
  • 单元测试、音频性能追踪、双端诊断信息

USBLinkMic 源码在 GitHub。


做完以后,时间主要花在安装、连接、状态提示和出错后的清理上。把这些环节接起来,用户才不用碰终端。对我来说,这些收尾比再加一个功能更能说明项目有没有做完整。

留下你的回应

提交后等待审核

正在加载回应…