设备属性(核心音频 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.
//-----------------------------------------------------------
#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 函数,为系统中的音频终结点设备创建枚举器。 除非调用程序之前调用 CoInitializeCoInitializeEx 函数来初始化 COM 库,否则 CoCreateInstance 调用将失败。 有关 CoCreateInstanceCoInitializeCoInitializeEx的详细信息,请参阅 Windows SDK 文档。

有关 IMMDeviceEnumeratorIMMDeviceCollectionIMMDevice 接口的详细信息,请参阅 MMDevice API

音频终结点设备