I have been using CoreAudio to switch the output device for audio output, but this technique is no longer available in macOS 13 Ventura.
How can I switch the output device in Ventura as well?
correct available output devices are
private func availableDevices() -> Array<AudioDeviceID> {
var property: AudioObjectPropertyAddress = AudioObjectPropertyAddress(mSelector: kAudioHardwarePropertyDevices, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster)
var dataSize:UInt32 = 0
let status: OSStatus = AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &property, 0, nil, &dataSize)
var devices:Array<AudioDeviceID> = Array()
if status != kAudioHardwareNoError {
devices = Array()
} else {
let deviceCount: Int = Int(dataSize) / MemoryLayout<AudioDeviceID>.size
var foundDevices: Array<AudioDeviceID> = Array<AudioDeviceID>(repeating: 0, count: deviceCount)
foundDevices.withUnsafeMutableBufferPointer { ( item: inout UnsafeMutableBufferPointer<AudioDeviceID>) -> () in
let error: OSStatus = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &property, 0, nil, &dataSize, item.baseAddress!)
if error != kAudioHardwareNoError { print("each device ID Get Error: \(error)") }
}// end withUnsafeMutableBufferPointer
devices = Array(foundDevices)
}// end if
return devices
}// end availableDevices
And assign output audio device to output node is
internal func assignAudioDeviceTo (engine audioEngine: AVAudioEngine, selector key: SpeechPreferenceKey) {
let output: AVAudioOutputNode = audioEngine.outputNode
if let audioUnit: AudioUnit = output.audioUnit {
let audioDevices: AudioDevices = AudioDevices()
var deviceID: AudioDeviceID = AudioDevices.currentOutputtDevice().deviceID
if let deviceName: String = key.string {
if let device = audioDevices.outputDevices[deviceName]?.deviceID { deviceID = device }
}// end if output device name is defined
let error: OSStatus = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Output, 0, &deviceID, UInt32(MemoryLayout<AudioDeviceID>.size))
if error != noErr {
print("output device can not assign user selected device: \(error)")
}// end if
audioEngine.connect(audioEngine.mainMixerNode, to: output, fromBus: 0, toBus: 0, format: nil)
}// end if output node have audio unit
do {
audioEngine.prepare()
try audioEngine.start()
} catch let error {
print("output device start error: \(error)")
}// end do try - catch start output device engine
}// end func assignAudioDeviceTo
I'm not sure why your method isn't successful, but using
audioEngine.outputNode.auAudioUnit.setDeviceID(deviceID)
works in my testing.