yea
This commit is contained in:
172
AsuroTool/AudioApi.cpp
Normal file
172
AsuroTool/AudioApi.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ImguiBase.h"
|
||||
#include "Util.h"
|
||||
#include "AudioApi.h"
|
||||
#include "PolicyConfig.h"
|
||||
|
||||
HRESULT getDeviceProperty(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData)
|
||||
{
|
||||
PropVariantInit(outData);
|
||||
HRESULT nameResult = propertyStore->GetValue(propertyKey, outData);
|
||||
return nameResult;
|
||||
}
|
||||
|
||||
HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData, const wchar_t*& outString, const wchar_t* defaultStr)
|
||||
{
|
||||
HRESULT result = getDeviceProperty(propertyStore, propertyKey, outData);
|
||||
outString = outData->vt != VT_LPWSTR ? defaultStr : outData->pwszVal;
|
||||
return result;
|
||||
}
|
||||
|
||||
void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ERole role)
|
||||
{
|
||||
IPolicyConfigVista* pPolicyConfig;
|
||||
|
||||
HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient), NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID*)&pPolicyConfig);
|
||||
if (!isError(hr, "Failed to set default audio device: "))
|
||||
{
|
||||
hr = pPolicyConfig->SetDefaultEndpoint(deviceId, role);
|
||||
pPolicyConfig->Release();
|
||||
reloadDeviceLists(appData);
|
||||
}
|
||||
}
|
||||
|
||||
void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType)
|
||||
{
|
||||
deviceList.clear();
|
||||
|
||||
HRESULT err;
|
||||
IMMDeviceEnumerator* deviceEnumerator = NULL;
|
||||
IMMDeviceCollection* deviceCollection = NULL;
|
||||
|
||||
err = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator));
|
||||
if (isError(err, "Failed to set up audio device enumerator: ")) return;
|
||||
|
||||
err = deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection);
|
||||
if (isError(err, "Failed to enumerate audio devices: ")) return;
|
||||
|
||||
UINT deviceCount;
|
||||
err = deviceCollection->GetCount(&deviceCount);
|
||||
if (isError(err, "Failed to count audio devices: ")) return;
|
||||
|
||||
IMMDevice* defaultConsoleDevice = NULL;
|
||||
LPWSTR defaultConsoleId = nullptr;
|
||||
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice);
|
||||
if (!FAILED(err))
|
||||
{
|
||||
defaultConsoleDevice->GetId(&defaultConsoleId);
|
||||
}
|
||||
|
||||
IMMDevice* defaultMediaOutput = NULL;
|
||||
LPWSTR defaultMediaId = nullptr;
|
||||
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput);
|
||||
if (!FAILED(err))
|
||||
{
|
||||
defaultMediaOutput->GetId(&defaultMediaId);
|
||||
}
|
||||
|
||||
IMMDevice* defaultCommunicationOutput = NULL;
|
||||
LPWSTR defaultCommunicationId = nullptr;
|
||||
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput);
|
||||
if (!FAILED(err))
|
||||
{
|
||||
defaultCommunicationOutput->GetId(&defaultCommunicationId);
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < deviceCount; i += 1)
|
||||
{
|
||||
IMMDevice* device;
|
||||
err = deviceCollection->Item(i, &device);
|
||||
isError(err, std::stringstream("Failed to get device ") << i << ": ");
|
||||
|
||||
LPWSTR deviceId;
|
||||
err = device->GetId(&deviceId);
|
||||
isError(err, std::stringstream("Failed to get device id ") << i << ": ");
|
||||
|
||||
IPropertyStore* propertyStore;
|
||||
err = device->OpenPropertyStore(STGM_READ, &propertyStore);
|
||||
isError(err, std::stringstream("Failed to open device ") << i << "prop store: ");
|
||||
|
||||
PROPVARIANT deviceNameProp;
|
||||
const wchar_t* deviceName;
|
||||
err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName);
|
||||
isError(err, std::stringstream("Failed to read name of device ") << i << ": ");
|
||||
|
||||
DWORD deviceState;
|
||||
err = device->GetState(&deviceState);
|
||||
isError(err, std::stringstream("Failed to reat state of device ") << i << ": ");
|
||||
|
||||
IAudioEndpointVolume* volumeInterface;
|
||||
err = device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&volumeInterface);
|
||||
isError(err, "Failed to get audio endpoint volume interface: ");
|
||||
|
||||
IAudioMeterInformation* meterInterface;
|
||||
err = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&meterInterface);
|
||||
isError(err, "Failed to get audio meter interface: ");
|
||||
|
||||
deviceList.push_back({
|
||||
device,
|
||||
volumeInterface,
|
||||
meterInterface,
|
||||
std::wstring(deviceId),
|
||||
utf8Encode(deviceName),
|
||||
deviceState,
|
||||
utf8Encode(defaultConsoleId) == utf8Encode(deviceId),
|
||||
utf8Encode(defaultMediaId) == utf8Encode(deviceId),
|
||||
utf8Encode(defaultCommunicationId) == utf8Encode(deviceId),
|
||||
});
|
||||
|
||||
// Free stuff
|
||||
if (propertyStore)
|
||||
{
|
||||
propertyStore->Release();
|
||||
}
|
||||
CoTaskMemFree(deviceId);
|
||||
}
|
||||
|
||||
if (deviceEnumerator)
|
||||
{
|
||||
deviceEnumerator->Release();
|
||||
}
|
||||
if (deviceCollection)
|
||||
{
|
||||
deviceCollection->Release();
|
||||
}
|
||||
|
||||
std::sort(deviceList.begin(), deviceList.end(), [](AudioDevice& a, AudioDevice& b) { return a.state < b.state; });
|
||||
}
|
||||
|
||||
void reloadDeviceLists(ApplicationData* appData)
|
||||
{
|
||||
loadAudioDevices(appData->playbackDevices, EDataFlow::eRender);
|
||||
loadAudioDevices(appData->recordingDevices, EDataFlow::eCapture);
|
||||
}
|
||||
|
||||
float getVolume(IAudioEndpointVolume* volumeInterface)
|
||||
{
|
||||
float volume;
|
||||
if (FAILED(volumeInterface->GetChannelVolumeLevel(0, &volume)))
|
||||
{
|
||||
volume = 0.;
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
float getMeterValue(IAudioMeterInformation* meterInterface)
|
||||
{
|
||||
float volume;
|
||||
if (FAILED(meterInterface->GetPeakValue(&volume)))
|
||||
{
|
||||
volume = 0.;
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
Reference in New Issue
Block a user