레거시 Windows 멀티미디어 애플리케이션에 대한 디바이스 역할

참고

MMDevice API는 디바이스 역할을 지원합니다. 그러나 Windows Vista의 사용자 인터페이스는 이 기능에 대한 지원을 구현하지 않습니다. 디바이스 역할에 대한 사용자 인터페이스 지원은 이후 버전의 Windows에서 구현될 수 있습니다. 자세한 내용은 Windows Vista의 디바이스 역할을 참조하세요.

 

레거시 Windows 멀티미디어 waveOutXxxwaveInXxx 함수는 애플리케이션이 사용자가 특정 디바이스 역할에 할당한 오디오 엔드포인트 디바이스를 선택할 수 있는 수단을 제공하지 않습니다. 그러나 Windows Vista에서는 핵심 오디오 API를 Windows 멀티미디어 애플리케이션과 함께 사용하여 디바이스 역할에 따라 디바이스를 선택할 수 있습니다. 예를 들어 MMDevice API의 도움으로 waveOutXxx 애플리케이션은 역할에 할당된 오디오 엔드포인트 디바이스를 식별하고, 해당 파형 출력 디바이스를 식별하고, waveOutOpen 함수를 호출하여 디바이스의 instance 열 수 있습니다. waveOutXxxwaveInXxx에 대한 자세한 내용은 Windows SDK 설명서를 참조하세요.

다음 코드 예제에서는 특정 디바이스 역할에 할당된 렌더링 엔드포인트 디바이스에 대한 파형 디바이스 ID를 가져오는 방법을 보여 줍니다.

//-----------------------------------------------------------
// This function gets the waveOut ID of the audio endpoint
// device that is currently assigned to the specified device
// role. The caller can use the waveOut ID to open the
// waveOut device that corresponds to the endpoint device.
//-----------------------------------------------------------
#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

HRESULT GetWaveOutId(ERole role, int *pWaveOutId)
{
    HRESULT hr;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    WCHAR *pstrEndpointIdKey = NULL;
    WCHAR *pstrEndpointId = NULL;

    if (pWaveOutId == NULL)
    {
        return E_POINTER;
    }

    // Create an audio endpoint device enumerator.
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                          NULL, CLSCTX_INPROC_SERVER,
                          __uuidof(IMMDeviceEnumerator),
                          (void**)&pEnumerator);
    EXIT_ON_ERROR(hr)

    // Get the audio endpoint device that the user has
    // assigned to the specified device role.
    hr = pEnumerator->GetDefaultAudioEndpoint(eRender, role,
                                              &pDevice);
    EXIT_ON_ERROR(hr)

    // Get the endpoint ID string of the audio endpoint device.
    hr = pDevice->GetId(&pstrEndpointIdKey);
    EXIT_ON_ERROR(hr)

    // Get the size of the endpoint ID string.
    size_t  cbEndpointIdKey;

    hr = StringCbLength(pstrEndpointIdKey,
                        STRSAFE_MAX_CCH * sizeof(WCHAR),
                        &cbEndpointIdKey);
    EXIT_ON_ERROR(hr)

    // Include terminating null in string size.
    cbEndpointIdKey += sizeof(WCHAR);

    // Allocate a buffer for a second string of the same size.
    pstrEndpointId = (WCHAR*)CoTaskMemAlloc(cbEndpointIdKey);
    if (pstrEndpointId == NULL)
    {
        EXIT_ON_ERROR(hr = E_OUTOFMEMORY)
    }

    // Each for-loop iteration below compares the endpoint ID
    // string of the audio endpoint device to the endpoint ID
    // string of an enumerated waveOut device. If the strings
    // match, then we've found the waveOut device that is
    // assigned to the specified device role.
    int waveOutId;
    int cWaveOutDevices = waveOutGetNumDevs();

    for (waveOutId = 0; waveOutId < cWaveOutDevices; waveOutId++)
    {
        MMRESULT mmr;
        size_t cbEndpointId;

        // Get the size (including the terminating null) of
        // the endpoint ID string of the waveOut device.
        mmr = waveOutMessage((HWAVEOUT)IntToPtr(waveOutId),
                             DRV_QUERYFUNCTIONINSTANCEIDSIZE,
                             (DWORD_PTR)&cbEndpointId, NULL);
        if (mmr != MMSYSERR_NOERROR ||
            cbEndpointIdKey != cbEndpointId)  // do sizes match?
        {
            continue;  // not a matching device
        }

        // Get the endpoint ID string for this waveOut device.
        mmr = waveOutMessage((HWAVEOUT)IntToPtr(waveOutId),
                             DRV_QUERYFUNCTIONINSTANCEID,
                             (DWORD_PTR)pstrEndpointId,
                             cbEndpointId);
        if (mmr != MMSYSERR_NOERROR)
        {
            continue;
        }

        // Check whether the endpoint ID string of this waveOut
        // device matches that of the audio endpoint device.
        if (lstrcmpi(pstrEndpointId, pstrEndpointIdKey) == 0)
        {
            *pWaveOutId = waveOutId;  // found match
            hr = S_OK;
            break;
        }
    }

    if (waveOutId == cWaveOutDevices)
    {
        // We reached the end of the for-loop above without
        // finding a waveOut device with a matching endpoint
        // ID string. This behavior is quite unexpected.
        hr = E_UNEXPECTED;
    }

Exit:
    SAFE_RELEASE(pEnumerator);
    SAFE_RELEASE(pDevice);
    CoTaskMemFree(pstrEndpointIdKey);  // NULL pointer okay
    CoTaskMemFree(pstrEndpointId);
    return hr;
}

앞의 코드 예제에서 GetWaveOutId 함수는 디바이스 역할(eConsole, eMultimedia 또는 eCommunications)을 입력 매개 변수로 허용합니다. 두 번째 매개 변수는 함수가 지정된 역할에 할당된 파형 출력 디바이스에 대한 파형 디바이스 ID를 작성하는 포인터입니다. 그러면 애플리케이션이 이 ID로 waveOutOpen 을 호출하여 디바이스를 열 수 있습니다.

앞의 코드 예제의 기본 루프에는 waveOutMessage 함수에 대한 두 가지 호출이 포함되어 있습니다. 첫 번째 호출은 waveOutId 매개 변수로 식별되는 파형 디바이스의 엔드포인트 ID 문자열의 크기(바이트)를 검색하기 위해 DRV_QUERYFUNCTIONINSTANCEIDSIZE 메시지를 보냅니다. (엔드포인트 ID 문자열은 파형 디바이스 추상화의 기초가 되는 오디오 엔드포인트 디바이스를 식별합니다.) 이 호출에서 보고하는 크기에는 문자열 끝에 있는 종료 null 문자에 대한 공간이 포함됩니다. 프로그램은 크기 정보를 사용하여 전체 엔드포인트 ID 문자열을 포함할 수 있을 만큼 큰 버퍼를 할당할 수 있습니다.

waveOutMessage에 대한 두 번째 호출은 DRV_QUERYFUNCTIONINSTANCEID 메시지를 보내 파형 출력 디바이스의 디바이스 ID 문자열을 검색합니다. 예제 코드는 이 문자열을 지정된 디바이스 역할과 오디오 엔드포인트 디바이스의 디바이스 ID 문자열과 비교합니다. 문자열이 일치하면 함수는 파형 디바이스 ID를 pWaveOutId 매개 변수가 가리키는 위치에 씁니다. 호출자는 이 ID를 사용하여 지정된 디바이스 역할이 있는 파형 출력 디바이스를 열 수 있습니다.

Windows Vista는 DRV_QUERYFUNCTIONINSTANCEIDSIZE 및 DRV_QUERYFUNCTIONINSTANCEID 메시지를 지원합니다. Windows Server 2003, Windows XP 및 Windows 2000을 비롯한 이전 버전의 Windows에서는 지원되지 않습니다.

앞의 코드 예제의 함수는 렌더링 디바이스에 대한 파형 디바이스 ID를 가져오지만 몇 가지 수정을 통해 캡처 디바이스에 대한 파형 디바이스 ID를 가져오도록 조정할 수 있습니다. 그런 다음 애플리케이션은 이 ID로 waveInOpen 을 호출하여 디바이스를 열 수 있습니다. 이전 코드 예제를 변경하여 특정 역할에 할당된 오디오 캡처 엔드포인트 디바이스의 파형 디바이스 ID를 가져오려면 다음을 수행합니다.

  • 이전 예제의 모든 waveOutXxx 함수 호출을 해당 waveInXxx 함수 호출로 바꿉다.
  • 핸들 형식 HWAVEOUT을 HWAVEIN으로 변경합니다.
  • ERole 열거형 상수 eRender를 eCapture로 바꿉다.

Windows Vista에서 waveOutOpenwaveInOpen 함수는 항상 만든 오디오 스트림을 기본 세션에 할당합니다. 세션 GUID 값으로 식별되는 프로세스별 세션은 GUID_NULL.

레거시 오디오 API와의 상호 운용성