Expondo nós multicanal

Em versões do Microsoft Windows anteriores ao Windows XP, os drivers de áudio WDM não têm uma maneira simplificada de expor nós multicanal dos seguintes tipos:

KSNODETYPE_VOLUME

KSNODETYPE_MUTE

KSNODETYPE_TONE

Em particular, não existe nenhum mecanismo para consultar explicitamente um nó para o número de canais aos quais ele dá suporte. Embora existam soluções alternativas para esse problema, elas têm desvantagens. Por exemplo, um cliente pode usar a propriedade KSPROPERTY_AUDIO_VOLUMELEVEL para consultar iterativamente um nó de volume (KSNODETYPE_VOLUME) para o nível de volume de cada canal – 0, 1 e assim por diante – até que a solicitação retorne um erro indicando que não existe mais canais. No entanto, essa técnica requer várias consultas e é muito ineficiente para lidar com dispositivos de áudio multicanal mais recentes. No Windows XP e em sistemas operacionais posteriores, essa limitação é resolvida definindo dois bits de sinalizador adicionais no membro Flags da estrutura KSPROPERTY_MEMBERSHEADER , que o manipulador de propriedades gera em resposta a uma consulta de suporte básico:

  • KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL

    Durante uma solicitação de propriedade de suporte básico em um nó, o manipulador define esse bit de sinalizador para indicar que o membro MembersCount de KSPROPERTY_MEMBERSHEADER contém o número de canais compatíveis com o nó. Para sistemas operacionais Windows Vista e posteriores do Windows, esse sinalizador deve ser definido para cada propriedade de canal.

  • KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM

    O manipulador executa um OR bit a bit entre esse bit de sinalizador e o bit de sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL para indicar que um único valor de propriedade é aplicado uniformemente em todos os canais em um nó. Por exemplo, se o hardware fornecer apenas um único controle de nível de volume para todos os canais, o manipulador de suporte básico para o nó de volume definirá o sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM para indicar essa restrição. Se esse sinalizador não estiver definido, o nível de volume de cada canal poderá ser controlado independentemente dos níveis de volume para os outros canais.

    Nota O sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM não é usado pelo sistema operacional Windows Vista.

Em drivers de miniporto para Windows XP e posteriores, o manipulador de propriedades de um nó de volume multicanal deve definir o bit KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL em resposta a uma consulta de suporte básico KSPROPERTY_AUDIO_VOLUMELEVEL. O manipulador retorna uma matriz de estruturas de KSPROPERTY_STEPPING_LONG – uma para cada canal exposto pelo nó – e define MembersSize como sizeof(KSPROPERTY_STEPPING_LONG). Cada elemento de matriz descreve os níveis de volume mínimo e máximo de um canal e o delta entre valores sucessivos no intervalo. Um intervalo diferente pode ser especificado para cada canal individual para que os canais com intervalos não uniformes possam ser expostos corretamente. Por exemplo, um canal subwoofer pode ter um intervalo diferente daquele dos outros canais.

O exemplo de código a seguir mostra como lidar com uma consulta de suporte básico para uma propriedade de áudio com valores de propriedade não uniformes. A pDescription variável na primeira linha de código abaixo aponta para a estrutura KSPROPERTY_DESCRIPTION no início do buffer de dados no qual o manipulador grava as informações de suporte básico:

  //
  // Fill in the members header.
  //
  PKSPROPERTY_MEMBERSHEADER pMembers = PKSPROPERTY_MEMBERSHEADER(pDescription + 1);

  pMembers->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
  pMembers->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
  pMembers->MembersCount = ulNumChannels;
  pMembers->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL;

  //
  // Fill in the stepped range with the driver default.
  //
  PKSPROPERTY_STEPPING_LONG pRange = PKSPROPERTY_STEPPING_LONG(pMembers + 1);
  pRange->Reserved = 0;

  for (ULONG i=0; i<ulNumChannels; i++)
  {
      pRange[i].Bounds.SignedMinimum = ulChannelMin[i];
      pRange[i].Bounds.SignedMaximum = ulChannelMax[i];
      pRange[i].SteppingDelta = ChannelStepping[i];
  }

  pPropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION) +
                                sizeof(KSPROPERTY_MEMBERSHEADER) + 
                                ulNumChannels * sizeof(KSPROPERTY_STEPPING_LONG);

A figura a seguir mostra o layout do buffer de dados para este exemplo. Os ponteiros pDescription, pMembers e pRange são mostrados apontando para seus respectivos deslocamentos dentro do buffer.

Diagrama ilustrando o layout de um buffer de dados para uma consulta de suporte básico com ponteiros pDescription, pMembers e pRange.

Para este exemplo, o manipulador define MembersCount como ulNumChannels, o número de canais. O tamanho em bytes da matriz de intervalo é

MembersSize * MembersCount

Observe que, se o sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM fosse definido neste exemplo, o manipulador definiria todas as estruturas de KSPROPERTY_STEPPING_LONG na matriz para o mesmo intervalo.

O manipulador de suporte básico para a propriedade KSPROPERTY_AUDIO_BASS, KSPROPERTY_AUDIO_TREBLE ou KSPROPERTY_AUDIO_MID de um nó de tom opera de maneira semelhante.

Se um nó multicanal tiver uma propriedade com um valor de propriedade por canal do tipo BOOL, o manipulador de suporte básico deverá preencher valores para uma matriz de intervalo de etapas. Nesse caso, o manipulador define os membros para os valores mostrados no exemplo de código a seguir. Dois exemplos desse tipo de propriedade são a propriedade KSPROPERTY_AUDIO_MUTE de um nó mudo e a propriedade KSPROPERTY_AUDIO_BASS_BOOST de um nó de tom.

O exemplo de código a seguir mostra como lidar com a solicitação de suporte básico para um nó multicanal, no caso de uma propriedade com um valor de propriedade por canal do tipo BOOL:

  //
  // Fill in the members header.
  //
  PKSPROPERTY_MEMBERSHEADER pMembers = PKSPROPERTY_MEMBERSHEADER(pDescription + 1);

  pMembers->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
  pMembers->MembersSize = sizeof (KSPROPERTY_STEPPING_LONG);
  pMembers->MembersCount = ulNumChannels;
  pMembers->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL;

  pPropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION) +
                                sizeof(KSPROPERTY_MEMBERSHEADER) + 
                                ulNumChannels * sizeof(KSPROPERTY_STEPPING_LONG);

  //
  // Fill in the stepped range with values in FOR loop.
  //
  PKSPROPERTY_STEPPING_LONG pRange = PKSPROPERTY_STEPPING_LONG(pMembers + 1);
  pRange->Reserved = 0;

  for (ULONG i=0; i<ulNumChannels; i++)
  {
      pRange[i].Bounds.SignedMinimum = 0;
      pRange[i].Bounds.SignedMaximum = 1;
      pRange[i].SteppingDelta = 1;
  }

Observe que, no exemplo de código anterior, o loop FOR usa um zero (0) e um (1) para definir os valores mínimo e máximo para os intervalos por canal. Isso ocorre porque estamos configurando um nó multicanal com um valor de propriedade por canal do tipo BOOL.

Se a propriedade channel for uniforme, uma operação OR bit a bit poderá ser executada entre o sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM e o sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL e o resultado atribuído ao membro pMembers-Flags>. Esse valor é usado para indicar que o hardware aplica o mesmo valor de propriedade uniformemente em todos os canais em um nó.

Usar os sinalizadores KSPROPERTY_MEMBER_FLAG_UNIFORM e KSPROPERTY_MEMBER_FLAG_MULTICHANNEL elimina a necessidade de agrupar os canais em pares e expor um nó de volume estéreo separado para cada par de canais, como é feito no driver de exemplo Ac97 no WDK (Windows Driver Kit). Como as versões do Windows anteriores ao Windows XP não dão suporte a esses sinalizadores, o manipulador de suporte básico para o driver deve usar a interface IPortClsVersion para consultar a versão do Portcls.sys para determinar se deseja usar esses sinalizadores.

O analisador de topologia (no driver do sistema WDMAud no modo kernel, Wdmaud.sys) obtém a topologia de um dispositivo de áudio de seu driver de áudio WDM. O analisador expõe esse dispositivo como um dispositivo de mixer tradicional por meio da API herdada do mixer do Windows Multimídia. No Windows XP e posterior, o WDMAud usa o sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL para determinar o número de canais a serem relatados no membro cChannels da estrutura MIXERLINE. Além disso, se o manipulador de suporte básico do nó especificar o sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM, WDMAud definirá o sinalizador MIXERCONTROL_CONTROLF_UNIFORM na estrutura MIXERCONTROL correspondente. Por meio desse sinalizador, os aplicativos podem determinar se podem ajustar cada canal individualmente ou todos os canais uniformemente por meio de um controle master. Para obter mais informações sobre MIXERCONTROL, MIXERLINE e a API do mixer, consulte a documentação do SDK do Microsoft Windows.

No Windows XP e posterior, o programa de controle de volume SndVol32 (consulte SysTray e SndVol32) exibe controles para dispositivos multicanal, conforme mostrado na figura a seguir.

Captura de tela da caixa de diálogo controle de volume SndVol32 exibindo controles para dispositivos multicanal.

Se sndVol32 detectar uma linha que tem mais de dois canais, ele substituirá o controle de painel normal por um botão rotulado Volume do Locutor, que aparece acima do controle deslizante de volume main na figura anterior. Clicar no botão Volume do Locutor abrirá uma caixa de diálogo exibindo controles para todos os canais de uma linha específica, conforme mostrado na figura a seguir.

Captura de tela da caixa de diálogo volume do locutor exibindo controles para todos os canais e propriedades de áudio avançadas.

Como a API do mixer expõe canais por número, ela infere os nomes de canal da configuração do alto-falante que está selecionada atualmente na caixa de diálogo Propriedades Avançadas de Áudio no painel de controle multimídia do Windows (Mmsys.cpl).

Por exemplo, se um dispositivo expor quatro canais em uma linha e o usuário tiver selecionado "Alto-falantes quadrafônicos", os nomes dos canais serão "Left" (canal 0), "Right" (canal 1), "Back Left" (canal 2) e "Back Right" (canal 3), conforme mostrado na figura anterior. Alterar a configuração do alto-falante para "Alto-falantes de som surround" resultará em um mapeamento de canal de "Esquerda" (canal 0), "Direita" (canal 1), "Front Center" (canal 2) e "Back Center" (canal 3).

No nível do driver, a propriedade KSPROPERTY_AUDIO_CHANNEL_CONFIG usa um valor de máscara de KSAUDIO_SPEAKER_QUAD ou KSAUDIO_SPEAKER_SURROUND para representar uma configuração de alto-falante quadrafônico ou surround, respectivamente. O arquivo de cabeçalho Ksmedia.h define esses valores da seguinte maneira:

  #define KSAUDIO_SPEAKER_QUAD      (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \
                                     SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)

  #define KSAUDIO_SPEAKER_SURROUND  (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \
                                     SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)

Qualquer máscara contém quatro bits que especificam as posições do alto-falante dos quatro canais. Em ambos os casos, a propriedade KSPROPERTY_AUDIO_VOLUMELEVEL identifica esses mesmos quatro canais que os canais 0, 1, 2 e 3, respectivamente.

Se o manipulador de suporte básico do nó definir o bit de sinalizador KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM, os controles deslizantes mostrados na caixa de diálogo Volume do Locutor serão movidos em uníssono com alterações feitas em qualquer controle deslizante único.