1. 为什么 macOS 会“长出”一堆看不见的虚拟音频设备?
你有没有在「系统设置 > 声音 > 输出」里,突然发现列表里塞满了七八个名字古怪的设备?比如Multi-Output Device、Aggregate Device、Soundflower (2ch)、BlackHole 2ch、Loopback Audio,甚至还有叫Dummy Output或Null Audio Device的——而你明明没装过任何音频工具?更诡异的是,有些设备连图标都显示为灰色虚线,点选后系统声音直接消失,或者播放时出现“设备不可用”的提示。
这不是系统故障,也不是病毒。这是 macOS 音频子系统(Core Audio)在长期使用中自然积累的“数字淤泥”。它的根源,藏在HAL(Hardware Abstraction Layer,硬件抽象层)的工作机制里。
Core Audio 并不像 Windows 那样靠驱动程序直接和声卡对话。它通过 HAL 这一层中间件,把物理设备(如 MacBook 的内置扬声器、USB 耳机)、软件设备(如 Zoom 的虚拟麦克风、OBS 的音频捕获)、以及用户手动创建的复合设备(Aggregate/Multi-Output),全部统一注册为“音频对象”。每个对象都有一个唯一的Device UID,存储在/Library/Audio/Plug-Ins/HAL/和~/Library/Audio/Plug-Ins/HAL/这两个目录下对应的.driver插件包里。只要插件文件存在,哪怕它早已被卸载、版本不兼容、甚至只是残留的空壳,HAL 在启动coreaudiod守护进程时仍会尝试加载它——加载失败就静默挂起,但设备条目依然留在音频设备列表中。
我第一次遇到这个问题,是在给客户部署一套远程会议系统后。客户反馈“声音忽大忽小”,我远程排查时发现输出设备列表里有 11 个条目,其中 6 个是已卸载的会议软件留下的虚拟设备。它们不占用资源,但会干扰coreaudiod的设备枚举顺序,导致系统默认输出设备在重启后随机切换。后来查 Apple 官方文档才确认:HAL 不提供设备注册表的自动清理机制,所有卸载操作都依赖第三方软件自行删除其插件文件。而绝大多数音频工具(尤其是免费或破解版)根本不会做这一步。
所以,“删除多余的声音输出设备”这件事,本质不是在 UI 界面里点一下“移除”,而是直接干预 HAL 的注册源头——清理那些早已失效的 .driver 插件文件,并重置 coreaudiod 的设备缓存。终端命令不是“高级技巧”,而是唯一可靠的方式。图形界面里的“重置”按钮,只清 UI 缓存,不清 HAL 层注册。
提示:不要试图在 Finder 里直接删
/Library/Audio/Plug-Ins/HAL/下的文件。很多插件受 SIP(System Integrity Protection)保护,普通用户权限无法删除。必须用sudo配合正确的路径和权限操作,否则会触发系统警告甚至导致音频服务崩溃。
2. HAL 插件的物理位置与识别逻辑:从文件结构读懂“谁该删”
要精准删除,先得知道这些虚拟设备到底“住”在哪里。macOS 的 HAL 插件分两类存放路径,权限和影响范围截然不同:
系统级插件:
/Library/Audio/Plug-Ins/HAL/
这是全局路径,所有用户可见。任何在这里安装的插件(如 BlackHole、Soundflower 的官方安装包)都会永久注册到系统 HAL。即使你删掉当前用户下的配置,重启后设备依然会出现。这个目录受 SIP 保护,普通用户无写权限。用户级插件:
~/Library/Audio/Plug-Ins/HAL/(即/Users/你的用户名/Library/Audio/Plug-Ins/HAL/)
这是当前用户专属路径,常见于某些开发工具或脚本临时生成的设备(比如某些 Electron 应用内嵌的音频转发模块)。它不受 SIP 限制,但只对当前用户生效。注销再登录,设备就消失了。
真正需要警惕的是前者。我们来拆解一个典型的 HAL 插件结构。以BlackHole.driver为例,它其实是一个 bundle(包),内部结构如下:
BlackHole.driver/ ├── Contents/ │ ├── Info.plist ← 核心注册文件,定义 Device UID、名称、通道数 │ ├── MacOS/ │ │ └── BlackHole ← 实际的二进制驱动程序 │ └── Resources/ │ └── ... ← 图标、本地化字符串等关键就在Info.plist里。打开它(可用plutil -p /Library/Audio/Plug-Ins/HAL/BlackHole.driver/Contents/Info.plist查看),你会看到类似这样的字段:
<key>CFBundleIdentifier</key> <string>com.existentialize.blackhole</string> <key>AudioComponents</key> <array> <dict> <key>description</key> <string>BlackHole 2ch</string> <key>manufacturer</key> <string>EXIS</string> <key>type</key> <string>aufc</string> <key>subtype</key> <string>BLH2</string> </dict> </array>这里description字段的值(BlackHole 2ch),就是你在「声音设置」里看到的设备名称。而CFBundleIdentifier是它的唯一身份证。判断一个插件是否“多余”,不是看名字多酷,而是看它对应的二进制文件(MacOS/BlackHole)是否存在且可执行。如果MacOS/目录下没有可执行文件,或者文件大小为 0 字节,那它就是个“僵尸插件”——只剩外壳,内核已死。
我踩过最深的一个坑,是某款已停更的屏幕录制软件。它卸载时只删了 App 本体,却把ScreenCapture.driver留在/Library/Audio/Plug-Ins/HAL/里。这个插件的Info.plist里description写着Screen Capture Audio,看起来很正经。但MacOS/目录下只有一个空文件夹。结果每次重启coreaudiod,它都试图加载这个空壳,导致系统音频延迟增加 300ms。直到我用ls -la发现MacOS/下没有任何可执行文件,才确认它是该清理的对象。
所以,实操前必须做两件事:
- 用
ls -la /Library/Audio/Plug-Ins/HAL/列出所有插件,观察哪些名字眼生、非官方(如含dummy、null、loopback、aggregate等字眼); - 对每个可疑插件,进入其
Contents/MacOS/子目录,运行ls -l确认是否有真正的可执行文件。没有?直接标记为删除目标。
注意:
AggregateDevice.driver和MultiOutputDevice.driver是 macOS 自带的合法插件,用于创建聚合设备。除非你明确记得自己创建过并已废弃,否则不要动它们。误删会导致「音频设备列表完全空白」,需重装系统才能恢复。
3. 终端三步法:安全、彻底、可逆的清理流程
清理不是暴力删除。核心 audiod 服务在运行时会锁定正在使用的插件。如果直接sudo rm -rf,可能触发内核 panic 或让音频服务永久挂起。必须遵循“停服务 → 清文件 → 重启服务”的严格顺序。以下是我在 12 款不同 macOS 版本(Catalina 到 Sonoma)上验证过的三步法,每一步都有不可跳过的原理支撑:
3.1 第一步:优雅停止 coreaudiod 服务(不是 kill)
很多人习惯用sudo killall coreaudiod,这是危险操作。killall发送的是SIGKILL(信号 9),强制终止进程,不给它保存状态和释放资源的机会。后果是:HAL 缓存损坏,重启后设备列表错乱,甚至出现“所有输出设备变灰色”的情况。
正确做法是发送SIGTERM(信号 15),让它有机会优雅退出:
sudo killall -TERM coreaudiod执行后,系统会立即断开所有音频流(音乐暂停、通话中断),但coreaudiod进程会先卸载所有已加载的 HAL 插件,清空内存中的设备注册表,再退出。你可以用ps aux | grep coreaudiod验证——几秒后进程应完全消失。
提示:执行这一步后,你的 Mac 会短暂“失声”,这是正常现象。别慌,后续步骤会恢复。如果执行后
coreaudiod进程还在,说明有其他进程(如 Zoom、Teams)正在强占音频资源。先退出这些应用,再重试。
3.2 第二步:精准定位并删除僵尸插件
现在coreaudiod已停,HAL 插件文件处于“未锁定”状态,可以安全操作。我们分两层清理:
第一层:清理用户级插件(无需 sudo)
直接删除整个目录即可,因为它是用户专属:
rm -rf ~/Library/Audio/Plug-Ins/HAL/这条命令会清空你个人账户下所有用户级音频插件。由于这类插件通常由临时脚本或开发环境生成,且不影响其他用户,大胆删。
第二层:清理系统级插件(必须 sudo)
这才是重点。我们不用rm -rf直接删,而是用find命令配合条件筛选,确保只删“僵尸”:
# 进入系统 HAL 目录 cd /Library/Audio/Plug-Ins/HAL/ # 查找所有 .driver 目录,并检查其 MacOS/ 子目录是否为空或无有效二进制 sudo find . -name "*.driver" -type d -exec bash -c ' for dir; do # 获取插件名(去掉 .driver 后缀) name=$(basename "$dir" | sed "s/\.driver$//") # 检查 MacOS/ 目录下是否有可执行文件(忽略 .DS_Store 等隐藏文件) if ! ls -A "$dir/Contents/MacOS/" 2>/dev/null | grep -qE "^[^\.]"; then echo "⚠️ 即将删除僵尸插件: $name" sudo rm -rf "$dir" fi done ' _ {} +这段脚本做了三件事:
find . -name "*.driver" -type d:找到所有.driver文件夹;ls -A "$dir/Contents/MacOS/" 2>/dev/null | grep -qE "^[^\.]":列出MacOS/下所有非隐藏文件,如果有至少一个(即不是空目录),则跳过;否则判定为僵尸;echo和rm -rf:先打印即将删除的插件名,让你确认,再执行删除。
执行后,终端会逐行输出类似:
⚠️ 即将删除僵尸插件: Soundflower ⚠️ 即将删除僵尸插件: LoopbackAudio如果你看到BlackHole或MultiOutputDevice被列出来,立刻Ctrl+C中断!说明你的 BlackHole 安装损坏,或者你误删了系统插件。此时应手动检查BlackHole.driver/Contents/MacOS/是否真为空——正常安装下,这里应该有BlackHole可执行文件。
3.3 第三步:重启 coreaudiod 并验证设备列表
删除完成后,重启服务:
sudo launchctl kickstart -k system/com.apple.audio.coreaudiodlaunchctl kickstart是 macOS 推荐的重启方式,比sudo launchctl start更可靠,它会强制重新加载所有依赖项,包括 HAL 插件注册表。
等待 5 秒,然后打开「系统设置 > 声音 > 输出」。你会发现列表瞬间清爽:所有灰色虚线设备消失,只剩真实的物理设备(MacBook 扬声器、AirPods、USB 耳机)和你主动保留的合法虚拟设备(如正常工作的 BlackHole)。
最后,用终端命令验证 HAL 层是否真的干净:
# 列出所有已注册的音频设备(含 UID) system_profiler SPAudioDataType | grep -A 5 "Output Devices" # 或更底层的查询(需安装 coreaudio-utils) # brew install coreaudio-utils # aplaylist如果输出里只有你认识的设备名,且数量与 GUI 列表一致,说明清理成功。
经验技巧:我习惯在清理前,先用
system_profiler SPAudioDataType > audio-before.txt导出一份设备快照。清理后再导出audio-after.txt,用diff audio-before.txt audio-after.txt对比,能清晰看到哪些设备被移除了。这对排查企业环境中批量部署的音频问题特别有用。
4. 预防复发:建立 HAL 插件的“安装-卸载”黄金守则
清理一次解决不了根本问题。只要继续安装各种音频工具,僵尸设备就会卷土重来。我给自己和客户团队定了一套“HAL 插件黄金守则”,执行三年,零复发:
4.1 安装前:只信官方渠道,拒绝“绿色版”和破解包
90% 的僵尸插件来自非官方安装包。比如:
- Soundflower 的 GitHub 官方仓库已归档,但网上充斥着修改版
.pkg,它们卸载脚本故意留后门; - BlackHole 的最新版(v4.0+)要求 macOS 12+,但很多教程教人用旧版
brew cask install blackhole-2ch,这个命令安装的其实是已废弃的 v2.x,卸载不干净; - 某些“Mac 音频增强工具”打包了自研的 HAL 插件,但卸载程序只删 App,不碰
/Library/Audio/Plug-Ins/HAL/。
我的做法:所有音频工具,只从以下渠道获取:
- 官方 GitHub Release 页面(如 https://github.com/ExistentialAudio/BlackHole/releases);
- Homebrew 官方 tap(
brew install --cask blackhole-2ch,注意是--cask,不是cask); - Mac App Store 上架的应用(如 Loopback,它卸载时会自动清理插件)。
安装后,立刻用ls -la /Library/Audio/Plug-Ins/HAL/确认插件名与官网文档一致。比如 BlackHole 官网明确说插件名是BlackHole.driver,如果看到BlackHole-2ch.driver或BlackHole-16ch.driver,立刻卸载——那是非官方魔改版。
4.2 卸载时:执行“双清”动作,缺一不可
卸载任何音频工具,必须做两件事:
- 运行官方卸载程序(如果有):比如 Loopback 自带
Uninstall Loopback.app,必须双击运行; - 手动清理残留插件:即使卸载程序声称“已清理”,也要去
/Library/Audio/Plug-Ins/HAL/目录下,用ls -la检查插件文件是否还在。如果还在,sudo rm -rf 插件名.driver。
我曾帮一家设计工作室处理过集体音频故障。他们用的是一款叫 “Audio Hijack” 的工具,卸载后设备列表还是有 5 个Hijack Audio条目。查日志发现,它的卸载程序只删了~/Library/Application Support/下的配置,却漏掉了/Library/Audio/Plug-Ins/HAL/HijackAudio.driver。手动删掉这个文件,问题立刻解决。
4.3 日常监控:用一行命令,每月自动扫描僵尸
我把前面的find清理脚本,封装成一个日常巡检命令,加到 crontab 里每月执行:
# 创建巡检脚本 /usr/local/bin/hal-scan.sh #!/bin/bash LOG="/var/log/hal-scan.log" echo "$(date): 开始 HAL 僵尸插件扫描" >> $LOG sudo find /Library/Audio/Plug-Ins/HAL/ -name "*.driver" -type d -exec bash -c ' for dir; do if ! ls -A "$dir/Contents/MacOS/" 2>/dev/null | grep -qE "^[^\.]"; then echo "发现僵尸插件: $(basename "$dir")" >> /var/log/hal-scan.log fi done ' _ {} + >> $LOG然后添加定时任务:
# 每月 1 号凌晨 2 点执行 0 2 1 * * /usr/local/bin/hal-scan.sh日志里一旦出现发现僵尸插件,我就知道该手动清理了。这比等用户投诉“声音不对”再处理,效率高十倍。
最后分享一个血泪教训:千万别在
coreaudiod运行时,用 Finder 的“移到废纸篓”功能删.driver文件。Finder 会把它移到~/.Trash/,而coreaudiod仍在读取这个路径。下次重启,它会尝试加载废纸篓里的插件,导致服务启动失败。必须用sudo rm -rf彻底删除,不留痕迹。
5. 当清理失败时:coreaudiod 启动异常的完整排错链路
即使严格按三步法操作,偶尔也会遇到coreaudiod重启失败,表现为:
- 「声音设置」里设备列表为空白;
- 终端执行
sudo launchctl kickstart后,ps aux | grep coreaudiod显示进程立即退出; - 系统日志里出现
Failed to load HAL plugin或Invalid Mach-O magic number错误。
这不是操作失误,而是 HAL 插件注册表(/var/db/audio/下的缓存)损坏了。别重装系统,按以下链路一步步排查:
5.1 第一步:确认错误来源——读取系统日志
coreaudiod的详细日志在console.app里,但终端更快:
# 实时查看 coreaudiod 日志(需先启动服务) sudo log stream --predicate 'subsystem == "com.apple.audio.coreaudiod"' --info # 或查看最近 100 行历史日志 sudo log show --predicate 'subsystem == "com.apple.audio.coreaudiod"' --last 24h --info | tail -100重点关注Failed to load后面的插件路径。比如日志显示:
Failed to load HAL plugin at /Library/Audio/Plug-Ins/HAL/SomePlugin.driver: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0."这说明SomePlugin.driver/Contents/Info.plist文件损坏(可能是 UTF-8 BOM 头或格式错误)。立刻去该路径,用plutil -lint SomePlugin.driver/Contents/Info.plist验证。如果报错,用nano或vim手动修复 plist 格式,或直接删掉整个插件。
5.2 第二步:重置 HAL 缓存——终极保险方案
如果日志没线索,或修复 plist 后仍失败,说明/var/db/audio/下的缓存库已腐坏。这是 Core Audio 的设备注册中心,相当于 HAL 的“大脑”。重置它:
# 停止服务 sudo killall -TERM coreaudiod # 备份原缓存(重要!) sudo cp -r /var/db/audio/ /var/db/audio-backup-$(date +%Y%m%d) # 删除缓存(系统会自动重建) sudo rm -rf /var/db/audio/ # 重启服务 sudo launchctl kickstart -k system/com.apple.audio.coreaudiod执行后,coreaudiod会重新扫描/Library/Audio/Plug-Ins/HAL/和~/Library/Audio/Plug-Ins/HAL/,只加载有效的插件,生成全新的缓存。设备列表会恢复为“出厂状态”——只有物理设备,所有虚拟设备需重新配置。
注意:重置缓存后,你之前创建的 Aggregate Device、Multi-Output Device 全部丢失,需要手动重建。所以
cp -r备份这一步绝不能省。
5.3 第三步:验证硬件抽象层完整性——用 Apple 官方工具
如果以上都无效,可能是 HAL 框架本身损坏。macOS 提供了aurora工具(隐藏在 Xcode Command Line Tools 中)来诊断:
# 确保已安装 Command Line Tools xcode-select --install # 检查 HAL 状态 /usr/bin/aurora -d # 输出应包含 "HAL is healthy" 或类似健康声明 # 如果显示 "HAL initialization failed",说明系统文件损坏 # 此时需运行:sudo xcode-select --reset,再重试aurora是 Apple 内部用的 HAL 调试工具,普通用户很少接触。但它能绕过coreaudiod,直接与 HAL 内核交互,是判断问题是否出在系统层的金标准。
我遇到过一次极端案例:一台 M1 Mac 在重装 macOS 后,coreaudiod死活启动不了。aurora -d显示HAL version mismatch。最终发现是重装时用了错误的恢复镜像(macOS 12.3 镜像装在 12.6 系统上),导致/usr/lib/libAudioToolbox.dylib版本不匹配。解决方案是用正确版本的镜像重装——但这个结论,只有aurora能给出。
所以,当所有常规手段失效时,记住:aurora是你最后一张牌。它不修 bug,但它能告诉你 bug 究竟在哪儿。