Monday 31 December 2012

Programmatically change the default sound device in Windows 7

I got a new monitor last week and it came with integrated speakers, which I didn't think I would use, but it occurred to me that it would be handy to use these speakers rather than my Logitech 5.1 system when browsing the internet. I normally have the speakers off at the sub woofer for one main reason, the system uses 30 Watts in stand by, which roughly equates to £30 a year in wasted electricity and since I normally use my desktop only to watch movies or TV series this is not a major inconvenience, but sometimes it's annoying. At any rate, I was looking for a way of changing the default  sound device using PowerShell, but it looks like it's not possible, however, it is possible to do it programmatically.

I'm reproducing the code here because I thought it was interesting. This is not my code, the original article can be found here.

PolicyConfig.h:
// ----------------------------------------------------------------------------
// PolicyConfig.h
// Undocumented COM-interface IPolicyConfig.
// Use for set default audio render endpoint
// @author EreTIk
// ----------------------------------------------------------------------------
 
#pragma once
 
interface DECLSPEC_UUID("f8679f50-850a-41cf-9c72-430f290290c8")
IPolicyConfig;
class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9")
CPolicyConfigClient;
// ----------------------------------------------------------------------------
// class CPolicyConfigClient
// {870af99c-171d-4f9e-af0d-e63df40c2bc9}
//
// interface IPolicyConfig
// {f8679f50-850a-41cf-9c72-430f290290c8}
//
// Query interface:
// CComPtr[IPolicyConfig] PolicyConfig;
// PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigClient));
//
// @compatible: Windows 7 and Later
// ----------------------------------------------------------------------------
interface IPolicyConfig : public IUnknown
{
public:
 
    virtual HRESULT GetMixFormat(
        PCWSTR,
        WAVEFORMATEX **
    );
 
    virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
        PCWSTR,
        INT,
        WAVEFORMATEX **
    );
 
    virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
        PCWSTR
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
        PCWSTR,
        WAVEFORMATEX *,
        WAVEFORMATEX *
    );
 
    virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
        PCWSTR,
        INT,
        PINT64,
        PINT64
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
        PCWSTR,
        PINT64
    );
 
    virtual HRESULT STDMETHODCALLTYPE GetShareMode(
        PCWSTR,
        struct DeviceShareMode *
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetShareMode(
        PCWSTR,
        struct DeviceShareMode *
    );
 
    virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
        PCWSTR,
        const PROPERTYKEY &,
        PROPVARIANT *
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
        PCWSTR,
        const PROPERTYKEY &,
        PROPVARIANT *
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
        __in PCWSTR wszDeviceId,
        __in ERole eRole
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
        PCWSTR,
        INT
    );
};
 
interface DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620")
IPolicyConfigVista;
class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862")
CPolicyConfigVistaClient;
// ----------------------------------------------------------------------------
// class CPolicyConfigVistaClient
// {294935CE-F637-4E7C-A41B-AB255460B862}
//
// interface IPolicyConfigVista
// {568b9108-44bf-40b4-9006-86afe5b5a620}
//
// Query interface:
// CComPtr[IPolicyConfigVista] PolicyConfig;
// PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigVistaClient));
//
// @compatible: Windows Vista and Later
// ----------------------------------------------------------------------------
interface IPolicyConfigVista : public IUnknown
{
public:
 
    virtual HRESULT GetMixFormat(
        PCWSTR,
        WAVEFORMATEX **
    );  // not available on Windows 7, use method from IPolicyConfig
 
    virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
        PCWSTR,
        INT,
        WAVEFORMATEX **
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
        PCWSTR,
        WAVEFORMATEX *,
        WAVEFORMATEX *
    );
 
    virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
        PCWSTR,
        INT,
        PINT64,
        PINT64
    );  // not available on Windows 7, use method from IPolicyConfig
 
    virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
        PCWSTR,
        PINT64
    );  // not available on Windows 7, use method from IPolicyConfig
 
    virtual HRESULT STDMETHODCALLTYPE GetShareMode(
        PCWSTR,
        struct DeviceShareMode *
    );  // not available on Windows 7, use method from IPolicyConfig
 
    virtual HRESULT STDMETHODCALLTYPE SetShareMode(
        PCWSTR,
        struct DeviceShareMode *
    );  // not available on Windows 7, use method from IPolicyConfig
 
    virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
        PCWSTR,
        const PROPERTYKEY &,
        PROPVARIANT *
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
        PCWSTR,
        const PROPERTYKEY &,
        PROPVARIANT *
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
        __in PCWSTR wszDeviceId,
        __in ERole eRole
    );
 
    virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
        PCWSTR,
        INT
    );  // not available on Windows 7, use method from IPolicyConfig
};
Console App Code:

#include "stdio.h"
#include "wchar.h"
#include "tchar.h"
#include "windows.h"
#include "Mmdeviceapi.h"
#include "PolicyConfig.h"
#include "Propidl.h"
#include "Functiondiscoverykeys_devpkey.h"
 
HRESULT SetDefaultAudioPlaybackDevice(LPCWSTR devID)
{
 IPolicyConfigVista *pPolicyConfig;
 ERole reserved = eConsole;
 
    HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient),
  NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID *)&pPolicyConfig);
 if (SUCCEEDED(hr))
 {
  hr = pPolicyConfig->SetDefaultEndpoint(devID, reserved);
  pPolicyConfig->Release();
 }
 return hr;
}
 
// EndPointController.exe [NewDefaultDeviceID]
int _tmain(int argc, _TCHAR* argv[])
{
 // read the command line option, -1 indicates list devices.
 int option = -1;
 if (argc == 2) option = atoi((char*)argv[1]);
 
 HRESULT hr = CoInitialize(NULL);
 if (SUCCEEDED(hr))
 {
  IMMDeviceEnumerator *pEnum = NULL;
  // Create a multimedia device enumerator.
  hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
   CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnum);
  if (SUCCEEDED(hr))
  {
   IMMDeviceCollection *pDevices;
   // Enumerate the output devices.
   hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
   if (SUCCEEDED(hr))
   {
    UINT count;
    pDevices->GetCount(&count);
    if (SUCCEEDED(hr))
    {
     for (int i = 0; i < count; i++)
     {
      IMMDevice *pDevice;
      hr = pDevices->Item(i, &pDevice);
      if (SUCCEEDED(hr))
      {
       LPWSTR wstrID = NULL;
       hr = pDevice->GetId(&wstrID);
       if (SUCCEEDED(hr))
       {
        IPropertyStore *pStore;
        hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);
        if (SUCCEEDED(hr))
        {
         PROPVARIANT friendlyName;
         PropVariantInit(&friendlyName);
         hr = pStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);
         if (SUCCEEDED(hr))
         {
          // if no options, print the device
          // otherwise, find the selected device and set it to be default
          if (option == -1) printf("Audio Device %d: %ws\n",i, friendlyName.pwszVal);
          if (i == option) SetDefaultAudioPlaybackDevice(wstrID);
          PropVariantClear(&friendlyName);
         }
         pStore->Release();
        }
       }
       pDevice->Release();
      }
     }
    }
    pDevices->Release();
   }
   pEnum->Release();
  }
 }
 return hr;
}
As mentioned above this is not my code, copied from here.

No comments:

Post a Comment