Mac系统音频录制全攻略:ScreenCaptureKit与BlackHole实践

📅 发布时间:2026/8/26 14:18:01
Mac系统音频录制全攻略:ScreenCaptureKit与BlackHole实践 如果你在 Mac 上做过录课、直播、游戏高光剪辑或者只是想把一段在线音乐保存下来大概率会遇到一个很尴尬的处境Mac 能录屏幕、能录麦克风但就是没法“直接录电脑里正在播放的声音”。Windows 上有一个叫“立体声混音”的虚拟设备可以把系统输出当成输入来录。Mac 没有这个东西。QuickTime Player 虽然能录屏但录进去的声音要么来自麦克风要么什么都没有。想录浏览器里的音乐、会议软件的回放、游戏音效你得自己想办法。DesktopAudio 就是近期出现在 Hacker News “Show HN”板块的一个 Mac 小工具定位很直接录制 Mac 播放出来的声音把系统内部音频变成可保存的文件。它的出现恰恰踩中了很多 Mac 用户长期存在的痛点。不过今天这篇文章不只是介绍一个工具。我会把“在 Mac 上录制系统音频”这件事完整地拆开它为什么难、都有哪些可行方案、权限是怎么卡的、代码该怎么写、常见坑有哪些。读完你会理解这类工具背后的技术链路也能自己动手做一个甚至用脚本直接实现系统音频录制。1. 为什么在 Mac 上录制系统播放的声音会这么麻烦先说结论macOS 并没有提供一个稳定的“录制系统输出”的公共接口。你在系统设置里看到的“麦克风权限”管的是外部物理输入不是内部音频流。Mac 的音频架构以 Core Audio 为核心。系统播放声音时音频数据走向输出设备比如内置扬声器、耳机、HDMI 显示器录音软件读取的是输入设备比如麦克风。普通程序想拿到“正在播放的那份音频数据”系统层面默认是不给路的。这个设计的背后有几个原因隐私与安全。如果任何应用都能读取系统播放的音频那意味着它可以录制任意 App 的声音包括语音通话、会议内容、视频里的对话。macOS 对这类“敏感数据”的访问控制非常严格。设备模型不同。macOS 把输出设备和输入设备当作独立对象。默认情况下系统不会创建一个“虚拟输入”来接收内部播放的音频所以录音软件没有天然的入口。兼容性差异。即便通过驱动层方案去桥接不同 Mac 芯片、不同 macOS 版本之间的行为也可能不一样不是所有工具都能一键跑通。这就导致了一个现实想录制 Mac 播放的声音必须借助第三方方案。DesktopAudio 这类工具做的事情本质上就是解决“系统输出到可写入文件”这条链路。从技术栈上看目前主要有四条实现路径ScreenCaptureKit 框架、虚拟声卡驱动BlackHole/Soundflower、底层 Core Audio 接口、以及商业音频捕获软件。下面我会逐一拆解它们的基本原理和适用场景。2. 系统音频录制的基础概念输出、输入与虚拟设备在动手之前先理清几个容易混淆的术语。系统音频System AudioMac 系统播放出来的所有声音包括浏览器、音乐 App、会议软件、游戏、通知音。麦克风输入Microphone Input通过物理麦克风采集的外部声音属于“输入设备”数据。输出设备Output Device系统将音频送往的目标例如内置扬声器、耳机、HDMI 显示器。输入设备Input Device系统从音频来源读取数据的入口例如内置麦克风、USB 麦克风。虚拟音频设备Virtual Audio Device由驱动创建的“假”设备不连接物理硬件。系统既可以把音频输出给虚拟设备也可以从虚拟设备读取音频输入。理解虚拟音频设备是理解这套方案的关键。如果系统把音频同时输出到物理扬声器和虚拟声卡录音软件再从虚拟声卡读取数据就等效于“录下了系统播放的声音”。BlackHole、Soundflower 都是走这条路。但虚拟声卡有一个体验问题安装驱动时系统会有安全提示部分老驱动还需要开启内核扩展MAC 的“安全策略”设置不对就会直接拒绝加载。而且在 macOS 新版本中虚拟声卡需要用户手动在“音频 MIDI 设置”里创建一个“多输出设备”否则声音会“消失”——因为音频已经被重定向到虚拟设备物理扬声器反而拿不到声音了。和虚拟声卡不同ScreenCaptureKit 是 Apple 在 macOS 12.3 引入的屏幕捕捉框架官方支持同时捕获屏幕和系统音频。这意味着它在系统层面提供了获取内部音频的能力不需要额外安装驱动。不过它也有一个特点ScreenCaptureKit 是从“屏幕捕获”这个入口去拿音频的。即便你只想录音代码层面通常也要同时开启一个正被捕获的视频流然后从同一流中提取音频帧。这在后面会详细演示。如果你理解了“输出与输入隔离”和“虚拟设备桥接”这两个点再看任何系统音频录制工具都不会觉得神秘。3. 方案盘点四条主流路径对比为了让你快速判断自己该用哪种方案我把常见思路整理成了对比表格方案原理优点缺点适合谁ScreenCaptureKit系统框架捕获屏幕时同步捕获系统音频原生、无需驱动、可同时录屏需要 macOS 12.3需要屏幕录制权限代码量稍大开发者想做自定义录制工具BlackHole开源虚拟音频驱动稳定、多通道适配范围广需要安装驱动需手工配置多输出设备日常录音、直播、音频备份Soundflower老牌虚拟声卡历史久、资料多新系统兼容性一般内核扩展可能被拒兼容老方案的用户Audio Hijack商业录音软件零代码、操作直观、功能强大付费价格较高非开发者愿意付费从当前时间点看我的建议很明确如果只是临时录一段系统声音装 BlackHole ffmpeg 是最快的路径。如果想做自己的录制工具、自动化处理或二次开发优先使用 ScreenCaptureKit。如果完全不想写代码又愿意付费商业软件能帮你省下大量折腾时间。DesktopAudio 这类工具大多数是选择 ScreenCaptureKit 或 BlackHole 中的某条路径来实现的。你看懂了这两条路就看懂了工具的内部逻辑。4. 环境准备与权限配置无论选择哪条路径Mac 的环境配置是绕不开的第一步。下面以 ScreenCaptureKit 为主同时补充 BlackHole 方案的准备步骤。4.1 确认系统版本ScreenCaptureKit 要求 macOS 12.3 或更高版本。先确认一下系统版本sw_vers如果版本低于 12.3要么升级系统要么改用 BlackHole 虚拟声卡方案。4.2 授予屏幕录制权限使用 ScreenCaptureKit 捕获音频时系统会要求“屏幕录制”权限。这个权限并不仅限于画面也包含系统音频流。操作路径打开“系统设置” → “隐私与安全性” → “屏幕录制”。把你运行工具的程序加入允许列表例如“终端”或者打包后的 App。如果修改过权限需要重新启动程序才能生效。这里有一个非常容易踩的坑如果你的工具是在终端里运行的授权对象是终端 App不是脚本本身。很多人代码没有写错却一直收不到音频最后发现是终端没有被勾选屏幕录制权限。4.3 安装 Xcode Command Line Tools编译 Swift 示例需要命令行工具xcode-select --install如果你已经安装过完整的 Xcode也可以直接用 Xcode 打开工程。4.4 安装 BlackHole可选如果选择虚拟声卡方案可以通过 Homebrew 安装brew install blackhole-2ch安装完成后打开“音频 MIDI 设置”你会看到新增了一个“BlackHole 2ch”设备。很多人在这一步会忽略权限问题macOS 安装音频驱动时会在“系统设置”中要求允许系统扩展此时需要在“隐私与安全性”页面进行确认。如果直接忽略驱动不会被加载。5. 完整示例用 ScreenCaptureKit 做系统音频采集这部分的目标是写出一个最小可用示例通过 ScreenCaptureKit 捕获系统音频帧并打印基础信息。这个示例可以直接在 Xcode 命令行工程中运行。5.1 Swift 最小实现创建 Swift 命令行工程后把main.swift替换为以下内容// 文件路径main.swift import ScreenCaptureKit import Foundation // 音频输出处理类接收音频 sample buffer final class AudioOutput: NSObject, SCStreamOutput { func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) { guard type .audio else { return } let duration sampleBuffer.duration.seconds let size sampleBuffer.totalSampleSize print(收到音频帧时长\(duration) 秒字节数\(size)) } } main struct AudioRecord { static func main() async throws { // 1. 获取可捕获的显示器 let content try await SCShareableContent.excludingDesktopWindows( false, onScreenWindowsOnly: true ) guard let display content.displays.first else { fatalError(未找到可捕获的显示器) } // 2. 创建筛选器捕获整个显示器内容 let filter SCContentFilter(display: display, excludingWindows: []) // 3. 配置捕获流开启音频捕获 let config SCStreamConfiguration() config.width 1 config.height 1 config.minimumFrameInterval CMTime(value: 1, timescale: 30) config.capturesAudio true config.sampleRate 48000 config.channelCount 2 // 4. 创建 SCStream添加音频输出回调 let audioOutput AudioOutput() let stream SCStream(filter: filter, configuration: config, delegate: nil) try stream.addStreamOutput(audioOutput, type: .audio, sampleHandlerQueue: .main) // 5. 启动捕获 try await stream.startCapture() print(系统音频捕获已启动按回车停止...) _ readLine() try await stream.stopCapture() print(已停止) } }5.2 编译与运行在终端切换到文件所在目录执行swiftc main.swift -o audio-record ./audio-record如果你用 Xcode 工程运行直接⌘R即可。5.3 关键逻辑说明第一个要注意的地方是为什么代码不直接创建“音频流”而是先获取显示器因为 ScreenCaptureKit 的音频捕获依赖屏幕捕获流。我在代码里把width和height都设为 1就是为了降低视频处理开销——我们并不关心画面音频才是唯一目标。第二个要注意的是权限。程序首次运行会弹出系统提示询问是否允许“屏幕录制”。你需要点击允许然后重新启动程序。如果直接拒绝后续任何SCStream都无法产生音频帧。第三个点是回调线程。我将sampleHandlerQueue设置为.main方便打印和调试。实际项目中不要在主线程做耗时操作否则会导致音频数据堆积。5.4 如何保存为文件如果只是打印信息当然不够实际使用时你需要把音频帧写入文件。推荐的思路是使用AVAssetWriter初始化时指定文件类型为.m4a每收到一个音频 sample buffer就调用append(_:)。停止时调用finishWriting()。不过要注意SCStream 输出的音频格式可能与AVAssetWriter期望的格式不一致需要先检查CMSampleBuffer的格式描述必要时通过AVAudioConverter或AVAudioFile做转换。这一步也是新手容易写错的地方后面最佳实践部分会细说。6. 完整示例用 BlackHole 虚拟声卡录制系统声音如果你不想写 Swift 代码只想通过命令行完成系统音频录制BlackHole ffmpeg 是最快的路径。6.1 创建多输出设备安装 BlackHole 后打开“音频 MIDI 设置”Audio MIDI Setup。点击左下角“”选择“创建多输出设备”。在右侧勾选“内置扬声器”和“BlackHole 2ch”然后把这个多输出设备设为默认输出设备右键 → 设为默认输出。这样Mac 播放的声音会同时送到物理扬声器和 BlackHole 虚拟声卡。录音软件可以从 BlackHole 读取这段声音。6.2 安装 ffmpegbrew install ffmpeg6.3 查看音频设备列表ffmpeg -f avfoundation -list_devices true -i 输出中会列出所有视频输入和音频输入设备。找到类似BlackHole 2ch的条目记下对应的音频设备索引。例如如果 BlackHole 的索引是 2那么录制命令如下ffmpeg -f avfoundation -i :2 -c:a aac -b:a 192k output.m4a参数说明-f avfoundation使用 macOS 的 AVFoundation 采集接口。-i :2以“视频设备为空音频设备取索引 2”的方式读取 BlackHole。-c:a aac -b:a 192k使用 AAC 编码码率 192kbps。output.m4a输出文件名。录制过程中按CtrlC停止。停止后可以用下面命令检查文件是否有效afinfo output.m4a也可以直接播放afplay output.m4a这里最常遇到的问题有两个一是系统没有把默认输出设备切到多输出设备导致录音静音二是设备索引选错ffmpeg 提示找不到设备。出现问题时先回到“音频 MIDI 设置”确认默认输出。7. 常见问题与排查思路在实际操作中无论是用 ScreenCaptureKit 还是 BlackHole你都会遇到一些典型问题。我整理了一个排查表格问题现象可能原因排查方式解决方案启动后收不到任何音频屏幕录制权限未授予“系统设置”→“隐私与安全性”→“屏幕录制”中确认授权添加对应 App如终端修改后重启程序ScreenCaptureKit 创建流报错macOS 版本过低执行sw_vers检查版本升级到 macOS 12.3使用 BlackHole 后扬声器无声多输出设备未配置打开“音频 MIDI 设置”查看默认输出创建多输出设备并勾选物理扬声器ffmpeg 找不到 BlackHole设备索引不正确执行ffmpeg -f avfoundation -list_devices true -i 根据输出结果选择正确的音频索引录音文件无声音或杂音采样率或声道数不匹配检查系统音频设置与录制参数统一为 48kHz / 2 声道修改权限后仍无法录音进程没有重启检查终端或 App 是否已重新启动退出后重新运行程序录制过程中内存占用持续上涨回调里做了耗时处理检查回调线程是否阻塞将处理逻辑放到异步队列及时释放 sample buffer如果问题还没有解决最简单的排查思路是“分层隔离”先确认系统能正常播放声音再确认权限再确认虚拟设备是否被系统识别最后才怀疑代码逻辑。很多问题其实都出在系统和权限层面和代码没有关系。8. 工程实践与安全边界当你真正把录制系统音频做成一个工程而不只是跑通一个 Demo 时有几个问题值得认真对待。8.1 权限设计要克制ScreenCaptureKit 的“屏幕录制”权限是系统级敏感权限。获得该权限后App 不仅能看到系统音频还能捕获整个屏幕画面。如果你的工具只需要录音UI 上要明确告诉用户“不会录制屏幕内容”并尽量把捕获区域限制到最小。Apple 在上架审核时对这类权限的使用理由审查很严格。如果工具在后台持续录制必须具备清晰的使用场景否则很难通过 App Store 审核。独立分发命令行工具虽然是另一条路但用户授权时的体验直接影响信任感。8.2 音频格式与保存策略系统音频的原始 PCM 数据量非常大。以 48kHz、16bit、双声道为例一分钟未压缩音频大约 11MB一小时超过 660MB。如果你录制的是会议或游戏声音长时间不处理会产生大量脏数据。建议的保存策略在线录制时直接编码为 AAC 或 MP4避免先写裸 PCM 再转换。使用AVAssetWriter或 ffmpeg 的编码器目标码率设为 128kbps 到 192kbps足够用于语音和音乐。录制结束时检查文件头是否完整避免崩溃导致输出不可用。另外这些音频文件会占据“系统数据”空间。Mac 用户常常抱怨“系统数据”越来越大很多情况下就是这类录制文件、缓存和日志在堆积。建议工具提供默认输出路径和自动清理策略避免用户使用几个月后发现磁盘被占满。8.3 性能与资源控制ScreenCaptureKit 即使只捕获音频也会有一个最低限度的视频帧在跑。如果你的配置里把width设成 1920 × 1080录制一小时会白白消耗大量 CPU 和 GPU 资源。最小化视频配置是性能优化的第一步。同时要注意回调线程。SCStream 的输出回调频率不低不要把文件写入直接放在回调里同步执行。更合理的做法是使用DispatchQueue做数据缓冲再通过异步写入器落盘。8.4 日志与可观测性录制工具最常见的故障是“静默失败”系统没有声音、权限被断开、设备被移除但程序还在运行。开发阶段就要加上关键节点的日志是否获取到显示器列表是否成功创建 SCStream是否收到第一帧音频停止时是否正常完成任务。对于命令行工具建议输出结构化日志方便用户排查。DesktopAudio 这类工具如果能在终端打印清晰的错误原因用户体验会明显提升。9. 总结与后续学习方向DesktopAudio 这类工具之所以有价值不是因为它实现了多么复杂的新算法而是它把 Mac 系统音频录制这个“刚需”从麻烦变成了简单。它解决的链路本质上是 macOS 出于隐私安全考虑而故意断开的那段通路。通过这篇文章你应该掌握几件事知道为什么 Mac 没有“立体声混音”系统输出与输入在 Core Audio 层面是隔离的。知道录制系统音频的两大类主流方案虚拟声卡和 ScreenCaptureKit。知道权限配置是最容易踩坑的一环屏幕录制权限直接影响音频采集。知道最小可用的 Swift 代码长什么样以及如何用 ffmpeg 快速完成录制。知道工程化时要注意的格式、性能、日志和隐私问题。这还不够。如果你想继续深入有下面几个方向值得研究。第一应用级音频分离。ScreenCaptureKit 目前只能获取整个系统的音频流做不到“只录 App A 不录 App B”。如果你想实现单应用音频捕获需要结合 Core Audio 的进程级音频路由或者借助虚拟声卡做路由分配。第二音频后处理。录制只是第一步下一步可以做降噪、音量归一化、语音转文字、自动字幕。这些技术和录制链路结合后可以做成一个自动化会议记录工具。第三录屏与录音的结合。如果你需要把系统声音、麦克风、屏幕画面同时录下来可以基于 ScreenCaptureKit 的 screen 和 audio 双输出用同步时间戳生成最终的视频文件。这个功能在录课、主播场景中非常实用。最后给你一个实践建议不要一开始就写完整工具。先用 ffmpeg BlackHole 跑通一次系统音频录制感受一下虚拟设备的路由逻辑再用 ScreenCaptureKit 写一个打印音频帧的最小 Demo最后才考虑加文件保存、格式转换和 CLI 参数。每走一步都确认数据的到达能帮你省下大量排错时间。如果你正在为 Mac 系统音频录制犯愁或者按照文章里的方案试出了新问题欢迎在评论区把你卡住的点写出来。这类工具的坑往往不在代码而在系统版本、权限配置和设备路由上多交流一次后面的人就能少踩一次坑。