Question

I am looking to incorporate a NSSlider in a Cocoa application that controls the master volume of a Mac. I do not want to do this through AppleScript though, even though I know it is probably easier.

I found this code that should be able to do the trick but does not because since 10.5 AudioDeviceGetProperty and its ilk have been deprecated. What needs to be changed to make this work?

- (float) getVolume 
{
float            b_vol;
OSStatus        err;
AudioDeviceID        device;
UInt32            size;
UInt32            channels[2];
float            volume[2];

// get device
size = sizeof device;
err = AudioObjectGetPropertyData(kAudioHardwarePropertyDefaultOutputDevice, &device, <#UInt32 inQualifierDataSize#>, <#const void *inQualifierData#>, &size, <#void *outData#>);
if(err!=noErr) 
{
    NSLog(@"audio-volume error get device");
    return 0.0;
}

// try set master volume (channel 0)
size = sizeof b_vol;
err = AudioDeviceGetProperty(device, 0, 0, kAudioDevicePropertyVolumeScalar, &size, &b_vol);    //kAudioDevicePropertyVolumeScalarToDecibels
if(noErr==err) return b_vol;

// otherwise, try seperate channels
// get channel numbers
size = sizeof(channels);
err = AudioDeviceGetProperty(device, 0, 0,kAudioDevicePropertyPreferredChannelsForStereo, &size,&channels);
if(err!=noErr) NSLog(@"error getting channel-numbers");

size = sizeof(float);
err = AudioDeviceGetProperty(device, channels[0], 0, kAudioDevicePropertyVolumeScalar, &size, &volume[0]);
if(noErr!=err) NSLog(@"error getting volume of channel %d",channels[0]);
err = AudioDeviceGetProperty(device, channels[1], 0, kAudioDevicePropertyVolumeScalar, &size, &volume[1]);
if(noErr!=err) NSLog(@"error getting volume of channel %d",channels[1]);

b_vol = (volume[0]+volume[1])/2.00;

return  b_vol;
}

- (void)setVolume:(float)involume {
OSStatus        err;
AudioDeviceID        device;
UInt32            size;
Boolean            canset    = false;
UInt32            channels[2];
//float            volume[2];

// get default device
size = sizeof device;
printf("setVolume:: value of the volume set =%lf", involume);
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
if(err!=noErr) {
    NSLog(@"audio-volume error get device");
    return;
}


// try set master-channel (0) volume
size = sizeof canset;
err = AudioDeviceGetPropertyInfo(device, 0, false, kAudioDevicePropertyVolumeScalar, &size, &canset);
if(err==noErr && canset==true) {
    size = sizeof involume;
    err = AudioDeviceSetProperty(device, NULL, 0, false, kAudioDevicePropertyVolumeScalar, size, &involume);
    return;
}

// else, try seperate channes
// get channels
size = sizeof(channels);
err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size,&channels);
if(err!=noErr) {
    NSLog(@"error getting channel-numbers");
    return;
}

// set volume
size = sizeof(float);
err = AudioDeviceSetProperty(device, 0, channels[0], false, kAudioDevicePropertyVolumeScalar, size, &involume);
if(noErr!=err) NSLog(@"error setting volume of channel %d",channels[0]);
err = AudioDeviceSetProperty(device, 0, channels[1], false, kAudioDevicePropertyVolumeScalar, size, &involume);
if(noErr!=err) NSLog(@"error setting volume of channel %d",channels[1]);

}

Thanks in advance!

Was it helpful?

Solution

This will do the trick - I just copied and pasted it out of one of my projects, so there are a few extraneous variables and functions but you should be able to get the gist of it:

BOOL gotMaster = NO;
BOOL gotLeft = NO;
BOOL gotRight = NO;
float volume = 1, lvolume = 1, rvolume = 1;
float inVolume = 1, inLvolume = 1, inRvolume = 1;
OSStatus result = noErr;
AudioObjectPropertyAddress thePropertyAddress;
UInt32 thePropSize = sizeof(Float32);
thePropertyAddress.mSelector = kAudioDevicePropertyVolumeScalar;
thePropertyAddress.mScope = kAudioDevicePropertyScopeOutput;    
thePropertyAddress.mElement = kAudioObjectPropertyElementMaster;
// see if the device supports volume control, if so, then get it
if (AudioObjectHasProperty(_targetDevice, &thePropertyAddress)) {
  result = AudioObjectGetPropertyData(_targetDevice, &thePropertyAddress, 0, NULL, &thePropSize, &volume);
  if (result) { cwlog("AudioDeviceManager: Error in AudioObjectGetPropertyData: %d", result); return -1; }
  gotMaster = YES;
} else {
  cwlog("AudioDeviceManager: The target device does not support getting the master volume");
}
// see if the device supports left channel volume control, if so, then get it
thePropertyAddress.mElement = 1;
if (AudioObjectHasProperty(_targetDevice, &thePropertyAddress)) {
  result = AudioObjectGetPropertyData(_targetDevice, &thePropertyAddress, 0, NULL, &thePropSize, &lvolume);
  if (result) { cwlog("AudioDeviceManager: Error in AudioObjectGetPropertyData: %d", result); return -1; }
  gotLeft = YES;
} else {
  cwlog("AudioDeviceManager: The target device does not support getting the left channel volume");
}
thePropertyAddress.mElement = 2;
// see if the device supports right channel volume control, if so, then get it
if (AudioObjectHasProperty(_targetDevice, &thePropertyAddress)) {
  result = AudioObjectGetPropertyData(_targetDevice, &thePropertyAddress, 0, NULL, &thePropSize, &rvolume);
  if (result) { cwlog("AudioDeviceManager: Error in AudioObjectGetPropertyData: %d", result); return -1; }
  gotRight = YES;
} else {
  // if the device does not support master volume control, do nothing
  cwlog("AudioDeviceManager: The target device does not support getting the right channel volume");
}
if(!gotMaster && !gotLeft && !gotRight) {
  cwlog("AudioDeviceManager: Could not get any volume settings for %s (%u)", [[self nameOfDevice:_targetDevice] UTF8String], _targetDevice);
  return -1;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top