9

If I go to Settings on a Windows 10 (1803) computer, I have access to a page ("App Volume and Device Preferences") that lets me set the default input and output device for a running application.

Screenshot of App Volume and Device Preferences page

How can I set these options programmatically?

Related:

Mitch
  • 21,223
  • 6
  • 63
  • 86
  • If you are trying to select the appropriate input and output sound devices within an application you are coding, a cross platform way to do that would be using a library like openal. – CodeSurgeon Sep 04 '19 at 01:44
  • @CodeSurgeon, thanks. This is for a third party program. We are trying to deploy a policy which prefers a headset for a VoIP softphone that just selects the default input/output device. – Mitch Sep 04 '19 at 03:35
  • 1
    For pure Windows stuff, check out the various `waveInXxx` and `waveOutXxx` fuctions, as listed here: https://learn.microsoft.com/en-gb/windows/win32/multimedia/waveform-functions – Adrian Mole Sep 04 '19 at 06:18
  • https://github.com/Belphemur/AudioEndPointLibrary This project can give you some help. – Jeffreys Sep 04 '19 at 06:42
  • Did you find a solution for setting the default audio endpoint? – vinnybad Sep 11 '20 at 04:44
  • 1
    @vinnybad, no. There does not seem to be a documented API. Some undocumented COM API’s do exist, but those come with the normal risks for undocumented API’s – so I’m not using them. – Mitch Sep 11 '20 at 15:22

2 Answers2

7

Here you can enumerate all the playback devices

#include <windows.h>
#include <mmsystem.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Winmm.lib")

int main()
{
    int nSoundCardCount = waveOutGetNumDevs();

    for (int i = 0; i < nSoundCardCount; i++)
    {
        WAVEOUTCAPS woc;
        waveOutGetDevCaps(i, &woc, sizeof(woc));

        cout << woc.szPname << endl; 
    }

    system("pause");
    return 0;
}

Here you need to use PolicyConfig.h and SetDefaultAudioPlaybackDevice to add .h files and interfaces. Refer to this project

1.Add the header file PolicyConfig.h

2.Add the head file and interface.

#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;
}

3.Use the above interface to write a function to set the default output device.

It's MFC Project. Maybe you need to change.

Which output device needs to be set, you can modify the content of the macro yourself. I get the name of output device using waveOutGetDevCaps()

//Set the default audio playback device 
#define  DEF_AUDIO_NAME _T("Speakers (2- Logitech USB Heads")  //modify it, my device is Speakers (2- Logitech USB Heads

void InitDefaultAudioDevice()
{
    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))
        {
            //Determine if it is the default audio device
            bool bExit = false;
            IMMDevice  *pDefDevice = NULL;
            hr = pEnum->GetDefaultAudioEndpoint(eRender, eMultimedia,&pDefDevice);
            if (SUCCEEDED(hr))
            {
                IPropertyStore *pStore;
                hr = pDefDevice->OpenPropertyStore(STGM_READ, &pStore);
                if (SUCCEEDED(hr))
                {
                    PROPVARIANT friendlyName;
                    PropVariantInit(&friendlyName);
                    hr = pStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);
                    if (SUCCEEDED(hr))
                    {
                        CString strTmp = friendlyName.pwszVal;
                        if (strTmp.Find(DEF_AUDIO_NAME) != -1)
                        {
                            bExit = true;
                        }
                        PropVariantClear(&friendlyName);
                    }
                    pStore->Release();
                }
                pDefDevice->Release();
            }
            if (bExit)
            {
                pEnum->Release();
                return;
            }

            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++)
                    {
                        bool bFind = false;
                        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
                                        CString strTmp = friendlyName.pwszVal;
                                        if (strTmp.Find(DEF_AUDIO_NAME) != -1)
                                        {
                                            SetDefaultAudioPlaybackDevice(wstrID);
                                            bFind = true;
                                        }
                                        PropVariantClear(&friendlyName);
                                    }
                                    pStore->Release();
                                }
                            }
                            pDevice->Release();
                        }

                        if (bFind)
                        {
                            break;
                        }
                    }
                }
                pDevices->Release();
            }
            pEnum->Release();
        }
    }
    CoUninitialize();
}

This sample can only change the output of Master volume. I don't know whether it can meet your requirements? If you need to change other apps, you have to explore for a while.

Jeffreys
  • 431
  • 2
  • 8
  • 2
    How do you compile with PolicyConfig.h? I receive: undefined reference to `_GUID const& __mingw_uuidof()' undefined reference to `_GUID const& __mingw_uuidof()' I run it like: "$ g++ program.cc -lwinmm -lole32 && ./a.exe". I use MinGW-w64 Nuwens dist on Windows 10. – sockevalley Apr 06 '20 at 06:21
  • @sockevalley I have exactly same probelm with MinGW... g++ %name%.cpp -lole32 -o %name% | It seems that MinGW can't find this esoteric header's library... And we have no idea what lib it uses, cos its undocumented! Try to build it in Visual Studio, it seems to be only solution, for now... I hate VS, but it leaves me no choice =( – ScienceDiscoverer Jun 19 '22 at 06:53
4

So I have been using SoundVolumeView for a while that let me mute and unmute my mic for meeting with a command line and I have discovered recently (because of OBS and monitoring audio) that it can also change device for an app or global default device

And using /SetDefault and /SetAppDefault as shown in the doc example to the bottom of the page

I have put that in a batch script and bind a macro to my keyboard and it's doing a good job so far :)

slhad
  • 41
  • 2