Search code examples
objective-cosx-mountain-lioncore-audio

Change OS X system volume programmatically


How can I change the volume programmatically from Objective-C?

I found this question, Controlling OS X volume in Snow Leopard which suggests to do:

Float32 volume = 0.5;
UInt32 size = sizeof(Float32);

AudioObjectPropertyAddress address = {
    kAudioDevicePropertyVolumeScalar,
    kAudioDevicePropertyScopeOutput,
    1 // Use values 1 and 2 here, 0 (master) does not seem to work
};

OSStatus err;
err = AudioObjectSetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, size, &volume);
NSLog(@"status is %i", err);

This does nothing for me, and prints out status is 2003332927.

I also tried using values 2 and 0 in the address structure, same result for both.

How can I fix this and make it actually decrease the volume to 50%?


Solution

  • You need to get the default audio device first:

    #import <CoreAudio/CoreAudio.h>
    
    AudioObjectPropertyAddress getDefaultOutputDevicePropertyAddress = {
      kAudioHardwarePropertyDefaultOutputDevice,
      kAudioObjectPropertyScopeGlobal,
      kAudioObjectPropertyElementMaster
    };
    
    AudioDeviceID defaultOutputDeviceID;
    UInt32 volumedataSize = sizeof(defaultOutputDeviceID);
    OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
                                                 &getDefaultOutputDevicePropertyAddress,
                                                 0, NULL,
                                                 &volumedataSize, &defaultOutputDeviceID);
    
    if(kAudioHardwareNoError != result)
    {
      // ... handle error ...
    }
    

    You can then set your volume on channel 1 (left) and channel 2 (right). Note that channel 0 (master) does not seem to be supported (the set command returns 'who?')

    AudioObjectPropertyAddress volumePropertyAddress = {
      kAudioDevicePropertyVolumeScalar,
      kAudioDevicePropertyScopeOutput,
      1 /*LEFT_CHANNEL*/
    };
    
    Float32 volume;
    volumedataSize = sizeof(volume);
    
    result = AudioObjectSetPropertyData(defaultOutputDeviceID,
                                        &volumePropertyAddress,
                                        0, NULL,
                                        sizeof(volume), &volume);
    if (result != kAudioHardwareNoError) {
      // ... handle error ...
    }
    

    Hope this answers your question!