如何在系统偏好设置默认声音更改时获得通知

8
这很简单(我想)。我只是想在我的应用程序中得到一个通知,每当用户在“系统偏好设置 - 声音”中更改默认的声音输入或声音输出设备。但是,我真的找不到苹果文档中的相关信息。
另外说一下,这是针对OSX而不是IOS的。
谢谢!

尝试使用搜索 (https://dev59.com/u1nUa4cB1Zd3GeqPZ2KN)。 - toohtik
当默认的声音输入或输出设备选择更改时,这种方法就不起作用了。它非常适用于检测音量级别,但不适合检测设备选择更改。 - Chuck D
2个回答

8

为默认输出设备设置AudioObjectPropertyAddress

AudioObjectPropertyAddress outputDeviceAddress = {
    kAudioHardwarePropertyDefaultOutputDevice,
    kAudioObjectPropertyScopeGlobal,
    kAudioObjectPropertyElementMaster
};

接下来使用AudioObjectAddPropertyListener为默认设备注册监听器:

AudioObjectAddPropertyListener(kAudioObjectSystemObject, 
                                 &outputDeviceAddress,
                                 &callbackFunction, nil);

回调函数长这样:
OSStatus callbackFunction(AudioObjectID inObjectID, 
                            UInt32 inNumberAddresses,
                            const AudioObjectPropertyAddress inAddresses[],             
                            void *inClientData)

作为一个附注,你还应该使用AudioObjectPropertyAddress来告诉HAL管理自己的线程以进行通知。通过将运行循环选择器设置为NULL来实现此操作。实际上,在设置输出设备侦听器之前,我会执行这个步骤。
AudioObjectPropertyAddress runLoopAddress = {
    kAudioHardwarePropertyRunLoop, 
    kAudioObjectPropertyScopeGlobal,
    kAudioObjectPropertyElementMaster
};

CFRunLoopRef runLoop = NULL;
UInt32 size = sizeof(CFRunLoopRef);
AudioObjectSetPropertyData(kAudioObjectSystemObject, 
                            &runLoopAddress, 0, NULL, size, &runLoop);

8
这是如何在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<AudioObjectPropertyAddress>) {
    
          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
         }
    
    }
    
当然,如果您想监控其他音频设备属性,您可以简单地在switch语句中添加更多的cases。调用addListenerBlock来添加您感兴趣的任何设备和属性地址。

在这一行 let address: AudioObjectPropertyAddress = addresses[0] 你是不是想用 index 而不是 0 - GW.Rodriguez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接