Partilhar via


Usando a interface IKsControl para acessar propriedades de áudio

Em casos raros, um aplicativo de áudio especializado pode precisar usar a interface IKsControl para acessar determinados recursos de hardware de um adaptador de áudio que não são expostos pela API DeviceTopology ou pela API MMDevice. A interface IKsControl disponibiliza as propriedades, eventos e métodos de dispositivos kernel-streaming (KS) para aplicativos de modo de usuário. De interesse primário para aplicações de áudio são propriedades KS. A interface IKsControl pode ser usada em conjunto com a API DeviceTopology e a API MMDevice para acessar as propriedades KS dos adaptadores de áudio.

A interface IKsControl destina-se principalmente ao uso por fornecedores de hardware que escrevem aplicativos do painel de controle para gerenciar seu hardware de áudio. IKsControl é menos útil para aplicativos de áudio de uso geral que não estão vinculados a dispositivos de hardware específicos. A razão é que os fornecedores de hardware frequentemente implementam mecanismos proprietários para acessar as propriedades de áudio de seus dispositivos. Em contraste com a API DeviceTopology, que oculta peculiaridades de driver específicas de hardware e fornece uma interface relativamente uniforme para acessar propriedades de áudio, os aplicativos usam IKsControl para se comunicar diretamente com os drivers. Para obter mais informações sobre IKsControl, consulte a documentação do Windows DDK.

Conforme discutido em Topologias de dispositivo, uma subunidade na topologia de um dispositivo adaptador pode oferecer suporte a uma ou mais das interfaces de controle específicas da função mostradas na coluna esquerda da tabela a seguir. Cada entrada na coluna direita da tabela é a propriedade KS que corresponde à interface de controle à esquerda. A interface de controle fornece acesso conveniente à propriedade. A maioria dos drivers de áudio usa propriedades KS para representar os recursos de processamento específicos da função das subunidades (também conhecidas como nós KS) nas topologias de seus adaptadores de áudio. Para obter mais informações sobre as propriedades do KS e nós do KS, consulte a documentação do DDK do Windows.

Interface de controle Propriedade 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
IAudioMudo 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

 

As topologias de alguns adaptadores de áudio podem conter subunidades que têm propriedades KS que não estão listadas na tabela anterior. Por exemplo, suponha que uma chamada para o método IPart::GetSubType para uma subunidade específica recupera o valor GUID KSNODETYPE_TONE. Este GUID de subtipo indica que a subunidade suporta uma ou mais das seguintes propriedades KS:

  • KSPROPERTY_AUDIO_BASS
  • KSPROPERTY_AUDIO_MID
  • KSPROPERTY_AUDIO_TREBLE
  • KSPROPERTY_AUDIO_BASS_BOOST

As três primeiras propriedades dessa lista podem ser acessadas por meio das interfaces de controle que aparecem na tabela anterior, mas a propriedade KSPROPERTY_AUDIO_BASS_BOOST não tem nenhuma interface de controle correspondente na API DeviceTopology. No entanto, um aplicativo pode usar a interface IKsControl para acessar essa propriedade, se a subunidade oferece suporte à propriedade.

As etapas a seguir são necessárias para acessar a propriedade KSPROPERTY_AUDIO_BASS_BOOST de uma subunidade do subtipo KSNODETYPE_TONE:

  1. Chame o método IConnector::GetDeviceIdConnectedTo ou IDeviceTopology::GetDeviceId para obter a cadeia de caracteres de ID do dispositivo que identifica o dispositivo adaptador. Essa cadeia de caracteres é semelhante a uma cadeia de caracteres de ID de ponto de extremidade, exceto que ela identifica um dispositivo adaptador em vez de um dispositivo de ponto de extremidade. Para obter mais informações sobre a diferença entre um dispositivo adaptador e um dispositivo de ponto de extremidade, consulte Dispositivos de ponto de extremidade de áudio.
  2. Obtenha a interface IMMDevice do dispositivo adaptador chamando o método IMMDeviceEnumerator::GetDevice com a cadeia de caracteres de ID do dispositivo. Essa interface IMMDevice é a mesma que a interface descrita em IMMDevice Interface, mas representa um dispositivo adaptador em vez de um dispositivo de ponto de extremidade.
  3. Obtenha a interface IKsControl na subunidade chamando o método IMMDevice::Activate com o parâmetro iid definido como REFIID IID_IKsControl. Observe que as interfaces suportadas por esse método Activate , que é para um dispositivo adaptador, são diferentes das interfaces suportadas pelo método Activate para um dispositivo de ponto de extremidade. Em particular, o método Activate para um dispositivo adaptador suporta IKsControl.
  4. Chame o método IPart::GetLocalId para obter a ID local da subunidade.
  5. Construa uma solicitação de propriedade KS. O ID do nó KS necessário para a solicitação está contido nos 16 bits menos significativos do ID local obtidos na etapa anterior.
  6. Envie a solicitação de propriedade KS para o driver de áudio chamando o método IKsControl::KsProperty. Para obter mais informações sobre esse método, consulte a documentação do DDK do Windows.

O exemplo de código a seguir recupera o valor da propriedade KSPROPERTY_AUDIO_BASS_BOOST de uma subunidade do subtipo 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;
}

No exemplo de código anterior, a função GetBassBoost usa os seguintes três parâmetros:

  • pEnumerator aponta para a interface IMMDeviceEnumerator de um enumerador de ponto de extremidade de áudio.
  • pPart aponta para a interface IPart de uma subunidade que tem um subtipo de KSNODETYPE_TONE.
  • pbValue aponta para uma variável BOOL na qual a função grava o valor da propriedade.

Um programa chama GetBassBoost somente depois de chamar IPart::GetSubType e determina que o subtipo da subunidade é KSNODETYPE_TONE. O valor da propriedade será TRUE se o aumento de graves estiver habilitado. É FALSO se o reforço de graves estiver desativado.

No início da função GetBassBoost, a chamada para o método IPart::GetTopologyObject obtém a interface IDeviceTopology do dispositivo adaptador que contém a subunidade KSNODETYPE_TONE. A chamada do método IDeviceTopology::GetDeviceId recupera a cadeia de caracteres de ID do dispositivo que identifica o dispositivo adaptador. A chamada do método IMMDeviceEnumerator::GetDevice usa a cadeia de caracteres de ID do dispositivo como um parâmetro de entrada e recupera a interface IMMDevice do dispositivo adaptador. Em seguida, a chamada do método IMMDevice::Activate recupera a interface IKsControl da subunidade. Para obter mais informações sobre a interface IKsControl, consulte a documentação do Windows DDK.

Em seguida, o exemplo de código anterior cria uma estrutura KSNODEPROPERTY_AUDIO_CHANNEL que descreve a propriedade bass-boost. O exemplo de código passa um ponteiro para a estrutura para o método IKsControl::KsProperty, que usa as informações na estrutura para recuperar o valor da propriedade. Para obter mais informações sobre a estrutura KSNODEPROPERTY_AUDIO_CHANNEL e o método IKsControl::KsProperty, consulte a documentação do DDK do Windows.

O hardware de áudio normalmente atribui um estado de reforço de graves separado a cada canal em um fluxo de áudio. Em princípio, o reforço de graves pode ser ativado para alguns canais e desativado para outros. A estrutura KSNODEPROPERTY_AUDIO_CHANNEL contém um membro do canal que especifica o número do canal . Se um fluxo contiver N canais, os canais serão numerados de 0 a N— 1. O exemplo de código anterior obtém o valor da propriedade bass-boost somente para o canal 0. Essa implementação assume implicitamente que as propriedades bass-boost para todos os canais são definidas uniformemente para o mesmo estado. Assim, a leitura da propriedade bass-boost para o canal 0 é suficiente para determinar o valor da propriedade bass-boost para o fluxo. Para ser consistente com essa suposição, uma função correspondente para definir a propriedade bass-boost definiria todos os canais para o mesmo valor da propriedade bass-boost. Essas são convenções razoáveis, mas nem todos os fornecedores de hardware necessariamente as seguem. Por exemplo, um fornecedor pode fornecer um aplicativo de painel de controle que permite o aumento de graves apenas para canais que acionam alto-falantes de alcance total. (Um alto-falante de alcance completo é capaz de reproduzir sons em toda a faixa de graves a agudos.) Nesse caso, o valor da propriedade recuperado pelo exemplo de código anterior pode não representar com precisão o estado bass-boost do fluxo.

Os clientes que usam as interfaces de controle listadas na tabela anterior podem chamar o método IPart::RegisterControlChangeCallback para registrar notificações quando o valor de um parâmetro de controle é alterado. Observe que a interface IKsControl não fornece um meio semelhante para os clientes se registrarem para notificações quando um valor de propriedade é alterado. Se o IKsControl oferecesse suporte a notificações de alteração de propriedade, ele poderia informar um aplicativo quando outro aplicativo alterou um valor de propriedade. No entanto, em contraste com os controles mais comumente usados que são monitorados por meio de notificações IPart, as propriedades gerenciadas por IKsControl destinam-se principalmente ao uso por fornecedores de hardware, e essas propriedades provavelmente serão alteradas apenas por aplicativos do painel de controle escritos pelos fornecedores. Se um aplicativo deve detectar alterações de propriedade feitas por outro aplicativo, ele pode detectar as alterações pesquisando periodicamente o valor da propriedade por meio de IKsControl.

Guia de programação