录制 Mac 正在播放的声音,听起来像是一个很基础的需求:想保存一段网页直播、记录视频会议的讨论、采集某个播放器的音频,或者给游戏画面配上操作解说。但在 macOS 上,这件事并没有想象中那么简单。系统默认只允许录音软件读取麦克风这类输入设备,而扬声器、耳机对应的是输出设备,普通应用默认拿不到正在播放的内容。于是出现了 DesktopAudio 这类工具——它做的事情,就是让 Mac 正在播放的声音能够被录制下来。这篇文章会从 macOS 音频链路说起,把一个可以实际运行的“系统录音”流程完整搭起来,再讲清楚参数、验证、排错和生产环境注意事项。
1. 先理解 macOS 音频链路:为什么系统声音录不下来
1.1 默认状态下,输出设备与输入设备是两条不同链路
macOS 的音频体系建立在 Core Audio 之上。系统把声音设备分为输入和输出两端:麦克风是输入设备,扬声器、耳机、蓝牙音箱是输出设备。播放器把音频数据交给 Core Audio,Core Audio 再送到默认输出设备;录音软件请求的却是输入设备,拿到的是麦克风或其他输入源的数据。
这两条链路在系统层面默认不互通。所以你在录音软件里看到的“麦克风”列表里,不会出现“系统正在播放的声音”这个选项。这不是某个 App 的限制,而是 macOS 音频架构的设计结果。要录制系统声音,必须先做一个“桥接”:让系统输出的数据,能出现在某个输入端口上。
理解这一点,能解释很多看似奇怪的现象。例如录屏软件可以录到画面,却经常录不到电脑内部声音;又例如把系统音量静音后,录音结果也跟着变静音。这些现象都指向同一个根因:系统声音不是天然可采集的视频轨或音频轨,它需要一个专门的采集入口。
1.2 虚拟声卡:把输出“送进”输入端口
虚拟声卡(Virtual Audio Device)就是这座桥。它不是一个物理设备,而是一个借助系统音频驱动接口实现的虚拟设备。BlackHole 是这类工具里非常有代表性的开源实现:安装后,系统里会出现一个名为 “BlackHole 2ch” 的设备,它同时具备输出和输入两端。
应用向 BlackHole 播放声音时,声音不会进入真实扬声器,而是直接落到 BlackHole 的输入端口。录音应用从这个输入端口读取数据,就能拿到系统正在播放的内容。整个过程没有接线、没有物理设备,纯粹是系统音频引擎内部的数据流转。
这里有一个容易误解的地方:BlackHole 本身不会“录音”,它只负责把数据从输出端搬到输入端。真正把数据落盘的任务,仍然要由录音软件或脚本完成。把虚拟声卡当成“一根虚拟音频线”来理解,比把它当成“录音机”更准确。
1.3 DesktopAudio 在整套方案里的位置
DesktopAudio 这类工具通常做的事情,是把上面这套流程封装成更简单的操作:要么提供图形界面,要么把“选择虚拟设备、设置采样率、开始录制、保存文件”几步串成一个命令行工具。工具外壳会变,核心链路不变。不管用 DesktopAudio、ffmpeg、Audacity,还是自己写脚本,最终都要依赖“虚拟音频设备 + 录音程序”的组合。
所以在实际踩坑的时候,不要一遇到问题就怀疑工具本身。如果系统链路没有问题、虚拟声卡工作正常、录音程序也读到了数据,那么改哪一层都是改封装,而不是改核心。下面先从最直接的方式把链路搭出来,再解释参数和排查手段。这样即使以后换一个录制工具,排查思路也完全复用。
补充一下,macOS 上出现过多个类似方案,了解它们能帮助选型:
| 方案 | 是否开源 | 维护状态 | 特点 |
|---|---|---|---|
| Soundflower | 开源 | 不再活跃维护 | 早期常用虚拟声卡,Apple Silicon 下存在兼容问题 |
| BlackHole | 开源 | 活跃 | 免费、稳定,支持多通道版本 |
| Loopback | 商业软件 | 活跃 | 面向多应用混音,易用性好 |
| Background Music | 开源 | 更新较慢 | 可调整单个应用音量,同时支持录音 |
2. 环境准备:在 Mac 上先搭好虚拟音频链路
2.1 确认 macOS 版本和芯片
开始前先确认 Mac 是哪一代系统、是 Intel 还是 Apple Silicon。查询方法:
sw_vers uname -m输出示例:
ProductName: macOS ProductVersion: 14.5 BuildVersion: 23F79 arm64arm64表示 Apple Silicon,x86_64表示 Intel。这个信息决定了后续安装驱动时是否要处理权限问题。BlackHole 的安装包在这两类芯片上都能用,但如果是自行编译或使用旧版驱动,一定要确认对应架构,否则会出现设备安装成功却无法识别的问题。
2.2 安装 Homebrew 作为基础包管理器
虚拟声卡和录音工具都用 Homebrew 安装,最省事。如果系统里还没有,执行官方安装命令:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装后确认:
brew --version如果提示command not found: brew,通常是 Apple Silicon 上 Homebrew 的路径/opt/homebrew/bin没有加入 PATH。可以在 shell 配置文件中加入:
export PATH="/opt/homebrew/bin:$PATH"然后把新配置重新加载进当前会话,再检查版本。
2.3 安装 BlackHole 虚拟声卡
BlackHole 有不同的通道版本。日常录制系统声音,2ch版本就够用:
brew install blackhole-2ch安装完成后,建议刷新一次 Core Audio 服务,让系统立即识别新设备:
sudo killall coreaudiod这个命令会短暂中断所有音频输出,执行完恢复正常后再继续。随后检查设备是否出现:
system_profiler SPAudioDataType在输出中应能看到类似内容:
BlackHole 2ch: Type: Audio Input Channels: 2 Output Channels: 2 Manufacturer: ExistentialAudio到这里,虚拟声卡已经进入系统,可以被负责录音的应用识别了。
2.4 用多输出设备避免录音时完全静音
如果直接把系统默认输出切换成 BlackHole,系统播放的声音会全部进入虚拟声卡,扬声器听不到任何声音,操作变成“盲录”。常见的做法是创建一个“多输出设备”,把真实扬声器和 BlackHole 绑定在一起,让同一份音频同时送到扬声器和虚拟声卡。
操作路径:打开“音频 MIDI 设置”(Audio MIDI Setup),它位于“应用程序 > 实用工具”,也可以在启动台搜索。点击左下角的“+”号,选择“创建多输出设备”,然后在右侧设备列表里勾选“扬声器”和“BlackHole 2ch”。
创建后,把多输出设备设为系统默认输出:系统设置 > 声音 > 输出,选择刚创建的多输出设备。此时播放任意音频,扬声器能听到,BlackHole 输入端口也能收到同样内容,录音链路完整。
注意:多输出设备只是把音频同时路由给多个输出,它不保证这些设备的时钟完全一致。短时间录屏没有问题,长时间专业录制建议按文末“生产环境建议”处理。
3. 最小可运行案例:把系统声音真正录下来
环境搭好后,先用最简单的方式录一段音频,验证链路是否通。
3.1 先用 ffmpeg 做一次纯音频录制
ffmpeg 是目前最方便的录音工具,先确认是否安装:
ffmpeg -version没有安装则执行:
brew install ffmpegffmpeg 在 macOS 上通过 avfoundation 框架接入音频设备。先查看设备列表:
ffmpeg -f avfoundation -list_devices true -i ""输出里会列出视频设备和音频设备。音频设备部分通常能看到:
[AVFoundation indev @ 0x...] Found audio device: BlackHole 2ch [AVFoundation indev @ 0x...] Found audio device: MacBook Pro Microphoneavfoundation 的输入格式是“视频设备:音频设备”。只录声音时,视频位置写none:
ffmpeg -f avfoundation -i "none:BlackHole 2ch" -c:a aac -b:a 192k record_output.m4a按Ctrl+C停止录制。录制期间播放一段音乐或视频,就能得到系统声音的录音文件。
如果设备名里的空格或特殊字符带来干扰,可以改用设备序号,序号以-list_devices显示为准:
ffmpeg -f avfoundation -i "none:1" -c:a aac record_output.m4a3.2 用 Python 脚本实现同样的流程
不依赖 ffmpeg 时,可以用 Python 的sounddevice库完成录制。安装依赖:
pip install sounddevice numpy写一个最小脚本record_system.py:
import sounddevice as sd import numpy as np import wave DEVICE_NAME = "BlackHole 2ch" SAMPLE_RATE = 48000 DURATION_SECONDS = 10 OUTPUT_FILE = "system_audio.wav" sd.default.device = DEVICE_NAME recording = sd.rec( int(DURATION_SECONDS * SAMPLE_RATE), samplerate=SAMPLE_RATE, channels=2, dtype="int16", ) sd.wait() with wave.open(OUTPUT_FILE, "wb") as wf: wf.setnchannels(2) wf.setsampwidth(2) wf.setframerate(SAMPLE_RATE) wf.writeframes(recording.tobytes()) print(f"录音完成,已保存: {OUTPUT_FILE}")运行:
python3 record_system.py脚本会等待 10 秒,期间播放任意声音,结束后生成一个 WAV 文件。如果sounddevice找不到 “BlackHole 2ch”,先打印设备列表确认名称:
import sounddevice as sd print(sd.query_devices())3.3 两种方式怎么选
| 方式 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| ffmpeg | 命令简单、支持格式多、可直接压制编码 | 参数略隐晦,依赖 FFmpeg | 快速录制、批量脚本 |
| Python 脚本 | 可编程、可叠加处理、便于二次开发 | 需要安装依赖,适合定制逻辑 | 自动化链路、定时任务 |
实际项目中,两种方式可以同时用:Python 负责触发和调度,ffmpeg 负责最终编码。下一步要理解采样率、通道数这些参数,因为大部分录音异常都出在这里。
4. 参数选择与原理解释:采样率、通道数、编码格式
4.1 采样率务必统一,否则音频会快慢失真
采样率是每秒采样次数。常见值有 44100Hz(CD 标准)和 48000Hz(视频、流媒体标准)。BlackHole 设备本身可以在运行时切换采样率,但同一时刻,系统默认输出设备、BlackHole、录音程序三者的采样率最好保持一致。
如果播放器以 44.1kHz 解码,而 ffmpeg 以 48kHz 去读 BlackHole,Core Audio 会尝试做采样率转换。多数情况下能工作,但可能出现音调偏高、时长缩短或偶发爆音。尤其是某些应用不遵循系统采样率设置时,录音结果会明显不对劲。
推荐做法:在音频 MIDI 设置里,把内置扬声器、BlackHole 2ch 的格式统一调整到 48000Hz。操作方式:选中设备,在右侧“格式”下拉框选择“48000.0 Hz”。这样无论播放什么内容,系统统一的采样率就是 48kHz。
4.2 通道数:2ch 足够,多通道要留意映射
BlackHole 有blackhole-2ch、blackhole-16ch、blackhole-64ch等版本。通道数代表虚拟声卡能同时传递多少路音频。系统立体声是左右两个声道,2ch版本已经覆盖常见需求。除非要做多声道混音、音乐制作,或者把不同 App 分配到独立通道,否则没有必要用 16ch。
用错通道数的一个典型问题:用 2ch 版虚拟声卡,却在录音软件里选择 16 通道,录出来的文件会有大量静音通道,占用空间且不好处理。反过来,录音程序只选 1 个通道,左右声道会被混到一路,丢失立体声信息。
4.3 比特深度与编码格式
采样率之外,还有比特深度和编码格式。
- 比特深度决定每个采样点的精度,常见 16bit 和 24bit。录音中间素材建议 24bit,动态范围更大;最终交付常用 16bit。
- 编码格式上,WAV 无损但体积大,AAC 有损但兼容性好,FLAC 无损压缩适合存档。
判断文件大小时,可以用公式估算:字节数 = 采样率 × 通道数 × 比特深度 / 8 × 时长。例如 48000Hz、2 通道、24bit、1 小时的 WAV 文件,体积约 48000 × 2 × 3 × 3600 = 1036800000 字节,接近 1GB。压缩编码会明显降低体积,但要做后期剪辑时,建议先从无损格式录制,最终再压成 AAC。
ffmpeg 常见组合:
# 无损中间格式 ffmpeg -f avfoundation -i "none:BlackHole 2ch" -c:a pcm_s24le record_master.wav # 压缩交付格式 ffmpeg -f avfoundation -i "none:BlackHole 2ch" -c:a aac -b:a 192k record_delivery.m4a按用途选参数:
| 场景 | 采样率 | 比特深度 | 编码 |
|---|---|---|---|
| 录制后剪辑 | 48000 | 24bit | WAV / PCM |
| 视频配音 | 48000 | 16bit | AAC 192k 以上 |
| 播客存档 | 48000 | 24bit | FLAC 或 WAV |
| 快速分享 | 44100 或 48000 | 16bit | M4A / AAC |
5. 运行验证与结果检查
5.1 确认设备和采样率
录制前先检查设备状态:
system_profiler SPAudioDataType查看 BlackHole 的Nominal Sample Rate是否与计划一致。如果显示 48000,说明设备已按 48kHz 工作。
5.2 检查录音文件是否正常
录制完成后,用 ffprobe 查看文件信息:
ffprobe record_delivery.m4a关注时长、声道数、编码格式。时长应与实际录制时间接近。再用播放器试听,确认左右声道都有内容、没有爆音和拉伸感。
如果想用脚本检查波形幅值,可以用 Python 快速统计:
import wave import numpy as np with wave.open("system_audio.wav", "rb") as wf: data = np.frombuffer(wf.readframes(wf.getnframes()), dtype=np.int16) print(f"采样点数量: {len(data)}") print(f"最大幅值: {np.max(np.abs(data))}") print(f"有效数据比例: {np.mean(np.abs(data) > 100):.2%}")如果最大幅值很低,说明录音中没有信号或输入电平设置太低;如果有效数据比例接近 0%,大概率是链路没有接通。
5.3 长时间录制先做稳定性测试
短录音成功不代表长录音没问题。建议先用 1 到 3 分钟的长度测试,观察是否出现声音漂移、周期卡顿或文件尾部截断。这类问题在多输出设备场景下更容易出现,原因是扬声器和虚拟声卡的时钟来源不同。测试时关注两个点:实际录制时长与计划时长是否一致、中途是否有明显丢帧。
确认链路稳定后再进入正式录制,避免录到一半发现素材不可用。
6. 常见问题排查:从现象倒推原因
以下整理这套方案里最容易出现的几个问题,按“现象 -> 原因 -> 检查 -> 解决”的顺序说明。
6.1 录音时听不到声音
现象:录制程序在跑,但扬声器没有声音,或者录音文件是静音。
原因:默认输出设备被切换成了单独的 BlackHole,系统把声音全部送进虚拟声卡,真实扬声器拿不到数据。
检查:
system_profiler SPAudioDataType看默认输出设备是否为“多输出设备”。
解决:在音频 MIDI 设置里创建多输出设备,把扬声器和 BlackHole 都勾上,并将默认输出切换到这个多输出设备。如果只是长时间录音、不需要实时监听,也可以不做多输出,但操作时属于“盲录”,要留意时间点。
6.2 录音速度明显变快或音调不对
现象:录制出来的声音比原声音调高、时长偏短,或者明显偏慢。
原因:播放端和录制端的采样率不一致。比如系统输出 44.1kHz,而录音程序以 48kHz 读取,就会出现音调和速度漂移。
检查:在音频 MIDI 设置中逐个查看内置扬声器、BlackHole 的采样率,确认三者一致。
解决:统一设置采样率为 48000Hz。设置后重启播放器和录音程序,让所有应用重新读取设备格式。
6.3 录音文件有周期性爆音或卡顿
现象:录制过程中间隔几秒就出现“咔咔”声,或者音频片段丢失。
原因:可能来自两处。一是多输出设备没有时钟同步,长时间使用后两个输出端开始漂移;二是录音程序的缓冲区太小,系统处理不过来。
检查:观察录制时 CPU 占用是否过高,尝试调大录音程序的缓冲设置。
解决:如果只是监听用途,可以把多输出设备换成“仅 BlackHole + 录音软件内置监听”;如果必须同时听和录,优先选择支持时钟同步的聚合设备方案,或在正式录制前用短测试确认无卡顿。ffmpeg 录制时还可以减少不必要的滤镜,降低 CPU 压力。
6.4 录音 App 看不到 BlackHole 设备
现象:录音软件里找遍设备列表,始终没有 BlackHole。
原因:设备驱动已安装,但应用仍处于旧音频会话中;或者 coreaudiod 没有正确刷新。
检查:在终端执行system_profiler SPAudioDataType,如果能看到 BlackHole,说明系统已识别。
解决:退出所有录音相关 App,执行:
sudo killall coreaudiod再重新打开录音软件。如果仍然看不到,检查是否在卸载后重装时驱动未完全注册,重新安装并重启 Mac。
6.5 麦克风权限或屏幕录制权限导致的静音
现象:录音软件没有报错,但录出来是无声;或者新安装的录音工具首次运行时提示需要权限。
原因:从 macOS Catalina 开始,应用访问麦克风需要用户授权;录制屏幕声音时还需要屏幕录制权限。BlackHole 被系统视为输入设备,录音应用读取它时可能触发麦克风授权。
检查:系统设置 > 隐私与安全性 > 麦克风,确认对应 App 已勾选;如果是录屏相关,还要检查“屏幕录制”授权。
解决:勾选授权后完全退出 App 再启动。第一次授权失败后,个别系统版本需要删除该 App 的权限记录,再重新授权一次。
注意:录音应用如果在“屏幕录制”权限未开启的状态下启动,可能拿不到系统级音频数据。排查时优先看授权,而不是反复重装虚拟声卡。
6.6 问题速查表
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 录音静音 | 默认输出切成了单独 BlackHole | 查看声音输出设置 | 创建多输出设备并设为默认 |
| 音调偏高、时长偏短 | 采样率不一致 | 音频 MIDI 设置 | 统一设为 48000Hz |
| 周期性爆音 | 多输出时钟漂移或缓冲过小 | 观察 CPU、调大缓冲 | 换聚合设备或减少负载 |
| 设备不识别 | coreaudiod 未刷新 | system_profiler | 重启 coreaudiod 或重启系统 |
| 无声但程序正常 | 麦克风/屏幕录制权限缺失 | 系统隐私设置 | 授权后重启 App |
7. 生产环境使用建议与扩展方向
7.1 不同场景选不同链路
- 录教程视频:需要“系统声音 + 麦克风人声”同时录制,建议用多输出设备,并在后期把两条音轨分开处理。
- 录播客:重点是麦克风音质和对端远程语音。应优先确保输入设备稳定,虚拟声卡只做辅助,不要为了让系统声音进录音而反复切换默认设备。
- 多人协作或直播:避免频繁改动系统默认输出。建议给每个场景单独创建一套多输出设备配置,在音频 MIDI 设置里命名区分。
7.2 用定时任务实现自动录制
需要让 Mac 在固定时间自动录制某个播放源时,可以把 ffmpeg 命令写进 shell 脚本,再用launchd调度。脚本示例:
#!/bin/bash OUT_DIR="$HOME/Desktop/audio_records" STAMP=$(date +"%Y%m%d_%H%M%S") mkdir -p "$OUT_DIR" ffmpeg -f avfoundation -i "none:BlackHole 2ch" \ -c:a aac -b:a 192k \ "$OUT_DIR/rec_$STAMP.m4a"执行权限:
chmod +x record.sh生产环境使用脚本时,要补充日志、磁盘空间检查和失败退出码。录音任务长期运行时,还要定期清理旧文件,否则磁盘会被占满。
7.3 后期混流与降噪
录制完成后,视频和音频分开了,可以用 ffmpeg 合并:
ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a aac -shortest merged.mp4如果录的是远程会议,对端声音可能存在回声和压缩损失,建议在后期用专业音频软件做降噪和电平处理。前期采样格式和采样率越高,后期处理余地越大。
7.4 生产环境维护清单
- 所有音频设备采样率统一为 48000Hz,并写入团队文档。
- 录音脚本具备失败退出码、日志输出和磁盘空间预检查。
- 长期运行的录制任务定期清理旧文件,避免占满磁盘。
- 升级 macOS 前确认虚拟声卡驱动兼容性,保留前一个系统版本用于回滚。
- 重要录制先做 1 分钟链路测试,再进入正式流程。
- 涉及人声采集时,明确区分麦克风授权和屏幕录制授权,分别检查。
整体来看,DesktopAudio 这类工具的出现,本质上是把 macOS 系统音频输出“重新打通”的过程封装成了易用产品。只要理解了虚拟声卡在 Core Audio 里的作用,自己搭一套录制链路并不复杂;真正影响成品质量的,往往是采样率一致性、设备选择和权限管理这些细节。对刚接触的同学,建议先把 BlackHole 加多输出设备的链路跑通,再用 ffmpeg 录一段 10 秒音频检查文件;跑通之后再进入定时录制、多通道混音和自动化处理,就不会被各种报错牵着走了。