Partager via


Contrôles de volume de point de terminaison

Les interfaces ISimpleAudioVolume, IChannelAudioVolumeet interfaces IAudioStreamVolume permettent aux clients de contrôler les niveaux de volume des sessions audio , qui sont des collections de flux audio en mode partagé. Ces interfaces ne fonctionnent pas avec des flux audio en mode exclusif.

Les applications qui gèrent des flux en mode exclusif peuvent contrôler les niveaux de volume de ces flux via l’interface IAudioEndpointVolume. Cette interface contrôle le niveau de volume de l’appareil de point de terminaison audio . Il utilise le contrôle de volume matériel pour l’appareil de point de terminaison si le matériel audio implémente un tel contrôle. Sinon, l’interface IAudioEndpointVolume implémente le contrôle de volume dans les logiciels.

Si un appareil dispose d’un contrôle de volume matériel, les modifications apportées au contrôle via l’interface IAudioEndpointVolume affectent le niveau de volume en mode partagé et en mode exclusif. Si un appareil ne dispose pas de contrôles de volume matériel et de désactivation, les modifications apportées au volume logiciel et aux contrôles de désactivation par le biais de cette interface affectent le niveau de volume en mode partagé, mais pas en mode exclusif. En mode exclusif, l’application et le matériel audio échangent directement des données audio, en contournant les contrôles logiciels.

En règle générale, les applications doivent éviter d’utiliser l’interface IAudioEndpointVolume pour contrôler les niveaux de volume des flux en mode partagé. Au lieu de cela, les applications doivent utiliser leISimpleAudioVolume, IChannelAudioVolumeou interface IAudioStreamVolume à cet effet.

Si une application affiche un contrôle de volume qui utilise l’interface IAudioEndpointVolume pour contrôler le niveau de volume d’un appareil de point de terminaison audio, ce contrôle de volume doit mettre en miroir le contrôle de volume de point de terminaison affiché par le programme de contrôle de volume système, Sndvol. Comme expliqué précédemment, le contrôle de volume de point de terminaison apparaît sur le côté gauche de la fenêtre Sndvol, dans la zone de groupe intitulée Appareil. Si l’utilisateur modifie le volume de point de terminaison d’un appareil par le biais du contrôle de volume dans Sndvol, le contrôle de volume de point de terminaison correspondant dans l’application doit se déplacer union avec le contrôle dans Sndvol. De même, si l’utilisateur modifie le niveau de volume par le biais du contrôle de volume de point de terminaison dans la fenêtre de l’application, le contrôle de volume correspondant dans Sndvol doit se déplacer union avec le contrôle de volume de l’application.

Pour vous assurer que le contrôle de volume de point de terminaison dans une fenêtre d’application reflète le contrôle de volume de point de terminaison dans Sndvol, l’application doit implémenter une interface IAudioEndpointVolumeCallback et inscrire cette interface pour recevoir des notifications. Par la suite, chaque fois que l’utilisateur modifie le niveau de volume de point de terminaison dans Sndvol, l’application reçoit un appel de notification via sa méthode IAudioEndpointVolumeCallback ::OnNotify. Pendant cet appel, la méthode OnNotify peut mettre à jour le contrôle de volume de point de terminaison dans la fenêtre d’application pour qu’il corresponde au paramètre de contrôle affiché dans Sndvol. De même, chaque fois que l’utilisateur modifie le niveau de volume du point de terminaison par le biais du contrôle de volume dans la fenêtre de l’application, Sndvol reçoit une notification et met immédiatement à jour son contrôle de volume de point de terminaison pour afficher le nouveau niveau de volume.

L’exemple de code suivant est un fichier d’en-tête qui montre une implémentation possible de l’interface 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 classe CAudioEndpointVolumeCallback dans l’exemple de code précédent est une implémentation de l’interface IAudioEndpointVolumeCallback. Étant donné que IAudioEndpointVolumeCallback hérite de IUnknown, la définition de classe contient des implémentations des méthodes IUnknownAddRef, Releaseet QueryInterface. La méthode OnNotify dans la définition de classe est appelée chaque fois que l’une des méthodes suivantes modifie le niveau de volume du point de terminaison :

L’implémentation de la méthode OnNotify dans l’exemple de code précédent envoie des messages au contrôle de volume dans la fenêtre d’application pour mettre à jour le niveau de volume affiché.

Une application appelle la méthode IAudioEndpointVolume ::RegisterControlChangeNotify pour inscrire son interface IAudioEndpointVolumeCallback pour recevoir des notifications. Lorsque l’application n’a plus besoin de notifications, elle appelle la méthode IAudioEndpointVolume ::UnregisterControlChangeNotify pour supprimer l’inscription.

L’exemple de code suivant est une application Windows qui appelle les méthodes RegisterControlChangeNotify et UnregisterControlChangeNotify pour inscrire et annuler l’inscription de la classe CAudioEndpointVolumeCallback dans l’exemple de code précédent :

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

Dans l’exemple de code précédent, la fonction WinMain appelle la fonction CoCreateInstance pour créer une instance de l’interface IMMDeviceEnumerator et appelle l’interface IMMDeviceEnumerator ::GetDefaultAudioEndpoint pour obtenir l’interface IMMDevice de l’appareil de rendu par défaut. WinMain appelle la méthode IMMDevice ::Activate pour obtenir l’interface IAudioEndpointVolume de l’appareil et appelle RegisterControlChangeNotify pour inscrire l’application afin de recevoir des notifications de modifications de volume de point de terminaison. Ensuite, WinMain ouvre une boîte de dialogue pour afficher un contrôle de volume de point de terminaison pour l’appareil. La boîte de dialogue affiche également une case à cocher qui indique si l’appareil est désactivé. La case à cocher contrôle de volume et désactivation du point de terminaison dans la boîte de dialogue reflète les paramètres du contrôle de volume de point de terminaison et la case à cocher Désactiver le son affiché par Sndvol. Pour plus d’informations sur WinMain et CoCreateInstance, consultez la documentation du Kit de développement logiciel (SDK) Windows. Pour plus d’informations sur IMMDeviceEnumerator et IMMDevice, consultez énumération d’appareils audio.

La procédure de boîte de dialogue DlgProc, dans l’exemple de code précédent, gère les modifications apportées par l’utilisateur au volume et désactive les paramètres via les contrôles de la boîte de dialogue. Lorsque DlgProc appelle SetMasterVolumeLevelScalar ou SetMute, Sndvol reçoit la notification de la modification et met à jour le contrôle correspondant dans sa fenêtre pour refléter le nouveau volume ou le paramètre de désactivation. Si, au lieu d’utiliser la boîte de dialogue, l’utilisateur met à jour les paramètres de volume et de désactivation par le biais des contrôles dans la fenêtre Sndvol, la méthode OnNotify dans la classe CAudioEndpointVolumeCallback met à jour les contrôles de la boîte de dialogue pour afficher les nouveaux paramètres.

Si l’utilisateur modifie le volume via les contrôles de la boîte de dialogue, la méthode OnNotify dans la classe CAudioEndpointVolumeCallback n’envoie pas de messages pour mettre à jour les contrôles de la boîte de dialogue. Pour ce faire, il serait redondant. OnNotify met à jour les contrôles dans la boîte de dialogue uniquement si la modification du volume provient de Sndvol ou dans une autre application. Le deuxième paramètre de la méthode SetMasterVolumeLevelScalar et appels de méthode SetMute dans la fonction DlgProc est un pointeur vers un GUID de contexte d’événement transmis à OnNotify. OnNotify vérifie la valeur du GUID de contexte d’événement pour déterminer si la boîte de dialogue est la source du changement de volume. Pour plus d’informations sur les GUID de contexte d’événement, consultez IAudioEndpointVolumeCallback ::OnNotify.

Lorsque l’utilisateur quitte la boîte de dialogue, l’appel UnregisterControlChangeNotify dans l’exemple de code précédent supprime l’inscription de la classe CAudioEndpointVolumeCallback avant la fin du programme.

Vous pouvez facilement modifier l’exemple de code précédent pour afficher les contrôles de volume et de désactiver le son pour l’appareil de capture par défaut. Dans la fonction WinMain, remplacez la valeur du premier paramètre de l’appel par la méthode IMMDeviceEnumerator ::GetDefaultAudioEndpoint d’eRender en eCapture.

L’exemple de code suivant est le script de ressource qui définit le volume et les contrôles de désactivation qui apparaissent dans l’exemple de code précédent :

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

L’exemple de code suivant est le fichier d’en-tête de ressource qui définit les identificateurs de contrôle qui apparaissent dans les exemples de code précédents :

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

Les exemples de code précédents se combinent pour former une application simple pour contrôler et surveiller le volume de point de terminaison de l’appareil de rendu par défaut. Une application plus utile peut également avertir l’utilisateur lorsque l’état de l’appareil change. Par exemple, l’appareil peut être désactivé, débranché ou supprimé. Pour plus d’informations sur la surveillance de ces types d’événements, consultez événements d’appareil.

contrôles de volume