设备属性(核心音频 API)
在枚举音频终结点设备的过程中,客户端应用程序可以询问终结点对象的设备属性。 设备属性在 MMDevice API 的 IPropertyStore 接口实现中公开。 给定终结点对象的 IMMDevice 接口引用后,客户端可通过调用 IMMDevice::OpenPropertyStore 方法来获取终结点对象属性存储的引用。
客户端可以读取这些属性,但不应进行设置。 属性值以 PROPVARIANT 结构进行存储。
终结点管理器为终结点设置基本设备属性。 终结点管理器是负责检测音频终结点设备是否存在的 Windows 组件。
以下列表中的每个 PKEY_Xxx 属性标识符都是 PROPERTYKEY 类型的常量,该常量在头文件 Functiondiscoverykeys_devpkey.h 中定义。 所有音频终结点设备都具有这些设备属性。
properties | 说明 |
---|---|
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 函数中的 for 循环体调用了 IMMDevice::GetId 方法,以获取音频终结点设备的终结点 ID 字符串,该音频终结点设备由 IMMDevice 接口实例表示。 相对于系统中的所有其他音频终结点设备,该字符串可唯一标识设备。 客户端可以通过调用 IMMDeviceEnumerator::GetDevice 方法,在稍后时间或不同进程中使用终结点 ID 字符串来创建音频终结点设备实例。 客户端应将终结点 ID 字符串的内容视为不透明。 也就是说,客户端不应尝试解析字符串的内容来获取有关设备的信息。 原因是字符串格式并未定义,在不同的 MMDevice API 实现中可能会发生变化。
在前面的代码示例中,通过 PrintEndpointNames 函数获得的友好设备名称和终结点 ID 字符串与 DirectSound 在设备枚举过程中提供的友好设备名称和终结点 ID 字符串完全相同。 有关详细信息,请参阅传统音频应用程序的音频事件。
在前面的代码示例中,PrintEndpointNames 函数调用 CoCreateInstance 函数,为系统中的音频终结点设备创建一个枚举器。 除非调用程序先前调用了 CoInitialize 或 CoInitializeEx 函数来初始化 COM 库,否则 CoCreateInstance 调用将失败。 有关 CoCreateInstance、CoInitialize 和 CoInitializeEx 的详细信息,请参阅 Windows SDK 文档。
有关 IMMDeviceEnumerator、IMMDeviceCollection 和 IMMDevice 接口的更多信息,请参阅 MMDevice API。