Endpunktvolumesteuerelemente
Mit den Schnittstellen ISimpleAudioVolume, IChannelAudioVolumeund IAudioStreamVolume können Clients die Lautstärke von Audiositzungensteuern. Dabei handelt es sich um Sammlungen von Audiostreams im freigegebenen Modus. Diese Schnittstellen funktionieren nicht mit Audiostreams im exklusiven Modus.
Anwendungen, die Streams im exklusiven Modus verwalten, können die Volumenebenen dieser Streams über die IAudioEndpointVolume-Schnittstelle steuern. Diese Schnittstelle steuert die Lautstärke des Audioendpunktgeräts. Es verwendet die Hardwarevolumesteuerung für das Endpunktgerät, wenn die Audiohardware ein solches Steuerelement implementiert. Andernfalls implementiert die IAudioEndpointVolume-Schnittstelle die Volumesteuerung in software.
Wenn ein Gerät über eine Hardwarevolumesteuerung verfügt, wirken sich Änderungen, die über die IAudioEndpointVolume-Schnittstelle am Steuerelement vorgenommen werden, sowohl im freigegebenen als auch im exklusiven Modus auf die Volumeebene aus. Wenn auf einem Gerät keine Hardwarevolume- und Stummschaltungssteuerelemente verfügbar sind, wirken sich änderungen am Softwarevolume und den Stummschaltungssteuerelementen über diese Schnittstelle auf die Volumeebene im freigegebenen Modus aus, jedoch nicht im exklusiven Modus. Im exklusiven Modus tauschen die Anwendung und die Audiohardware Audiodaten direkt aus, wobei die Softwaresteuerelemente umgangen werden.
Im Allgemeinen sollten Anwendungen die Verwendung der IAudioEndpointVolume-Schnittstelle vermeiden, um die Volumeebenen von Datenströmen im freigegebenen Modus zu steuern. Stattdessen sollten Anwendungen für diesen Zweck die ISimpleAudioVolume-, IChannelAudioVolume-oder IAudioStreamVolume-Schnittstelle verwenden.
Wenn eine Anwendung ein Volumesteuerelement anzeigt, das die IAudioEndpointVolume-Schnittstelle verwendet, um die Volumeebene eines Audioendpunktgeräts zu steuern, sollte diese Volumesteuerung die vom Systemvolumesteuerungsprogramm Sndvol angezeigte Endpunktvolumesteuerung spiegeln. Wie bereits erläutert, wird die Endpunktvolumesteuerung auf der linken Seite des Sndvol-Fensters im Gruppenfeld mit der Bezeichnung Gerät angezeigt. Wenn der Benutzer das Endpunktvolume eines Geräts über die Volumesteuerung in Sndvol ändert, sollte die entsprechende Endpunktvolume-Steuerung in der Anwendung mit dem Steuerelement in Sndvol übereinstimmen. Wenn der Benutzer die Volumeebene über die Endpunktvolumesteuerung im Anwendungsfenster ändert, sollte die entsprechende Volumesteuerung in Sndvol entsprechend mit der Volumesteuerung der Anwendung übereinstimmen.
Um sicherzustellen, dass die Endpunktvolumesteuerung in einem Anwendungsfenster die Endpunktvolumesteuerung in Sndvol spiegelt, sollte die Anwendung eine IAudioEndpointVolumeCallback-Schnittstelle implementieren und diese Schnittstelle registrieren, um Benachrichtigungen zu empfangen. Danach empfängt die Anwendung jedes Mal, wenn der Benutzer die Endpunktvolumeebene in Sndvol ändert, einen Benachrichtigungsaufruf über ihre IAudioEndpointVolumeCallback::OnNotify-Methode. Während dieses Aufrufs kann die OnNotify-Methode das Endpunktvolumesteuerelement im Anwendungsfenster entsprechend der in Sndvol angezeigten Steuerelementeinstellung aktualisieren. Ebenso erhält Sndvol jedes Mal, wenn der Benutzer die Endpunktvolumeebene über die Volumesteuerung im Anwendungsfenster ändert, eine Benachrichtigung und aktualisiert sofort die Endpunktvolumesteuerung, um die neue Volumeebene anzuzeigen.
Das folgende Codebeispiel ist eine Headerdatei, die eine mögliche Implementierung der IAudioEndpointVolumeCallback-Schnittstelle zeigt:
// 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:
- IAudioEndpointVolume::SetChannelVolumeLevel
- IAudioEndpointVolume::SetChannelVolumeLevelScalar
- IAudioEndpointVolume::SetMasterVolumeLevel
- IAudioEndpointVolume::SetMasterVolumeLevelScalar
- IAudioEndpointVolume::SetMute
- IAudioEndpointVolume::VolumeStepDown
- IAudioEndpointVolume::VolumeStepUp
Die Implementierung der OnNotify-Methode im vorherigen Codebeispiel sendet Nachrichten an das Volumesteuerelement im Anwendungsfenster, um die angezeigte Volumeebene zu aktualisieren.
Eine Anwendung ruft die IAudioEndpointVolume::RegisterControlChangeNotify-Methode auf, um ihre IAudioEndpointVolumeCallback-Schnittstelle für den Empfang 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 Methoden RegisterControlChangeNotify und UnregisterControlChangeNotify aufruft, um die CAudioEndpointVolumeCallback-Klasse im vorherigen Codebeispiel zu registrieren und deren Registrierung zu aufheben:
// 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 vorherigen 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 Standardrenderinggeräts abzurufen. WinMain ruft die IMMDevice::Activate-Methode auf, um die IAudioEndpointVolume-Schnittstelle des Geräts abzurufen, und ruft RegisterControlChangeNotify auf, um die Anwendung zum Empfangen von Benachrichtigungen über Änderungen des Endpunktvolumes zu registrieren. Als Nächstes öffnet WinMain ein Dialogfeld, in dem eine Endpunktvolumesteuerung für das Gerät angezeigt wird. Das Dialogfeld zeigt auch ein Kontrollkästchen an, das angibt, ob das Gerät stummgeschaltet ist. Das Kontrollkästchen "Endpunktvolumesteuerung und -stummschalten" im Dialogfeld spiegelt die Einstellungen des von Sndvol angezeigten Kontrollkästchens für Die Endpunktvolumesteuerung und das Stummschalten wider. Weitere Informationen zu WinMain und CoCreateInstance finden Sie in der Windows SDK-Dokumentation. Weitere Informationen zu IMMDeviceEnumerator und IMMDevice finden Sie unter Auflisten von Audiogeräten.
Die Dialogfeldprozedur DlgProc im vorherigen Codebeispiel verarbeitet die Änderungen, die der Benutzer am Volume vornimmt, und stummschaltt einstellungen über die Steuerelemente im Dialogfeld. Wenn DlgProc SetMasterVolumeLevelScalar oder SetMuteaufruft, empfängt Sndvol eine Benachrichtigung über die Änderung und aktualisiert das entsprechende Steuerelement in seinem Fenster, um die neue Volume- oder Mute-Einstellung widerzuspiegeln. Wenn der Benutzer anstelle des Dialogfelds das Volume aktualisiert und die Einstellungen über die Steuerelemente im Sndvol-Fenster stummschaltt, aktualisiert die OnNotify-Methode in der CAudioEndpointVolumeCallback-Klasse die Steuerelemente im Dialogfeld, um die neuen Einstellungen anzuzeigen.
Wenn der Benutzer das Volume über die Steuerelemente im Dialogfeld ändert, sendet die OnNotify-Methode in der CAudioEndpointVolumeCallback-Klasse keine Nachrichten, um die Steuerelemente im Dialogfeld zu aktualisieren. Dies wäre redundant. OnNotify aktualisiert die Steuerelemente im Dialogfeld nur, wenn die Volumeänderung aus Sndvol oder einer anderen Anwendung stammt. Der zweite Parameter in den Methodenaufrufen SetMasterVolumeLevelScalar und SetMute in der DlgProc-Funktion ist ein Zeiger auf eine Ereigniskontext-GUID, die eine der Methoden an OnNotify übergibt. 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 problemlos ändern, um Lautstärke- und Stummschaltsteuerelemente für das Standarderfassungsgerät anzuzeigen. Ändern Sie in der WinMain-Funktion den Wert des ersten Parameters im Aufruf der IMMDeviceEnumerator::GetDefaultAudioEndpoint-Methode von eRender in eCapture.
Das folgende Codebeispiel ist das Ressourcenskript, das das Volume und die 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 Ressourcenheaderdatei, 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 bilden eine einfache Anwendung zum Steuern und Überwachen des Endpunktvolumes des Standardrenderinggeräts. Eine nützlichere Anwendung kann den Benutzer zusätzlich benachrichtigen, wenn sich der Status des Geräts ändert. Beispielsweise kann das Gerät deaktiviert, entfernt oder entfernt werden. Weitere Informationen zum Überwachen dieser Ereignistypen finden Sie unter Geräteereignisse.