Compartir a través de


Controles de volumen de punto de conexión

Las interfaces ISimpleAudioVolume, IChannelAudioVolumey IAudioStreamVolume permiten a los clientes controlar los niveles de volumen de sesiones de audio, que son colecciones de secuencias de audio en modo compartido. Estas interfaces no funcionan con secuencias de audio en modo exclusivo.

Las aplicaciones que administran secuencias en modo exclusivo pueden controlar los niveles de volumen de esas secuencias a través de la interfaz IAudioEndpointVolume. Esta interfaz controla el nivel de volumen del dispositivo de punto de conexión de audio . Usa el control de volumen de hardware para el dispositivo de punto de conexión si el hardware de audio implementa dicho control. De lo contrario, la interfaz IAudioEndpointVolume implementa el control de volumen en el software.

Si un dispositivo tiene un control de volumen de hardware, los cambios realizados en el control a través del IAudioEndpointVolume interfaz afectan al nivel de volumen tanto en modo compartido como en modo exclusivo. Si un dispositivo carece de controles de volumen de hardware y silenciar, los cambios realizados en el volumen de software y los controles silenciados a través de esta interfaz afectan al nivel de volumen en modo compartido, pero no en modo exclusivo. En modo exclusivo, la aplicación y el hardware de audio intercambian datos de audio directamente, pasando los controles de software.

Como regla general, las aplicaciones deben evitar el uso de la interfaz IAudioEndpointVolume para controlar los niveles de volumen de secuencias en modo compartido. En su lugar, las aplicaciones deben usar elISimpleAudioVolume , IChannelAudioVolumeo interfaz IAudioStreamVolume para ese propósito.

Si una aplicación muestra un control de volumen que usa el IAudioEndpointVolume interfaz para controlar el nivel de volumen de un dispositivo de punto de conexión de audio, ese control de volumen debe reflejar el control de volumen del punto de conexión mostrado por el programa de control de volumen del sistema, Sndvol. Como se explicó anteriormente, el control de volumen del punto de conexión aparece en el lado izquierdo de la ventana de Sndvol, en el cuadro de grupo etiquetado Dispositivo. Si el usuario cambia el volumen del punto de conexión de un dispositivo a través del control de volumen en Sndvol, el control de volumen del punto de conexión correspondiente de la aplicación debe moverse unísono con el control en Sndvol. Del mismo modo, si el usuario cambia el nivel de volumen a través del control de volumen del punto de conexión en la ventana de la aplicación, el control de volumen correspondiente en Sndvol debe moverse unísono con el control de volumen de la aplicación.

Para asegurarse de que el control de volumen del punto de conexión en una ventana de la aplicación refleja el control de volumen del punto de conexión en Sndvol, la aplicación debe implementar un IAudioEndpointVolumeCallback interfaz y registrar esa interfaz para recibir notificaciones. Después, cada vez que el usuario cambia el nivel de volumen del punto de conexión en Sndvol, la aplicación recibe una llamada de notificación a través de su método IAudioEndpointVolumeCallback::OnNotify. Durante esta llamada, el método OnNotify puede actualizar el control de volumen del punto de conexión en la ventana de la aplicación para que coincida con la configuración de control que se muestra en Sndvol. Del mismo modo, cada vez que el usuario cambia el nivel de volumen del punto de conexión a través del control de volumen en la ventana de la aplicación, Sndvol recibe una notificación y actualiza inmediatamente su control de volumen de punto de conexión para mostrar el nuevo nivel de volumen.

El ejemplo de código siguiente es un archivo de encabezado que muestra una posible implementación de la interfaz IAudioEndpointVolumeCallback:

// Epvolume.h -- Implementation of IAudioEndpointVolumeCallback interface

#include <windows.h>
#include <commctrl.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include "resource.h"

// Dialog handle from dialog box procedure
extern HWND g_hDlg;

// Client's proprietary event-context GUID
extern GUID g_guidMyContext;

// Maximum volume level on trackbar
#define MAX_VOL  100

#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

//-----------------------------------------------------------
// Client implementation of IAudioEndpointVolumeCallback
// interface. When a method in the IAudioEndpointVolume
// interface changes the volume level or muting state of the
// endpoint device, the change initiates a call to the
// client's IAudioEndpointVolumeCallback::OnNotify method.
//-----------------------------------------------------------
class CAudioEndpointVolumeCallback : public IAudioEndpointVolumeCallback
{
    LONG _cRef;

public:
    CAudioEndpointVolumeCallback() :
        _cRef(1)
    {
    }

    ~CAudioEndpointVolumeCallback()
    {
    }

    // IUnknown methods -- AddRef, Release, and QueryInterface

    ULONG STDMETHODCALLTYPE AddRef()
    {
        return InterlockedIncrement(&_cRef);
    }

    ULONG STDMETHODCALLTYPE Release()
    {
        ULONG ulRef = InterlockedDecrement(&_cRef);
        if (0 == ulRef)
        {
            delete this;
        }
        return ulRef;
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface)
    {
        if (IID_IUnknown == riid)
        {
            AddRef();
            *ppvInterface = (IUnknown*)this;
        }
        else if (__uuidof(IAudioEndpointVolumeCallback) == riid)
        {
            AddRef();
            *ppvInterface = (IAudioEndpointVolumeCallback*)this;
        }
        else
        {
            *ppvInterface = NULL;
            return E_NOINTERFACE;
        }
        return S_OK;
    }

    // Callback method for endpoint-volume-change notifications.

    HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify)
    {
        if (pNotify == NULL)
        {
            return E_INVALIDARG;
        }
        if (g_hDlg != NULL && pNotify->guidEventContext != g_guidMyContext)
        {
            PostMessage(GetDlgItem(g_hDlg, IDC_CHECK_MUTE), BM_SETCHECK,
                        (pNotify->bMuted) ? BST_CHECKED : BST_UNCHECKED, 0);

            PostMessage(GetDlgItem(g_hDlg, IDC_SLIDER_VOLUME),
                        TBM_SETPOS, TRUE,
                        LPARAM((UINT32)(MAX_VOL*pNotify->fMasterVolume + 0.5)));
        }
        return S_OK;
    }
};

La clase CAudioEndpointVolumeCallback del ejemplo de código anterior es una implementación de la interfaz IAudioEndpointVolumeCallback. Dado que IAudioEndpointVolumeCallback hereda de IUnknown , la definición de clase contiene implementaciones de los métodos IUnknown AddRef, Releasey QueryInterface. El método OnNotify de la definición de clase se llama cada vez que uno de los métodos siguientes cambia el nivel de volumen del punto de conexión:

La implementación del método OnNotify en el ejemplo de código anterior envía mensajes al control de volumen en la ventana de la aplicación para actualizar el nivel de volumen mostrado.

Una aplicación llama al método IAudioEndpointVolume::RegisterControlChangeNotify para registrar su interfaz IAudioEndpointVolumeCallback para recibir notificaciones. Cuando la aplicación ya no requiere notificaciones, llama al método IAudioEndpointVolume::UnregisterControlChangeNotify para eliminar el registro.

El ejemplo de código siguiente es una aplicación de Windows que llama a los métodos RegisterControlChangeNotify y UnregisterControlChangeNotify para registrar y anular el registro de la clase CAudioEndpointVolumeCallback en el ejemplo de código anterior:

// Epvolume.cpp -- WinMain and dialog box functions

#include "stdafx.h"
#include "Epvolume.h"

HWND g_hDlg = NULL;
GUID g_guidMyContext = GUID_NULL;

static IAudioEndpointVolume *g_pEndptVol = NULL;
static BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

#define EXIT_ON_ERROR(hr)  \
              if (FAILED(hr)) { goto Exit; }
#define ERROR_CANCEL(hr)  \
              if (FAILED(hr)) {  \
                  MessageBox(hDlg, TEXT("The program will exit."),  \
                             TEXT("Fatal error"), MB_OK);  \
                  EndDialog(hDlg, TRUE); return TRUE; }

//-----------------------------------------------------------
// WinMain -- Registers an IAudioEndpointVolumeCallback
//   interface to monitor endpoint volume level, and opens
//   a dialog box that displays a volume control that will
//   mirror the endpoint volume control in SndVol.
//-----------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
                     int nCmdShow)
{
    HRESULT hr = S_OK;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    CAudioEndpointVolumeCallback EPVolEvents;

    if (hPrevInstance)
    {
        return 0;
    }

    CoInitialize(NULL);

    hr = CoCreateGuid(&g_guidMyContext);
    EXIT_ON_ERROR(hr)

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

    // Get default audio-rendering device.
    hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
    EXIT_ON_ERROR(hr)

    hr = pDevice->Activate(__uuidof(IAudioEndpointVolume),
                           CLSCTX_ALL, NULL, (void**)&g_pEndptVol);
    EXIT_ON_ERROR(hr)

    hr = g_pEndptVol->RegisterControlChangeNotify(
                     (IAudioEndpointVolumeCallback*)&EPVolEvents);
    EXIT_ON_ERROR(hr)

    InitCommonControls();
    DialogBox(hInstance, L"VOLUMECONTROL", NULL, (DLGPROC)DlgProc);

Exit:
    if (FAILED(hr))
    {
        MessageBox(NULL, TEXT("This program requires Windows Vista."),
                   TEXT("Error termination"), MB_OK);
    }
    if (g_pEndptVol != NULL)
    {
        g_pEndptVol->UnregisterControlChangeNotify(
                    (IAudioEndpointVolumeCallback*)&EPVolEvents);
    }
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pDevice)
    SAFE_RELEASE(g_pEndptVol)
    CoUninitialize();
    return 0;
}

//-----------------------------------------------------------
// DlgProc -- Dialog box procedure
//-----------------------------------------------------------

BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    HRESULT hr;
    BOOL bMute;
    float fVolume;
    int nVolume;
    int nChecked;

    switch (message)
    {
    case WM_INITDIALOG:
        g_hDlg = hDlg;
        SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME, TBM_SETRANGEMIN, FALSE, 0);
        SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME, TBM_SETRANGEMAX, FALSE, MAX_VOL);
        hr = g_pEndptVol->GetMute(&bMute);
        ERROR_CANCEL(hr)
        SendDlgItemMessage(hDlg, IDC_CHECK_MUTE, BM_SETCHECK,
                           bMute ? BST_CHECKED : BST_UNCHECKED, 0);
        hr = g_pEndptVol->GetMasterVolumeLevelScalar(&fVolume);
        ERROR_CANCEL(hr)
        nVolume = (int)(MAX_VOL*fVolume + 0.5);
        SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME, TBM_SETPOS, TRUE, nVolume);
        return TRUE;

    case WM_HSCROLL:
        switch (LOWORD(wParam))
        {
        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
        case SB_LINERIGHT:
        case SB_LINELEFT:
        case SB_PAGERIGHT:
        case SB_PAGELEFT:
        case SB_RIGHT:
        case SB_LEFT:
            // The user moved the volume slider in the dialog box.
            SendDlgItemMessage(hDlg, IDC_CHECK_MUTE, BM_SETCHECK, BST_UNCHECKED, 0);
            hr = g_pEndptVol->SetMute(FALSE, &g_guidMyContext);
            ERROR_CANCEL(hr)
            nVolume = SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME, TBM_GETPOS, 0, 0);
            fVolume = (float)nVolume/MAX_VOL;
            hr = g_pEndptVol->SetMasterVolumeLevelScalar(fVolume, &g_guidMyContext);
            ERROR_CANCEL(hr)
            return TRUE;
        }
        break;

    case WM_COMMAND:
        switch ((int)LOWORD(wParam))
        {
        case IDC_CHECK_MUTE:
            // The user selected the Mute check box in the dialog box.
            nChecked = SendDlgItemMessage(hDlg, IDC_CHECK_MUTE, BM_GETCHECK, 0, 0);
            bMute = (BST_CHECKED == nChecked);
            hr = g_pEndptVol->SetMute(bMute, &g_guidMyContext);
            ERROR_CANCEL(hr)
            return TRUE;
        case IDCANCEL:
            EndDialog(hDlg, TRUE);
            return TRUE;
        }
        break;
    }
    return FALSE;
}

En el ejemplo de código anterior, La funciónWinMain llama a la función CoCreateInstance para crear una instancia del método IMMDeviceEnumerator y llama a la interfaz IMMDeviceEnumerator::GetDefaultAudioEndpoint para obtener la interfaz IMMDevice del dispositivo de representación predeterminado. WinMain llama al método IMMDevice::Activate para obtener la interfaz IAudioEndpointVolume del dispositivo y llama a RegisterControlChangeNotify para registrar la aplicación para recibir notificaciones de los cambios de volumen del punto de conexión. A continuación, winMain abre un cuadro de diálogo para mostrar un control de volumen de punto de conexión para el dispositivo. El cuadro de diálogo también muestra una casilla que indica si el dispositivo está silenciado. La casilla control de volumen del punto de conexión y silenciar del cuadro de diálogo refleja la configuración del control de volumen del punto de conexión y la casilla silenciar mostrada por Sndvol. Para obtener más información sobre winMain y CoCreateInstance, consulte la documentación de Windows SDK. Para obtener más información sobre de IMMDeviceEnumerator y IMMDevice, vea Enumerar dispositivos de audio.

El procedimiento del cuadro de diálogo DlgProc, en el ejemplo de código anterior, controla los cambios que realiza el usuario en el volumen y silencia la configuración a través de los controles del cuadro de diálogo. Cuando DlgProc llama a SetMasterVolumeLevelScalar o SetMute, Sndvol recibe una notificación del cambio y actualiza el control correspondiente en su ventana para reflejar el nuevo volumen o la configuración de silenciación. Si, en lugar de usar el cuadro de diálogo, el usuario actualiza la configuración de volumen y silenciar a través de los controles de la ventana de Sndvol, el método OnNotify de la clase CAudioEndpointVolumeCallback actualiza los controles del cuadro de diálogo para mostrar la nueva configuración.

Si el usuario cambia el volumen a través de los controles del cuadro de diálogo, el método OnNotify de la clase CAudioEndpointVolumeCallback no envía mensajes para actualizar los controles del cuadro de diálogo. Para ello, sería redundante. OnNotify actualiza los controles del cuadro de diálogo solo si el cambio de volumen se originó en Sndvol o en alguna otra aplicación. El segundo parámetro de la SetMasterVolumeLevelScalar y llamadas de método setMute en la función DlgProc es un puntero a un GUID de contexto de evento que el método pasa a OnNotify. OnNotify comprueba el valor del GUID de contexto de evento para determinar si el cuadro de diálogo es el origen del cambio de volumen. Para obtener más información sobre los GUID de contexto de eventos, vea IAudioEndpointVolumeCallback::OnNotify.

Cuando el usuario sale del cuadro de diálogo, la UnregisterControlChangeNotify llamada en el ejemplo de código anterior elimina el registro de la clase CAudioEndpointVolumeCallback antes de que finalice el programa.

Puede modificar fácilmente el ejemplo de código anterior para mostrar controles de volumen y silenciar para el dispositivo de captura predeterminado. En la funciónWinMain, cambie el valor del primer parámetro de la llamada a la IMMDeviceEnumerator::GetDefaultAudioEndpoint método de eRender a eCapture.

El siguiente ejemplo de código es el script de recursos que define los controles de volumen y silenciar que aparecen en el ejemplo de código anterior:

// Epvolume.rc -- Resource script

#include "resource.h"
#include "windows.h"
#include "commctrl.h"

//
// Dialog box
//
VOLUMECONTROL DIALOGEX 0, 0, 160, 60
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU | DS_SETFONT
CAPTION "Audio Endpoint Volume"
FONT 8, "Arial Rounded MT Bold", 400, 0, 0x0
BEGIN
    LTEXT      "Min",IDC_STATIC_MINVOL,10,10,20,12
    RTEXT      "Max",IDC_STATIC_MAXVOL,130,10,20,12
    CONTROL    "",IDC_SLIDER_VOLUME,"msctls_trackbar32",
               TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,10,20,140,12
    CONTROL    "Mute",IDC_CHECK_MUTE,"Button",
               BS_AUTOCHECKBOX | WS_TABSTOP,20,40,70,12
END

El ejemplo de código siguiente es el archivo de encabezado de recurso que define los identificadores de control que aparecen en los ejemplos de código anteriores:

// Resource.h -- Control identifiers (epvolume)

#define IDC_SLIDER_VOLUME      1001
#define IDC_CHECK_MUTE         1002
#define IDC_STATIC_MINVOL      1003
#define IDC_STATIC_MAXVOL      1004

Los ejemplos de código anteriores se combinan para formar una aplicación sencilla para controlar y supervisar el volumen del punto de conexión del dispositivo de representación predeterminado. Además, una aplicación más útil podría notificar al usuario cuándo cambia el estado del dispositivo. Por ejemplo, el dispositivo puede estar deshabilitado, desconectado o quitado. Para obtener más información sobre cómo supervisar estos tipos de eventos, consulte Eventos de dispositivo.

controles de volumen de