Trigger Windows' automatic audio ducking without ducking own app's audio

Hello, all.

I am excusing myself beforehand for the not Qt-related question but still, I know that your expertise extends a lot further than Qt.
The question is Windows-related and more specifically - Windows Core Audio which is strangely named similarly to Apple’s Core Audio. The application being developed relies heavily on Qt and is playing some of its sounds through it but still, the background audio ducking is controlled currently only through platform-related APIs.

I am attempting to activate the Windows’ default automatic audio ducking inside my C++ desktop app so that I can duck only the audio of the rest of the applications but not that of mine so that any important audio is heard and not overlapped by a background such. The Windows’ ducking can be either:

a) automatic: one that can be system-wide configured through the Sound control panel (mmsys.cpl) → Communications tab. The background applications’ audio can be lowered by:

  • 100% - Muted
  • 80%
  • 50%
  • 0% - Do nothing

b) manual: where one opts-out from the automatic one and can receive notifications when audio ducking would be appropriate to be started/stopped

The problem is that I not only duck the audio of the rest of the applications - Spotify, browser’s audio like YouTube, but also that of my application.

I have extracted the audio ducking functionality from this Microsoft example which can be downloaded from here.

The most obvious way to notice that the audio of the current application is also ducked is to set the audio ducking setting inside the Windows sound settings to “Mute all other sounds” as shown here.

The audio ducking example provided above simulates a communication session/activity as far as I know - a WASAPI chat. I presume this is the reason that my audio is ducked as well since despite being my app opens a communication stream still this sample communication activity from the Microsoft’s example is probably overriding my app’s audio in terms of priority. That is just a presumption/hypothesis. Presumably something should be changed in this part of the example’s code.

I am open to all suggestions what should be fixed/changed/added. I confirm again that I want to use so-called “automatic” or I would say ready-made integrated audio ducking provided by Windows - the one shown on the screenshot above. I don’t want to provide a custom ducking behavior by lowering the other apps volume to arbitrary levels.

There are two APIs that directly mention the audio ducking:
IAudioSessionControl2::SetDuckingPreference
IAudioClientDuckingControl::SetDuckingOptionsForCurrentStream

The first one only switches between the automatic ducking behavior and a custom one i.e. switch the automatic off. I am currently testing the second one. The problem with it is the minimum required Windows version.

Here’s the simplest code that triggers the automatic audio ducking on Windows:

CComPtr<IMMDeviceEnumerator> deviceEnumerator;
HRESULT hr = CoCreateInstance(
    __uuidof(MMDeviceEnumerator),
    nullptr,
    CLSCTX_ALL /* CLSCTX_INPROC_SERVER */,
    IID_PPV_ARGS(&deviceEnumerator));
if (FAILED(hr))
{
    return;
}

CComPtr<IMMDevice> communicationsDevice;
hr = deviceEnumerator->GetDefaultAudioEndpoint(
            eRender, // eCapture for microphone
            eCommunications,
            &communicationsDevice);
if (FAILED(hr))
{
    return;
}

CComPtr<IAudioClient3> audioClient;
hr = communicationsDevice->Activate(
        __uuidof(IAudioClient3),
        CLSCTX_ALL /* CLSCTX_INPROC_SERVER */,
        nullptr,
        reinterpret_cast<LPVOID*>(&audioClient));
if (FAILED(hr))
{
    return;
}

WAVEFORMATEX* mixFormat = nullptr;
hr = audioClient->GetMixFormat(&mixFormat);
if (FAILED(hr))
{
    return false;
}

hr = audioClient->Initialize(
        AUDCLNT_SHAREMODE_SHARED,
        AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
        | AUDCLNT_STREAMFLAGS_EVENTCALLBACK
        | AUDCLNT_STREAMFLAGS_NOPERSIST,
        500000,
        0,
        mixFormat,
        nullptr);
if (FAILED(hr))
{
    return;
}

CoTaskMemFree(mixFormat);
mixFormat = nullptr;

hr = audioClient->Start();
if (FAILED(hr))
{
    return;
}

Additionally, there are buffer manipulations - both initial and on a separate thread but they don’t seem to be part of the minimum requirements to trigger the audio ducking.

1 Like