Change OS X system volume programmatically

醉酒当歌 提交于 2019-12-01 08:28:11

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!

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.

You could run a bash script that will change the master volume. This prevents setting the audio first to one side:

Muted:

execlp("osascript", "osascript", "-e", "set volume output muted true", NULL);

Change volume (scale 0-10):

    execlp("osascript", "osascript", "-e", "set volume 5", NULL);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!