Larry Osterman's WebLog

Confessions of an Old Fogey
Blog - Title

How do I change the master volume in Windows Vista

How do I change the master volume in Windows Vista

  • Comments 32

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.

#include <stdio.h>
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>

void Usage()
{
  printf("Usage: \n");
  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[])
{
  HRESULT hr;
  bool decibels = false;
  bool scalar = false;
  double newVolume;
  if (argc != 3 && argc != 1)
  {
    Usage();
    return -1;
  }
  if (argc == 3)
  {
    if (argv[1][0] == '-')
    {
      if (argv[1][1] == 'f')
      {
        scalar = true;
      }
      else if (argv[1][1] == 'd')
      {
        decibels = true;
      }
    }
    else
    {
      Usage();
      return -1;
    }

    newVolume = _tstof(argv[2]);
  }

  // -------------------------
  CoInitialize(NULL);
  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->Release();
  deviceEnumerator = NULL;

  IAudioEndpointVolume *endpointVolume = NULL;
  hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
  defaultDevice->Release();
  defaultDevice = NULL; 

  // -------------------------
  float currentVolume = 0;
  endpointVolume->GetMasterVolumeLevel(&currentVolume);
  printf("Current volume in dB is: %f\n", currentVolume);

  hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
  printf("Current volume as a scalar is: %f\n", currentVolume);
  if (decibels)
  {
    hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
  }
  else if (scalar)
  {
    hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
  }
  endpointVolume->Release();

  CoUninitialize();
  return 0;
}

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.

  • Nike, I'm not sure - I'd go looking for the KSJACK_DESCRIPTION definition and see what's up.

  • Hi Larry,

    I add the Vista SDK to my visual studio environment(Tools/Options/Projects and Solutions/vc++ Directories/Show directories for/Include files,,add c:\program files\microsoft SDKs\Windows\v6.0\include).

    i do at this in my stdafx.h file.

    #define NTDDI_VERSION  NTDDI_LONGHORN

    Or

    #define NTDDI_VERSION  NTDDI_VISTA

    but,

    c:\program files\microsoft sdks\windows\v6.0\include\shtypes.h(450) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

    c:\program files\microsoft sdks\windows\v6.0\include\propsys.h(438) : error C2061: syntax error : identifier 'REFPROPVARIANT'

    VistaVolume - 22 error(s), 0 warning(s)

    Can you help me ?Thanks.

Page 3 of 3 (32 items) 123