Device Properties

Previous Next

Device Properties

During the process of enumerating audio endpoint devices, a client application can interrogate the endpoint objects for their device properties. Given a reference to the IMMDevice interface of an endpoint object, a client can obtain a reference to the endpoint object's property store by calling the IMMDevice::OpenPropertyStore method. The property-store object has an IPropertyStore interface. The two primary methods in this interface are IPropertyStore::GetValue, which gets a device property value, and IPropertyStore::SetValue, which sets a device property value. For more information about IPropertyStore, see the Windows SDK documentation.

Typically, third-party client applications call the GetValue method but not the SetValue method. The endpoint manager sets the basic device properties for endpoints. The endpoint manager is the Windows Vista component that is responsible for detecting the presence of audio endpoint devices.

All audio endpoint devices have the following three properties.

Property Description
PKEY_DeviceInterface_FriendlyName The friendly name of the audio adapter to which the endpoint device is attached (for example, "XYZ Audio Adapter"). PROPVARIANT member vt is set to VT_LPWSTR and member pwszVal points to a null-terminated, wide-character string that contains the friendly name.
PKEY_Device_DeviceDesc The device description of the endpoint device (for example, "Speakers"). PROPVARIANT member vt is set to VT_LPWSTR and member pwszVal points to a null-terminated, wide-character string that contains the device description.
PKEY_Device_FriendlyName The friendly name of the endpoint device (for example, "Speakers (XYZ Audio Adapter)"). PROPVARIANT member vt is set to VT_LPWSTR and member pwszVal points to a null-terminated, wide-character string that contains the friendly name.

Each PKEY_Xxx property identifier in the preceding list is a constant of type PROPERTYKEY that is defined in header file Functiondiscoverykeys_devpkey.h. Some audio endpoint devices might have additional properties that do not appear in the preceding list. For more information about additional properties, see Audio Endpoint Properties. For more information about PROPERTYKEY, see the Windows SDK documentation.

The following code example prints the display names of all audio-rendering endpoint devices in the system:

//-----------------------------------------------------------
// 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)

        // 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)
}

The FAILED macro in the preceding code example is defined in header file Winerror.h.

In the preceding code example, the for-loop body in the PrintEndpointNames function calls the IMMDevice::GetId method to obtain the endpoint ID string for the audio endpoint device that is represented by the IMMDevice interface instance. The string uniquely identifies the device with respect to all of the other audio endpoint devices in the system. A client can use the endpoint ID string to create an instance of the audio endpoint device at a later time or in a different process by calling the IMMDeviceEnumerator::GetDevice method. Clients should treat the contents of the endpoint ID string as opaque. That is, clients should not attempt to parse the contents of the string to obtain information about the device. The reason is that the string format is undefined and might change from one implementation of the MMDevice API to the next.

The friendly device names and endpoint ID strings that are obtained by the PrintEndpointNames function in the preceding code example are identical to the friendly device names and endpoint ID strings that are provided by DirectSound during device enumeration. For more information, see Audio Events for Legacy Audio Applications.

In the preceding code example, the PrintEndpointNames function calls the CoCreateInstance function to create an enumerator for the audio endpoint devices in the system. Unless the calling program previously called either the CoInitialize or CoInitializeEx function to initialize the COM library, the CoCreateInstance call will fail. For more information about CoCreateInstance, CoInitialize, and CoInitializeEx, see the Windows SDK documentation.

For more information about the IMMDeviceEnumerator, IMMDeviceCollection, and IMMDevice interfaces, see MMDevice API.

Previous Next