mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 19:26:39 +02:00
153 lines
4.5 KiB
C++
153 lines
4.5 KiB
C++
|
|
#include "MicrophoneDevice.h"
|
||
|
|
|
||
|
|
#include "Logging.h"
|
||
|
|
|
||
|
|
#include <Functiondiscoverykeys_devpkey.h>
|
||
|
|
|
||
|
|
MicrophoneDevice::MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint) :
|
||
|
|
_device{ std::move(device) },
|
||
|
|
_endpoint{ std::move(endpoint) }
|
||
|
|
{
|
||
|
|
if (!_device || !_endpoint)
|
||
|
|
{
|
||
|
|
throw std::logic_error("MicrophoneDevice was initialized with null objects");
|
||
|
|
}
|
||
|
|
_device->GetId(&_id);
|
||
|
|
wil::com_ptr_nothrow<IPropertyStore> props;
|
||
|
|
_device->OpenPropertyStore(
|
||
|
|
STGM_READ, &props);
|
||
|
|
if (props)
|
||
|
|
{
|
||
|
|
props->GetValue(PKEY_Device_FriendlyName, &_friendly_name);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
LOG("MicrophoneDevice::MicrophoneDevice couldn't open property store");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
MicrophoneDevice::~MicrophoneDevice()
|
||
|
|
{
|
||
|
|
if (_notifier)
|
||
|
|
{
|
||
|
|
_endpoint->UnregisterControlChangeNotify(_notifier.get());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MicrophoneDevice::active() const noexcept
|
||
|
|
{
|
||
|
|
DWORD state = 0;
|
||
|
|
_device->GetState(&state);
|
||
|
|
return state == DEVICE_STATE_ACTIVE;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MicrophoneDevice::set_muted(const bool muted) noexcept
|
||
|
|
{
|
||
|
|
_endpoint->SetMute(muted, nullptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MicrophoneDevice::muted() const noexcept
|
||
|
|
{
|
||
|
|
BOOL muted = FALSE;
|
||
|
|
_endpoint->GetMute(&muted);
|
||
|
|
return muted;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MicrophoneDevice::toggle_muted() noexcept
|
||
|
|
{
|
||
|
|
set_muted(!muted());
|
||
|
|
}
|
||
|
|
|
||
|
|
std::wstring_view MicrophoneDevice::id() const noexcept
|
||
|
|
{
|
||
|
|
return _id ? _id.get() : FALLBACK_ID;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::wstring_view MicrophoneDevice::name() const noexcept
|
||
|
|
{
|
||
|
|
return _friendly_name.pwszVal ? _friendly_name.pwszVal : FALLBACK_NAME;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MicrophoneDevice::set_mute_changed_callback(mute_changed_cb_t callback) noexcept
|
||
|
|
{
|
||
|
|
_mute_changed_callback = std::move(callback);
|
||
|
|
_notifier = winrt::make<VolumeNotifier>(this);
|
||
|
|
|
||
|
|
_endpoint->RegisterControlChangeNotify(_notifier.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
std::optional<MicrophoneDevice> MicrophoneDevice::getDefault()
|
||
|
|
{
|
||
|
|
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
||
|
|
if (!deviceEnumerator)
|
||
|
|
{
|
||
|
|
LOG("MicrophoneDevice::getDefault MMDeviceEnumerator returned null");
|
||
|
|
return std::nullopt;
|
||
|
|
}
|
||
|
|
wil::com_ptr_nothrow<IMMDevice> captureDevice;
|
||
|
|
deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &captureDevice);
|
||
|
|
if (!captureDevice)
|
||
|
|
{
|
||
|
|
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
||
|
|
return std::nullopt;
|
||
|
|
}
|
||
|
|
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
|
||
|
|
captureDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(µphoneEndpoint));
|
||
|
|
if (!microphoneEndpoint)
|
||
|
|
{
|
||
|
|
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
||
|
|
return std::nullopt;
|
||
|
|
}
|
||
|
|
return std::make_optional<MicrophoneDevice>(std::move(captureDevice), std::move(microphoneEndpoint));
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<MicrophoneDevice> MicrophoneDevice::getAllActive()
|
||
|
|
{
|
||
|
|
std::vector<MicrophoneDevice> microphoneDevices;
|
||
|
|
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
||
|
|
if (!deviceEnumerator)
|
||
|
|
{
|
||
|
|
LOG("MicrophoneDevice::getAllActive MMDeviceEnumerator returned null");
|
||
|
|
return microphoneDevices;
|
||
|
|
}
|
||
|
|
|
||
|
|
wil::com_ptr_nothrow<IMMDeviceCollection> captureDevices;
|
||
|
|
deviceEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &captureDevices);
|
||
|
|
if (!captureDevices)
|
||
|
|
{
|
||
|
|
LOG("MicrophoneDevice::getAllActive EnumAudioEndpoints returned null");
|
||
|
|
return microphoneDevices;
|
||
|
|
}
|
||
|
|
UINT nDevices = 0;
|
||
|
|
captureDevices->GetCount(&nDevices);
|
||
|
|
microphoneDevices.reserve(nDevices);
|
||
|
|
for (UINT i = 0; i < nDevices; ++i)
|
||
|
|
{
|
||
|
|
wil::com_ptr_nothrow<IMMDevice> device;
|
||
|
|
captureDevices->Item(i, &device);
|
||
|
|
if (!device)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
|
||
|
|
device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(µphoneEndpoint));
|
||
|
|
if (!microphoneEndpoint)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
microphoneDevices.emplace_back(std::move(device), std::move(microphoneEndpoint));
|
||
|
|
}
|
||
|
|
return microphoneDevices;
|
||
|
|
}
|
||
|
|
|
||
|
|
MicrophoneDevice::VolumeNotifier::VolumeNotifier(MicrophoneDevice* subscribedDevice) :
|
||
|
|
_subscribedDevice{ subscribedDevice }
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
HRESULT __stdcall MicrophoneDevice::VolumeNotifier::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data)
|
||
|
|
{
|
||
|
|
_subscribedDevice->_mute_changed_callback(data->bMuted);
|
||
|
|
return S_OK;
|
||
|
|
}
|