mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 09:28:03 +08:00
[VCM] Track newly added microphones (#16199)
* [VCM] Track newly added microphones when [All] is selected in the settings * [VCM] handle case when no mics are left * fixup: fix crashes onNotify * fixup: fix build
This commit is contained in:
parent
2e3a2b3f96
commit
176f2c2870
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@ -498,6 +498,7 @@ dxgi
|
|||||||
dxgiformat
|
dxgiformat
|
||||||
dxguid
|
dxguid
|
||||||
ecount
|
ecount
|
||||||
|
EData
|
||||||
EDITKEYBOARD
|
EDITKEYBOARD
|
||||||
editkeyboardwindow
|
editkeyboardwindow
|
||||||
editorconfig
|
editorconfig
|
||||||
@ -527,6 +528,7 @@ EREOF
|
|||||||
EResize
|
EResize
|
||||||
ERRORMESSAGE
|
ERRORMESSAGE
|
||||||
ERRORTITLE
|
ERRORTITLE
|
||||||
|
ERole
|
||||||
ESettings
|
ESettings
|
||||||
esize
|
esize
|
||||||
esrp
|
esrp
|
||||||
@ -1551,6 +1553,7 @@ programdata
|
|||||||
PROGRAMFILES
|
PROGRAMFILES
|
||||||
projectname
|
projectname
|
||||||
PROPBAG
|
PROPBAG
|
||||||
|
PROPERTYKEY
|
||||||
propkey
|
propkey
|
||||||
propvarutil
|
propvarutil
|
||||||
prvpane
|
prvpane
|
||||||
|
@ -132,7 +132,7 @@ public
|
|||||||
auto names = gcnew List<String ^>();
|
auto names = gcnew List<String ^>();
|
||||||
for (const auto& device : MicrophoneDevice::getAllActive())
|
for (const auto& device : MicrophoneDevice::getAllActive())
|
||||||
{
|
{
|
||||||
names->Add(gcnew String(device.name().data()));
|
names->Add(gcnew String(device->name().data()));
|
||||||
}
|
}
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "AudioDeviceNotificationClient.h"
|
||||||
|
|
||||||
|
AudioDeviceNotificationClient::AudioDeviceNotificationClient()
|
||||||
|
{
|
||||||
|
(void)CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_deviceEnumerator));
|
||||||
|
if (!_deviceEnumerator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(_deviceEnumerator->RegisterEndpointNotificationCallback(this)))
|
||||||
|
{
|
||||||
|
_deviceEnumerator->Release();
|
||||||
|
_deviceEnumerator = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDeviceNotificationClient::~AudioDeviceNotificationClient()
|
||||||
|
{
|
||||||
|
if (!_deviceEnumerator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_deviceEnumerator->UnregisterEndpointNotificationCallback(this);
|
||||||
|
_deviceEnumerator->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AudioDeviceNotificationClient::AddRef()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AudioDeviceNotificationClient::Release()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AudioDeviceNotificationClient::QueryInterface(REFIID, void**)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AudioDeviceNotificationClient::OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY)
|
||||||
|
{
|
||||||
|
_deviceConfigurationChanged = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AudioDeviceNotificationClient::OnDeviceAdded(LPCWSTR)
|
||||||
|
{
|
||||||
|
_deviceConfigurationChanged = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AudioDeviceNotificationClient::OnDeviceRemoved(LPCWSTR)
|
||||||
|
{
|
||||||
|
_deviceConfigurationChanged = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AudioDeviceNotificationClient::OnDeviceStateChanged(LPCWSTR, DWORD)
|
||||||
|
{
|
||||||
|
_deviceConfigurationChanged = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AudioDeviceNotificationClient::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR)
|
||||||
|
{
|
||||||
|
if (role == eConsole && (flow == eCapture || flow == eAll))
|
||||||
|
{
|
||||||
|
_deviceConfigurationChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <MMDeviceAPI.h>
|
||||||
|
|
||||||
|
struct AudioDeviceNotificationClient : IMMNotificationClient
|
||||||
|
{
|
||||||
|
AudioDeviceNotificationClient();
|
||||||
|
~AudioDeviceNotificationClient();
|
||||||
|
|
||||||
|
bool PullPendingNotifications()
|
||||||
|
{
|
||||||
|
const bool result = _deviceConfigurationChanged;
|
||||||
|
_deviceConfigurationChanged = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ULONG AddRef() override;
|
||||||
|
ULONG Release() override;
|
||||||
|
HRESULT QueryInterface(REFIID, void**) override;
|
||||||
|
HRESULT OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) override;
|
||||||
|
HRESULT OnDeviceAdded(LPCWSTR) override;
|
||||||
|
HRESULT OnDeviceRemoved(LPCWSTR) override;
|
||||||
|
HRESULT OnDeviceStateChanged(LPCWSTR, DWORD) override;
|
||||||
|
HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) override;
|
||||||
|
|
||||||
|
IMMDeviceEnumerator* _deviceEnumerator = nullptr;
|
||||||
|
|
||||||
|
bool _deviceConfigurationChanged = false;
|
||||||
|
};
|
@ -126,6 +126,12 @@ LRESULT Toolbar::WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARA
|
|||||||
}
|
}
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
{
|
{
|
||||||
|
if (toolbar->audioConfChangesNotifier.PullPendingNotifications())
|
||||||
|
{
|
||||||
|
instance->onMicrophoneConfigurationChanged();
|
||||||
|
}
|
||||||
|
toolbar->microphoneMuted = instance->getMicrophoneMuteState();
|
||||||
|
|
||||||
if (toolbar->generalSettingsUpdateScheduled)
|
if (toolbar->generalSettingsUpdateScheduled)
|
||||||
{
|
{
|
||||||
instance->onGeneralSettingsChanged();
|
instance->onGeneralSettingsChanged();
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <common/Display/monitors.h>
|
#include <common/Display/monitors.h>
|
||||||
|
|
||||||
|
#include "AudioDeviceNotificationClient.h"
|
||||||
|
|
||||||
struct ToolbarImages
|
struct ToolbarImages
|
||||||
{
|
{
|
||||||
Gdiplus::Image* camOnMicOn = nullptr;
|
Gdiplus::Image* camOnMicOn = nullptr;
|
||||||
@ -43,6 +45,7 @@ private:
|
|||||||
|
|
||||||
ToolbarImages darkImages;
|
ToolbarImages darkImages;
|
||||||
ToolbarImages lightImages;
|
ToolbarImages lightImages;
|
||||||
|
AudioDeviceNotificationClient audioConfChangesNotifier;
|
||||||
|
|
||||||
bool cameraMuted = false;
|
bool cameraMuted = false;
|
||||||
bool cameraInUse = false;
|
bool cameraInUse = false;
|
||||||
|
@ -111,6 +111,7 @@ xcopy /y /I "$(ProjectDir)black.bmp*" "$(OutDir)"</Command>
|
|||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="AudioDeviceNotificationClient.h" />
|
||||||
<ClInclude Include="framework.h" />
|
<ClInclude Include="framework.h" />
|
||||||
<ClInclude Include="Toolbar.h" />
|
<ClInclude Include="Toolbar.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
@ -118,6 +119,7 @@ xcopy /y /I "$(ProjectDir)black.bmp*" "$(OutDir)"</Command>
|
|||||||
<ClInclude Include="VideoConferenceModule.h" />
|
<ClInclude Include="VideoConferenceModule.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="AudioDeviceNotificationClient.cpp" />
|
||||||
<ClCompile Include="dllmain.cpp" />
|
<ClCompile Include="dllmain.cpp" />
|
||||||
<ClCompile Include="trace.cpp" />
|
<ClCompile Include="trace.cpp" />
|
||||||
<ClCompile Include="Toolbar.cpp" />
|
<ClCompile Include="Toolbar.cpp" />
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<ClCompile Include="pch.cpp" />
|
<ClCompile Include="pch.cpp" />
|
||||||
<ClCompile Include="VideoConferenceModule.cpp" />
|
<ClCompile Include="VideoConferenceModule.cpp" />
|
||||||
<ClCompile Include="trace.cpp" />
|
<ClCompile Include="trace.cpp" />
|
||||||
|
<ClCompile Include="AudioDeviceNotificationClient.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="framework.h" />
|
<ClInclude Include="framework.h" />
|
||||||
@ -13,6 +14,7 @@
|
|||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="VideoConferenceModule.h" />
|
<ClInclude Include="VideoConferenceModule.h" />
|
||||||
<ClInclude Include="trace.h" />
|
<ClInclude Include="trace.h" />
|
||||||
|
<ClInclude Include="AudioDeviceNotificationClient.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Image Include="black.bmp" />
|
<Image Include="black.bmp" />
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <common/debug_control.h>
|
#include <common/debug_control.h>
|
||||||
#include <common/SettingsAPI/settings_helpers.h>
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
@ -51,20 +52,22 @@ void VideoConferenceModule::reverseMicrophoneMute()
|
|||||||
bool muted = false;
|
bool muted = false;
|
||||||
for (auto& controlledMic : instance->_controlledMicrophones)
|
for (auto& controlledMic : instance->_controlledMicrophones)
|
||||||
{
|
{
|
||||||
const bool was_muted = controlledMic.muted();
|
const bool was_muted = controlledMic->muted();
|
||||||
controlledMic.toggle_muted();
|
controlledMic->toggle_muted();
|
||||||
muted = muted || !was_muted;
|
muted = muted || !was_muted;
|
||||||
}
|
}
|
||||||
if (muted)
|
if (muted)
|
||||||
{
|
{
|
||||||
Trace::MicrophoneMuted();
|
Trace::MicrophoneMuted();
|
||||||
}
|
}
|
||||||
|
instance->_mic_muted_state_during_disconnect = !instance->_mic_muted_state_during_disconnect;
|
||||||
|
|
||||||
toolbar.setMicrophoneMute(muted);
|
toolbar.setMicrophoneMute(muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoConferenceModule::getMicrophoneMuteState()
|
bool VideoConferenceModule::getMicrophoneMuteState()
|
||||||
{
|
{
|
||||||
return instance->_microphoneTrackedInUI ? instance->_microphoneTrackedInUI->muted() : false;
|
return instance->_microphoneTrackedInUI ? instance->_microphoneTrackedInUI->muted() : instance->_mic_muted_state_during_disconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoConferenceModule::reverseVirtualCameraMuteState()
|
void VideoConferenceModule::reverseVirtualCameraMuteState()
|
||||||
@ -268,6 +271,46 @@ void VideoConferenceModule::onModuleSettingsChanged()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoConferenceModule::onMicrophoneConfigurationChanged()
|
||||||
|
{
|
||||||
|
if (!_controllingAllMics)
|
||||||
|
{
|
||||||
|
// Don't care if we don't control all the mics
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool mutedStateForNewMics = _microphoneTrackedInUI ? _microphoneTrackedInUI->muted() : _mic_muted_state_during_disconnect;
|
||||||
|
std::unordered_set<std::wstring_view> currentlyTrackedMicsIds;
|
||||||
|
for (const auto& controlledMic : _controlledMicrophones)
|
||||||
|
{
|
||||||
|
currentlyTrackedMicsIds.emplace(controlledMic->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto allMics = MicrophoneDevice::getAllActive();
|
||||||
|
for (auto& newMic : allMics)
|
||||||
|
{
|
||||||
|
if (currentlyTrackedMicsIds.contains(newMic->id()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutedStateForNewMics)
|
||||||
|
{
|
||||||
|
newMic->set_muted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_controlledMicrophones.emplace_back(std::move(newMic));
|
||||||
|
}
|
||||||
|
// Restore invalidated pointer
|
||||||
|
_microphoneTrackedInUI = controlledDefaultMic();
|
||||||
|
if (_microphoneTrackedInUI)
|
||||||
|
{
|
||||||
|
_microphoneTrackedInUI->set_mute_changed_callback([](const bool muted) {
|
||||||
|
toolbar.setMicrophoneMute(muted);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VideoConferenceModule::VideoConferenceModule() :
|
VideoConferenceModule::VideoConferenceModule() :
|
||||||
_generalSettingsWatcher{ PTSettingsHelper::get_powertoys_general_save_file_location(), [this] {
|
_generalSettingsWatcher{ PTSettingsHelper::get_powertoys_general_save_file_location(), [this] {
|
||||||
toolbar.scheduleGeneralSettingsUpdate();
|
toolbar.scheduleGeneralSettingsUpdate();
|
||||||
@ -388,47 +431,56 @@ void VideoConferenceModule::updateControlledMicrophones(const std::wstring_view
|
|||||||
{
|
{
|
||||||
for (auto& controlledMic : _controlledMicrophones)
|
for (auto& controlledMic : _controlledMicrophones)
|
||||||
{
|
{
|
||||||
controlledMic.set_muted(false);
|
controlledMic->set_muted(false);
|
||||||
}
|
}
|
||||||
_controlledMicrophones.clear();
|
_controlledMicrophones.clear();
|
||||||
_microphoneTrackedInUI = nullptr;
|
_microphoneTrackedInUI = nullptr;
|
||||||
auto allMics = MicrophoneDevice::getAllActive();
|
auto allMics = MicrophoneDevice::getAllActive();
|
||||||
if (new_mic == L"[All]")
|
if (new_mic == L"[All]")
|
||||||
{
|
{
|
||||||
|
_controllingAllMics = true;
|
||||||
_controlledMicrophones = std::move(allMics);
|
_controlledMicrophones = std::move(allMics);
|
||||||
if (auto defaultMic = MicrophoneDevice::getDefault())
|
_microphoneTrackedInUI = controlledDefaultMic();
|
||||||
{
|
|
||||||
for (auto& controlledMic : _controlledMicrophones)
|
|
||||||
{
|
|
||||||
if (controlledMic.id() == defaultMic->id())
|
|
||||||
{
|
|
||||||
_microphoneTrackedInUI = &controlledMic;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_controllingAllMics = false;
|
||||||
for (auto& controlledMic : allMics)
|
for (auto& controlledMic : allMics)
|
||||||
{
|
{
|
||||||
if (controlledMic.name() == new_mic)
|
if (controlledMic->name() == new_mic)
|
||||||
{
|
{
|
||||||
_controlledMicrophones.emplace_back(std::move(controlledMic));
|
_controlledMicrophones.emplace_back(std::move(controlledMic));
|
||||||
_microphoneTrackedInUI = &_controlledMicrophones[0];
|
_microphoneTrackedInUI = _controlledMicrophones[0].get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_microphoneTrackedInUI)
|
if (_microphoneTrackedInUI)
|
||||||
{
|
{
|
||||||
_microphoneTrackedInUI->set_mute_changed_callback([&](const bool muted) {
|
_microphoneTrackedInUI->set_mute_changed_callback([](const bool muted) {
|
||||||
toolbar.setMicrophoneMute(muted);
|
toolbar.setMicrophoneMute(muted);
|
||||||
});
|
});
|
||||||
toolbar.setMicrophoneMute(_microphoneTrackedInUI->muted());
|
toolbar.setMicrophoneMute(_microphoneTrackedInUI->muted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MicrophoneDevice* VideoConferenceModule::controlledDefaultMic()
|
||||||
|
{
|
||||||
|
if (auto defaultMic = MicrophoneDevice::getDefault())
|
||||||
|
{
|
||||||
|
for (auto& controlledMic : _controlledMicrophones)
|
||||||
|
{
|
||||||
|
if (controlledMic->id() == defaultMic->id())
|
||||||
|
{
|
||||||
|
return controlledMic.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void toggleProxyCamRegistration(const bool enable)
|
void toggleProxyCamRegistration(const bool enable)
|
||||||
{
|
{
|
||||||
if (!is_process_elevated())
|
if (!is_process_elevated())
|
||||||
|
@ -61,10 +61,14 @@ public:
|
|||||||
|
|
||||||
void onGeneralSettingsChanged();
|
void onGeneralSettingsChanged();
|
||||||
void onModuleSettingsChanged();
|
void onModuleSettingsChanged();
|
||||||
|
void onMicrophoneConfigurationChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void init_settings();
|
void init_settings();
|
||||||
void updateControlledMicrophones(const std::wstring_view new_mic);
|
void updateControlledMicrophones(const std::wstring_view new_mic);
|
||||||
|
MicrophoneDevice* controlledDefaultMic();
|
||||||
|
|
||||||
// all callback methods and used by callback have to be static
|
// all callback methods and used by callback have to be static
|
||||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||||
static bool isKeyPressed(unsigned int keyCode);
|
static bool isKeyPressed(unsigned int keyCode);
|
||||||
@ -73,7 +77,9 @@ private:
|
|||||||
static HHOOK hook_handle;
|
static HHOOK hook_handle;
|
||||||
bool _enabled = false;
|
bool _enabled = false;
|
||||||
|
|
||||||
std::vector<MicrophoneDevice> _controlledMicrophones;
|
bool _mic_muted_state_during_disconnect = false;
|
||||||
|
bool _controllingAllMics = false;
|
||||||
|
std::vector<std::unique_ptr<MicrophoneDevice>> _controlledMicrophones;
|
||||||
MicrophoneDevice* _microphoneTrackedInUI = nullptr;
|
MicrophoneDevice* _microphoneTrackedInUI = nullptr;
|
||||||
|
|
||||||
std::optional<SerializedSharedMemory> _imageOverlayChannel;
|
std::optional<SerializedSharedMemory> _imageOverlayChannel;
|
||||||
|
@ -869,6 +869,13 @@ VideoCaptureProxyFilter::~VideoCaptureProxyFilter()
|
|||||||
|
|
||||||
_worker_cv.notify_one();
|
_worker_cv.notify_one();
|
||||||
_worker_thread.join();
|
_worker_thread.join();
|
||||||
|
if (_settingsUpdateChannel)
|
||||||
|
{
|
||||||
|
_settingsUpdateChannel->access([](auto settingsMemory) {
|
||||||
|
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
|
||||||
|
settings->cameraInUse = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoCaptureProxyFilter::SyncedSettings VideoCaptureProxyFilter::SyncCurrentSettings()
|
VideoCaptureProxyFilter::SyncedSettings VideoCaptureProxyFilter::SyncCurrentSettings()
|
||||||
|
@ -76,34 +76,34 @@ void MicrophoneDevice::set_mute_changed_callback(mute_changed_cb_t callback) noe
|
|||||||
_endpoint->RegisterControlChangeNotify(_notifier.get());
|
_endpoint->RegisterControlChangeNotify(_notifier.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<MicrophoneDevice> MicrophoneDevice::getDefault()
|
std::unique_ptr<MicrophoneDevice> MicrophoneDevice::getDefault()
|
||||||
{
|
{
|
||||||
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
||||||
if (!deviceEnumerator)
|
if (!deviceEnumerator)
|
||||||
{
|
{
|
||||||
LOG("MicrophoneDevice::getDefault MMDeviceEnumerator returned null");
|
LOG("MicrophoneDevice::getDefault MMDeviceEnumerator returned null");
|
||||||
return std::nullopt;
|
return nullptr;
|
||||||
}
|
}
|
||||||
wil::com_ptr_nothrow<IMMDevice> captureDevice;
|
wil::com_ptr_nothrow<IMMDevice> captureDevice;
|
||||||
deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &captureDevice);
|
deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &captureDevice);
|
||||||
if (!captureDevice)
|
if (!captureDevice)
|
||||||
{
|
{
|
||||||
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
||||||
return std::nullopt;
|
return nullptr;
|
||||||
}
|
}
|
||||||
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
|
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
|
||||||
captureDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(µphoneEndpoint));
|
captureDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(µphoneEndpoint));
|
||||||
if (!microphoneEndpoint)
|
if (!microphoneEndpoint)
|
||||||
{
|
{
|
||||||
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
||||||
return std::nullopt;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_optional<MicrophoneDevice>(std::move(captureDevice), std::move(microphoneEndpoint));
|
return std::make_unique<MicrophoneDevice>(std::move(captureDevice), std::move(microphoneEndpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MicrophoneDevice> MicrophoneDevice::getAllActive()
|
std::vector<std::unique_ptr<MicrophoneDevice>> MicrophoneDevice::getAllActive()
|
||||||
{
|
{
|
||||||
std::vector<MicrophoneDevice> microphoneDevices;
|
std::vector<std::unique_ptr<MicrophoneDevice>> microphoneDevices;
|
||||||
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
||||||
if (!deviceEnumerator)
|
if (!deviceEnumerator)
|
||||||
{
|
{
|
||||||
@ -135,7 +135,7 @@ std::vector<MicrophoneDevice> MicrophoneDevice::getAllActive()
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
microphoneDevices.emplace_back(std::move(device), std::move(microphoneEndpoint));
|
microphoneDevices.push_back(std::make_unique<MicrophoneDevice>(std::move(device), std::move(microphoneEndpoint)));
|
||||||
}
|
}
|
||||||
return microphoneDevices;
|
return microphoneDevices;
|
||||||
}
|
}
|
||||||
@ -147,6 +147,8 @@ MicrophoneDevice::VolumeNotifier::VolumeNotifier(MicrophoneDevice* subscribedDev
|
|||||||
|
|
||||||
HRESULT __stdcall MicrophoneDevice::VolumeNotifier::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data)
|
HRESULT __stdcall MicrophoneDevice::VolumeNotifier::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data)
|
||||||
{
|
{
|
||||||
_subscribedDevice->_mute_changed_callback(data->bMuted);
|
if (_subscribedDevice && _subscribedDevice->_mute_changed_callback)
|
||||||
|
_subscribedDevice->_mute_changed_callback(data->bMuted);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include <wil/resource.h>
|
#include <wil/resource.h>
|
||||||
#include <wil/com.h>
|
#include <wil/com.h>
|
||||||
|
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -47,7 +46,8 @@ private:
|
|||||||
constexpr static inline std::wstring_view FALLBACK_ID = L"UNKNOWN_ID";
|
constexpr static inline std::wstring_view FALLBACK_ID = L"UNKNOWN_ID";
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MicrophoneDevice(MicrophoneDevice&&) noexcept = default;
|
MicrophoneDevice(MicrophoneDevice&&) noexcept = delete;
|
||||||
|
MicrophoneDevice(const MicrophoneDevice&) noexcept = delete;
|
||||||
MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint);
|
MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint);
|
||||||
~MicrophoneDevice();
|
~MicrophoneDevice();
|
||||||
|
|
||||||
@ -60,6 +60,6 @@ public:
|
|||||||
std::wstring_view name() const noexcept;
|
std::wstring_view name() const noexcept;
|
||||||
void set_mute_changed_callback(mute_changed_cb_t callback) noexcept;
|
void set_mute_changed_callback(mute_changed_cb_t callback) noexcept;
|
||||||
|
|
||||||
static std::optional<MicrophoneDevice> getDefault();
|
static std::unique_ptr<MicrophoneDevice> getDefault();
|
||||||
static std::vector<MicrophoneDevice> getAllActive();
|
static std::vector<std::unique_ptr<MicrophoneDevice>> getAllActive();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user