如何在macOS上列出可用AirPlay输出设备?Ventura适配方案求助
获取Ventura系统下的AirPlay音频输出设备列表
我需要获取可用的AirPlay音频输出设备列表,对编程语言没有限制。在Ventura系统之前,我使用以下AppleScript代码实现该功能:
set devices to {} tell application "System Preferences" reveal pane id "com.apple.preference.sound" end tell tell application "System Events" tell application process "System Preferences" repeat until exists tab group 1 of window "Sound" end repeat tell tab group 1 of window "Sound" click radio button "Output" tell table 1 of scroll area 1 set selected_row to (first UI element whose selected is true) set currentOutput to value of text field 1 of selected_row as text repeat with r in rows try set deviceName to value of text field 1 of r as text set deviceType to value of text field 2 of r as text set end of devices to { deviceName, deviceType } end try end repeat end tell end tell end tell end tell if application "System Preferences" is running then tell application "System Preferences" to quit end if return [ devices, "currentOutput", currentOutput ]
但升级到Ventura后,该脚本失效,且无法调整适配。请问如何更新脚本适配Ventura,或者提供Swift/Objective-C的实现方案及相关说明?
解决方案1:适配Ventura的AppleScript脚本
Ventura系统中,声音偏好设置的UI结构和应用名称都有变化,以下是更新后的可用脚本:
set devices to {} set currentOutput to "" tell application "System Settings" activate reveal pane id "com.apple.preference.sound" end tell tell application "System Events" tell application process "System Settings" -- 等待声音设置界面加载完成 repeat until exists group 1 of window "Sound" delay 0.1 end repeat tell window "Sound" -- 切换到输出标签页 click radio button "Output" of group 1 -- 获取设备列表的滚动区域 tell scroll area 1 of group 1 -- 获取当前选中的设备 set selectedRow to first row of table 1 whose selected is true set currentOutput to value of text field 1 of selectedRow as text -- 遍历所有设备行 repeat with r in rows of table 1 try set deviceName to value of text field 1 of r as text set deviceType to value of text field 2 of r as text set end of devices to {deviceName, deviceType} end try end repeat end tell end tell end tell end tell -- 关闭系统设置 if application "System Settings" is running then tell application "System Settings" to quit end if return {devices, "currentOutput", currentOutput}
关键调整点
- 原
System Preferences替换为Ventura新的System Settings应用 - 界面控件层级变更,原
tab group改为group,控件路径对应更新 - 增加短延迟确保界面加载完成,避免因加载速度导致的脚本执行失败
解决方案2:使用CoreAudio框架(Swift实现)
如果UI自动化的AppleScript不够稳定,推荐直接使用系统原生的CoreAudio框架获取设备列表,这种方式无需依赖UI界面,更可靠。
import CoreAudio func getAudioOutputDevices() -> [(name: String, type: String, isAirPlay: Bool)] { var devices: [(name: String, type: String, isAirPlay: Bool)] = [] var address = AudioObjectPropertyAddress( mSelector: kAudioHardwarePropertyDevices, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster ) var size = UInt32(MemoryLayout<AudioDeviceID>.stride) var count: UInt32 = 0 // 获取设备总数 guard AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &count) == noErr else { return devices } var deviceIDs = [AudioDeviceID](repeating: 0, count: Int(count)) size = count * UInt32(MemoryLayout<AudioDeviceID>.stride) // 获取所有设备ID guard AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &size, &deviceIDs) == noErr else { return devices } for deviceID in deviceIDs { // 检查是否为输出设备 var isOutput = false var outputSize = UInt32(MemoryLayout<Bool>.stride) address.mSelector = kAudioDevicePropertyStreamConfiguration address.mScope = kAudioDevicePropertyScopeOutput if AudioObjectGetPropertyDataSize(deviceID, &address, 0, nil, &outputSize) == noErr { isOutput = true } guard isOutput else { continue } // 获取设备名称 var name = [UInt8](repeating: 0, count: 256) size = UInt32(name.count) address.mSelector = kAudioDevicePropertyDeviceNameCFString guard AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &name) == noErr else { continue } let deviceName = String(cString: name) // 判断是否为AirPlay设备 var isAirPlay = false address.mSelector = kAudioDevicePropertyTransportType var transportType = AudioDeviceTransportType() size = UInt32(MemoryLayout<AudioDeviceTransportType>.stride) if AudioObjectGetPropertyData(deviceID, &address, 0, nil, &size, &transportType) == noErr { isAirPlay = transportType == kAudioDeviceTransportTypeAirPlay } // 生成设备类型描述 let deviceType = isAirPlay ? "AirPlay" : "本地设备" devices.append((name: deviceName, type: deviceType, isAirPlay: isAirPlay)) } return devices } // 使用示例 let outputDevices = getAudioOutputDevices() for device in outputDevices { print("名称: \(device.name), 类型: \(device.type), 是否AirPlay: \(device.isAirPlay)") }
核心说明
- CoreAudio是系统原生音频框架,直接与硬件交互,稳定性远高于UI自动化
- 通过
kAudioDevicePropertyTransportType属性可直接判断设备是否为AirPlay类型 - 无需申请辅助功能权限(AppleScript的UI自动化需要用户授权)
- 项目中需导入
CoreAudio框架才能编译运行
内容的提问来源于stack exchange,提问作者Fez Vrasta
相关产品推荐
相关产品推荐

