From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/sound/sound_windows.cpp | 122 ++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/detection/sound/sound_windows.cpp (limited to 'src/detection/sound/sound_windows.cpp') diff --git a/src/detection/sound/sound_windows.cpp b/src/detection/sound/sound_windows.cpp new file mode 100644 index 0000000..6d6307a --- /dev/null +++ b/src/detection/sound/sound_windows.cpp @@ -0,0 +1,122 @@ +extern "C" { +#include "sound.h" +#include "common/windows/com.h" +} +#include "common/windows/unicode.hpp" +#include "common/windows/variant.hpp" + +#include +#include +#include +#include + +static void ffCoTaskMemFreeWrapper(void* pptr) { + assert(pptr != NULL); + void* ptr = *(void**) pptr; + if (ptr) { + CoTaskMemFree(ptr); + } +} +#define FF_COTASK_AUTO_FREE FF_A_CLEANUP(ffCoTaskMemFreeWrapper) + +static const char* detectSoundDevice(FFlist* devices /* List of FFSoundDevice */, IMMDevice* immDevice, LPWSTR mainDeviceId) { + LPWSTR FF_COTASK_AUTO_FREE immDeviceId = NULL; + if (FAILED(immDevice->GetId(&immDeviceId))) { + return "immDevice->GetId() failed"; + } + + IPropertyStore* FF_AUTO_RELEASE_COM_OBJECT immPropStore = NULL; + if (FAILED(immDevice->OpenPropertyStore(STGM_READ, &immPropStore))) { + return "immDevice->OpenPropertyStore() failed"; + } + + DWORD immState; + if (FAILED(immDevice->GetState(&immState))) { + return "immDevice->GetState() failed"; + } + + FFSoundDevice* device = FF_LIST_ADD(FFSoundDevice, *devices); + device->type = (FFSoundType) ((!mainDeviceId || wcscmp(immDeviceId, mainDeviceId) == 0 ? FF_SOUND_TYPE_MAIN : FF_SOUND_TYPE_NONE) | + ((immState & DEVICE_STATE_ACTIVE) ? FF_SOUND_TYPE_ACTIVE : FF_SOUND_TYPE_NONE)); + device->volume = FF_SOUND_VOLUME_UNKNOWN; + ffStrbufInitWS(&device->identifier, immDeviceId); + ffStrbufInit(&device->name); + ffStrbufInitStatic(&device->platformApi, "Core Audio APIs"); + + { + FFPropVariant friendlyName; + if (SUCCEEDED(immPropStore->GetValue(PKEY_Device_FriendlyName, &friendlyName))) { + ffStrbufSetWSV(&device->name, friendlyName.get()); + } else if (SUCCEEDED(immPropStore->GetValue(PKEY_Device_DeviceDesc, &friendlyName))) { + ffStrbufSetWSV(&device->name, friendlyName.get()); + } else { + ffStrbufSetStatic(&device->name, "Unknown Device"); + } + } + + IAudioEndpointVolume* FF_AUTO_RELEASE_COM_OBJECT immEndpointVolume = NULL; + if (SUCCEEDED(immDevice->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**) &immEndpointVolume))) { + BOOL muted; + if (FAILED(immEndpointVolume->GetMute(&muted)) || !muted) { + FLOAT volume; + if (SUCCEEDED(immEndpointVolume->GetMasterVolumeLevelScalar(&volume))) { + device->volume = (uint8_t) (volume * 100 + 0.5); + } + } + } + + return NULL; +} + +const char* ffDetectSound(FFSoundOptions* options, FFlist* devices /* List of FFSoundDevice */) { + const char* error = ffInitCom(); + if (error) { + return error; + } + + IMMDeviceEnumerator* FF_AUTO_RELEASE_COM_OBJECT pEnum = NULL; + + if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pEnum)))) { + return "CoCreateInstance(CLSID_MMDeviceEnumerator) failed"; + } + + LPWSTR FF_COTASK_AUTO_FREE mainDeviceId = NULL; + + { + IMMDevice* FF_AUTO_RELEASE_COM_OBJECT pDefaultDevice = NULL; + + if (FAILED(pEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDefaultDevice))) { + return "GetDefaultAudioEndpoint() failed"; + } + + if (options->soundType & FF_SOUND_TYPE_MAIN) { + return detectSoundDevice(devices, pDefaultDevice, NULL); + } + + if (FAILED(pDefaultDevice->GetId(&mainDeviceId))) { + return "pDefaultDevice->GetId() failed"; + } + } + + IMMDeviceCollection* FF_AUTO_RELEASE_COM_OBJECT pDevices = NULL; + + if (FAILED(pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE | (options->soundType & FF_SOUND_TYPE_ACTIVE ? 0 : DEVICE_STATE_DISABLED), &pDevices))) { + return "EnumAudioEndpoints() failed"; + } + + uint32_t deviceCount; + if (FAILED(pDevices->GetCount(&deviceCount))) { + return "pDevices->GetCount() failed"; + } + + for (uint32_t deviceIdx = 0; deviceIdx < deviceCount; ++deviceIdx) { + IMMDevice* FF_AUTO_RELEASE_COM_OBJECT immDevice = NULL; + if (FAILED(pDevices->Item(deviceIdx, &immDevice))) { + continue; + } + + detectSoundDevice(devices, immDevice, mainDeviceId); + } + + return NULL; +} -- cgit v1.2.3