Verwenden der IKsControl-Schnittstelle für den Zugriff auf Audioeigenschaften

In seltenen Fällen muss eine spezialisierte Audioanwendung möglicherweise die IKsControl-Schnittstelle verwenden, um auf bestimmte Hardwarefunktionen eines Audioadapters zuzugreifen, die nicht von der DeviceTopology-API oder der MMDevice-API verfügbar gemacht werden. Die IKsControl-Schnittstelle stellt die Eigenschaften, Ereignisse und Methoden von Kernelstreaminggeräten (KS) für Anwendungen im Benutzermodus zur Verfügung. Von primärem Interesse für Audioanwendungen sind KS-Eigenschaften. Die IKsControl-Schnittstelle kann in Verbindung mit der DeviceTopology-API und der MMDevice-API verwendet werden, um auf die KS-Eigenschaften von Audioadaptern zuzugreifen.

Die IKsControl-Schnittstelle ist in erster Linie für die Verwendung von Hardwareanbietern vorgesehen, die Systemsteuerungsanwendungen zur Verwaltung ihrer Audiohardware schreiben. IKsControl ist weniger nützlich für allgemeine Audioanwendungen, die nicht an bestimmte Hardwaregeräte gebunden sind. Der Grund ist, dass Hardwarehersteller häufig proprietäre Mechanismen implementieren, um auf die Audioeigenschaften ihrer Geräte zuzugreifen. Im Gegensatz zur DeviceTopology-API, die hardwarespezifische Treiber-Macken ausblendet und eine relativ einheitliche Schnittstelle für den Zugriff auf Audioeigenschaften bereitstellt, verwenden Anwendungen IKsControl , um direkt mit Treibern zu kommunizieren. Weitere Informationen zu IKsControl finden Sie in der Windows DDK-Dokumentation.

Wie unter Gerätetopologien erläutert, kann eine Untereinheit in der Topologie eines Adaptergeräts eine oder mehrere der funktionsspezifischen Steuerelementschnittstellen unterstützen, die in der linken Spalte der folgenden Tabelle angezeigt werden. Jeder Eintrag in der rechten Spalte der Tabelle ist die KS-Eigenschaft, die der Steuerungsschnittstelle auf der linken Seite entspricht. Die Steuerungsschnittstelle bietet bequemen Zugriff auf die Eigenschaft. Die meisten Audiotreiber verwenden KS-Eigenschaften, um die funktionsspezifischen Verarbeitungsfunktionen der Untereinheiten (auch als KS-Knoten bezeichnet) in den Topologien ihrer Audioadapter darzustellen. Weitere Informationen zu KS-Eigenschaften und KS-Knoten finden Sie in der Windows DDK-Dokumentation.

Steuerungsschnittstelle KS-Eigenschaft
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

 

Die Topologien einiger Audioadapter können Untereinheiten enthalten, die über KS-Eigenschaften verfügen, die in der vorherigen Tabelle nicht aufgeführt sind. Angenommen, ein Aufruf der IPart::GetSubType-Methode für eine bestimmte Untereinheit ruft den GUID-Wert KSNODETYPE_TONE ab. Diese Untertyp-GUID gibt an, dass die Untereinheit mindestens eine der folgenden KS-Eigenschaften unterstützt:

  • KSPROPERTY_AUDIO_BASS
  • KSPROPERTY_AUDIO_MID
  • KSPROPERTY_AUDIO_TREBLE
  • KSPROPERTY_AUDIO_BASS_BOOST

Auf die ersten drei Eigenschaften in dieser Liste kann über die Steuerelementschnittstellen zugegriffen werden, die in der vorherigen Tabelle angezeigt werden, aber die KSPROPERTY_AUDIO_BASS_BOOST-Eigenschaft verfügt über keine entsprechende Steuerelementschnittstelle in der DeviceTopology-API. Eine Anwendung kann jedoch die IKsControl-Schnittstelle verwenden, um auf diese Eigenschaft zuzugreifen, wenn die Untereinheit die -Eigenschaft unterstützt.

Die folgenden Schritte sind erforderlich, um auf die KSPROPERTY_AUDIO_BASS_BOOST-Eigenschaft einer Untereinheit des Untertyps KSNODETYPE_TONE zuzugreifen:

  1. Rufen Sie die IConnector::GetDeviceIdConnectedTo - oder IDeviceTopology::GetDeviceId-Methode auf, um die Geräte-ID-Zeichenfolge abzurufen, die das Adaptergerät identifiziert. Diese Zeichenfolge ähnelt einer Endpunkt-ID-Zeichenfolge, mit der Ausnahme, dass sie ein Adaptergerät anstelle eines Endpunktgeräts identifiziert. Weitere Informationen zum Unterschied zwischen einem Adaptergerät und einem Endpunktgerät finden Sie unter Audioendpunktgeräte.
  2. Rufen Sie die IMMDevice-Schnittstelle des Adaptergeräts ab, indem Sie die METHODE IMMDeviceEnumerator::GetDevice mit der Geräte-ID-Zeichenfolge aufrufen. Diese IMMDevice-Schnittstelle ist mit der in IMMDevice-Schnittstelle beschriebenen Schnittstelle identisch, stellt jedoch ein Adaptergerät anstelle eines Endpunktgeräts dar.
  3. Rufen Sie die IKsControl-Schnittstelle für die Untereinheit ab, indem Sie die IMMDevice::Activate-Methode aufrufen, wobei parameter iid auf REFIID IID_IKsControl festgelegt ist. Beachten Sie, dass sich die von dieser Activate-Methode unterstützten Schnittstellen für ein Adaptergerät von den Schnittstellen unterscheiden, die von der Activate-Methode für ein Endpunktgerät unterstützt werden. Insbesondere unterstützt die Activate-Methode für ein Adaptergerät IKsControl.
  4. Rufen Sie die IPart::GetLocalId-Methode auf, um die lokale ID der Untereinheit abzurufen.
  5. Erstellen Sie eine KS-Eigenschaftsanforderung. Die für die Anforderung erforderliche KS-Knoten-ID ist in den 16 kleinsten Bits der lokalen ID enthalten, die im vorherigen Schritt abgerufen wurde.
  6. Senden Sie die Anforderung der KS-Eigenschaft an den Audiotreiber, indem Sie die IKsControl::KsProperty-Methode aufrufen. Weitere Informationen zu dieser Methode finden Sie in der Dokumentation zu Windows DDK.

Im folgenden Codebeispiel wird der Wert der KSPROPERTY_AUDIO_BASS_BOOST-Eigenschaft aus einer Untereinheit des Untertyps KSNODETYPE_TONE abgerufen:

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

Im vorherigen Codebeispiel akzeptiert die GetBassBoost-Funktion die folgenden drei Parameter:

  • pEnumerator verweist auf die IMMDeviceEnumerator-Schnittstelle eines Audioendpunkt-Enumerators.
  • pPart verweist auf die IPart-Schnittstelle einer Untereinheit mit dem Untertyp KSNODETYPE_TONE.
  • pbValue zeigt auf eine BOOL-Variable , in die die Funktion den Eigenschaftswert schreibt.

Ein Programm ruft GetBassBoost erst auf, nachdem es IPart::GetSubType aufgerufen hat und bestimmt, dass der Untertyp der Untereinheit KSNODETYPE_TONE ist. Der Eigenschaftswert ist TRUE , wenn die Bassverstärkung aktiviert ist. Dies ist FALSE , wenn die Bassverstärkung deaktiviert ist.

Am Anfang der GetBassBoost-Funktion ruft der Aufruf der IPart::GetTopologyObject-Methode die IDeviceTopology-Schnittstelle des Adaptergeräts ab, das die KSNODETYPE_TONE Untereinheit enthält. Der IDeviceTopology::GetDeviceId-Methodenaufruf ruft die Geräte-ID-Zeichenfolge ab, die das Adaptergerät identifiziert. Der IMMDeviceEnumerator::GetDevice-Methodenaufruf verwendet die Geräte-ID-Zeichenfolge als Eingabeparameter und ruft die IMMDevice-Schnittstelle des Adaptergeräts ab. Als Nächstes ruft der AUFRUF der IMMDevice::Activate-Methode die IKsControl-Schnittstelle der Untereinheit ab. Weitere Informationen zur IKsControl-Schnittstelle finden Sie in der Windows DDK-Dokumentation.

Als Nächstes wird im vorherigen Codebeispiel eine KSNODEPROPERTY_AUDIO_CHANNEL Struktur erstellt, die die Eigenschaft bass-boost beschreibt. Das Codebeispiel übergibt einen Zeiger auf die Struktur an die IKsControl::KsProperty-Methode , die die Informationen in der Struktur verwendet, um den Eigenschaftswert abzurufen. Weitere Informationen zur KSNODEPROPERTY_AUDIO_CHANNEL-Struktur und zur IKsControl::KsProperty-Methode finden Sie in der Windows DDK-Dokumentation.

Audiohardware weist in der Regel jedem Kanal in einem Audiostream einen separaten Bass-Boost-Zustand zu. Grundsätzlich kann der Bass boost für einige Kanäle aktiviert und für andere deaktiviert werden. Die KSNODEPROPERTY_AUDIO_CHANNEL-Struktur enthält einen Kanalmember , der die Kanalnummer angibt. Wenn ein Stream N-Kanäle enthält, werden die Kanäle von 0 bis N–1 nummeriert. Im vorherigen Codebeispiel wird nur der Wert der Eigenschaft bass-boost für Kanal 0 abgerufen. Bei dieser Implementierung wird implizit davon ausgegangen, dass die Bass-Boost-Eigenschaften für alle Kanäle einheitlich auf den gleichen Zustand festgelegt sind. Daher reicht das Lesen der Bass-Boost-Eigenschaft für Kanal 0 aus, um den Wert der Bass-Boost-Eigenschaft für den Stream zu bestimmen. Um dieser Annahme zu entsprechen, würde eine entsprechende Funktion zum Festlegen der Bass-Boost-Eigenschaft alle Kanäle auf den gleichen Bass-Boost-Eigenschaftswert festlegen. Dies sind vernünftige Konventionen, aber nicht alle Hardwareanbieter folgen diesen unbedingt. Beispielsweise kann ein Anbieter eine Systemsteuerungsanwendung bereitstellen, die die Bassverstärkung nur für Kanäle ermöglicht, die Vollbereichslautsprecher antreiben. (Ein Full-Range-Lautsprecher kann Sounds über den gesamten Bereich von Bass bis Höhen wiedergeben.) In diesem Fall stellt der vom vorherigen Codebeispiel abgerufene Eigenschaftswert möglicherweise nicht genau den Bass-Boost-Zustand des Datenstroms dar.

Clients, die die in der obigen Tabelle aufgeführten Steuerelementschnittstellen verwenden, können die IPart::RegisterControlChangeCallback-Methode aufrufen, um sich für Benachrichtigungen zu registrieren, wenn sich der Wert eines Steuerelementparameters ändert. Beachten Sie, dass die IKsControl-Schnittstelle keine ähnliche Möglichkeit für Clients bietet, sich für Benachrichtigungen zu registrieren, wenn sich ein Eigenschaftswert ändert. Wenn IKsControl Eigenschaftsänderungsbenachrichtigungen unterstützt, kann es eine Anwendung darüber informieren, wenn eine andere Anwendung einen Eigenschaftswert geändert hat. Im Gegensatz zu den häufiger verwendeten Steuerelementen, die über IPart-Benachrichtigungen überwacht werden, sind die von IKsControl verwalteten Eigenschaften in erster Linie für die Verwendung durch Hardwarehersteller vorgesehen, und diese Eigenschaften werden wahrscheinlich nur von Systemsteuerungsanwendungen geändert, die von den Anbietern geschrieben wurden. Wenn eine Anwendung Eigenschaftenänderungen erkennen muss, die von einer anderen Anwendung vorgenommen wurden, kann sie die Änderungen erkennen, indem sie den Eigenschaftswert regelmäßig über IKsControl abruft.

Programmierhandbuch