Windows Core Audio API : How can I access multiple Volume levels of a USB Device

kinaar 20 Reputation points
2023-09-20T15:07:05.9366667+00:00

For an audio device Control Software we need to access the different Windows volume levels of our device (Speaker level and Microphone level). We are using the Windows Core Audio API and right now we are able to access the Speaker level using a IAudioEndpointVolume. But for the Microphone level, as the control is located in the Speaker window, it becomes a bit tricky and we didn't managed yet.

Screenshot of the Controls

We tried to get a IAudioEndpointVolume out of the Capture device :

// Activate Callback for Input 
device_enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &default_device); 
default_device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&input_endpoint_volume);  
float input_vol = 0.0f; 
input_endpoint_volume->GetMasterVolumeLevel(&input_vol); 
//input_vol should now be the Microphone volume showed on the Speakers Properties window  

We also tried to get two IAudioEndpointVolume out of the Render device (suggested by ChatGPT) :

// Activate Callback for Input 
device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &default_device); 
default_device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&output_endpoint_volume);  
float output_vol = 0.0f; 
output_endpoint_volume->GetMasterVolumeLevel(&output_vol); 
//output_vol should now be the Speakers volume showed on the Speakers Properties window  

// Activate Callback for Input 
device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &default_device); 
default_device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&input_endpoint_volume);  
float input_vol = 0.0f; 
input_endpoint_volume->GetMasterVolumeLevel(&input_vol); 
//input_vol should now be the Microphone volume showed on the Speakers Properties window  

output_vol returns the right value but input_vol always returns 0.0f (even if I change the value in the properties). 

So none of these works and the Microsoft documentation doesn't give any details about it. Does anyone of you have an idea or faced the same issue ? If you have any hints, please get back to us. Thanks.

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,579 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,683 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 84,286 Reputation points
    2023-09-20T22:36:09.36+00:00

    You can try to enumerate endpoints like in the test below, and if you don't get it, you can adapt the code from

    https://github.com/parzival3/rusty-win-audio/blob/bf2e305dc78c9b3a77cdd6716f4b132b50c53961/cpp/src/enumeration.cpp

    (with WalkTreeBackwardsFromPart function)

                   {
                       CoInitialize(NULL);
                       IMMDeviceEnumerator* pDeviceEnumerator = NULL;
                       HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pDeviceEnumerator);
                       if (hr == S_OK)
                       {
                           IMMDeviceCollection* pDeviceCollection = NULL;
                           hr = pDeviceEnumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &pDeviceCollection);
                           if (hr == S_OK)
                           {
                               UINT nDeviceCount = 0;
                               hr = pDeviceCollection->GetCount(&nDeviceCount);
                               for (UINT i = 0; i < nDeviceCount; i++)
                               {
                                   IMMDevice* pDevice;
                                   hr = pDeviceCollection->Item(i, &pDevice);
                                   if (hr == S_OK)
                                   {
                                       TCHAR wsBuffer[255];
                                       IPropertyStore* propertyStore;
                                       hr = pDevice->OpenPropertyStore(STGM_READ, &propertyStore);
                                       PROPVARIANT pvFriendlyName;
                                       PropVariantInit(&pvFriendlyName);
                                       hr = propertyStore->GetValue(PKEY_Device_FriendlyName, &pvFriendlyName);
                                       TCHAR wsDeviceName[128];
                                       hr = StringCbPrintf(wsDeviceName, sizeof(wsDeviceName), _T("%s"), pvFriendlyName.vt != VT_LPWSTR ? _T("Unknown") : pvFriendlyName.pwszVal);
                                       PropVariantClear(&pvFriendlyName);
                                       wsprintf(wsBuffer, _T("Device Name : %s\r\n"), wsDeviceName);
                                       OutputDebugString(wsBuffer);
    
                                       IMMEndpoint* pEndpoint;
                                       EDataFlow flow;
                                       pDevice->QueryInterface<IMMEndpoint>(&pEndpoint);
                                       pEndpoint->GetDataFlow(&flow);
                                       pEndpoint->Release();
                                       LPWSTR pwsDeviceId;
                                       hr = pDevice->GetId(&pwsDeviceId);
                                       wsprintf(wsBuffer, _T("\tDevice Id : %s\r\n"), pwsDeviceId);
                                       OutputDebugString(wsBuffer);
                                       CoTaskMemFree(pwsDeviceId);
                                       TCHAR wsFlow[255];
                                       switch (flow) {
                                       case EDataFlow::eRender:
                                           lstrcpy(wsFlow, _T("Output"));
                                           break;
                                       case EDataFlow::eCapture:
                                           lstrcpy(wsFlow, _T("Input"));
                                           break;
                                       case EDataFlow::eAll:
                                           lstrcpy(wsFlow, _T("Input/Output"));
                                           break;
                                       }
                                       wsprintf(wsBuffer, _T("\tFlow : %s\r\n"), wsFlow);
                                       OutputDebugString(wsBuffer);
    
                                       IAudioEndpointVolume* pEndptVol = NULL;
                                       float nVolume = 0;
                                       hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pEndptVol);
                                       if (hr == S_OK)
                                       {
                                           hr = pEndptVol->GetMasterVolumeLevelScalar(&nVolume);
                                           pEndptVol->Release();
                                       }
                                       hr = StringCbPrintf(wsBuffer, sizeof(wsBuffer), _T("\tVolume : %.4lf\r\n"), nVolume);
                                       OutputDebugString(wsBuffer);
                                       pDevice->Release();
                                   }                                
                               }
                               pDeviceCollection->Release();
                           }
                           pDeviceEnumerator->Release();
                       }
                       CoUninitialize();
                   }
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.