How to get notification if System Preferences Default Sound changed

后端 未结 2 396
鱼传尺愫
鱼传尺愫 2021-02-06 16:15

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

2条回答
  •  梦谈多话
    2021-02-06 17:12

    Here's how to do it in Swift:

    1. 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))
         }
      
      ...
      
    2. 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.

提交回复
热议问题