Audio & Video 高级 20m
认识 Audio Workgroups
Meet Audio Workgroups
2020年6月25日
一句话判断
如果你在开发专业音频应用(DAW、音频处理器),Audio Workgroups 是你降低端到端延迟、提升多线程音频处理性能的关键新 API。
这场 Session 讲了什么
这场 Session 介绍了 macOS Big Sur 和 iOS 14 中全新的 Audio Workgroups 机制。在专业音频场景中,低延迟是核心需求——音乐人按下琴键到听到声音,延迟必须控制在几毫秒以内。传统做法是用单一的 Audio Unit 在实时音频线程中处理所有工作,但这对 CPU 的利用效率很低。
Audio Workgroups 允许开发者将多个 Audio Unit 组织成一个工作组,系统会以协调的方式调度这些 Audio Unit 的渲染。这意味着你可以将音频处理流水线拆分成多个阶段,每个阶段在不同的线程上执行,而系统保证整体渲染的时序一致性。演讲者用一个虚拟乐器插件的实际案例展示了从单个复杂 Audio Unit 拆分成多个轻量 Workgroup Member 的过程。
Session 还讨论了 Workgroup 与 Core Audio 底层调度器的交互方式,以及如何利用这个机制在不增加延迟的前提下充分利用多核 CPU。对于插件开发者来说,这意味着同一个插件在 8 核 Mac 上的性能可以接近线性提升。
值得深挖的点
- Workgroup 调度器的时序保证:普通的多线程音频处理最大的问题是无法保证线程间的同步——如果上游线程还没渲染完,下游线程就必须等待,导致 buffer underrun。Audio Workgroups 的调度器会追踪整个渲染图的数据依赖,确保所有渲染操作在音频硬件需要数据之前完成。
- 从 AUv2 到 AUv3 的迁移考量:Audio Workgroups 主要在 AUv3(App Extension 模型)中工作。如果你还在用 AUv2(传统 Component Manager 模型),迁移到 AUv3 不仅能获得 Workgroup 支持,还能获得更好的进程隔离和稳定性。
代码片段
// 创建 Audio Workgroup 并添加成员
import AVFoundation
// 获取当前 Audio Unit 的 Workgroup
func createRenderContext() -> AUAudioUnit {
let audioUnit = MyCustomAudioUnit(
componentDescription: AudioComponentDescription(
componentType: kAudioUnitType_MusicDevice,
componentSubType: 0x736e7468 // 'snth'
)
)
// 在渲染回调中使用 Workgroup 信息
audioUnit.renderBlock = { [weak self] actionFlags, timestamp, frameCount, outputData in
guard let self = self else { return noErr }
// 在 Workgroup 上下文中执行渲染
return self.render(frames: frameCount, to: outputData)
}
return audioUnit
}
// Audio Unit Extension 中的 Workgroup 实现
class WorkgroupManagedAudioUnit: AUAudioUnit {
private var workgroup: AUScheduleWorkgroup?
override func allocateRenderResources() throws {
try super.allocateRenderResources()
// 创建 Workgroup 用于非实时音频任务
workgroup = AUScheduleWorkgroup(name: "AudioProcessing")
}
func scheduleProcessing(
block: @escaping () -> Void
) {
// 在 Workgroup 线程池中调度非实时任务
workgroup?.schedule(block)
}
}
// C API 层面的 Workgroup 使用(适用于基于 C 的音频插件)
#include <AudioToolbox/AudioWorkgroup.h>
void setupWorkgroup(AudioUnit au) {
AudioWorkgroupRef workgroup;
OSStatus status = AudioWorkgroupCreate(&workgroup);
// 将渲染线程加入 Workgroup
AudioWorkgroupAddMember(workgroup, pthread_self());
// 在渲染循环中协调多线程
AudioWorkgroupStart(workgroup);
// ... 执行渲染 ...
AudioWorkgroupEnd(workgroup);
}
最佳实践
- 实时音频线程中绝不分配内存、不使用锁、不调用可能阻塞的系统函数——这条铁律在 Workgroup 时代依然适用
- 将 CPU 密集型处理(如 FFT、卷积混响)拆分到 Workgroup 的非实时线程中,实时线程只做最小化的数据搬运
- 使用 Instruments 的 Audio模板来测量 Workgroup 调度效率,确认你的拆分策略是否真的减少了延迟
- 测试时使用不同的 buffer size(64、128、256 samples)验证 Workgroup 在各种延迟要求下的表现
还有什么值得关注
- Audio Workgroups 与 macOS 的 Power Management 有深度交互,会影响 CPU 的频率调度策略
- 如果你在做 AUv3 插件,关注一下 Xcode 12 中 Audio Unit 模板的变化
- 搭配 “Record stereo audio with AVAudioSession” 和 “What’s new in streaming audio for Apple Watch” 一起看,可以全面了解 2020 年 Apple 音频生态的更新
WWDC 2020