macOS:如何通过命令行或Objective-C/Swift API修改音频MIDI设置?
在macOS程序化调整Audio Midi Setup配置的方案
当然可以!在macOS上完全可以通过命令行或原生Objective-C/Swift API来修改Audio Midi Setup里的设置,包括调整多输出设备的成员组成。下面给你分两种方式详细说明:
一、原生CoreAudio API(Objective-C/Swift)
这是最直接、可控的方式,通过macOS的CoreAudio框架直接操作音频设备配置,完全覆盖Audio Midi Setup能做的所有设置。
核心思路
多输出设备属于**聚合设备(Aggregate Device)**的一种类型(子类型为kAudioSubType_MultiOutput),我们可以通过CoreAudio的属性读写接口来修改它的成员列表:
- 枚举系统中的所有音频设备,定位到目标多输出设备
- 获取该设备的
kAudioDevicePropertyAggregateDeviceList属性(当前成员设备ID列表) - 修改成员列表后,将新列表写回该属性
- 保存系统音频配置,让修改生效
Swift 代码示例
import CoreAudio // 辅助函数:枚举所有音频设备,找到指定名称的多输出设备 func findMultiOutputDevice(named deviceName: String) -> AudioDeviceID? { var address = AudioObjectPropertyAddress( mSelector: kAudioHardwarePropertyDevices, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMain ) var deviceCount: UInt32 = 0 var status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &address, 0, nil, &deviceCount) guard status == noErr else { return nil } let deviceCountInt = Int(deviceCount) var devices = Array(repeating: AudioDeviceID(), count: deviceCountInt) status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, nil, &deviceCount, &devices) guard status == noErr else { return nil } for deviceID in devices { var nameSize: UInt32 = 0 var nameAddress = AudioObjectPropertyAddress( mSelector: kAudioDevicePropertyDeviceNameCFString, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMain ) status = AudioObjectGetPropertyDataSize(deviceID, &nameAddress, 0, nil, &nameSize) guard status == noErr else { continue } var deviceNameCF: CFString? status = AudioObjectGetPropertyData(deviceID, &nameAddress, 0, nil, &nameSize, &deviceNameCF) guard let name = deviceNameCF as String?, name == deviceName else { continue } // 验证是否为多输出设备 var subTypeSize: UInt32 = UInt32(MemoryLayout<AudioDeviceID>.stride) var subTypeAddress = AudioObjectPropertyAddress( mSelector: kAudioDevicePropertyDeviceSubType, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMain ) var subType = AudioDeviceID() status = AudioObjectGetPropertyData(deviceID, &subTypeAddress, 0, nil, &subTypeSize, &subType) if subType == kAudioSubType_MultiOutput { return deviceID } } return nil } // 修改多输出设备的成员列表 func updateMultiOutputMembers(multiOutputName: String, newMemberDeviceIDs: [AudioDeviceID]) -> OSStatus { guard let multiOutputID = findMultiOutputDevice(named: multiOutputName) else { return kAudioHardwareBadDeviceError } var propertySize = UInt32(MemoryLayout<AudioDeviceID>.stride * newMemberDeviceIDs.count) let address = AudioObjectPropertyAddress( mSelector: kAudioDevicePropertyAggregateDeviceList, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMain ) // 写入新的成员列表 var status = AudioObjectSetPropertyData(multiOutputID, &address, 0, nil, propertySize, newMemberDeviceIDs) guard status == noErr else { return status } // 保存系统音频配置,确保修改持久化 let configAddress = AudioObjectPropertyAddress( mSelector: kAudioSystemPropertyConfiguration, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMain ) status = AudioObjectSetPropertyData(kAudioObjectSystemObject, &configAddress, 0, nil, 0, nil) return status } // 使用示例:假设你已经知道要添加的成员设备ID // let memberIDs: [AudioDeviceID] = [0x123, 0x456] // let status = updateMultiOutputMembers(multiOutputName: "我的多输出设备", newMemberDeviceIDs: memberIDs) // print(status == noErr ? "修改成功" : "失败,错误码:\(status)")
注意事项
- 运行这类代码需要辅助功能权限(在「系统设置-隐私与安全性-辅助功能」中给你的应用授权)
- 如果是沙盒应用,还需要开启「音频输入/输出」权限,并且可能无法修改系统级配置,建议在沙盒外运行工具
- 修改配置后,部分应用可能需要重启才能识别到新的多输出设备
二、命令行方式
macOS没有原生的命令行工具直接修改多输出设备成员,但你可以基于上面的CoreAudio API自己编译一个命令行工具,或者使用第三方开源工具。
自制命令行工具
- 用Swift写一个简单的命令行程序,整合上面的代码逻辑
- 通过
swift build -c release编译成可执行文件 - 在终端直接调用该工具,传入多输出设备名称和成员设备ID参数
比如编译后的工具可以这样使用:
./MultiOutputUpdater --name "我的多输出设备" --members 0x123 0x456
第三方工具(可选)
部分开源项目如switchaudio-osx主要用于切换默认音频设备,但如果需要修改多输出设备,还是建议基于CoreAudio自己实现,这样更可控。
额外提示
如果你不确定设备的AudioDeviceID,可以在代码中添加枚举设备并打印ID的逻辑,来获取目标设备的ID。
内容的提问来源于stack exchange,提问作者Bri Bri
相关产品推荐
相关产品推荐

