디바이스 속성(핵심 오디오 API)

오디오 엔드포인트 디바이스를 열거하는 동안 클라이언트 애플리케이션은 해당 디바이스 속성에 대한 엔드포인트 개체를 심문할 수 있습니다. 디바이스 속성은 MMDevice API의 IPropertyStore 인터페이스 구현에 노출됩니다. 엔드포인트 개체의 IMMDevice 인터페이스에 대한 참조가 제공되면 클라이언트는 IMMDevice::OpenPropertyStore 메서드를 호출하여 엔드포인트 개체의 속성 저장소에 대한 참조를 가져올 수 있습니다.

클라이언트는 이러한 속성을 읽을 수 있지만 설정하면 안 됩니다. 속성 값은 PROPVARIANT 구조체로 저장됩니다.

엔드포인트 관리자는 엔드포인트에 대한 기본 디바이스 속성을 설정합니다. 엔드포인트 관리자는 오디오 엔드포인트 디바이스의 존재를 감지하는 Windows 구성 요소입니다.

다음 목록의 각 PKEY_Xxx 속성 식별자는 헤더 파일 Functiondiscoverykeys_devpkey.h에 정의된 PROPERTYKEY 형식의 상수입니다. 모든 오디오 엔드포인트 디바이스에는 이러한 디바이스 속성이 있습니다.

속성 Description
PKEY_DeviceInterface_FriendlyName 엔드포인트 디바이스가 연결된 오디오 어댑터의 이름입니다(예: "XYZ 오디오 어댑터").
PKEY_Device_DeviceDesc 엔드포인트 디바이스에 대한 디바이스 설명입니다(예: "스피커").
PKEY_Device_FriendlyName 엔드포인트 디바이스의 이름입니다(예: "스피커(XYZ 오디오 어댑터)").
PKEY_Device_InstanceId 오디오 엔드포인트 디바이스 instance 식별자를 저장합니다. 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-loop 본문은 IMMDevice::GetId 메서드를 호출하여 IMMDevice 인터페이스 instance 나타내는 오디오 엔드포인트 디바이스에 대한 엔드포인트 ID 문자열을 가져옵니다. 문자열은 시스템의 다른 모든 오디오 엔드포인트 디바이스와 관련하여 디바이스를 고유하게 식별합니다. 클라이언트는 엔드포인트 ID 문자열을 사용하여 나중에 또는 다른 프로세스에서 IMMDeviceEnumerator::GetDevice 메서드를 호출하여 오디오 엔드포인트 디바이스의 instance 만들 수 있습니다. 클라이언트는 엔드포인트 ID 문자열의 내용을 불투명으로 처리해야 합니다. 즉, 클라이언트는 디바이스에 대한 정보를 얻기 위해 문자열의 내용을 구문 분석하려고 시도해서는 안 됩니다. 그 이유는 문자열 형식이 정의되지 않았고 MMDevice API의 한 구현에서 다음 구현으로 변경될 수 있기 때문입니다.

앞의 코드 예제에서 PrintEndpointNames 함수에서 가져온 친숙한 디바이스 이름 및 엔드포인트 ID 문자열은 디바이스 열거 중에 DirectSound에서 제공하는 친숙한 디바이스 이름 및 엔드포인트 ID 문자열과 동일합니다. 자세한 내용은 레거시 오디오 애플리케이션에 대한 오디오 이벤트를 참조하세요.

앞의 코드 예제에서 PrintEndpointNames 함수는 CoCreateInstance 함수를 호출하여 시스템의 오디오 엔드포인트 디바이스에 대한 열거자를 만듭니다. 이전에 COM 라이브러리를 초기화하기 위해 CoInitialize 또는 CoInitializeEx 함수를 호출한 호출 프로그램이 아니면 CoCreateInstance 호출이 실패합니다. CoCreateInstance, CoInitialize 및 CoInitializeEx에 대한 자세한 내용은 Windows SDK 설명서를 참조하세요.

IMMDeviceEnumerator, IMMDeviceCollectionIMMDevice 인터페이스에 대한 자세한 내용은 MMDevice API를 참조하세요.

오디오 엔드포인트 디바이스