【免费下载链接】sill
Any window from your Mac, live on your iPhone or iPad. Touch, Apple Pencil, trackpad and keys. Free, open source, no servers.
Sill 是一款免费、开源的 Mac 到 iPhone / iPad 串流工具,把 Mac 上的任意窗口或整个桌面实时投到你的移动设备上,支持触控、Apple Pencil、触控板和键盘操作,且全程无需自建服务器。它的音频功能(Send Audio)会把 Mac 上被串流应用的声音同步送到设备端播放——声音永远滞后画面一点点,但绝不会提前。本文带你拆解 Sill 音频管线背后的三个关键设计:AAC-ELD 128 kbps 编码、10 ms 音频分片,以及逐包漂移校正的音视频同步机制。
一、功能速览:Mac 的声音如何到达 iPad
在 Sill 的 Mac 端菜单或 设置 › Streaming 中打开Send Audio(Beta)后,Sill for Mac 会捕获当前串流应用(或整个桌面)的声音,编码后经本地网络发送到 iPhone / iPad 播放。它有两个重要特性(见 README.md):
- 声音跟随画面:设备端播放的声音"片刻滞后于画面,但绝不超过画面";
- 双端都有声:Mac 自己照常出声,每台设备可以用 Sound 按钮单独静音。
整条管线的蓝图写在设计文档 docs/audio-plan.md 中,Mac 端核心代码集中在 Sources/SillHost/,设备端播放模型在 iOSClient/AudioPlayout.swift。
二、为什么选择 AAC-ELD 128 kbps 编码
编码器的选择不是拍脑袋,而是用真实信号实测出来的。Sill 团队把一段 6 秒的忙碌信号(噪声叠加三个音调)分别送入 AudioToolbox 的各款编码器,测量"端到端延迟"(从突发信号进入编码器到离开解码器的时间):
| 编码器 | 每包帧数 | 端到端延迟(10 ms 分片) | 编码/解码 CPU(单核) |
|---|---|---|---|
| AAC-LC | 1024(21.3 ms) | 74.7 ms | 0.49% / 0.05% |
| AAC-LD | 512(10.7 ms) | 30.7 ms | 0.52% / 0.06% |
| AAC-ELD(480 帧) | 480(10.0 ms) | 15.0 ms | 0.52% / 0.07% |
| Opus(10 ms) | 480 | 16.5 ms | 0.95% / 0.32% |
AAC-ELD 胜出的理由很清晰(docs/audio-plan.md "Which codec: measured"):
- 延迟最低:AAC-LC 光固有延迟就有 65–75 ms,比画面整条链路还长;AAC-ELD 只有 15 ms 出头;
- CPU 更省:同样延迟下,编码 CPU 约为 Opus 的一半,解码只有其五分之一;
- 生态成熟:AirPlay 镜像传输的正是 AAC-ELD,是 Apple 自己的选择。
最终参数固定为:48 kHz、双声道、128 kbps,见 AudioEncoder.swift 中的三个常量。编码由 AudioToolbox 的AudioConverter完成,每块输入正好产出一个数据包。
三、10 ms 分片:把 PCM 切成 480 帧一包的节奏
声音捕获走的是一条独立的、只含音频的 SCStream(AudioCapture.swift 中capturesAudio = true,画面尺寸设为 2×2 每秒 1 帧后直接丢弃)。这样做的好处是:画面管线重启(旋转、缩放、切换编码器)时声音不受影响,声音失败也只影响声音本身。
捕获来的 PCM 块交给纯函数式的AudioPacketizer(AudioPacketizer.swift),它做三件事:
- 定包长:看第一个音频块的帧数——是 512 的整数倍就用 512 帧一包(10.7 ms),否则用 480 帧一包(正好10 ms)。能整除捕获块的分片方式端到端快 9–10 ms;
- 打时间戳:每个块的时间戳取自"该包解码后首个样本对应输入帧"的主机时钟时刻。由于编码器有 240/256 帧的固有延迟(priming),时间戳要往前补偿这段距离;
- 断段保护:音频块迟到或早到超过 1/4 块(约 2.5 ms),就判定捕获出了断口——旧段直接丢弃,不补齐、不填零,从这一块开始新的一段。因为"为过去的帧现在造一个包"只会让设备端误以为链路抖动,白白抬高缓冲。
编码后的每个包立刻转成 kind 43 消息发往网络(StreamMessage.swift),时间戳在发送瞬间由主机时钟换算成墙上时钟(AudioPipeline.swift),与视频帧的打戳方式完全一致。
四、不用时钟同步:一个"地板值"锚定两台设备
这里是最精巧的部分。两台设备的时钟会互相漂移(每秒差几十微秒级),传统做法要做 NTP 式时钟同步——Sill 完全没做。它的方案只需要一个稳定的参照物,而不是绝对时间:
地板值(floor)= 最近 10 秒内所有音频包
(到达时刻 − 时间戳)的最小值。
原理:网络延迟会波动,但"最快的那一路"近似稳定。一个时间戳为 T 的音频包,应在设备单调时钟的T + floor + delay时刻被听到(AudioPlayout.swift)。两个时钟慢慢漂移时,这个滑动最小值会自动跟着漂移走,声音永远被"锚"在画面旁边。
delay取两项的较大值:
- need:抖动覆盖(最近 10 秒内
到达 − 时间戳 − floor的最大值,在家 20–150 ms 区间,外出 60–600 ms)+ 一个包(10 ms)+ IO 缓冲 + 输出延迟 + 2 ms 余量; - 画面守卫:最近 2 秒视频帧的中位滞后 + 1.5 个刷新 + 4 ms,再多加一帧。这条规则保证了铁律——声音永远不会跑到画面前面。
五、逐包漂移校正:每秒 ±1 帧的"微调术"
时钟漂移不会一次到位,所以模型每秒比较一次"正在播放的样本应在哪"与"它实际在哪",然后每个数据包最多增删 1 帧(AudioPlayout.swift):
- 声音快了 → 在该包最安静的点复制一帧插入(取相邻均值,听不出痕迹);
- 声音慢了 →删掉一帧(保留与前一帧的均值);
- 幅度约 2 ms/秒,远大于时钟漂移速度(0.1 ms/秒),完全不可闻。
小误差用微调消化,大误差另走"跳变"通道:一旦误差超过 40 ms(链路停顿、路由切换),或声音即将越过画面,就立即丢包或插入静默完成对齐,并配 5 ms 淡入淡出(iOSClient/AudioPlayout.swift 常量jumpOver = 0.040)。若连续一秒的包都悬在地板值上方 50 ms 以上(或新地板突然低 20 ms),则判定 Mac 时钟跳变,整个窗口重新开始统计。
其他细节同样讲究:最近 256 个(epoch, seq)去重、断点后整包丢弃再淡入、10 秒无声自动停掉音频引擎等,都写在这份纯 Foundation 模型里,可用模拟时钟单独跑测试(Tests/checks/audio-playout/)。
六、声音与画面共享同一条链路:音频优先
声音和视频走同一条 TCP 连接,但规则是"声音不让路,画面让路":
- 在家时,音频消息不计入画面的在途计数(
inflight),不会被丢帧规则误伤; - 外出(Remote Access)时,音频字节计入远程预算,拥塞发生时
paceRemote只丢视频帧、从不丢声音——链路扛不住时画面降帧等关键帧,声音继续保持约 16 KB/s 稳定流出; - 音频在独立队列编码、生成即发(AudioPipeline.swift),一帧画面也从不为声音等待。
设备端的诊断 HUD 上还能看到sound XX字样,表示声音当前滞后画面多少毫秒(DiagnosticsHUD.swift)。
七、如何开启并验证
- Mac 端:Sill 状态菜单或 设置 › Streaming 中打开Send audio(Beta);CLI 宿主可用
--audio启动参数; - 设备端:顶部工具栏出现 Sound 按钮,点击静音/恢复仅影响本设备,无需 Mac 确认;
- 观察同步效果:开一个有清晰鼓点的应用,用诊断 HUD 查看
sound滞后值——典型约 50 ms,符合"1–2 帧之后"的设计目标。
八、核心模块速查
- 设计文档:docs/audio-plan.md
- 捕获(音频专属 SCStream):Sources/SillHost/AudioCapture.swift
- 分片与打戳:Sources/SillHost/AudioPacketizer.swift
- AAC-ELD 编码器:Sources/SillHost/AudioEncoder.swift
- 管线编排:Sources/SillHost/AudioPipeline.swift
- 线上协议(kind 43):Sources/StreamProtocol/Audio.swift
- 设备端同步模型:iOSClient/AudioPlayout.swift
- 纯逻辑测试:Tests/checks/audio-packetizer/、Tests/checks/audio-playout/
一句话总结:Sill 用"最小编码延迟 + 10 ms 定长分片 + 滑动地板值 + 逐包 ±1 帧微调"四步组合,在没有时钟同步的前提下把 Mac 的声音稳稳锚在画面之后——这正是开源项目少见的、以实测数据驱动的精密同步工程。
【免费下载链接】sill
Any window from your Mac, live on your iPhone or iPad. Touch, Apple Pencil, trackpad and keys. Free, open source, no servers.
相关推荐
OpenParsec音频管线深度剖析:C音频模块与AVAudioSession混音机制
OpenParsec音频管线深度剖析:C音频模块与AVAudioSession混音机制 OpenParsec 是一款开源的 iOS/iPadOS 端 Parse
Compressor音频处理深度剖析:AAC直通逻辑与24位PCM音量缩放器源码精讲
Compressor音频处理深度剖析:AAC直通逻辑与24位PCM音量缩放器源码精讲 Compressor 是一款开源、无广告、超轻量的 Android 原生视
Subtitle Edit 多点同步(Point Sync):用多个参考点校正非线性漂移的字幕同步指南
Subtitle Edit 多点同步(Point Sync):用多个参考点校正非线性漂移的字幕同步指南 导读 本文讲解 Subtitle Edit 的 Poin
桌面应用音视频OCR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考