Share via


IKsControl 인터페이스를 사용하여 오디오 속성 액세스

드문 경우로, 특수 오디오 애플리케이션은 IKsControl 인터페이스를 사용하여 DeviceTopology API 또는 MMDevice API에서 노출되지 않는 오디오 어댑터의 특정 하드웨어 기능에 액세스해야 할 수 있습니다. IKsControl 인터페이스를 사용하면 KS(커널 스트리밍) 디바이스의 속성, 이벤트 및 메서드를 사용자 모드 애플리케이션에서 사용할 수 있습니다. 오디오 애플리케이션의 주요 관심사는 KS 속성입니다. IKsControl 인터페이스는 DeviceTopology API 및 MMDevice API와 함께 사용하여 오디오 어댑터의 KS 속성에 액세스할 수 있습니다.

IKsControl 인터페이스는 주로 오디오 하드웨어를 관리하기 위해 제어판 애플리케이션을 작성하는 하드웨어 공급업체에서 사용하기 위한 것입니다. IKsControl 은 특정 하드웨어 디바이스에 연결되지 않은 범용 오디오 애플리케이션에 덜 유용합니다. 그 이유는 하드웨어 공급업체가 디바이스의 오디오 속성에 액세스하기 위해 독점 메커니즘을 자주 구현하기 때문입니다. 하드웨어별 드라이버 단점을 숨기고 오디오 속성에 액세스하기 위한 비교적 균일한 인터페이스를 제공하는 DeviceTopology API와 달리 애플리케이션은 IKsControl 을 사용하여 드라이버와 직접 통신합니다. IKsControl에 대한 자세한 내용은 Windows DDK 설명서를 참조하세요.

디바이스 토폴로지에서 설명한 대로 어댑터 디바이스 토폴로지의 하위 단위는 다음 표의 왼쪽 열에 표시된 하나 이상의 함수별 제어 인터페이스를 지원할 수 있습니다. 테이블의 오른쪽 열에 있는 각 항목은 왼쪽의 컨트롤 인터페이스에 해당하는 KS 속성입니다. 컨트롤 인터페이스는 속성에 편리하게 액세스할 수 있도록 합니다. 대부분의 오디오 드라이버는 KS 속성을 사용하여 오디오 어댑터의 토폴로지에서 하위 단위(KS 노드라고도 함)의 기능별 처리 기능을 나타냅니다. KS 속성 및 KS 노드에 대한 자세한 내용은 Windows DDK 설명서를 참조하세요.

컨트롤 인터페이스 KS 속성
IAudioAutoGainControl KSPROPERTY_AUDIO_AGC
IAudioBass KSPROPERTY_AUDIO_BASS
IAudioChannelConfig KSPROPERTY_AUDIO_CHANNEL_CONFIG
IAudioInputSelector KSPROPERTY_AUDIO_MUX_SOURCE
IAudioLoudness KSPROPERTY_AUDIO_LOUDNESS
IAudioMidrange KSPROPERTY_AUDIO_MID
IAudioMute KSPROPERTY_AUDIO_MUTE
IAudioOutputSelector KSPROPERTY_AUDIO_DEMUX_DEST
IAudioPeakMeter KSPROPERTY_AUDIO_PEAKMETER
IAudioTreble KSPROPERTY_AUDIO_TREBLE
IAudioVolumeLevel KSPROPERTY_AUDIO_VOLUMELEVEL
IDeviceSpecificProperty KSPROPERTY_AUDIO_DEV_SPECIFIC

 

일부 오디오 어댑터의 토폴로지에는 앞의 표에 나열되지 않은 KS 속성이 있는 하위 단위가 포함될 수 있습니다. 예를 들어 특정 하위 단위에 대한 IPart::GetSubType 메서드를 호출하면 KSNODETYPE_TONE GUID 값이 검색된다고 가정합니다. 이 하위 형식 GUID는 하위 단위가 다음 KS 속성 중 하나 이상을 지원한다는 것을 나타냅니다.

  • KSPROPERTY_AUDIO_BASS
  • KSPROPERTY_AUDIO_MID
  • KSPROPERTY_AUDIO_TREBLE
  • KSPROPERTY_AUDIO_BASS_BOOST

이 목록의 처음 세 속성은 앞의 표에 표시된 컨트롤 인터페이스를 통해 액세스할 수 있지만 KSPROPERTY_AUDIO_BASS_BOOST 속성에는 DeviceTopology API에 해당 컨트롤 인터페이스가 없습니다. 그러나 하위 단위가 속성을 지원하는 경우 애플리케이션에서 IKsControl 인터페이스를 사용하여 이 속성에 액세스할 수 있습니다.

하위 형식 KSNODETYPE_TONE 하위 그룹의 KSPROPERTY_AUDIO_BASS_BOOST 속성에 액세스하려면 다음 단계가 필요합니다.

  1. IConnector::GetDeviceIdConnectedTo 또는 IDeviceTopology::GetDeviceId 메서드를 호출하여 어댑터 디바이스를 식별하는 디바이스 ID 문자열을 가져옵니다. 이 문자열은 엔드포인트 디바이스 대신 어댑터 디바이스를 식별한다는 점을 제외하고 엔드포인트 ID 문자열과 비슷합니다. 어댑터 디바이스와 엔드포인트 디바이스 간의 차이점에 대한 자세한 내용은 오디오 엔드포인트 디바이스를 참조하세요.
  2. 디바이스 ID 문자열을 사용하여 IMMDeviceEnumerator::GetDevice 메서드를 호출하여 어댑터 디바이스의 IMMDevice 인터페이스를 가져옵니다. 이 IMMDevice 인터페이스는 IMMDevice 인터페이스에 설명된 인터페이스와 동일하지만 엔드포인트 디바이스 대신 어댑터 디바이스를 나타냅니다.
  3. 매개 변수 iidREFIID IID_IKsControl 설정된 IMMDevice::Activate 메서드를 호출하여 하위 단위에서 IKsControl 인터페이스를 가져옵니다. 어댑터 디바이스에 대한 이 Activate 메서드에서 지원하는 인터페이스는 엔드포인트 디바이스에 대한 Activate 메서드에서 지원하는 인터페이스와 다릅니다. 특히 어댑터 디바이스에 대한 Activate 메서드는 IKsControl을 지원합니다.
  4. IPart::GetLocalId 메서드를 호출하여 하위 그룹의 로컬 ID를 가져옵니다.
  5. KS 속성 요청을 생성합니다. 요청에 필요한 KS 노드 ID는 이전 단계에서 얻은 로컬 ID의 16개 가장 중요하지 않은 비트에 포함됩니다.
  6. IKsControl::KsProperty 메서드를 호출하여 오디오 드라이버에 KS 속성 요청을 보냅니다. 이 방법에 대한 자세한 내용은 Windows DDK 설명서를 참조하세요.

다음 코드 예제에서는 하위 형식 KSNODETYPE_TONE 하위 그룹에서 KSPROPERTY_AUDIO_BASS_BOOST 속성의 값을 검색합니다.

//-----------------------------------------------------------
// This function calls the IKsControl::Property method to get
// the value of the KSPROPERTY_AUDIO_BASS_BOOST property of
// a subunit. Parameter pPart should point to a part that is
// a subunit with a subtype GUID value of KSNODETYPE_TONE.
//-----------------------------------------------------------
#define PARTID_MASK 0x0000ffff
#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

const IID IID_IKsControl = __uuidof(IKsControl);

HRESULT GetBassBoost(IMMDeviceEnumerator *pEnumerator,
                     IPart *pPart, BOOL *pbValue)
{
    HRESULT hr;
    IDeviceTopology *pTopology = NULL;
    IMMDevice *pPnpDevice = NULL;
    IKsControl *pKsControl = NULL;
    LPWSTR pwszDeviceId = NULL;

    if (pEnumerator == NULL || pPart == NULL || pbValue == NULL)
    {
        return E_INVALIDARG;
    }

    // Get the topology object for the adapter device that contains
    // the subunit represented by the IPart interface.
    hr = pPart->GetTopologyObject(&pTopology);
    EXIT_ON_ERROR(hr)

    // Get the device ID string that identifies the adapter device.
    hr = pTopology->GetDeviceId(&pwszDeviceId);
    EXIT_ON_ERROR(hr)

    // Get the IMMDevice interface of the adapter device object.
    hr = pEnumerator->GetDevice(pwszDeviceId, &pPnpDevice);
    EXIT_ON_ERROR(hr)

    // Activate an IKsControl interface on the adapter device object.
    hr = pPnpDevice->Activate(IID_IKsControl, CLSCTX_ALL, NULL, (void**)&pKsControl);
    EXIT_ON_ERROR(hr)

    // Get the local ID of the subunit (contains the KS node ID).
    UINT localId = 0;
    hr = pPart->GetLocalId(&localId);
    EXIT_ON_ERROR(hr)

    KSNODEPROPERTY_AUDIO_CHANNEL ksprop;
    ZeroMemory(&ksprop, sizeof(ksprop));
    ksprop.NodeProperty.Property.Set = KSPROPSETID_Audio;
    ksprop.NodeProperty.Property.Id = KSPROPERTY_AUDIO_BASS_BOOST;
    ksprop.NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
    ksprop.NodeProperty.NodeId = localId & PARTID_MASK;
    ksprop.Channel = 0;

    // Send the property request.to the device driver.
    BOOL bValue = FALSE;
    ULONG valueSize;
    hr = pKsControl->KsProperty(
                         &ksprop.NodeProperty.Property, sizeof(ksprop),
                         &bValue, sizeof(bValue), &valueSize);
    EXIT_ON_ERROR(hr)

    *pbValue = bValue;

Exit:
    SAFE_RELEASE(pTopology)
    SAFE_RELEASE(pPnpDevice)
    SAFE_RELEASE(pKsControl)
    CoTaskMemFree(pwszDeviceId);
    return hr;
}

앞의 코드 예제에서 GetBassBoost 함수는 다음 세 가지 매개 변수를 사용합니다.

  • pEnumerator 는 오디오 엔드포인트 열 거자의 IMMDeviceEnumerator 인터페이스를 가리킵니다.
  • pPart 는 하위 형식이 KSNODETYPE_TONE 하위 단위의 IPart 인터페이스를 가리킵니다.
  • pbValue 는 함수가 속성 값을 쓰는 BOOL 변수를 가리킵니다.

프로그램은 IPart::GetSubType 을 호출하고 하위 단위의 하위 유형이 KSNODETYPE_TONE 확인한 후에만 GetBassBoost를 호출합니다. 베이스 부스트를 사용하는 경우 속성 값은 TRUE 입니다. 베이스 부스트를 사용하지 않도록 설정하면 FALSE 입니다.

GetBassBoost 함수의 시작 부분에서 IPart::GetTopologyObject 메서드를 호출하면 KSNODETYPE_TONE 하위 단위가 포함된 어댑터 디바이스의 IDeviceTopology 인터페이스를 가져옵니다. IDeviceTopology::GetDeviceId 메서드 호출은 어댑터 디바이스를 식별하는 디바이스 ID 문자열을 검색합니다. IMMDeviceEnumerator::GetDevice 메서드 호출은 디바이스 ID 문자열을 입력 매개 변수로 사용하고 어댑터 디바이스의 IMMDevice 인터페이스를 검색합니다. 다음으로, IMMDevice::Activate 메서드 호출은 하위 단위의 IKsControl 인터페이스를 검색합니다. IKsControl 인터페이스에 대한 자세한 내용은 Windows DDK 설명서를 참조하세요.

다음으로 앞의 코드 예제에서는 bass-boost 속성을 설명하는 KSNODEPROPERTY_AUDIO_CHANNEL 구조를 만듭니다. 이 코드 예제에서는 구조체의 정보를 사용하여 속성 값을 검색하는 IKsControl::KsProperty 메서드에 구조체에 대한 포인터를 전달합니다. KSNODEPROPERTY_AUDIO_CHANNEL 구조체 및 IKsControl::KsProperty 메서드에 대한 자세한 내용은 Windows DDK 설명서를 참조하세요.

오디오 하드웨어는 일반적으로 오디오 스트림의 각 채널에 별도의 베이스 부스트 상태를 할당합니다. 원칙에 따라 일부 채널에 대해 베이스 부스트를 사용하도록 설정하고 다른 채널에서는 사용하지 않도록 설정할 수 있습니다. KSNODEPROPERTY_AUDIO_CHANNEL 구조에는 채널 번호를 지정하는 채널 멤버가 포함됩니다. 스트림에 N 채널이 포함된 경우 채널 번호는 0에서 N- 1로 지정됩니다. 앞의 코드 예제에서는 채널 0에 대해서만 bass-boost 속성의 값을 가져옵니다. 이 구현에서는 모든 채널의 bass-boost 속성이 동일한 상태로 균일하게 설정된다고 암시적으로 가정합니다. 따라서 채널 0의 bass-boost 속성을 읽으면 스트림의 bass-boost 속성 값을 결정하기에 충분합니다. 이 가정과 일치하기 위해 bass-boost 속성을 설정하는 해당 함수는 모든 채널을 동일한 bass-boost 속성 값으로 설정합니다. 이는 합리적인 규칙이지만 모든 하드웨어 공급업체가 반드시 따르는 것은 아닙니다. 예를 들어 공급업체는 전체 범위 스피커를 구동하는 채널에 대해서만 저음 향상을 가능하게 하는 제어판 애플리케이션을 제공할 수 있습니다. (풀 레인지 스피커는 저음에서 고음까지 전체 범위에서 소리를 재생할 수 있습니다.) 이 경우 이전 코드 예제에서 검색한 속성 값이 스트림의 bass-boost 상태를 정확하게 나타내지 않을 수 있습니다.

앞의 표에 나열된 컨트롤 인터페이스를 사용하는 클라이언트는 IPart::RegisterControlChangeCallback 메서드를 호출하여 컨트롤 매개 변수 값이 변경될 때 알림을 등록할 수 있습니다. IKsControl 인터페이스는 속성 값이 변경되면 클라이언트가 알림을 등록할 수 있는 유사한 방법을 제공하지 않습니다. IKsControl이 속성 변경 알림을 지원한 경우 다른 애플리케이션이 속성 값을 변경할 때 애플리케이션에 알릴 수 있습니다. 그러나 IPart 알림을 통해 모니터링되는 더 일반적으로 사용되는 컨트롤과 달리 IKsControl 에서 관리하는 속성은 주로 하드웨어 공급업체에서 사용하기 위한 것이며, 이러한 속성은 공급업체에서 작성한 제어판 애플리케이션에서만 변경될 수 있습니다. 애플리케이션이 다른 애플리케이션의 속성 변경 내용을 검색해야 하는 경우 IKsControl을 통해 속성 값을 주기적으로 폴링하여 변경 내용을 검색할 수 있습니다.

프로그래밍 가이드