You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 22:55:18