It's actually easier in Vista than it was in XP. For Vista, we recognized that one of the key customer scenarios was going to be setting the master volume, and since we'd removed the old mechanism that was used to set the volume, we knew we had to provide an easier mechanism for Vista.
Just for grins, I threw together a tiny app that demonstrates it. To save space, all error checking was removed.
printf(" SetVolume [Reports the current volume]\n");
printf(" SetVolume -d <new volume in decibels> [Sets the current default render device volume to the new volume]\n");
printf(" SetVolume -f <new volume as an amplitude scalar> [Sets the current default render device volume to the new volume]\n");
int _tmain(int argc, _TCHAR* argv)
bool decibels = false;
bool scalar = false;
if (argc != 3 && argc != 1)
if (argc == 3)
if (argv == '-')
if (argv == 'f')
scalar = true;
else if (argv == 'd')
decibels = true;
newVolume = _tstof(argv);
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator = NULL;
IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
defaultDevice = NULL;
float currentVolume = 0;
printf("Current volume in dB is: %f\n", currentVolume);
hr = endpointVolume->GetMasterVolumeLevelScalar(¤tVolume);
printf("Current volume as a scalar is: %f\n", currentVolume);
hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
else if (scalar)
hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
This program has essentially 3 parts. The first parses the command line, the second retrieves an endpoint volume interface on the default endpoint, the third retrieves the current volume and sets the volume.
I'm going to ignore the first part, it's the same junk you'll see in any CS 101 class.
The second part instantiates an MMDeviceEnumerator object which implements the IMMDeviceEnumerator interface. The IMMDeviceEnumerator interface is the gateway object to the new audio subsystem - it can be used to enumerate audio endpoints and retrieve information about the various endpoints. In this case, I'm only interested in the GetDefaultAudioEndpoint method, it returns an IMMDevice object that points to the current endpoint.
Again, there are a bunch of things I can do with an IMMDevice object, but I'm only really interested in the "Activate" method. The idea is that each MMDevice object supports lots of different interfaces, you "Activate" the interface to access the functionality associated with that object. Again, in this case, I'm only interested in the IAudioEndpointVolume interface - there are other interfaces, like IDeviceTopology, and IAudioClient that can be activated from the endpoint.
The IAudioEndpointVolume interface is where the good stuff lives, right now I'm only interested in four methods, which retrieve (and set) the current endpoint volume in either decibels or as a scalar value.
The decibels version of the IAudioEndointVolume interface instructs the driver to set the desired master volume (input or output) to the decibel value specified, it's intended to be used for applications that want to have exact control over the output dB value of the audio solution.
The scalar version is a bit more complicated. It's intended for use in applications that have volume sliders, and provides a linear volume taper (represented as a floating point value between 0.0 and 1.0). In other words, the perceived volume when you set the scalar version of the API to .5 is twice as loud as when set to .25 and is half as loud as when set to 1.0.