Uso dell'interfaccia IKsControl per accedere alle proprietà audio

In rari casi, un'applicazione audio specializzata potrebbe dover usare l'interfaccia IKsControl per accedere a determinate funzionalità hardware di una scheda audio non esposta dall'APIDeviceTopology o dall'API MMDevice. L'interfaccia IKsControl rende disponibili le proprietà, gli eventi e i metodi dei dispositivi kernel-streaming (KS) per le applicazioni in modalità utente. Di interesse principale per le applicazioni audio sono le proprietà KS. L'interfaccia IKsControl può essere usata insieme all'API DeviceTopology e all'API MMDevice per accedere alle proprietà KS delle schede audio.

L'interfaccia IKsControl è destinata principalmente all'uso da parte dei fornitori di hardware che scrivono applicazioni del pannello di controllo per gestire l'hardware audio. IKsControl è meno utile per le applicazioni audio per utilizzo generico che non sono associate a particolari dispositivi hardware. Il motivo è che i fornitori di hardware implementano spesso meccanismi proprietari per accedere alle proprietà audio dei propri dispositivi. A differenza dell'API DeviceTopology, che nasconde i problemi di driver specifici dell'hardware e fornisce un'interfaccia relativamente uniforme per l'accesso alle proprietà audio, le applicazioni usano IKsControl per comunicare direttamente con i driver. Per altre informazioni su IKsControl, vedere la documentazione di Windows DDK.

Come illustrato in Topologie di dispositivo, una subunit nella topologia di un dispositivo adattatore potrebbe supportare una o più interfacce di controllo specifiche della funzione illustrate nella colonna sinistra della tabella seguente. Ogni voce nella colonna destra della tabella è la proprietà KS corrispondente all'interfaccia di controllo a sinistra. L'interfaccia di controllo fornisce un accesso pratico alla proprietà . La maggior parte dei driver audio usa le proprietà KS per rappresentare le funzionalità di elaborazione specifiche della funzione delle sottounite (dette anche nodi KS) nelle topologie delle schede audio. Per altre informazioni sulle proprietà KS e sui nodi KS, vedere la documentazione di Windows DDK.

Interfaccia di controllo Proprietà 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

 

Le topologie di alcune schede audio potrebbero contenere sottounità con proprietà KS non elencate nella tabella precedente. Si supponga, ad esempio, che una chiamata al metodo IPart::GetSubType per un determinato subunit recuperi il valore GUID KSNODETYPE_TONE. Questo GUID del sottotipo indica che la subunit supporta una o più delle proprietà KS seguenti:

  • KSPROPERTY_AUDIO_BASS
  • KSPROPERTY_AUDIO_MID
  • KSPROPERTY_AUDIO_TREBLE
  • KSPROPERTY_AUDIO_BASS_BOOST

È possibile accedere alle prime tre proprietà di questo elenco tramite le interfacce di controllo visualizzate nella tabella precedente, ma la proprietà KSPROPERTY_AUDIO_BASS_BOOST non ha un'interfaccia di controllo corrispondente nell'API DeviceTopology. Tuttavia, un'applicazione può usare l'interfaccia IKsControl per accedere a questa proprietà, se la subunit supporta la proprietà .

Per accedere alla proprietà KSPROPERTY_AUDIO_BASS_BOOST di un sottotipo di sottotipo KSNODETYPE_TONE sono necessari i passaggi seguenti:

  1. Chiamare il metodo I Connessione or::GetDeviceId Connessione edTo o IDeviceTopology::GetDeviceId per ottenere la stringa ID dispositivo che identifica il dispositivo adattatore. Questa stringa è simile a una stringa ID endpoint, ad eccezione del fatto che identifica un dispositivo adattatore anziché un dispositivo endpoint. Per altre informazioni sulla differenza tra un dispositivo adattatore e un dispositivo endpoint, vedere Dispositivi endpoint audio.
  2. Ottenere l'interfaccia IMMDevice del dispositivo adattatore chiamando il metodo IMMDeviceEnumerator::GetDevice con la stringa ID dispositivo. Questa interfaccia IMMDevice è la stessa dell'interfaccia descritta in IMMDevice Interface, ma rappresenta un dispositivo adattatore anziché un dispositivo endpoint.
  3. Ottenere l'interfaccia IKsControl nella subunit chiamando il metodo IMMDevice::Activate con il parametro iid impostato su REFIID IID_IKsControl. Si noti che le interfacce supportate da questo metodo Activate , vale a dire per un dispositivo adattatore, sono diverse dalle interfacce supportate dal metodo Activate per un dispositivo endpoint. In particolare, il metodo Activate per un dispositivo adattatore supporta IKsControl.
  4. Chiamare il metodo IPart::GetLocalId per ottenere l'ID locale della subunit.
  5. Creare una richiesta di proprietà KS. L'ID del nodo KS necessario per la richiesta è contenuto nei 16 bit meno significativi dell'ID locale ottenuto nel passaggio precedente.
  6. Inviare la richiesta della proprietà KS al driver audio chiamando il metodo IKsControl::KsProperty. Per altre informazioni su questo metodo, vedere la documentazione di Windows DDK.

Nell'esempio di codice seguente viene recuperato il valore della proprietà KSPROPERTY_AUDIO_BASS_BOOST da un sottotipo di sottotipo KSNODETYPE_TONE:

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

Nell'esempio di codice precedente la funzione GetBassBoost accetta i tre parametri seguenti:

  • pEnumerator punta all'interfaccia IMMDeviceEnumerator di un enumeratore di endpoint audio.
  • pPart punta all'interfaccia IPart di una subunit con un sottotipo di KSNODETYPE_TONE.
  • pbValue punta a una variabile BOOL in cui la funzione scrive il valore della proprietà.

Un programma chiama GetBassBoost solo dopo che chiama IPart::GetSubType e determina che il sottotipo della subunit è KSNODETYPE_TONE. Il valore della proprietà è TRUE se l'aumento del basso è abilitato. È FAL edizione Standard se il basso boost è disabilitato.

All'inizio della funzione GetBassBoost, la chiamata al metodo IPart::GetTopologyObject ottiene l'interfaccia IDeviceTopology del dispositivo adattatore che contiene il KSNODETYPE_TONE subunit. La chiamata al metodo IDeviceTopology::GetDeviceId recupera la stringa ID dispositivo che identifica il dispositivo adattatore. La chiamata al metodo IMMDeviceEnumerator::GetDevice accetta la stringa ID dispositivo come parametro di input e recupera l'interfaccia IMMDevice del dispositivo adattatore. Successivamente, la chiamata al metodo IMMDevice::Activate recupera l'interfaccia IKsControl della subunit. Per altre informazioni sull'interfaccia IKsControl , vedere la documentazione di Windows DDK.

Successivamente, l'esempio di codice precedente crea una struttura KSNODEPROPERTY_AUDIO_CHANNEL che descrive la proprietà bass boost. L'esempio di codice passa un puntatore alla struttura al metodo IKsControl::KsProperty , che usa le informazioni nella struttura per recuperare il valore della proprietà. Per altre informazioni sulla struttura KSNODEPROPERTY_AUDIO_CHANNEL e sul metodo IKsControl::KsProperty , vedere la documentazione di Windows DDK.

L'hardware audio assegna in genere uno stato di basso boost separato a ogni canale in un flusso audio. In linea di principio, il basso boost può essere abilitato per alcuni canali e disabilitato per altri. La struttura KSNODEPROPERTY_AUDIO_CHANNEL contiene un membro Channel che specifica il numero di canale. Se un flusso contiene N canali, i canali vengono numerati da 0 a N- 1. L'esempio di codice precedente ottiene il valore della proprietà bass boost solo per channel 0. Questa implementazione presuppone implicitamente che le proprietà bass boost per tutti i canali siano impostate in modo uniforme sullo stesso stato. Pertanto, la lettura della proprietà bass boost per channel 0 è sufficiente per determinare il valore della proprietà bass boost per il flusso. Per essere coerente con questo presupposto, una funzione corrispondente per impostare la proprietà bass boost imposta tutti i canali sullo stesso valore della proprietà bass boost. Queste sono convenzioni ragionevoli, ma non tutti i fornitori di hardware li seguono necessariamente. Ad esempio, un fornitore potrebbe fornire un'applicazione pannello di controllo che consente l'aumento del basso solo per i canali che guidano altoparlanti a gamma completa. (Un altoparlante completo è in grado di riprodurre suoni su tutta la gamma tra basso e treble). In tal caso, il valore della proprietà recuperato dall'esempio di codice precedente potrebbe non rappresentare accuratamente lo stato bass boost del flusso.

I client che usano le interfacce di controllo elencate nella tabella precedente possono chiamare il metodo IPart::RegisterControlChangeCallback per eseguire la registrazione per le notifiche quando cambia il valore di un parametro di controllo. Si noti che l'interfaccia IKsControl non fornisce un modo simile per i client di registrarsi per le notifiche quando viene modificato un valore della proprietà. Se IKsControl supporta le notifiche di modifica delle proprietà, potrebbe informare un'applicazione quando un'altra applicazione ha modificato un valore di proprietà. Tuttavia, a differenza dei controlli usati più comunemente monitorati tramite le notifiche IPart , le proprietà gestite da IKsControl sono destinate principalmente all'uso da parte dei fornitori di hardware e tali proprietà sono probabilmente modificate solo dalle applicazioni del pannello di controllo scritte dai fornitori. Se un'applicazione deve rilevare le modifiche apportate alle proprietà da un'altra applicazione, può rilevare le modifiche eseguendo periodicamente il polling del valore della proprietà tramite IKsControl.

Guida per programmatori