Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I register for a notification for then the sound volume changes?

I need my app to be notified when the OS X sound volume has changed. This is for a Desktop app, not for iOS. How can I register for this notification?

like image 703
dan Avatar asked Jul 19 '11 12:07

dan


1 Answers

This can be a tiny bit tricky because some audio devices support a master channel, but most don't so the volume will be a per-channel property. Depending on what you need to do you could observe only one channel and assume that all other channels the device supports have the same volume. Regardless of how many channels you want to watch, you observe the volume by registering a property listener for the AudioObject in question:

// Some devices (but not many) support a master channel
AudioObjectPropertyAddress propertyAddress = { 
    kAudioDevicePropertyVolumeScalar, 
    kAudioDevicePropertyScopeOutput,
    kAudioObjectPropertyElementMaster 
};

if(AudioObjectHasProperty(deviceID, &propertyAddress)) {
    OSStatus result = AudioObjectAddPropertyListener(deviceID, &propertyAddress, myAudioObjectPropertyListenerProc, self);
    // Error handling omitted
}
else {
    // Typically the L and R channels are 1 and 2 respectively, but could be different
    propertyAddress.mElement = 1;
    OSStatus result = AudioObjectAddPropertyListener(deviceID, &propertyAddress, myAudioObjectPropertyListenerProc, self);
    // Error handling omitted

    propertyAddress.mElement = 2;
    result = AudioObjectAddPropertyListener(deviceID, &propertyAddress, myAudioObjectPropertyListenerProc, self);
    // Error handling omitted
}

Your listener proc should be something like:

static OSStatus
myAudioObjectPropertyListenerProc(AudioObjectID                         inObjectID,
                                  UInt32                                inNumberAddresses,
                                  const AudioObjectPropertyAddress      inAddresses[],
                                  void                                  *inClientData)
{
    for(UInt32 addressIndex = 0; addressIndex < inNumberAddresses; ++addressIndex) {
        AudioObjectPropertyAddress currentAddress = inAddresses[addressIndex];

        switch(currentAddress.mSelector) {
            case kAudioDevicePropertyVolumeScalar:
            {
                Float32 volume = 0;
                UInt32 dataSize = sizeof(volume);
                OSStatus result = AudioObjectGetPropertyData(inObjectID, &currentAddress, 0, NULL, &dataSize, &volume);

                if(kAudioHardwareNoError != result) {
                    // Handle the error
                    continue;
                }

                // Process the volume change

                break;
            }
        }
    }
}
like image 106
sbooth Avatar answered Sep 18 '22 22:09

sbooth