Compartilhar via


Eventos de áudio para aplicativos de áudio herdados

AS APIs de áudio herdadas, como DirectSound, DirectShow e as funções waveOutXxx, permitem que os aplicativos obtenham e definam os níveis de volume de fluxos de áudio. Os aplicativos podem usar os recursos de controle de volume nessas APIs para exibir controles deslizantes de volume em suas janelas de aplicativo.

No Windows Vista, o programa de controle de volume do sistema, Sndvol, permite que os usuários controlem os níveis de volume de áudio para aplicativos individuais. Os controles deslizantes de volume exibidos por aplicativos devem ser vinculados aos controles deslizantes de volume correspondentes no Sndvol. Se um usuário ajustar o volume do aplicativo por meio de um controle deslizante de volume em uma janela do aplicativo, o controle deslizante de volume correspondente no Sndvol será movido imediatamente para indicar o novo nível de volume. Por outro lado, se o usuário ajustar o volume do aplicativo por meio do Sndvol, os controles deslizantes de volume na janela do aplicativo deverão se mover para indicar o novo nível de volume.

No Windows Vista, o Sndvol reflete imediatamente as alterações de volume que um aplicativo faz por meio de chamadas para o método IDirectSoundBuffer::SetVolume ou função waveOutSetVolume. No entanto, uma API de áudio herdada, como DirectSound ou waveOutXxx funções, não fornece meios para notificar um aplicativo quando o usuário altera o volume do aplicativo por meio do Sndvol. Se um aplicativo exibir um controle deslizante de volume, mas não receber notificações de alterações de volume, o controle deslizante não refletirá as alterações feitas pelo usuário no Sndvol. Para implementar o comportamento apropriado, o designer de aplicativos deve de alguma forma compensar a falta de notificações pela API de áudio herdada.

Uma solução pode ser que o aplicativo defina um temporizador para lembrá-lo periodicamente para verificar o nível de volume para ver se ele foi alterado.

Uma solução mais elegante é que o aplicativo use os recursos de notificação de eventos das APIs de áudio principais. Em particular, o aplicativo pode registrar uma interface IAudioSessionEvents para receber retornos de chamada quando ocorrem alterações de volume ou outros tipos de eventos de áudio. Quando o volume é alterado, a rotina de retorno de chamada de alteração de volume pode atualizar imediatamente o controle deslizante de volume do aplicativo para refletir a alteração.

O exemplo de código a seguir mostra como um aplicativo pode se registrar para receber notificações de alterações de volume e outros eventos de áudio:

//-----------------------------------------------------------
// Register the application to receive notifications when the
// volume level changes on the default process-specific audio
// session (with session GUID value GUID_NULL) on the audio
// endpoint device with the specified data-flow direction
// (eRender or eCapture) and device role.
//-----------------------------------------------------------
#define EXIT_ON_ERROR(hr)  \
              if (FAILED(hr)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

class AudioVolumeEvents
{
    HRESULT _hrStatus;
    IAudioSessionManager *_pManager;
    IAudioSessionControl *_pControl;
    IAudioSessionEvents *_pAudioEvents;
public:
    AudioVolumeEvents(EDataFlow, ERole, IAudioSessionEvents*);
    ~AudioVolumeEvents();
    HRESULT GetStatus() { return _hrStatus; };
};

// Constructor
AudioVolumeEvents::AudioVolumeEvents(EDataFlow flow, ERole role,
                                     IAudioSessionEvents *pAudioEvents)
{
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;

    _hrStatus = S_OK;
    _pManager = NULL;
    _pControl = NULL;
    _pAudioEvents = pAudioEvents;

    if (_pAudioEvents == NULL)
    {
        _hrStatus = E_POINTER;
        return;
    }

    _pAudioEvents->AddRef();

    // Get the enumerator for the audio endpoint devices
    // on this system.
    _hrStatus = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                                 NULL, CLSCTX_INPROC_SERVER,
                                 __uuidof(IMMDeviceEnumerator),
                                 (void**)&pEnumerator);
    EXIT_ON_ERROR(_hrStatus)

    // Get the audio endpoint device with the specified data-flow
    // direction (eRender or eCapture) and device role.
    _hrStatus = pEnumerator->GetDefaultAudioEndpoint(flow, role,
                                                     &pDevice);
    EXIT_ON_ERROR(_hrStatus)

    // Get the session manager for the endpoint device.
    _hrStatus = pDevice->Activate(__uuidof(IAudioSessionManager),
                                  CLSCTX_INPROC_SERVER, NULL,
                                  (void**)&_pManager);
    EXIT_ON_ERROR(_hrStatus)

    // Get the control interface for the process-specific audio
    // session with session GUID = GUID_NULL. This is the session
    // that an audio stream for a DirectSound, DirectShow, waveOut,
    // or PlaySound application stream belongs to by default.
    _hrStatus = _pManager->GetAudioSessionControl(NULL, 0, &_pControl);
    EXIT_ON_ERROR(_hrStatus)

    _hrStatus = _pControl->RegisterAudioSessionNotification(_pAudioEvents);
    EXIT_ON_ERROR(_hrStatus)

Exit:
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pDevice)
}

// Destructor
AudioVolumeEvents::~AudioVolumeEvents()
{
    if (_pControl != NULL)
    {
        _pControl->UnregisterAudioSessionNotification(_pAudioEvents);
    }
    SAFE_RELEASE(_pManager)
    SAFE_RELEASE(_pControl)
    SAFE_RELEASE(_pAudioEvents)
};

O exemplo de código anterior implementa uma classe chamada AudioVolumeEvents. Durante a inicialização do programa, o aplicativo de áudio habilita notificações de evento de áudio criando um objeto AudioVolumeEvents. O construtor dessa classe usa três parâmetros de entrada:

  • fluxo— a direção do fluxo de dados do dispositivo de ponto de extremidade de áudio (um valor de enumeração EDataFlow).
  • função— a função de dispositivo atual do dispositivo de ponto de extremidade (um valor de enumeraçãoERole).
  • pAudioEvents— ponteiro para um objeto (uma instância de interfaceIAudioSessionEvents) que contém um conjunto de rotinas de retorno de chamada implementadas pelo aplicativo.

O construtor fornece os valores de fluxo e função como parâmetros de entrada para o método IMMDeviceEnumerator::GetDefaultAudioEndpoint. O método cria um objeto IMMDevice que encapsula o dispositivo de ponto de extremidade de áudio com a direção do fluxo de dados e a função de dispositivo especificadas.

O aplicativo implementa o objeto apontado por pAudioEvents. (A implementação não é mostrada no exemplo de código anterior. Para obter um exemplo de código que implementa uma interface IAudioSessionEvents, consulte de Eventos de Sessão de Áudio .) Cada método nessa interface recebe notificações de um determinado tipo de evento de áudio. Se o aplicativo não estiver interessado em um tipo de evento específico, o método desse tipo de evento não deverá fazer nada além de retornar S_OK.

O métodoIAudioSessionEvents::OnSimpleVolumeChanged recebe notificações de alterações de volume. Normalmente, esse método atualiza o controle deslizante de volume do aplicativo.

No exemplo de código anterior, o construtor da classe AudioVolumeEvents registra notificações na sessão de áudio específica do processo identificada pelo valor guid da sessão GUID_NULL. Por padrão, APIs de áudio herdadas como DirectSound, DirectShow e as funções waveOutXxx atribuem seus fluxos a esta sessão. No entanto, um aplicativo DirectSound ou DirectShow pode, como uma opção, substituir o comportamento padrão e atribuir seus fluxos a uma sessão de processo cruzado ou a uma sessão identificada por um valor GUID diferente de GUID_NULL. (No momento, nenhum mecanismo é fornecido para um aplicativo waveOutXxx substituir o comportamento padrão de maneira semelhante.) Para obter um exemplo de código de um aplicativo DirectShow com esse comportamento, consulte funções de dispositivo para aplicativos DirectShow. Para acomodar esse aplicativo, você pode modificar o construtor no exemplo de código anterior para aceitar dois parâmetros de entrada adicionais: um GUID de sessão e um sinalizador para indicar se a sessão a ser monitorada é uma sessão interprocessada ou específica do processo. Passe esses parâmetros para a chamada para o método IAudioSessionManager::GetAudioSessionControl no construtor.

Depois que o construtor chama o método IAudioSessionControl::RegisterAudioSessionNotification para se registrar para notificações, o aplicativo continua recebendo notificações apenas desde que a interface IAudioSessionControl ou IAudioSessionManager exista. O objeto AudioVolumeEvents no exemplo de código anterior contém referências a essas interfaces até que seu destruidor seja chamado. Esse comportamento garante que o aplicativo continue recebendo notificações durante o tempo de vida do objeto AudioVolumeEvents.

Em vez de selecionar implicitamente um dispositivo de áudio com base em sua função de dispositivo, um aplicativo multimídia DirectSound ou herdado do Windows pode permitir que o usuário selecione explicitamente um dispositivo em uma lista de dispositivos disponíveis identificados por seus nomes amigáveis. Para dar suporte a esse comportamento, o exemplo de código anterior deve ser modificado para gerar notificações de evento de áudio para o dispositivo selecionado. Duas modificações são necessárias. Primeiro, altere a definição do construtor para aceitar uma cadeia de caracteres de ID do ponto de extremidade como um parâmetro de entrada (no lugar dos parâmetros de fluxo e função no exemplo de código). Essa cadeia de caracteres identifica o dispositivo de ponto de extremidade de áudio que corresponde ao dispositivo DirectSound ou de forma de onda herdado selecionado. Em segundo lugar, substitua a chamada para o métodoIMMDeviceEnumerator::GetDefaultAudioEndpoint por uma chamada para o método IMMDeviceEnumerator::GetDevice. A chamada GetDevice usa a cadeia de caracteres de ID do ponto de extremidade como um parâmetro de entrada e cria uma instância do dispositivo de ponto de extremidade que é identificado pela cadeia de caracteres.

A técnica para obter a cadeia de caracteres de ID do ponto de extremidade para um dispositivo DirectSound ou dispositivo de forma de onda herdada é a seguinte.

Primeiro, durante a enumeração do dispositivo, o DirectSound fornece a cadeia de caracteres de ID do ponto de extremidade para cada dispositivo enumerado. Para iniciar a enumeração do dispositivo, o aplicativo passa um ponteiro de função de retorno de chamada como um parâmetro de entrada para a função DirectSoundCreate ou DirectSoundCaptureCreate. A definição da função de retorno de chamada é:

BOOL DSEnumCallback(
  LPGUID  lpGuid,
  LPCSTR  lpcstrDescription,
  LPCSTR  lpcstrModule,
  LPVOID  lpContext
);

No Windows Vista, o parâmetro lpcstrModule aponta para a cadeia de caracteres de ID do ponto de extremidade. (Em versões anteriores do Windows, incluindo Windows Server 2003, Windows XP e Windows 2000, o parâmetro lpcstrModule aponta para o nome do módulo de driver do dispositivo.) O parâmetro lpcstrDescription aponta para uma cadeia de caracteres que contém o nome amigável do dispositivo. Para obter mais informações sobre a enumeração de dispositivo DirectSound, consulte a documentação do SDK do Windows.

Em segundo lugar, para obter a cadeia de caracteres de ID do ponto de extremidade para um dispositivo de forma de onda herdada, use a função waveOutMessage ou waveInMessage para enviar uma mensagem DRV_QUERYFUNCTIONINSTANCEID para o driver de dispositivo de forma de onda. Para obter um exemplo de código que mostra o uso dessa mensagem, consulte funções de dispositivo para aplicativos multimídia herdados do Windows.

interoperabilidade com APIs de áudio herdadas