This is fairly simple (I think). I\'m simply wanting to get a notification in my application whenever a user changes the default sound input or sound output device in System Pr
Here's how to do it in Swift:
Register for notifications by adding a listener block, for example when a View Controller loads its view. The addListenerBlock
function simplifies adding property listener blocks. Swift allows parameters to be variables, which is very convenient for the forPropertyAddress
parameter. When calling addListenerBlock
, the property address parameters are just plugged in.
import Cocoa
import CoreAudio
class ViewController: NSViewController {
// Utility function to simplify adding listener blocks:
func addListenerBlock( listenerBlock: AudioObjectPropertyListenerBlock, onAudioObjectID: AudioObjectID, var forPropertyAddress: AudioObjectPropertyAddress) {
if (kAudioHardwareNoError != AudioObjectAddPropertyListenerBlock(onAudioObjectID, &forPropertyAddress, nil, listenerBlock)) {
print("Error calling: AudioObjectAddPropertyListenerBlock") }
}
override func viewDidLoad() { super.viewDidLoad()
addListenerBlock(audioObjectPropertyListenerBlock,
onAudioObjectID: AudioObjectID(bitPattern: kAudioObjectSystemObject),
forPropertyAddress: AudioObjectPropertyAddress(
mSelector: kAudioHardwarePropertyDefaultOutputDevice,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster))
}
...
Provide a listener block function to receive the notifications. You're given an array that could potentially have more than one property address, so loop through and look for the one you want:
func audioObjectPropertyListenerBlock (numberAddresses: UInt32, addresses: UnsafePointer) {
var index: UInt32 = 0
while index < numberAddresses {
let address: AudioObjectPropertyAddress = addresses[0]
switch address.mSelector {
case kAudioHardwarePropertyDefaultOutputDevice:
let deviceID = getDefaultAudioOutputDevice()
print("kAudioHardwarePropertyDefaultOutputDevice: \(deviceID)")
default:
print("We didn't expect this!")
}
index += 1
}
// Utility function to get default audio output device:
func getDefaultAudioOutputDevice () -> AudioObjectID {
var devicePropertyAddress = AudioObjectPropertyAddress(mSelector: kAudioHardwarePropertyDefaultOutputDevice, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster)
var deviceID: AudioObjectID = 0
var dataSize = UInt32(truncatingBitPattern: sizeof(AudioDeviceID))
let systemObjectID = AudioObjectID(bitPattern: kAudioObjectSystemObject)
if (kAudioHardwareNoError != AudioObjectGetPropertyData(systemObjectID, &devicePropertyAddress, 0, nil, &dataSize, &deviceID)) { return 0 }
return deviceID
}
}
Of course, you can simply add more cases
to the switch
statement if you want to monitor other audio device properties. Call addListenerBlock
to add whatever devices and property addresses you're interested in.