Как управлять глобальной громкостью системы с помощью данного 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.

0 ответов

Другие вопросы по тегам