live update

This commit is contained in:
2022-07-15 02:34:34 +02:00
parent ff996e8e55
commit b621d1266c
9 changed files with 303 additions and 55 deletions

View File

@@ -1,9 +1,49 @@
#include "ApplicationData.h" #include "ApplicationData.h"
AudioDevice::AudioDevice()
{
}
AudioDevice::AudioDevice(AudioDevice&& other) noexcept
: device(other.device), volumeInterface(other.volumeInterface), meterInterface(other.meterInterface),
id(other.id), name(other.name), state(other.state),
isDefaultConsole(other.isDefaultConsole), isDefaultMedia(other.isDefaultMedia), isDefaultCommunication(other.isDefaultCommunication)
{
other.device = nullptr;
other.volumeInterface = nullptr;
other.meterInterface = nullptr;
}
AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept
{
this->device = other.device;
this->volumeInterface = other.volumeInterface;
this->meterInterface = other.meterInterface;
this->id = other.id;
this->name = other.name;
this->state = other.state;
this->isDefaultConsole = other.isDefaultConsole;
this->isDefaultMedia = other.isDefaultMedia;
this->isDefaultCommunication = other.isDefaultCommunication;
other.device = nullptr;
other.volumeInterface = nullptr;
other.meterInterface = nullptr;
return *this;
}
AudioDevice::~AudioDevice() AudioDevice::~AudioDevice()
{ {
if (volumeInterface)
{
volumeInterface->Release();
}
if (meterInterface)
{
meterInterface->Release();
}
if (device) if (device)
{ {
//device->Release(); device->Release();
} }
} }

View File

@@ -4,6 +4,7 @@
#include <endpointvolume.h> #include <endpointvolume.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "AudioNotificationListener.h"
class AudioDevice { class AudioDevice {
public: public:
@@ -17,6 +18,9 @@ public:
bool isDefaultMedia = {}; bool isDefaultMedia = {};
bool isDefaultCommunication = {}; bool isDefaultCommunication = {};
AudioDevice();
AudioDevice(AudioDevice&& other) noexcept;
AudioDevice& operator=(AudioDevice&& other) noexcept;
~AudioDevice(); ~AudioDevice();
}; };
@@ -31,4 +35,6 @@ public:
ApplicationSettings settings = {}; ApplicationSettings settings = {};
std::vector<AudioDevice> playbackDevices = {}; std::vector<AudioDevice> playbackDevices = {};
std::vector<AudioDevice> recordingDevices = {}; std::vector<AudioDevice> recordingDevices = {};
IMMDeviceEnumerator* deviceEnumerator = nullptr;
AudioNotificationListener* audioNotificationListener = nullptr;
}; };

View File

@@ -36,8 +36,16 @@ void init(DrawData& drawData, void* customData)
io.Fonts->AddFontFromFileTTF("remixicon.ttf", 14.0f, &icons_config, icons_ranges); io.Fonts->AddFontFromFileTTF("remixicon.ttf", 14.0f, &icons_config, icons_ranges);
// Set up audio device api // Set up audio device api
HRESULT initResult = CoInitializeEx(NULL, COINIT_MULTITHREADED); HRESULT audioResult;
isError(initResult, "Failed to initialize COM: "); audioResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
isError(audioResult, "Failed to initialize COM: ");
audioResult = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&appData->deviceEnumerator));
isError(audioResult, "Failed to set up audio device enumerator: ");
appData->audioNotificationListener = new AudioNotificationListener(appData);
audioResult = appData->deviceEnumerator->RegisterEndpointNotificationCallback(appData->audioNotificationListener);
isError(audioResult, "Failed to register audio notification listener: ");
reloadDeviceLists(appData); reloadDeviceLists(appData);
@@ -54,20 +62,24 @@ void draw(DrawData& drawData, void* customData)
{ {
ApplicationData* appData = static_cast<ApplicationData*>(customData); ApplicationData* appData = static_cast<ApplicationData*>(customData);
float customYCursor = 0; float customYCursor = 0;
ImVec2 viewportSize = ImGui::GetMainViewport()->Size;
// Menu Bar
customYCursor += menuBar(appData).y; customYCursor += menuBar(appData).y;
ImVec2 containingSize = ImGui::GetMainViewport()->Size; // Playback Devices
ImGui::SetNextWindowPos(ImVec2(0, customYCursor)); ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(containingSize.x, 0)); ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += audioDeviceWindow(appData, appData->playbackDevices, " \xEE\xB8\x84 Playback").y; customYCursor += audioDeviceWindow(appData, appData->playbackDevices, " \xEE\xB8\x84 Playback").y;
customYCursor += 5.; customYCursor += 5.;
// Recording devices
ImGui::SetNextWindowPos(ImVec2(0, customYCursor)); ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(containingSize.x, 0)); ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += audioDeviceWindow(appData, appData->recordingDevices, " \xEE\xBD\x8F Recording").y; customYCursor += audioDeviceWindow(appData, appData->recordingDevices, " \xEE\xBD\x8F Recording").y;
// Resize viewport
if (appData->settings.fitWindowHeight) if (appData->settings.fitWindowHeight)
{ {
drawData.window_size.y = customYCursor; drawData.window_size.y = customYCursor;
@@ -150,14 +162,18 @@ ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& dev
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.7, .7, .7, 1.)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.7, .7, .7, 1.));
} }
// Device Name
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text(dev.name.c_str()); ImGui::Text(dev.name.c_str());
// Volume
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (dev.state == DEVICE_STATE_ACTIVE) if (dev.state == DEVICE_STATE_ACTIVE)
{ {
float volume = log10f(getMeterValue(dev.meterInterface) * 9. + 1.); float volume = log10f(getMeterValue(dev.meterInterface) * 9. + 1.);
auto drawList = ImGui::GetWindowDrawList(); auto drawList = ImGui::GetWindowDrawList();
@@ -170,6 +186,7 @@ ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& dev
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + space.x * volume, lineY), IM_COL32(200, 200, 255, 255), 3.); drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + space.x * volume, lineY), IM_COL32(200, 200, 255, 255), 3.);
} }
// Defaults
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (dev.state == DEVICE_STATE_ACTIVE) if (dev.state == DEVICE_STATE_ACTIVE)
{ {

View File

@@ -145,6 +145,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="ApplicationData.cpp" /> <ClCompile Include="ApplicationData.cpp" />
<ClCompile Include="AsuroTool.cpp" /> <ClCompile Include="AsuroTool.cpp" />
<ClCompile Include="AudioNotificationListener.cpp" />
<ClCompile Include="Util.cpp" /> <ClCompile Include="Util.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -152,6 +153,7 @@
<ClInclude Include="AsuroTool.h" /> <ClInclude Include="AsuroTool.h" />
<ClCompile Include="AudioApi.cpp" /> <ClCompile Include="AudioApi.cpp" />
<ClInclude Include="AudioApi.h" /> <ClInclude Include="AudioApi.h" />
<ClInclude Include="AudioNotificationListener.h" />
<ClInclude Include="PolicyConfig.h" /> <ClInclude Include="PolicyConfig.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="Util.h" /> <ClInclude Include="Util.h" />

View File

@@ -13,20 +13,29 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter> </Filter>
<Filter Include="Source Files\Audio">
<UniqueIdentifier>{37b6f2f7-f9d0-428e-9a8f-4b034610a39a}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Audio">
<UniqueIdentifier>{b65d213d-ddf6-4816-90d1-bf0811a51abf}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="AsuroTool.cpp"> <ClCompile Include="AsuroTool.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="AudioApi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Util.cpp"> <ClCompile Include="Util.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="ApplicationData.cpp"> <ClCompile Include="ApplicationData.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="AudioApi.cpp">
<Filter>Source Files\Audio</Filter>
</ClCompile>
<ClCompile Include="AudioNotificationListener.cpp">
<Filter>Source Files\Audio</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="AsuroTool.h"> <ClInclude Include="AsuroTool.h">
@@ -38,15 +47,18 @@
<ClInclude Include="PolicyConfig.h"> <ClInclude Include="PolicyConfig.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="AudioApi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ApplicationData.h"> <ClInclude Include="ApplicationData.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="resource.h"> <ClInclude Include="resource.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="AudioApi.h">
<Filter>Header Files\Audio</Filter>
</ClInclude>
<ClInclude Include="AudioNotificationListener.h">
<Filter>Header Files\Audio</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CopyFileToFolders Include="Montserrat-Regular.ttf"> <CopyFileToFolders Include="Montserrat-Regular.ttf">

View File

@@ -38,18 +38,14 @@ void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ER
} }
} }
void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType) void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType)
{ {
deviceList.clear(); deviceList.clear();
HRESULT err; HRESULT err;
IMMDeviceEnumerator* deviceEnumerator = NULL;
IMMDeviceCollection* deviceCollection = NULL; IMMDeviceCollection* deviceCollection = NULL;
err = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator)); err = appData->deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection);
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; if (isError(err, "Failed to enumerate audio devices: ")) return;
UINT deviceCount; UINT deviceCount;
@@ -58,7 +54,7 @@ void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType
IMMDevice* defaultConsoleDevice = NULL; IMMDevice* defaultConsoleDevice = NULL;
LPWSTR defaultConsoleId = nullptr; LPWSTR defaultConsoleId = nullptr;
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice); err = appData->deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice);
if (!FAILED(err)) if (!FAILED(err))
{ {
defaultConsoleDevice->GetId(&defaultConsoleId); defaultConsoleDevice->GetId(&defaultConsoleId);
@@ -66,7 +62,7 @@ void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType
IMMDevice* defaultMediaOutput = NULL; IMMDevice* defaultMediaOutput = NULL;
LPWSTR defaultMediaId = nullptr; LPWSTR defaultMediaId = nullptr;
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput); err = appData->deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput);
if (!FAILED(err)) if (!FAILED(err))
{ {
defaultMediaOutput->GetId(&defaultMediaId); defaultMediaOutput->GetId(&defaultMediaId);
@@ -74,7 +70,7 @@ void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType
IMMDevice* defaultCommunicationOutput = NULL; IMMDevice* defaultCommunicationOutput = NULL;
LPWSTR defaultCommunicationId = nullptr; LPWSTR defaultCommunicationId = nullptr;
err = deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput); err = appData->deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput);
if (!FAILED(err)) if (!FAILED(err))
{ {
defaultCommunicationOutput->GetId(&defaultCommunicationId); defaultCommunicationOutput->GetId(&defaultCommunicationId);
@@ -82,48 +78,54 @@ void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType
for (UINT i = 0; i < deviceCount; i += 1) for (UINT i = 0; i < deviceCount; i += 1)
{ {
IMMDevice* device; AudioDevice deviceData{};
err = deviceCollection->Item(i, &device);
isError(err, std::stringstream("Failed to get device ") << i << ": "); err = deviceCollection->Item(i, &deviceData.device);
if (isError(err, std::stringstream("Failed to get device ") << i << ": "))
{
continue;
}
LPWSTR deviceId; LPWSTR deviceId;
err = device->GetId(&deviceId); err = deviceData.device->GetId(&deviceId);
isError(err, std::stringstream("Failed to get device id ") << i << ": "); isError(err, std::stringstream("Failed to get device id ") << i << ": ");
deviceData.id = std::wstring(deviceId);
IPropertyStore* propertyStore; IPropertyStore* propertyStore;
err = device->OpenPropertyStore(STGM_READ, &propertyStore); err = deviceData.device->OpenPropertyStore(STGM_READ, &propertyStore);
isError(err, std::stringstream("Failed to open device ") << i << "prop store: "); isError(err, std::stringstream("Failed to open device ") << i << "prop store: ");
PROPVARIANT deviceNameProp; PROPVARIANT deviceNameProp;
const wchar_t* deviceName; const wchar_t* deviceName;
err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName); err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName);
isError(err, std::stringstream("Failed to read name of device ") << i << ": "); isError(err, std::stringstream("Failed to read name of device ") << i << ": ");
deviceData.name = utf8Encode(deviceName);
DWORD deviceState; err = deviceData.device->GetState(&deviceData.state);
err = device->GetState(&deviceState);
isError(err, std::stringstream("Failed to reat state of device ") << i << ": "); isError(err, std::stringstream("Failed to reat state of device ") << i << ": ");
IAudioEndpointVolume* volumeInterface; err = deviceData.device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&deviceData.volumeInterface);
err = device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&volumeInterface);
isError(err, "Failed to get audio endpoint volume interface: "); isError(err, "Failed to get audio endpoint volume interface: ");
IAudioMeterInformation* meterInterface; IAudioMeterInformation* meterInterface;
err = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&meterInterface); err = deviceData.device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&deviceData.meterInterface);
isError(err, "Failed to get audio meter interface: "); isError(err, "Failed to get audio meter interface: ");
deviceList.push_back({ if (defaultConsoleId)
device, {
volumeInterface, deviceData.isDefaultConsole = wcscmp(defaultConsoleId, deviceId) == 0;
meterInterface, }
std::wstring(deviceId), if (defaultMediaId)
utf8Encode(deviceName), {
deviceState, deviceData.isDefaultMedia = wcscmp(defaultMediaId, deviceId) == 0;
utf8Encode(defaultConsoleId) == utf8Encode(deviceId), }
utf8Encode(defaultMediaId) == utf8Encode(deviceId), if (defaultCommunicationId)
utf8Encode(defaultCommunicationId) == utf8Encode(deviceId), {
}); deviceData.isDefaultCommunication = wcscmp(defaultCommunicationId, deviceId) == 0;
}
deviceList.push_back(std::move(deviceData));
// Free stuff
if (propertyStore) if (propertyStore)
{ {
propertyStore->Release(); propertyStore->Release();
@@ -131,22 +133,18 @@ void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType
CoTaskMemFree(deviceId); CoTaskMemFree(deviceId);
} }
if (deviceEnumerator) std::sort(deviceList.begin(), deviceList.end(), [](AudioDevice& a, AudioDevice& b) { return a.state < b.state; });
{
deviceEnumerator->Release();
}
if (deviceCollection) if (deviceCollection)
{ {
deviceCollection->Release(); deviceCollection->Release();
} }
std::sort(deviceList.begin(), deviceList.end(), [](AudioDevice& a, AudioDevice& b) { return a.state < b.state; });
} }
void reloadDeviceLists(ApplicationData* appData) void reloadDeviceLists(ApplicationData* appData)
{ {
loadAudioDevices(appData->playbackDevices, EDataFlow::eRender); loadAudioDevices(appData, appData->playbackDevices, EDataFlow::eRender);
loadAudioDevices(appData->recordingDevices, EDataFlow::eCapture); loadAudioDevices(appData, appData->recordingDevices, EDataFlow::eCapture);
} }
float getVolume(IAudioEndpointVolume* volumeInterface) float getVolume(IAudioEndpointVolume* volumeInterface)
@@ -169,4 +167,4 @@ float getMeterValue(IAudioMeterInformation* meterInterface)
} }
return volume; return volume;
} }

View File

@@ -7,7 +7,7 @@
HRESULT getDeviceProperty(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData); HRESULT getDeviceProperty(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData);
HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData, const wchar_t*& outString, const wchar_t* defaultStr = L"Unknown"); HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY propertyKey, PROPVARIANT* outData, const wchar_t*& outString, const wchar_t* defaultStr = L"Unknown");
void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ERole role); void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ERole role);
void loadAudioDevices(std::vector<AudioDevice>& deviceList, EDataFlow deviceType); void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType);
void reloadDeviceLists(ApplicationData* appData); void reloadDeviceLists(ApplicationData* appData);
float getVolume(IAudioEndpointVolume* volumeInterface); float getVolume(IAudioEndpointVolume* volumeInterface);
float getMeterValue(IAudioMeterInformation* meterInterface); float getMeterValue(IAudioMeterInformation* meterInterface);

View File

@@ -0,0 +1,150 @@
#include <windows.h>
#include "AudioApi.h"
#include "AudioNotificationListener.h"
AudioNotificationListener::AudioNotificationListener(ApplicationData* appData) : appData(appData)
{
}
HRESULT __stdcall AudioNotificationListener::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
{
auto updateDevice = [pwstrDeviceId, dwNewState](std::vector<AudioDevice>& deviceList)
{
for (auto& audioDevice : deviceList)
{
if (wcscmp(audioDevice.id.c_str(), pwstrDeviceId) == 0)
{
audioDevice.state = dwNewState;
}
}
};
updateDevice(appData->playbackDevices);
updateDevice(appData->recordingDevices);
return S_OK;
}
HRESULT __stdcall AudioNotificationListener::OnDeviceAdded(LPCWSTR pwstrDeviceId)
{
IMMDevice* newDevice;
HRESULT result = appData->deviceEnumerator->GetDevice(pwstrDeviceId, &newDevice);
if (SUCCEEDED(result) && newDevice != nullptr)
{
// TODO: add to device list
}
return result;
}
HRESULT __stdcall AudioNotificationListener::OnDeviceRemoved(LPCWSTR pwstrDeviceId)
{
auto deleteDevice = [pwstrDeviceId](std::vector<AudioDevice>& deviceList)
{
auto deviceListIterator = deviceList.begin();
while (deviceListIterator != deviceList.end())
{
if (wcscmp(deviceListIterator->id.c_str(), pwstrDeviceId) == 0)
{
deviceListIterator = deviceList.erase(deviceListIterator);
}
}
};
deleteDevice(appData->playbackDevices);
deleteDevice(appData->recordingDevices);
return S_OK;
}
HRESULT __stdcall AudioNotificationListener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId)
{
std::vector<AudioDevice>* deviceList;
if (flow == EDataFlow::eRender)
{
deviceList = &appData->playbackDevices;
}
else
{
deviceList = &appData->recordingDevices;
}
for (AudioDevice& audioDevice : *deviceList)
{
if (wcscmp(audioDevice.id.c_str(), pwstrDefaultDeviceId) == 0)
{
switch (role)
{
case ERole::eCommunications:
audioDevice.isDefaultCommunication = true;
break;
case ERole::eConsole:
audioDevice.isDefaultConsole = true;
break;
case ERole::eMultimedia:
audioDevice.isDefaultMedia = true;
break;
}
}
else
{
switch (role)
{
case ERole::eCommunications:
audioDevice.isDefaultCommunication = false;
break;
case ERole::eConsole:
audioDevice.isDefaultConsole = false;
break;
case ERole::eMultimedia:
audioDevice.isDefaultMedia = false;
break;
}
}
}
return S_OK;
}
HRESULT __stdcall AudioNotificationListener::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
{
return S_OK;
}
// Copy pasted stuff from Windows SDK Example
// No clue what it does lol
// https://github.com/pauldotknopf/WindowsSDK7-Samples/blob/master/multimedia/audio/osd/endpointMonitor.cpp
HRESULT __stdcall AudioNotificationListener::QueryInterface(REFIID riid, void** ppvObject)
{
if ((riid == __uuidof(IUnknown)) ||
(riid == __uuidof(IMMNotificationClient)))
{
*ppvObject = static_cast<IMMNotificationClient*>(this);
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG __stdcall AudioNotificationListener::AddRef(void)
{
return InterlockedIncrement(&refCount);
}
ULONG __stdcall AudioNotificationListener::Release(void)
{
long refCountResult = InterlockedDecrement(&refCount);
if (refCountResult == 0)
{
delete this;
}
return refCountResult;
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include <mmdeviceapi.h>
class ApplicationData;
class AudioNotificationListener : public IMMNotificationClient {
public:
ApplicationData* appData;
long refCount = 1;
AudioNotificationListener(ApplicationData* appData);
virtual HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) override;
virtual HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override;
virtual HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override;
virtual HRESULT __stdcall OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) override;
virtual HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) override;
virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject) override;
virtual ULONG __stdcall AddRef(void) override;
virtual ULONG __stdcall Release(void) override;
};