实时获取macOS输出设备音频缓冲区

5

我正在尝试在macOS上“拦截”当前选定的输出音频设备,因此我基本上有一个通过监听器,可以监视当前正在输出的音频流而不影响它。

我希望实时将这些数据复制到环形缓冲区,以便我可以对其进行单独操作。

苹果文档和过时的SO答案的组合使我困惑,是否需要编写hacky内核扩展程序,可以利用CoreAudio进行此操作,还是需要与HAL接口?

如果可能的话,我想用Swift来工作。

非常感谢

(附:我一直在查看这个这个)

1个回答

5
我不了解内核扩展——它们使用特殊的“呼叫我们”签名证书或关闭SIP的必要性会阻碍非正式探索。
但是,您可以使用CoreAudio和HAL AudioServer插件的组合来实现您想要的功能,而且您甚至不需要编写插件自己,有几个开源版本可供选择。
CoreAudio没有提供一种从输出设备录制(或“窃听”)的方法——您只能从输入设备录制,因此解决此问题的方法是创建一个虚拟的“通过”设备(AudioServerPlugin),不与任何硬件相关联,将输出复制到输入,然后将该通过设备设置为默认输出并从其输入进行录制。我使用开源AudioServer插件如BackgroundMusicBlackHole [TODO:添加更多]来完成这项工作。
为了从生成的设备中录制音频,您可以简单地向其添加一个AudioDeviceIOProc回调,或将该设备设置为kAudioUnitSubType_HALOutputAudioUnitkAudioOutputUnitProperty_CurrentDevice
上述虚拟直通设备方法存在两个问题:
1. 您听不到输出声音,因为它被直通设备消耗掉了。 2. 更改默认输出设备将切换到您的设备,直通将变得无声。
如果第一种方法是问题,则简单的解决方法是创建一个包含直通设备和实际输出设备(请参见截图)的多输出设备,并将其设置为默认输出设备。音量控件停止工作,但仍然可以在Audio MIDI Setup.app中更改实际输出设备的音量。
对于第二个问题,您可以在默认输出设备上添加一个监听器,并在更改时更新上面的多输出设备。
你可以使用Swift完成上述大部分操作,但是对于从缓冲区交付回调中存储环形缓冲区,你需要使用C或其他能够遵守实时音频规则(无锁,无内存分配等)的语言。你可以尝试使用AVAudioEngine来进行点击操作,但如果我没记错的话,更改输入设备会是一场痛苦的经历

Audio MIDI Setup app showing multi-output device set as default output, containing pass thru device (Background Music) and normal output device (Mac-mini speakers), Mac-mini speakers set as master device


这是一个非常全面的概述,谢谢。那么这个怎么样:
  1. 在程序启动时检测当前默认输出设备。
  2. 以编程方式将当前默认输出设备更改为虚拟AU,它只是原始默认输出设备的代理。
  3. 将监听器绑定到输出设备更改事件并更改代理委托的内容
  4. 始终在程序运行时强制输出设备为代理(无论何时更改)。 我的另一种选择是使用Blackhole,并让用户选择特定应用程序作为音频源,例如Spotify或Skype等?
- Darius
没错。你确定黑洞可以从单个应用程序重新路由音频吗?这听起来更像是RA的回送。 - Rhythmic Fistman
是的,说得对。我安装了Loopback,所以在我的脑海中混淆了这两个东西! - Darius
如果您有回环测试,可以将其设备配置为仅具有一个来源:应用程序,并使用答案中的方法从设备录制。我在答案中没有提到回环测试。我相信它使用完全不同的方法。 - Rhythmic Fistman
是的,我不能在解决方案中使用Loopback的原因主要是我想将这个应用程序分发给其他用户,并且无法保证他们会拥有Loopback或设置它的知识。不过,我仍在考虑你所写的内容,因为使用多输出设备可能会有一个很好的折衷方案。 - Darius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接