ETH-68:面向 Linux 的以太网音频接口
eth68 是一款面向 Linux 的以太网音频接口。
- 超低延迟:在 48 kHz 采样率、64 样本缓冲下,往返延迟仅为 3.620 毫秒
- 可扩展:可同步多台设备以增加通道数量,而无需增加音频往返延迟
- 6 路 1/4 英寸 TRS 接口的平衡线路电平输入
- 8 路 1/4 英寸 TRS 接口的平衡线路电平输出
- 支持 48 kHz 和 96 kHz 采样率
- 采用 Burr-Brown PCM3168A 编解码器
- 支持 DIN MIDI 连接
- 1U 19 英寸机架式机箱
与 JACK 配合使用
eth68 在 STM32H7 微控制器上运行定制的裸机固件,用于模拟 netJACK 主端点。要与 eth68 交换音频数据,请使用 netone 后端启动 JACK 服务器:
jackd -d netone
当收到 eth68 发送的第一个采集数据包时,JACK 将创建映射到物理 eth68 IO 的 IO 端口:
启动支持 JACK 的应用程序并将其连接到 eth68 的 IO:
与 PipeWire 配合使用
也可以使用 pw-eth68 客户端直接接入
PipeWire 会话。该 PipeWire 客户端实现了与使用 netone 后端的 JACK 服务器相似的行为。启动支持 PipeWire 的应用程序并将其连接到 eth68 的 IO:
音频延迟
音频延迟是音频信号在遍历音频硬件和软件层时产生的可感知延迟。这种延迟来源于硬件和软件中的缓冲机制,以及音频编解码器中数字滤波器的群延迟。可以通过环回线测量往返音频延迟。在音频延迟较大的系统中,按下 MIDI 键盘按键到从软件合成器听到声音之间会存在明显的延迟。多项实验确定的延迟感知阈值在 5 到 20 ms 之间,具体取决于聆听环境。
在 48 kHz 采样率、64 样本缓冲大小的设置下,eth68 的往返音频延迟为 3.620 毫秒,该数据是通过 jack_delay 工具和环回线测量得到的:
下表汇总了 eth68 在 48 和 96 kHz 采样率下不同缓冲大小的往返延迟测量结果1 2(使用 jack_delay):
jackd 获得的,命令为 jackd -S -d netone。
[2] 如果改用 PipeWire 客户端
pw-eth68,测得的往返延迟(使用 pw-jack jack_delay)与此处完全一致。
| 32 | 64 | 96 | 128 | 256 | |
| 48 kHz | 2.288 ms | 3.620 ms | 4.954 ms | 6.287 ms | 11.621 ms |
| 96 kHz | 1.148 ms | 1.814 ms | 2.480 ms | 3.147 ms | 5.814 ms |
与 RME HDSPe AIO Pro PCIe 声卡对比3:
[3] 测量数据来源于 此处
| 32 | 64 | 96 | 128 | 256 | |
| 48 kHz | -.--- -- | 3.62 ms | -.--- -- | 6.28 ms | 11.62 ms |
| 96 kHz | -.--- -- | 2.14 ms | -.--- -- | 3.48 ms | 6.14 ms |
eth68 在 48 kHz 下的延迟表现与 RME 声卡相当,在 96 kHz 下甚至比它还低 0.33 ms。
多设备同步
可以将多台 eth68 同步工作以增加通道数。同步方式如下:
- 共享高频(HF)时钟。其中一台 eth68 作为时钟主机,产生的高频时钟通过 BNC 线缆以菊花链方式连接到其他 eth68 设备。共享高频时钟可以消除设备间的采样漂移。
-
通过
eth68ctl.py发送 UDP 广播同步命令,消除设备间的采样偏移。所有设备会在约 1 个采样周期内(48 kHz 下为 20.8 微秒)收到同步广播消息,并立即重启各自的 DMA 传输。这样设备间的采样偏移就被控制在 -1、0 或 +1 个采样之间。
由于 netjack 本身并不支持在多个主机之间合并/拆分数据,通过 JACK 接口进行多设备运行需要借助一个中间代理程序 eth68proxy。eth68proxy 负责把多台 eth68 的采集包合并成一个更大的 netjack 兼容采集包,同时也把 netjack 传来的大播放包拆分成小包,分发给每台 eth68 设备。
在两台已同步的 eth684 上运行 eth68proxy 后,netjack 会自动检测到翻倍的通道数并创建相应的 JACK 端口:
下面的示波器截图展示了两台已同步设备各自的输出,两路信号都来自 Reaper 中同一个锯齿波振荡器:
上图中,示波器以锯齿波的下降沿触发,绿色波形为便于观察上移了 20 毫伏。两条波形对齐误差小于 1 微秒,即 48 kHz 下 1/20 个采样。
当使用多台同步的 eth68 时,往返音频延迟与单台 eth68 相同。我们将第一台设备的输出回环到第二台同步设备的输入,并运行 jack_delay 进行了验证。通过 eth68proxy 的额外跳转会给处理延迟带来微小开销,但在我的系统上这一开销尚不显著,不会造成可测量的 xrun(欠载/过载)频率增加。
使用 PipeWire 接口时,pw-eth68 负责管理来自/去往多台 eth68 的数据流,因此无需 eth68proxy。
处理延迟
处理延迟是指完成一块音频缓冲区全部处理所需的时间。处理延迟必须小于截止时间,否则会发生 xrun(欠载或过载),导致可听见的音频瑕疵。在没有 xrun 的情况下,处理延迟是不可听见的。可以通过多种方式降低和控制处理延迟,例如:优化宿主操作系统的响应性、使用性能更高的宿主机电脑等。
eth68 生成一个 3.3 V 的数字信号 LATMON,用于测量和调试处理延迟。该信号可从后面板的 BNC 接口获取。示波器上的显示如下:
一旦采集 DMA 缓冲区中有可用数据,LATMON 立即跳高。当 eth68 完成将接收到的播放数据拷贝到播放 DMA 缓冲区后,LATMON 跳低。因此,LATMON 的脉宽能准确衡量每个周期的总处理延迟,并受数据路径中所有环节的影响:微控制器的处理延迟、网络传输延迟、宿主 OS 延迟、DAW 中的信号处理延迟等。
对 LATMON 脉宽进行实时直方图统计,可以直观感受处理延迟及其相关抖动:
上图中的垂直虚线位于 1333 微秒处,即 48 kHz 下 64 个采样缓冲区的截止时间。若脉冲宽度落在虚线上或其右侧,就会导致 xrun 错误。典型周期的处理延迟约为 625 微秒,因此距离截止时间还有 708 微秒的余量(超过 50%)。上述数据是在 Bitwig 运行中等 DSP 负载的项目时捕获的。
我们可以通过运行stress -c 6 启动一些高负载任务来人为恶化延迟性能。这会使主机系统响应变慢,因为其忙于繁重的任务,从而将 LATMON 脉冲宽度分布推向截止时间附近:
网络配置
eth68 默认将捕获数据包发送到 12.12.12.10:3000。最简单的入门方式是直接设置主机 IP 为 12.12.12.10,然后运行 jackd -d netone。对于其他配置,
可以使用 eth68ctl.py 脚本调整 eth68 的网络设置。
使用 eth68ctl.py 查询 eth68 设置:
python eth68ctl.py 12.12.12.10 query
输出结果:
--------------------------
header: 2820800604
board_id: 3407900
source_ip: 12.12.12.100 (202116196)
netmask_ip: 255.255.255.0 (4294967040)
gateway_ip: 12.12.12.1 (202116097)
destination_ip: 12.12.12.10 (202116106)
destination_port: 3000
mode: 0
period_size: 64
sample_rate: 48000
capture_channels: 6
playback_channels: 8
footer: 2603798065
从输出可以看到,eth68 的 IP 地址是 12.12.12.100, 它将捕获数据包发送到 12.12.12.10:3000。
ethc68ctl.py 的第一个参数是主机在与 eth68 共享局域网连接的网络接口上的 IP。eth68ctl.py 使用此接口上的广播 UDP 来控制 eth68。使用广播 UDP 可确保即使网络配置错误,通信也始终可行。
可以使用 "set" 子命令修改设置。例如, 将目标 IP 更改为 12.12.12.50:
python eth68ctl.py 12.12.12.10 --board_id 3407900 set destination_ip 12.12.12.50
eth68ctl.py 也可用于修改采样率等非网络相关的设置:
python eth68ctl.py 12.12.12.10 --board_id 3407900 set sample_rate 96000
网络硬件
建议为 eth68 使用一个独立、与外部流量隔离的专用局域网。普通网络设备就能获得很好的效果,无需支持 AVB/TSN 的以太网硬件。多设备组网时推荐使用 1G 以太网交换机。eth68 以 100M 全双工模式连接,但主机与交换机之间使用 1G 全双工链路可以降低处理延迟。如果只用单个 eth68,可以不经交换机直接连接主机的网卡。
效果在很大程度上取决于主机的网卡。Intel I210 网卡表现出色,2026 年 PCIe 版价格在 15-30 美元。选择网卡的一个关键因素是其中断行为可以调整。网卡通常会实现某种形式的中断合并(interrupt coalescing),这可能与实时应用不兼容。Intel I210 似乎采用了较为合理的默认中断合并策略,因为使用默认设置时 eth68 的音频就很流畅。不过,通过延迟调试监视工具发现,用以下命令修改中断合并超时后,处理延迟可以降低整整 175 us(占截止时间的 13%):
ethtool -C enp9s0 rx-usecs 0
音频测量
我使用 Stanford Research DS360 超低失真函数发生器测量了(差分)输入的 THD+N 性能:
按照 AES17 标准,对 -1 dBFS 峰值输入信号施加陡峭的 20 kHz 低通滤波器,并在基频处施加 Q = 5 的陷波滤波器进行数字滤波。PCM3168A 数据手册标称在 48 kHz 采样率下 1 kHz 的 THD+N 典型值为 -93 dB。我在 1 kHz 实测的 THD+N 为 -94.8 dBFS(0.0018%)。
注意,10 kHz 附近 THD+N 的突然改善,是因为二次谐波落入了 20 kHz 低通滤波器的阻带。
可惜手头缺乏足够灵敏的测试仪器来测量输出的 THD+N(总谐波失真加噪声)。作为替代,我使用 eth68 的输入端,在回环配置下分析 eth68 的输出性能。由于输入端的 THD+N 会贡献给回环路径的 THD+N,这项测量实际上给出了输出性能的下限。
尽管如此,回环 THD+N 与使用 DS360 测得的输入 THD+N 相比,差距仅在 0.5 至 1 dBFS 以内。
保持回环连接,我进行了一次更精细的频率扫描,以检查通带平坦度:
输入加输出的总通带平坦度为 +/- 0.15 dBFS。
关闭信号发生器,在 20 kHz 带宽内使用 A 计权滤波器测量噪声水平,结果如下:
- 仅输入,输入端接地:48 kHz 时为 -107.8 dBFS,96 kHz 时为 -110.5 dBFS(A 计权)。
- 输入 + 输出(回环):48 kHz 时为 -106.2 dBFS,96 kHz 时为 -108.6 dBFS(A 计权)。
相对于 -3 dBFS RMS 满幅正弦波计算比值,动态范围为:
- 仅输入,输入端接地:48 kHz 时 DR = -104.8 dBFS,96 kHz 时 DR = -107.5 dBFS(A 计权)。
- 输入 + 输出(回环):48 kHz 时 DR = -103.2 dBFS,96 kHz 时 DR = -105.6 dBFS(A 计权)。
macOS 和 Windows
我主要关注 Linux 的兼容性,但 JACK 具有跨平台特性,eth68 能成功被 macOS 和 Windows 上的 JACK 服务器识别。遗憾的是,macOS 和 Windows 上的大多数音频应用并不支持 JACK;macOS 上的 Ableton Live 甚至不知道如何与 JACK 服务器通信。即使某些应用在 Linux 上支持 JACK,在其他操作系统上也不一定能用;例如 Reaper 在 Linux 上支持 JACK,但在 macOS 上不支持。JACK 项目旨在通过捆绑一个名为 "JACK-Router" 的虚拟驱动程序来解决这一问题,该驱动桥接了原生音频驱动接口(macOS 上的 CoreAudio,Windows 上的 ASIO)与 JACK 会话。
JACK-Router 目前的状况:
- JACK-Router 目前在 Windows 上可用,详情请见 此处。 该页面还列出了 Windows 平台上支持 JACK 的应用程序。
- 由于 macOS 10.15 的更新引入了变更,JACK-Router 在 macOS 上目前处于损坏状态。详情请见 此处。
工作台
用于回环测试的 eth68 修订版 B PCB 工作台照片:
宿主系统
- 操作系统:Ubuntu 24.04.3 LTS
- 内核:6.19.10-2-liquorix-amd64
- 处理器:AMD Ryzen 7 5700X
- 主板:ASUS B450-F
- 交换机:TP-LINK TL-SG608
- 网卡:Intel I210