【问题标题】:How to get notification if System Preferences Default Sound changed如果系统偏好设置默认声音发生更改,如何获得通知
【发布时间】:2014-09-27 00:20:16
【问题描述】:

这很简单(我认为)。每当用户更改系统偏好设置 - 声音中的默认声音输入或声音输出设备时,我只是想在我的应用程序中收到通知。但是,如果我能够从 Apple 文档中挖掘出来,那我就完蛋了。

附带说明,这是针对 OSX,而​​不是 IOS。

谢谢大家!

【问题讨论】:

  • 当默认声音输入或输出设备选择改变时,这不起作用。非常适合检测音量水平,不适用于检测设备选择变化。

标签: macos cocoa notifications core-audio


【解决方案1】:

为默认输出设备设置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);

【讨论】:

    【解决方案2】:

    以下是在 Swift 中的操作方法:

    1. 通过添加侦听器块来注册通知,例如当视图控制器加载其视图时。 addListenerBlock 函数简化了添加属性侦听器块的过程。 Swift允许参数为变量,这对于forPropertyAddress参数来说非常方便。调用addListenerBlock时,只是插入了属性地址参数。

      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. 提供一个监听块函数来接收通知。你得到了一个可能有多个属性地址的数组,所以循环并寻找你想要的:

         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 吗?
    猜你喜欢
    • 2018-02-19
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 2013-08-17
    相关资源
    最近更新 更多