This commit is contained in:
2022-07-15 04:32:36 +02:00
parent b621d1266c
commit be949ea8a3
7 changed files with 89 additions and 37 deletions

View File

@@ -37,13 +37,54 @@ AudioDevice::~AudioDevice()
if (volumeInterface) if (volumeInterface)
{ {
volumeInterface->Release(); volumeInterface->Release();
volumeInterface = nullptr;
} }
if (meterInterface) if (meterInterface)
{ {
meterInterface->Release(); meterInterface->Release();
meterInterface = nullptr;
} }
if (device) if (device)
{ {
device->Release(); device->Release();
device = nullptr;
}
}
AudioData::AudioData()
{
}
AudioData::AudioData(AudioData&& other) noexcept
: playbackDevices(std::move(other.playbackDevices)), recordingDevices(std::move(other.recordingDevices)),
deviceEnumerator(other.deviceEnumerator), audioNotificationListener(other.audioNotificationListener)
{
other.deviceEnumerator = nullptr;
other.audioNotificationListener = nullptr;
}
AudioData& AudioData::operator=(AudioData&& other) noexcept
{
playbackDevices = std::move(other.playbackDevices);
recordingDevices = std::move(other.recordingDevices);
deviceEnumerator = other.deviceEnumerator;
audioNotificationListener = other.audioNotificationListener;
other.deviceEnumerator = nullptr;
other.audioNotificationListener = nullptr;
return *this;
}
AudioData::~AudioData()
{
if (deviceEnumerator)
{
deviceEnumerator->Release();
deviceEnumerator = nullptr;
}
if (audioNotificationListener)
{
audioNotificationListener->Release();
audioNotificationListener = nullptr;
} }
} }

View File

@@ -24,6 +24,19 @@ public:
~AudioDevice(); ~AudioDevice();
}; };
class AudioData {
public:
std::vector<AudioDevice> playbackDevices = {};
std::vector<AudioDevice> recordingDevices = {};
IMMDeviceEnumerator* deviceEnumerator = nullptr;
AudioNotificationListener* audioNotificationListener = nullptr;
AudioData();
AudioData(AudioData&& other) noexcept;
AudioData& operator=(AudioData&& other) noexcept;
~AudioData();
};
class ApplicationSettings { class ApplicationSettings {
public: public:
bool showDisabledDevices = false; bool showDisabledDevices = false;
@@ -33,8 +46,5 @@ public:
class ApplicationData { class ApplicationData {
public: public:
ApplicationSettings settings = {}; ApplicationSettings settings = {};
std::vector<AudioDevice> playbackDevices = {}; std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>();
std::vector<AudioDevice> recordingDevices = {};
IMMDeviceEnumerator* deviceEnumerator = nullptr;
AudioNotificationListener* audioNotificationListener = nullptr;
}; };

View File

@@ -40,14 +40,14 @@ void init(DrawData& drawData, void* customData)
audioResult = CoInitializeEx(NULL, COINIT_MULTITHREADED); audioResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
isError(audioResult, "Failed to initialize COM: "); isError(audioResult, "Failed to initialize COM: ");
audioResult = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&appData->deviceEnumerator)); audioResult = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&appData->audioData->deviceEnumerator));
isError(audioResult, "Failed to set up audio device enumerator: "); isError(audioResult, "Failed to set up audio device enumerator: ");
appData->audioNotificationListener = new AudioNotificationListener(appData); appData->audioData->audioNotificationListener = new AudioNotificationListener(appData->audioData);
audioResult = appData->deviceEnumerator->RegisterEndpointNotificationCallback(appData->audioNotificationListener); audioResult = appData->audioData->deviceEnumerator->RegisterEndpointNotificationCallback(appData->audioData->audioNotificationListener);
isError(audioResult, "Failed to register audio notification listener: "); isError(audioResult, "Failed to register audio notification listener: ");
reloadDeviceLists(appData); reloadDeviceLists(*appData->audioData);
// Set window icon // Set window icon
LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1); LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1);
@@ -70,14 +70,14 @@ void draw(DrawData& drawData, void* customData)
// Playback Devices // Playback Devices
ImGui::SetNextWindowPos(ImVec2(0, customYCursor)); ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0)); ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += audioDeviceWindow(appData, appData->playbackDevices, " \xEE\xB8\x84 Playback").y; customYCursor += audioDeviceWindow(appData, appData->audioData->playbackDevices, " \xEE\xB8\x84 Playback").y;
customYCursor += 5.; customYCursor += 5.;
// Recording devices // Recording devices
ImGui::SetNextWindowPos(ImVec2(0, customYCursor)); ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0)); ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += audioDeviceWindow(appData, appData->recordingDevices, " \xEE\xBD\x8F Recording").y; customYCursor += audioDeviceWindow(appData, appData->audioData->recordingDevices, " \xEE\xBD\x8F Recording").y;
// Resize viewport // Resize viewport
if (appData->settings.fitWindowHeight) if (appData->settings.fitWindowHeight)
@@ -103,7 +103,7 @@ ImVec2 menuBar(ApplicationData* appData)
{ {
if (ImGui::Button("Manual Refresh")) if (ImGui::Button("Manual Refresh"))
{ {
reloadDeviceLists(appData); reloadDeviceLists(*appData->audioData);
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
@@ -196,7 +196,7 @@ ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& dev
} }
if (customButton("bn_d_", deviceIdUtf8.c_str(), "\xEE\xBE\x82", !dev.isDefaultConsole)) if (customButton("bn_d_", deviceIdUtf8.c_str(), "\xEE\xBE\x82", !dev.isDefaultConsole))
{ {
setDefaultAudioDevice(appData, dev.id.c_str(), ERole::eConsole); setDefaultAudioDevice(*appData->audioData, dev.id.c_str(), ERole::eConsole);
} }
ImGui::SameLine(); ImGui::SameLine();
@@ -206,7 +206,7 @@ ImVec2 audioDeviceWindow(ApplicationData* appData, std::vector<AudioDevice>& dev
} }
if (customButton("bn_c_", deviceIdUtf8.c_str(), "\xEE\xBF\xA9", !dev.isDefaultCommunication)) if (customButton("bn_c_", deviceIdUtf8.c_str(), "\xEE\xBF\xA9", !dev.isDefaultCommunication))
{ {
setDefaultAudioDevice(appData, dev.id.c_str(), ERole::eCommunications); setDefaultAudioDevice(*appData->audioData, dev.id.c_str(), ERole::eCommunications);
} }
} }

View File

@@ -6,7 +6,6 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "ImguiBase.h"
#include "Util.h" #include "Util.h"
#include "AudioApi.h" #include "AudioApi.h"
#include "PolicyConfig.h" #include "PolicyConfig.h"
@@ -25,7 +24,7 @@ HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY
return result; return result;
} }
void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ERole role) void setDefaultAudioDevice(AudioData& audioData, const wchar_t* deviceId, ERole role)
{ {
IPolicyConfigVista* pPolicyConfig; IPolicyConfigVista* pPolicyConfig;
@@ -34,18 +33,18 @@ void setDefaultAudioDevice(ApplicationData* appData, const wchar_t* deviceId, ER
{ {
hr = pPolicyConfig->SetDefaultEndpoint(deviceId, role); hr = pPolicyConfig->SetDefaultEndpoint(deviceId, role);
pPolicyConfig->Release(); pPolicyConfig->Release();
reloadDeviceLists(appData); reloadDeviceLists(audioData);
} }
} }
void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType) void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType)
{ {
deviceList.clear(); deviceList.clear();
HRESULT err; HRESULT err;
IMMDeviceCollection* deviceCollection = NULL; IMMDeviceCollection* deviceCollection = NULL;
err = appData->deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection); err = audioData.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;
@@ -54,7 +53,7 @@ void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& device
IMMDevice* defaultConsoleDevice = NULL; IMMDevice* defaultConsoleDevice = NULL;
LPWSTR defaultConsoleId = nullptr; LPWSTR defaultConsoleId = nullptr;
err = appData->deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice); err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice);
if (!FAILED(err)) if (!FAILED(err))
{ {
defaultConsoleDevice->GetId(&defaultConsoleId); defaultConsoleDevice->GetId(&defaultConsoleId);
@@ -62,7 +61,7 @@ void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& device
IMMDevice* defaultMediaOutput = NULL; IMMDevice* defaultMediaOutput = NULL;
LPWSTR defaultMediaId = nullptr; LPWSTR defaultMediaId = nullptr;
err = appData->deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput); err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput);
if (!FAILED(err)) if (!FAILED(err))
{ {
defaultMediaOutput->GetId(&defaultMediaId); defaultMediaOutput->GetId(&defaultMediaId);
@@ -70,7 +69,7 @@ void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& device
IMMDevice* defaultCommunicationOutput = NULL; IMMDevice* defaultCommunicationOutput = NULL;
LPWSTR defaultCommunicationId = nullptr; LPWSTR defaultCommunicationId = nullptr;
err = appData->deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput); err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput);
if (!FAILED(err)) if (!FAILED(err))
{ {
defaultCommunicationOutput->GetId(&defaultCommunicationId); defaultCommunicationOutput->GetId(&defaultCommunicationId);
@@ -141,10 +140,10 @@ void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& device
} }
} }
void reloadDeviceLists(ApplicationData* appData) void reloadDeviceLists(AudioData& audioData)
{ {
loadAudioDevices(appData, appData->playbackDevices, EDataFlow::eRender); loadAudioDevices(audioData, audioData.playbackDevices, EDataFlow::eRender);
loadAudioDevices(appData, appData->recordingDevices, EDataFlow::eCapture); loadAudioDevices(audioData, audioData.recordingDevices, EDataFlow::eCapture);
} }
float getVolume(IAudioEndpointVolume* volumeInterface) float getVolume(IAudioEndpointVolume* volumeInterface)

View File

@@ -6,8 +6,8 @@
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(AudioData& audioData, const wchar_t* deviceId, ERole role);
void loadAudioDevices(ApplicationData* appData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType); void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType);
void reloadDeviceLists(ApplicationData* appData); void reloadDeviceLists(AudioData& audioData);
float getVolume(IAudioEndpointVolume* volumeInterface); float getVolume(IAudioEndpointVolume* volumeInterface);
float getMeterValue(IAudioMeterInformation* meterInterface); float getMeterValue(IAudioMeterInformation* meterInterface);

View File

@@ -4,7 +4,7 @@
#include "AudioNotificationListener.h" #include "AudioNotificationListener.h"
AudioNotificationListener::AudioNotificationListener(ApplicationData* appData) : appData(appData) AudioNotificationListener::AudioNotificationListener(std::shared_ptr<AudioData> audioData) : audioData(audioData)
{ {
} }
@@ -22,8 +22,8 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceStateChanged(LPCWSTR pwstrD
} }
}; };
updateDevice(appData->playbackDevices); updateDevice(audioData->playbackDevices);
updateDevice(appData->recordingDevices); updateDevice(audioData->recordingDevices);
return S_OK; return S_OK;
} }
@@ -31,7 +31,7 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceStateChanged(LPCWSTR pwstrD
HRESULT __stdcall AudioNotificationListener::OnDeviceAdded(LPCWSTR pwstrDeviceId) HRESULT __stdcall AudioNotificationListener::OnDeviceAdded(LPCWSTR pwstrDeviceId)
{ {
IMMDevice* newDevice; IMMDevice* newDevice;
HRESULT result = appData->deviceEnumerator->GetDevice(pwstrDeviceId, &newDevice); HRESULT result = audioData->deviceEnumerator->GetDevice(pwstrDeviceId, &newDevice);
if (SUCCEEDED(result) && newDevice != nullptr) if (SUCCEEDED(result) && newDevice != nullptr)
{ {
// TODO: add to device list // TODO: add to device list
@@ -54,8 +54,8 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceRemoved(LPCWSTR pwstrDevice
} }
}; };
deleteDevice(appData->playbackDevices); deleteDevice(audioData->playbackDevices);
deleteDevice(appData->recordingDevices); deleteDevice(audioData->recordingDevices);
return S_OK; return S_OK;
} }
@@ -65,11 +65,11 @@ HRESULT __stdcall AudioNotificationListener::OnDefaultDeviceChanged(EDataFlow fl
std::vector<AudioDevice>* deviceList; std::vector<AudioDevice>* deviceList;
if (flow == EDataFlow::eRender) if (flow == EDataFlow::eRender)
{ {
deviceList = &appData->playbackDevices; deviceList = &audioData->playbackDevices;
} }
else else
{ {
deviceList = &appData->recordingDevices; deviceList = &audioData->recordingDevices;
} }
for (AudioDevice& audioDevice : *deviceList) for (AudioDevice& audioDevice : *deviceList)

View File

@@ -1,14 +1,16 @@
#pragma once #pragma once
#include <memory>
#include <mmdeviceapi.h> #include <mmdeviceapi.h>
class AudioData;
class ApplicationData; class ApplicationData;
class AudioNotificationListener : public IMMNotificationClient { class AudioNotificationListener : public IMMNotificationClient {
public: public:
ApplicationData* appData; std::shared_ptr<AudioData> audioData;
long refCount = 1; long refCount = 1;
AudioNotificationListener(ApplicationData* appData); AudioNotificationListener(std::shared_ptr<AudioData> audioData);
virtual HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) override; virtual HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) override;
virtual HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override; virtual HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override;