Freigeben über


Steuerelemente für Endpunktvolume

Die ISimpleAudioVolume, IChannelAudioVolumeund IAudioStreamVolume Schnittstellen ermöglichen Clients die Steuerung der Lautstärke von Audiositzungen, die Sammlungen von Audiodatenströmen im Modus sind. Diese Schnittstellen funktionieren nicht mit Exklusivmodus-Audiostreams.

Anwendungen, die Exklusivmodusdatenströme verwalten, können die Volumeebenen dieser Datenströme über die IAudioEndpointVolume--Schnittstelle steuern. Diese Schnittstelle steuert die Lautstärke des Audioendpunktgeräts. Es verwendet die Hardwarelautstärkesteuerung für das Endpunktgerät, wenn die Audiohardware ein solches Steuerelement implementiert. Andernfalls implementiert die IAudioEndpointVolume Schnittstelle die Lautstärkeregelung in der Software.

Wenn ein Gerät über eine Hardwarelautstärkesteuerung verfügt, wirken sich Änderungen am Steuerelement über die IAudioEndpointVolume Schnittstelle sowohl im gemeinsam genutzten Modus als auch im exklusiven Modus auf die Lautstärkeebene aus. Wenn auf einem Gerät keine Hardwarevolume- und Stummschaltungssteuerelemente vorhanden sind, wirken sich Änderungen am Softwarevolume und Stummschalten über diese Schnittstelle auf die Lautstärke im gemeinsam genutzten Modus aus, jedoch nicht im exklusiven Modus. Im exklusiven Modus tauschen die Anwendung und die Audiohardware Audiodaten direkt aus, um die Softwaresteuerelemente zu umgehen.

In der Regel sollten Anwendungen die Verwendung der IAudioEndpointVolume Schnittstelle vermeiden, um die Volumeebenen von Datenströmen für den gemeinsam genutzten Modus zu steuern. Stattdessen sollten Anwendungen die ISimpleAudioVolume, IChannelAudioVolumeoder IAudioStreamVolume Schnittstelle verwenden.

Wenn eine Anwendung ein Volumesteuerelement anzeigt, das die IAudioEndpointVolume- Schnittstelle verwendet, um die Lautstärke eines Audioendpunktgeräts zu steuern, sollte diese Lautstärkeregelung die Endpunktlautstärkesteuerung spiegeln, die vom Systemlautstärkeprogramm Sndvol angezeigt wird. Wie bereits erläutert, wird die Endpunktlautstärkesteuerung auf der linken Seite des Sndvol-Fensters im Gruppenfeld mit der Bezeichnung Deviceangezeigt. Wenn der Benutzer das Endpunktvolume eines Geräts über die Lautstärkeregelung in Sndvol ändert, sollte die entsprechende Endpunktvolumesteuerung in der Anwendung mit dem Steuerelement in Sndvol in Verbindung verschoben werden. Wenn der Benutzer die Lautstärke im Anwendungsfenster durch die Endpunktlautstärkesteuerung ändert, sollte sich die entsprechende Lautstärkeregelung in Sndvol mit der Lautstärkeregelung der Anwendung in Verbindung setzen.

Um sicherzustellen, dass die Endpunktlautstärkesteuerung in einem Anwendungsfenster die Endpunktlautstärkesteuerung in Sndvol spiegelt, sollte die Anwendung eine IAudioEndpointVolumeCallback-schnittstelle implementieren und diese Schnittstelle für den Empfang von Benachrichtigungen registrieren. Anschließend erhält die Anwendung jedes Mal, wenn der Benutzer die Endpunktvolumeebene in Sndvol ändert, einen Benachrichtigungsaufruf über die IAudioEndpointVolumeCallback::OnNotify-Methode. Während dieses Aufrufs kann die OnNotify-Methode die Endpunktlautstärkesteuerung im Anwendungsfenster so aktualisieren, dass sie mit der steuerelementeinstellung übereinstimmt, die in Sndvol angezeigt wird. Ebenso erhält Sndvol jedes Mal, wenn der Benutzer die Endpunktlautstärke im Anwendungsfenster ändert, eine Benachrichtigung und aktualisiert sofort seine Endpunktvolumesteuerung, um die neue Volumeebene anzuzeigen.

The following code example is a header file that shows a possible implementation of the IAudioEndpointVolumeCallback interface:

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

Die CAudioEndpointVolumeCallback-Klasse im vorherigen Codebeispiel ist eine Implementierung der IAudioEndpointVolumeCallback-Schnittstelle. Da IAudioEndpointVolumeCallback- von IUnknownerbt, enthält die Klassendefinition Implementierungen der IUnknown Methoden AddRef, Releaseund QueryInterface. Die OnNotify-Methode in der Klassendefinition wird jedes Mal aufgerufen, wenn eine der folgenden Methoden die Endpunktvolumeebene ändert:

Die Implementierung der OnNotify-Methode im vorherigen Codebeispiel sendet Nachrichten an die Lautstärkesteuerung im Anwendungsfenster, um die angezeigte Volumeebene zu aktualisieren.

Eine Anwendung ruft die IAudioEndpointVolume::RegisterControlChangeNotify-Methode auf, um die IAudioEndpointVolumeCallback Schnittstelle zum Empfangen von Benachrichtigungen zu registrieren. Wenn die Anwendung keine Benachrichtigungen mehr benötigt, ruft sie die IAudioEndpointVolume::UnregisterControlChangeNotify Methode auf, um die Registrierung zu löschen.

Das folgende Codebeispiel ist eine Windows-Anwendung, die die RegisterControlChangeNotify aufruft und UnregisterControlChangeNotify Methoden zum Registrieren und Aufheben der Registrierung der CAudioEndpointVolumeCallback-Klasse im vorherigen Codebeispiel auffordert:

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

Im vorangehenden Codebeispiel ruft die WinMain--Funktion die CoCreateInstance-Funktion auf, um eine Instanz der IMMDeviceEnumerator--Schnittstelle zu erstellen, und ruft die IMMDeviceEnumerator::GetDefaultAudioEndpoint Methode auf, um die IMMDevice Schnittstelle des Standardrendergeräts abzurufen. WinMain ruft die IMMDevice::Activate-Methode auf, um die IAudioEndpointVolume-Schnittstelle des Geräts abzurufen, und es ruft RegisterControlChangeNotify auf, um die Anwendung für den Empfang von Benachrichtigungen über Endpunktvolumeänderungen zu registrieren. Als Nächstes öffnet WinMain ein Dialogfeld, um ein Endpunktlautstärkesteuerelement für das Gerät anzuzeigen. Im Dialogfeld wird auch ein Kontrollkästchen angezeigt, das angibt, ob das Gerät stummgeschaltet ist. Das Kontrollkästchen für Die Endpunktlautstärkesteuerung und -stummschaltung im Dialogfeld spiegelt die Einstellungen des Endpunktlautstärkesteuerelements und des Kontrollkästchens stumm, das von Sndvol angezeigt wird. Weitere Informationen zu WinMain und CoCreateInstancefinden Sie in der Windows SDK-Dokumentation. Weitere Informationen zu IMMDeviceEnumerator und IMMDevice-finden Sie unter Enumerating Audio Devices.

Die Dialogfeldprozedur DlgProc im vorherigen Codebeispiel behandelt die Änderungen, die der Benutzer an dem Volume vorgibt, und schaltet Einstellungen über die Steuerelemente im Dialogfeld stumm. Wenn DlgProc SetMasterVolumeLevelScalar oder SetMuteaufruft, empfängt Sndvol die Änderung und aktualisiert das entsprechende Steuerelement in seinem Fenster so, dass es die neue Lautstärke- oder Stummschaltungseinstellung widerspiegelt. Wenn der Benutzer anstelle des Dialogfelds die Lautstärke aktualisiert und einstellungen über die Steuerelemente im Sndvol-Fenster stummschalten kann, aktualisiert die OnNotify-Methode in der CAudioEndpointVolumeCallback-Klasse die Steuerelemente im Dialogfeld, um die neuen Einstellungen anzuzeigen.

Wenn der Benutzer die Lautstärke über die Steuerelemente im Dialogfeld ändert, sendet die OnNotify-Methode in der CAudioEndpointVolumeCallback-Klasse keine Nachrichten, um die Steuerelemente im Dialogfeld zu aktualisieren. Dazu wäre redundant. OnNotify die Steuerelemente im Dialogfeld nur aktualisiert, wenn die Volumenänderung von Sndvol oder in einer anderen Anwendung stammt. Der zweite Parameter in der SetMasterVolumeLevelScalar und SetMute Methodenaufrufe in der DlgProc-Funktion ist ein Zeiger auf eine Ereigniskontext-GUID, die von beiden Methoden an OnNotifyübergeben wird. OnNotify überprüft den Wert der Ereigniskontext-GUID, um zu bestimmen, ob das Dialogfeld die Quelle der Volumeänderung ist. Weitere Informationen zu Ereigniskontext-GUIDs finden Sie unter IAudioEndpointVolumeCallback::OnNotify.

Wenn der Benutzer das Dialogfeld beendet, löscht der UnregisterControlChangeNotify Aufruf im vorherigen Codebeispiel die Registrierung der CAudioEndpointVolumeCallback-Klasse, bevor das Programm beendet wird.

Sie können das vorangehende Codebeispiel ganz einfach ändern, um Lautstärke- und Stummschaltungssteuerelemente für das Standardaufnahmegerät anzuzeigen. Ändern Sie im WinMain--Funktion den Wert des ersten Parameters im Aufruf des IMMDeviceEnumerator::GetDefaultAudioEndpoint-Methode von eRender in eCapture.

Das folgende Codebeispiel ist das Ressourcenskript, das die Volume- und Stummschaltungssteuerelemente definiert, die im vorherigen Codebeispiel angezeigt werden:

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

Das folgende Codebeispiel ist die Ressourcenkopfdatei, die die Steuerelementbezeichner definiert, die in den vorherigen Codebeispielen angezeigt werden:

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

Die obigen Codebeispiele kombinieren eine einfache Anwendung zum Steuern und Überwachen des Endpunktvolumens des Standardrenderinggeräts. Eine nützlichere Anwendung kann den Benutzer darüber hinaus benachrichtigen, wenn sich der Status des Geräts ändert. Beispielsweise kann das Gerät deaktiviert, nicht angeschlossen oder entfernt werden. Weitere Informationen zum Überwachen dieser Ereignistypen finden Sie unter Device Events.