设备属性(核心音频 API)

在枚举 音频终结点设备的过程中,客户端应用程序可以询问其设备属性的终结点对象。 设备属性在 MMDevice API IPropertyStore 接口的实现中公开。 给定对终结点对象的 IMMDevice 接口的引用,客户端可以通过调用 IMMDevice::OpenPropertyStore 方法获取对终结点对象属性存储的引用。

客户端可以读取这些属性,但不应设置这些属性。 属性值存储为 PROPVARIANT 结构。

终结点管理器设置终结点的基本设备属性。 终结点管理器是负责检测音频终结点设备存在的 Windows 组件。

以下列表中的每个 PKEY_Xxx 属性标识符都是在头文件 Functiondiscoverykeys_devpkey.h中定义的 PROPERTYKEY 类型的常量。 所有音频终结点设备都具有这些设备属性。

财产 描述
PKEY_DeviceInterface_FriendlyName 终结点设备附加到的音频适配器的友好名称(例如,“XYZ 音频适配器”)。
PKEY_Device_DeviceDesc 终结点设备的设备说明(例如“扬声器”)。
PKEY_Device_FriendlyName 终结点设备的友好名称(例如“扬声器(XYZ 音频适配器)”)。
PKEY_Device_InstanceId 存储设备实例标识符的音频终结点。 还可以通过 IMMDevice::GetId 方法获取该值。 有关此属性的详细信息,请参阅 终结点 ID 字符串 和 DEVPKEY_Device_InstanceId。
PKEY_Device_ContainerId 存储实现音频终结点的 PnP 设备的 容器标识符。 有关此属性的详细信息,请参阅 DEVPKEY_Device_ContainerId。

某些音频终结点设备可能具有其他属性,这些属性不会显示在前面的列表中。 有关其他属性的详细信息,请参阅 音频终结点属性。

有关 PROPERTYKEY的详细信息,请参阅 Windows 属性系统文档。

下面的代码示例打印系统中所有音频呈现终结点设备的显示名称:

//-----------------------------------------------------------
// This function enumerates all active (plugged in) audio
// rendering endpoint devices. It prints the friendly name
// and endpoint ID string of each endpoint device.
//-----------------------------------------------------------
#include <stdio.h>
#include <winerror.h>
#include <Mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>

#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);

void PrintEndpointNames()
{
    HRESULT hr = S_OK;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDeviceCollection *pCollection = NULL;
    IMMDevice *pEndpoint = NULL;
    IPropertyStore *pProps = NULL;
    LPWSTR pwszID = NULL;

    hr = CoCreateInstance(
           CLSID_MMDeviceEnumerator, NULL,
           CLSCTX_ALL, IID_IMMDeviceEnumerator,
           (void**)&pEnumerator);
    EXIT_ON_ERROR(hr)

    hr = pEnumerator->EnumAudioEndpoints(
                        eRender, DEVICE_STATE_ACTIVE,
                        &pCollection);
    EXIT_ON_ERROR(hr)

    UINT  count;
    hr = pCollection->GetCount(&count);
    EXIT_ON_ERROR(hr)

    if (count == 0)
    {
        printf("No endpoints found.\n");
    }

    // Each loop prints the name of an endpoint device.
    for (ULONG i = 0; i < count; i++)
    {
        // Get pointer to endpoint number i.
        hr = pCollection->Item(i, &pEndpoint);
        EXIT_ON_ERROR(hr)

        // Get the endpoint ID string.
        hr = pEndpoint->GetId(&pwszID);
        EXIT_ON_ERROR(hr)
        
        hr = pEndpoint->OpenPropertyStore(
                          STGM_READ, &pProps);
        EXIT_ON_ERROR(hr)

        PROPVARIANT varName;
        // Initialize container for property value.
        PropVariantInit(&varName);

        // Get the endpoint's friendly-name property.
        hr = pProps->GetValue(
                       PKEY_Device_FriendlyName, &varName);
        EXIT_ON_ERROR(hr)

        // GetValue succeeds and returns S_OK if PKEY_Device_FriendlyName is not found.
        // In this case vartName.vt is set to VT_EMPTY.      
        if (varName.vt != VT_EMPTY)
        {
            // Print endpoint friendly name and endpoint ID.
            printf("Endpoint %d: \"%S\" (%S)\n", 
                    i, varName.pwszVal, pwszID);
        }

        CoTaskMemFree(pwszID);
        pwszID = NULL;
        PropVariantClear(&varName);
        SAFE_RELEASE(pProps)
        SAFE_RELEASE(pEndpoint)
    }
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pCollection)
    return;

Exit:
    printf("Error!\n");
    CoTaskMemFree(pwszID);
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pCollection)
    SAFE_RELEASE(pEndpoint)
    SAFE_RELEASE(pProps)
}

前面的代码示例中的 FAILED 宏在头文件 Winerror.h 中定义。

在前面的代码示例中,PrintEndpointNames 函数中用于 -loop 正文的调用 IMMDevice::GetId 方法,以获取由 IMMDevice 接口实例表示的音频终结点设备的 终结点 ID 字符串。 该字符串唯一标识与系统中所有其他音频终结点设备相关的设备。 客户端可以使用终结点 ID 字符串在以后或通过调用 IMMDeviceEnumerator::GetDevice 方法在不同的进程中创建音频终结点设备的实例。 客户端应将终结点 ID 字符串的内容视为不透明。 也就是说,客户端不应尝试分析字符串的内容以获取有关设备的信息。 原因是字符串格式未定义,可能从 MMDevice API 的一个实现更改为下一个实现。

前面代码示例中 PrintEndpointNames 函数获取的友好设备名称和终结点 ID 字符串与 DirectSound 在设备枚举期间提供的友好设备名称和终结点 ID 字符串相同。 有关详细信息,请参阅 旧版音频应用程序的音频事件。

在前面的代码示例中,PrintEndpointNames 函数调用 CoCreateInstance 函数,为系统中的音频终结点设备创建枚举器。 除非调用程序之前调用 CoInitialize 或 CoInitializeEx 函数来初始化 COM 库,否则 CoCreateInstance 调用将失败。 有关 CoCreateInstance、CoInitialize和 CoInitializeEx的详细信息,请参阅 Windows SDK 文档。

有关 IMMDeviceEnumerator、IMMDeviceCollection和 IMMDevice 接口的详细信息,请参阅 MMDevice API。

音频终结点设备