Search code examples
c++windowswinapivolume

How to get system volume level as a scalar from 0 to 100?


I'm currently working on a "Volume mixer" to control the volume of each program on my PC (Windows 10).

How do I get the volume level of each program/audio session as a scalar from 0 to 100?

As you can see, in the code below, I found the GetPeakValue function, but it returns values like 0.0812654 or 0.021352.

I'm sure that these values are the volume of each audio session in a scalar from 1.0 to 0.0. But what I want is the volume limitation, which you can set in the windows audio mixer for example, and not the current level. So if I set the program volume level to 50%, I want a value like 0.5.

In the second function (getVolume), you'll see that I already got the master volume in a 0-100 scalar, but there the endpoint device has a function for the scalar level already. So I'll need the same function at least, or a calculation, to get such a scalar for every audio session as well.

void getSessions() {
    CoInitialize(NULL);

    IMMDeviceEnumerator *pDeviceEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    IAudioSessionManager2 *pAudioSessionManager2 = NULL;
    IAudioSessionEnumerator *pAudioSessionEnumerator = NULL;

    CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&pDeviceEnumerator);
    pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);

    pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void **) &pAudioSessionManager2);
    pAudioSessionManager2->GetSessionEnumerator(&pAudioSessionEnumerator);

    int nSessionCount;
    pAudioSessionEnumerator->GetCount(&nSessionCount);

    std::cout << "Session Count: " << nSessionCount << std::endl;

    while (true) {
        for (int nSessionIndex = 0; nSessionIndex < nSessionCount; nSessionIndex++) {
            IAudioSessionControl *pSessionControl = NULL;
            if (FAILED(pAudioSessionEnumerator->GetSession(nSessionIndex, &pSessionControl)))
                continue;

            IAudioMeterInformation *pAudioMeterInformation = NULL;
            pSessionControl->QueryInterface(&pAudioMeterInformation);

            float fPeak = NULL;
            pAudioMeterInformation->GetPeakValue(&fPeak);

            std::cout << "fPeak Value: " << fPeak << std::endl;
        }

        std::cout << "\n\n";
        Sleep(1000);
    }

    CoUninitialize();
}

double getVolume() {
    float currentVolume = 0;

    CoInitialize(NULL);
    IMMDeviceEnumerator *deviceEnumerator = NULL;
    CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
    IMMDevice *defaultDevice = NULL;
    deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
    deviceEnumerator->Release();
    deviceEnumerator = NULL;

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

    float fLevel;
    endpointVolume->GetMasterVolumeLevel(&fLevel);
    qDebug() << "FLevel: ";
    qDebug() << fLevel;

    endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
    endpointVolume->Release();

    CoUninitialize();

    return (double)(currentVolume * 100);
}

Solution

  • Ok guys, I've found the solution for my problem!

    I had to call QueryInterface on the SessionControl to gain access to ISimpleAudioVolume where you can use the functions GetMasterVolume and SetMasterVolume. It's a 0-1 scalar, but you can just multiply it with 100 to get a 0-100 scalar. If the system's master volume is on 50%, you get a output of 1 if the program volume is on 50% too, so the output is based on the system's master volume!

    Thanks for every comment and help!

    Here the working code:

    void getSessions() {
        CoInitialize(NULL);
    
        IMMDeviceEnumerator *pDeviceEnumerator;
        IMMDevice *pDevice;
        IAudioSessionManager2 *pAudioSessionManager2;
        IAudioSessionEnumerator *pAudioSessionEnumerator;
    
        CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&pDeviceEnumerator);
        pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
    
        pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void **) &pAudioSessionManager2);
        pAudioSessionManager2->GetSessionEnumerator(&pAudioSessionEnumerator);
    
        int nSessionCount;
        pAudioSessionEnumerator->GetCount(&nSessionCount);
    
        while (true) {
            for (int nSessionIndex = 0; nSessionIndex < nSessionCount; nSessionIndex++) {
                IAudioSessionControl *pSessionControl;
                if (FAILED(pAudioSessionEnumerator->GetSession(nSessionIndex, &pSessionControl)))
                    continue;
    
                ISimpleAudioVolume *pSimpleAudioVolume;
                pSessionControl->QueryInterface(&pSimpleAudioVolume);
    
                float fLevel;
                pSimpleAudioVolume->GetMasterVolume(&fLevel);
    
                std::cout << "fLevel Value: " << fLevel << std::endl;
            }
    
            Sleep(1000);
        }
    
        CoUninitialize();
    }