Im trying to direct audio from a MacOS application I've written in SWIFT directly to air play speakers.
I can direct audio to onboard sound outputs or say a USB DAC no problems. I can get audio device ids for say a connected USB DAC and direct audio specifically to that fine within my application but having trouble finding good samples/docs on doing it to airplay speakers with SWIFT/AVPLAYER.
Anyone seen any good docs / code samples on directing audio from a macOS (not ios) swift application to airplay speakers directly? i.e. how to get a list of airplay audio device ids and send output to them from avplayer?
For directing sound output to say a USB DAC I can get a list of playback audio device ids with this function -
func getOutputDevices() -> [AudioDevice] {
print_log ("")
print_log("+++ START AUDIO PLAYBACK DEVICES FOUND....")
print_log ("")
for device in AudioDevice.allOutputDevices() {
print("DEVICE NAME: " + device.name + " -> DEVICE ID: " + String(device.uid ?? "Empty Device"))
}
print_log ("")
print_log("+++ END AUDIO PLAYBACK DEVICES FOUND....")
print_log ("")
return AudioDevice.allOutputDevices()
}
and then play audio to one of those returned audio devices like so using avplayer and setting the audio audioOutputDeviceUniqueID -
print_log("Setting audio output device to " + String(playback_device.uid ?? "Empty"))
gbl_queue_player.audioOutputDeviceUniqueID=playback_device.uid
gbl_queue_player.addObserver(stage, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
gbl_queue_player.addObserver(stage, forKeyPath: "rate", options: NSKeyValueObservingOptions.new, context: nil)
gbl_queue_player.addObserver(stage, forKeyPath:"currentItem", options:NSKeyValueObservingOptions.new, context:nil)
gbl_queue_player.play()
I hope that all makes sense. Ive found some docs pertaining to IOS but not MacOS.
Thanks!
EDIT 01/07/2020
Gave this a try with the code below to instantiate a AVRoutePicker on button press.
GOOD NEWS: the picker appears and the builtin speakers are listed as an option.
BAD NEWS: No confirmed airplay devices, or USB DACs on my system show this way but they do in OS' sound picker.
@IBAction func airplay_button_clicked(_ sender: Any)
{
let frame = CGRect(x: 50, y: 50, width: 100, height: 50)
gbl_routePickerView = AVRoutePickerView(frame: frame)
view.addSubview(gbl_routePickerView) }
}
There's no sandboxing on this application.
*** EDIT SOLUTION 01/06/2020
As pointed out by Jon a player must be assigned to the route pickers player property
so the function for me became ....
@IBAction func airplay_button_clicked(_ sender: Any) {
print_log("Airplay button clicked")
let frame = CGRect(x: 50, y: 50, width: 100, height: 50)
if #available(OSX 10.15, *) {
gbl_routePickerView = AVRoutePickerView(frame: frame)
gbl_routePickerView.player=gbl_queue_player
view.addSubview(gbl_routePickerView)
} else {
// Fallback on earlier versions
print_log("OS Does not support avroute picker.")
}
}
Instantiate an AVRoutePickerView
in your view hierarchy then assign your AVPlayer
instance to the AVRoutePickerView
's player
property. You'll then have a GUI for choosing the AirPlay route(s) for your AVPlayer
.