Besturingselementen voor eindpuntvolumes
De ISimpleAudioVolume, IChannelAudioVolumeen IAudioStreamVolume interfaces stellen clients in staat om de volumeniveaus van audiosessies te beheren, die verzamelingen van audiostreams in de gedeelde modus zijn. Deze interfaces werken niet met audiostreams in de exclusieve modus.
Toepassingen die exclusieve-modusstreams beheren, kunnen de volumeniveaus van die streams beheren via de interface IAudioEndpointVolume. Deze interface bepaalt het volumeniveau van het audio-eindpuntapparaat. Het gebruikt de hardwarevolumeregeling voor het eindpuntapparaat als de audiohardware een dergelijk besturingselement implementeert. Anders implementeert de IAudioEndpointVolume-interface het volumebeheer in software.
Als een apparaat een hardwarevolumeregeling heeft, zijn wijzigingen in het besturingselement via de IAudioEndpointVolume interface van invloed op het volumeniveau, zowel in de gedeelde modus als in de exclusieve modus. Als een apparaat geen hardwarevolume heeft en besturingselementen voor dempen, zijn wijzigingen aangebracht in het softwarevolume en dempen via deze interface van invloed op het volumeniveau in de gedeelde modus, maar niet in de exclusieve modus. In de exclusieve modus wisselen de toepassing en de audiohardware audiogegevens rechtstreeks uit, waarbij de softwarebesturingselementen worden overgeslagen.
Als algemene regel moeten toepassingen het gebruik van de IAudioEndpointVolume-interface vermijden om de volumeniveaus van gedeelde-modusstreams te beheren. In plaats daarvan moeten toepassingen de ISimpleAudioVolume, IChannelAudioVolumeof interface IAudioStreamVolume gebruiken voor dat doel.
Als een toepassing een volumebesturingselement weergeeft dat gebruikmaakt van de IAudioEndpointVolume interface om het volumeniveau van een audio-eindpuntapparaat te regelen, moet dat volumebesturingselement het eindpuntvolumebesturingselement spiegelen dat wordt weergegeven door het systeemvolumebesturingsprogramma, Sndvol. Zoals eerder uitgelegd, wordt het eindpuntvolume aan de linkerkant van het Sndvol-venster weergegeven in het groepsvak met het label Device. Als de gebruiker het eindpuntvolume van een apparaat wijzigt via de volumeregeling in Sndvol, moet de bijbehorende eindpuntvolumeregeling in de toepassing in één richting worden verplaatst met het besturingselement in Sndvol. Als de gebruiker het volumeniveau wijzigt via het eindpuntvolumebesturingselement in het toepassingsvenster, moet de bijbehorende volumeregeling in Sndvol zich in één richting verplaatsen met de volumeregeling van de toepassing.
De toepassing moet een IAudioEndpointVolumeCallback-interface implementeren en die interface registreren om meldingen te ontvangen om ervoor te zorgen dat het eindpuntvolume in een toepassingsvenster overeenkomt met het volumebeheer van het eindpunt in Sndvol. Telkens wanneer de gebruiker het volumeniveau van het eindpunt wijzigt in Sndvol, ontvangt de toepassing vervolgens een meldingsaanroep via de methode IAudioEndpointVolumeCallback::OnNotify. Tijdens deze aanroep kan de methode OnNotify het eindpuntvolume in het toepassingsvenster bijwerken zodat deze overeenkomt met de besturingsinstelling die wordt weergegeven in Sndvol. Elke keer dat de gebruiker het volumeniveau van het eindpunt wijzigt via volumeregeling in het toepassingsvenster, ontvangt Sndvol een melding en wordt de volumeregeling van het eindpunt onmiddellijk bijgewerkt om het nieuwe volumeniveau weer te geven.
Het volgende codevoorbeeld is een headerbestand met een mogelijke implementatie van de 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;
}
};
De klasse CAudioEndpointVolumeCallback in het voorgaande codevoorbeeld is een implementatie van de interface IAudioEndpointVolumeCallback. Omdat IAudioEndpointVolumeCallback overgenomen van IUnknown-, bevat de klassedefinitie implementaties van de IUnknown methoden AddRef, Releaseen QueryInterface. De methode OnNotify in de klassedefinitie wordt aangeroepen telkens wanneer een van de volgende methoden het volumeniveau van het eindpunt wijzigt:
- IAudioEndpointVolume::SetChannelVolumeLevel
- IAudioEndpointVolume::SetChannelVolumeLevelScalar
- IAudioEndpointVolume::SetMasterVolumeLevel
- IAudioEndpointVolume::SetMasterVolumeLevelScalar
- IAudioEndpointVolume::SetMute-
- IAudioEndpointVolume::VolumeStepDown-
- IAudioEndpointVolume::VolumeStepUp-
De implementatie van de methode OnNotify in het voorgaande codevoorbeeld verzendt berichten naar het volumebeheer in het toepassingsvenster om het weergegeven volumeniveau bij te werken.
Een toepassing roept de methode IAudioEndpointVolume::RegisterControlChangeNotify methode aan om de IAudioEndpointVolumeCallback-interface te registreren om meldingen te ontvangen. Wanneer de toepassing geen meldingen meer nodig heeft, wordt de methode IAudioEndpointVolume::UnregisterControlChangeNotify methode aangeroepen om de registratie te verwijderen.
Het volgende codevoorbeeld is een Windows-toepassing die de methoden RegisterControlChangeNotify en UnregisterControlChangeNotify methoden aanroept om de CAudioEndpointVolumeCallback-klasse te registreren en de registratie ervan ongedaan te maken in het voorgaande codevoorbeeld:
// 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;
}
In het voorgaande codevoorbeeld, de functie WinMain roept de functie CoCreateInstance aan om een exemplaar van de IMMDeviceEnumerator interface te maken en roept de IMMDeviceEnumerator::GetDefaultAudioEndpoint methode aan om de IMMDevice-interface van het standaardweergaveapparaat te verkrijgen. WinMain roept de IMMDevice::Activate methode aan om de IAudioEndpointVolume-interface van het apparaat te verkrijgen en roept deze RegisterControlChangeNotify- aan om de toepassing te registreren voor het ontvangen van meldingen van wijzigingen in eindpuntvolumes. Vervolgens opent WinMain een dialoogvenster om een eindpuntvolumeregeling voor het apparaat weer te geven. In het dialoogvenster wordt ook een selectievakje weergegeven dat aangeeft of het apparaat is gedempt. Het eindpuntvolumebesturingselement en het dempen selectievakje in het dialoogvenster spiegelen de instellingen van het eindpuntvolumebesturingselement en het dempen selectievakje weergegeven door Sndvol. Zie de Windows SDK-documentatie voor meer informatie over WinMain en CoCreateInstance. Zie voor meer informatie over IMMDeviceEnumerator en IMMDeviceAudioapparaten inventariseren.
De procedure van het dialoogvenster, DlgProc, in het voorgaande codevoorbeeld, verwerkt de wijzigingen die de gebruiker aanbrengt in het volume en dempt instellingen via de besturingselementen in het dialoogvenster. Wanneer DlgProc SetMasterVolumeLevelScalar of SetMuteaanroept, ontvangt Sndvol een melding van de wijziging en werkt het bijbehorende besturingselement in het venster bij om het nieuwe volume of dempingsinstelling weer te geven. Als de gebruiker in plaats van het dialoogvenster het volume bijwerken en instellingen dempt via de besturingselementen in het Sndvol-venster, werkt de methode OnNotify in de CAudioEndpointVolumeCallback-klasse de besturingselementen in het dialoogvenster bij om de nieuwe instellingen weer te geven.
Als de gebruiker het volume wijzigt via de besturingselementen in het dialoogvenster, verzendt de methode OnNotify in de klasse CAudioEndpointVolumeCallback geen berichten om de besturingselementen in het dialoogvenster bij te werken. Om dit te doen, zou dit redundant zijn. OnNotify werkt de besturingselementen alleen bij in het dialoogvenster als de volumewijziging afkomstig is van Sndvol of in een andere toepassing. De tweede parameter in de SetMasterVolumeLevelScalar en SetMute methodeaanroepen in de functie DlgProc is een aanwijzer naar een gebeurteniscontext-GUID die door beide methoden wordt doorgegeven aan OnNotify-. OnNotify controleert de waarde van de gebeurteniscontext-GUID om te bepalen of het dialoogvenster de bron is van de volumewijziging. Zie IAudioEndpointVolumeCallback::OnNotifyvoor meer informatie over GUID's voor gebeurteniscontext.
Wanneer de gebruiker het dialoogvenster afsluit, verwijdert de UnregisterControlChangeNotify aanroep in het voorgaande codevoorbeeld de registratie van de klasse CAudioEndpointVolumeCallback voordat het programma wordt beëindigd.
U kunt eenvoudig het voorgaande codevoorbeeld wijzigen om volume- en dempingsbesturingselementen weer te geven voor het standaardopnameapparaat. Wijzig in de functie WinMain de waarde van de eerste parameter in de aanroep naar de IMMDeviceEnumerator::GetDefaultAudioEndpoint methode van eRender in eCapture.
Het volgende codevoorbeeld is het resourcescript dat het volume definieert en besturingselementen dempt die worden weergegeven in het voorgaande codevoorbeeld:
// 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
Het volgende codevoorbeeld is het resourceheaderbestand dat de besturings-id's definieert die worden weergegeven in de voorgaande codevoorbeelden:
// 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
De voorgaande codevoorbeelden combineren om een eenvoudige toepassing te vormen voor het beheren en bewaken van het eindpuntvolume van het standaardrenderingsapparaat. Een nuttigere toepassing kan de gebruiker ook op de hoogte stellen wanneer de status van het apparaat wordt gewijzigd. Het apparaat kan bijvoorbeeld worden uitgeschakeld, losgekoppeld of verwijderd. Zie Device Eventsvoor meer informatie over het bewaken van deze typen gebeurtenissen.
Verwante onderwerpen