Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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%?

like image 239
houbysoft Avatar asked Jul 18 '13 05:07

houbysoft


2 Answers

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!

like image 59
Thomas O'Dell Avatar answered Oct 28 '22 04:10

Thomas O'Dell


I ran the HALLab utility that comes with the developer tools (i.e. Audio Tools for Xcode). That allows you to open an info window for individual devices and that window has a tab showing notifications. When I change my system volume, I do indeed see that the kAudioDevicePropertyVolumeScalar property changes for each channel of the output device as Thomas O'Dell's answer suggests. However, I also see the property kAudioHardwareServiceDeviceProperty_VirtualMasterVolume change on the master channel. That seems much more promising since you don't have to manually set it for all channels and maintain the balance across them.

You would use the function AudioHardwareServiceSetPropertyData() from Audio Hardware Services to set that on the default output device. To be safe, you might first check that it's settable using AudioHardwareServiceIsPropertySettable().

The documentation for that property says:

kAudioHardwareServiceDeviceProperty_VirtualMasterVolume

A Float32 value that represents the value of the volume control.

The range for this property’s value is 0.0 (silence) through 1.0 (full level). The effect of this property depends on the hardware device associated with the HAL audio object. If the device has a master volume control, this property controls it. If the device has individual channel volume controls, this property applies to those identified by the device's preferred multichannel layout, or the preferred stereo pair if the device is stereo only. This control maintains relative balance between the channels it affects.

like image 45
Ken Thomases Avatar answered Oct 28 '22 05:10

Ken Thomases