Как управлять глобальной громкостью системы с помощью данного winrt BluetoothDevice
теперь у меня есть, когда пользователь использует это устройство Bluetooth, я хочу отслеживать глобальный объем системы на предмет изменений, а также получать и устанавливать его в любое время.
После некоторого поиска я нашел ответ, что они не могут быть реализованы в одиночку, мне может понадобиться.
Первоначально я отфильтровал ожидаемое, сравнивName property
сFriendlyName property
всех s, но эти два имени совпадали лишь частично и не были точно равными. Это сработало для некоторых пользователей, но для других
Name
сильно отличался от ожидаемого
FriendlyName
, что явно не является надежным решением.
Итак, мой вопрос: есть ли надежный способ найти
win32
аудио конечная точка, которая соответствует заданному
winrt
BluetoothDevice
? Или есть другой надежный способ реализовать функции, о которых я упоминал в начале, без использования
IMMDevice
?
Заранее спасибо!
Вот упрощенный код: (для его компиляции вам понадобится VS 2019 +
/std:latest
+
/await
)
#include <mutex>
#include <iostream>
#include <Windows.h>
#include <mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Devices.Bluetooth.h>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Devices::Bluetooth;
using namespace winrt::Windows::Devices::Enumeration;
using winrt_exception = winrt::hresult_error;
#define ASSERT(cond) \
while (!(cond)) { \
__debugbreak(); \
}
#define ASSERT_HRESULT(res) \
if (FAILED(res)) { \
std::cerr << "HRESULT FAILED. " << #res << std::endl; \
std::exit(1); \
}
#define UNRELIABLE_AND_INCOMPLETE_NAME_FROM_BLE_DEVICE L""
void init_winrt()
{
static std::once_flag once_flag;
std::call_once(once_flag, []() {
try {
winrt::init_apartment();
}
catch (const winrt_exception &) {
std::cerr << "Failed to initialize winrt." << std::endl;
std::exit(1);
}
});
}
auto connected_ble_devices()
{
std::vector<BluetoothDevice> result;
auto aqs = BluetoothDevice::GetDeviceSelectorFromConnectionStatus(
BluetoothConnectionStatus::Connected);
auto collection = DeviceInformation::FindAllAsync(aqs).get();
result.reserve(collection.Size());
for (uint32_t i = 0; i < collection.Size(); ++i) {
const auto &device_info = collection.GetAt(i);
try {
auto device = BluetoothDevice::FromIdAsync(device_info.Id()).get();
result.emplace_back(std::move(device));
}
catch (const winrt_exception &) {
std::cerr << "BluetoothDevice::FromIdAsync() failed." << std::endl;
std::exit(1);
}
}
return result;
}
auto find_desired_ble_device()
{
auto connected = connected_ble_devices();
ASSERT(connected.size() == 1);
return connected.front();
}
auto get_audio_endpoint_by_ble_device(const BluetoothDevice &ble_device)
{
// For simplicity, I have not freed some memory that should be freed, let's ignore all memory
// leaks
IMMDeviceEnumerator *device_enumerator;
ASSERT_HRESULT(CoCreateInstance(
__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
(void **)&device_enumerator));
IMMDeviceCollection *collection;
ASSERT_HRESULT(
device_enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection));
uint32_t count = 0;
ASSERT_HRESULT(collection->GetCount(&count));
IMMDevice *result = nullptr;
// The unreliable way currently I used
const auto &match_with_ble_device = [](IPropertyStore *property) {
PROPVARIANT variant;
ASSERT_HRESULT(property->GetValue(PKEY_DeviceInterface_FriendlyName, &variant));
ASSERT(variant.pwszVal != nullptr);
return std::wstring{variant.pwszVal}.starts_with(
UNRELIABLE_AND_INCOMPLETE_NAME_FROM_BLE_DEVICE);
};
for (uint32_t i = 0; i < count; ++i) {
IMMDevice *device;
ASSERT_HRESULT(collection->Item(i, &device));
IPropertyStore *property;
ASSERT_HRESULT(device->OpenPropertyStore(STGM_READ, &property));
if (!match_with_ble_device(property)) {
continue;
}
result = device;
#define CHECK_PROPERTY_VALUE_EXISTS(key) \
{ \
PROPVARIANT variant; \
ASSERT_HRESULT(property->GetValue(key, &variant)); \
if (variant.pwszVal != nullptr) { \
std::cout << "Property '" #key "' has a value.\n"; \
} \
}
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DeviceDesc);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_HardwareIds);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_CompatibleIds);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Service);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Class);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ClassGuid);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Driver);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ConfigFlags);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Manufacturer);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_FriendlyName);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_LocationInfo);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_PDOName);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Capabilities);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_UINumber);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_UpperFilters);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_LowerFilters);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_BusTypeGuid);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_LegacyBusType);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_BusNumber);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_EnumeratorName);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Security);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_SecuritySDS);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DevType);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Exclusive);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Characteristics);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Address);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_UINumberDescFormat);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_PowerData);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_RemovalPolicy);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_RemovalPolicyDefault);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_RemovalPolicyOverride);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_InstallState);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_LocationPaths);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_BaseContainerId);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DevNodeStatus);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ProblemCode);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_EjectionRelations);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_RemovalRelations);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_PowerRelations);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_BusRelations);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Parent);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Children);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Siblings);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_TransportRelations);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Reported);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Legacy);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_InstanceId);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ContainerId);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ModelId);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_FriendlyNameAttributes);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ManufacturerAttributes);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_PresenceNotForDevice);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_SignalStrength);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_IsAssociateableByUserAction);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Numa_Proximity_Domain);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DHP_Rebalance_Policy);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_Numa_Node);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_BusReportedDeviceDesc);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_InstallInProgress);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverDate);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverVersion);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverDesc);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverInfPath);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverInfSection);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverInfSectionExt);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_MatchingDeviceId);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverProvider);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverPropPageProvider);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverCoInstallers);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ResourcePickerTags);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_ResourcePickerExceptions);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverRank);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_DriverLogoLevel);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_NoConnectSound);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_GenericDriverInstalled);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_AdditionalSoftwareRequested);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_SafeRemovalRequired);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_Device_SafeRemovalRequiredOverride);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DrvPkg_Model);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DrvPkg_VendorWebSite);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DrvPkg_DetailedDescription);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DrvPkg_DocumentationLink);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DrvPkg_Icon);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DrvPkg_BrandingIcon);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_UpperFilters);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_LowerFilters);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_Security);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_SecuritySDS);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_DevType);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_Exclusive);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_Characteristics);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_Name);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_ClassName);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_Icon);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_ClassInstaller);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_PropPageProvider);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_NoInstallClass);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_NoDisplayClass);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_SilentInstall);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_NoUseClass);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_DefaultService);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_IconPath);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceClass_ClassCoInstallers);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceInterface_FriendlyName);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceInterface_Enabled);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceInterface_ClassGuid);
CHECK_PROPERTY_VALUE_EXISTS(PKEY_DeviceInterfaceClass_DefaultInterface);
#undef CHECK_PROPERTY_VALUE_EXISTS
if (result != nullptr) {
break;
}
}
return result;
}
int main()
{
init_winrt();
auto ble_device = find_desired_ble_device();
auto endpoint = get_audio_endpoint_by_ble_device(ble_device);
// do something with the endpoint...
}
Выход
Property 'PKEY_Device_DeviceDesc' has a value.
Property 'PKEY_Device_FriendlyName' has a value.
Property 'PKEY_Device_EnumeratorName' has a value.
Property 'PKEY_Device_ContainerId' has a value.
Property 'PKEY_DeviceClass_IconPath' has a value.
Property 'PKEY_DeviceInterface_FriendlyName' has a value.