Kontrolki woluminu punktu końcowego
Interfejsy ISimpleAudioVolume, IChannelAudioVolumei interfejsy IAudioStreamVolum e umożliwiają klientom kontrolowanie poziomów głośności sesji audio , które są kolekcjami strumieni audio trybu udostępnionego. Te interfejsy nie działają z strumieniami audio w trybie wyłącznym.
Aplikacje, które zarządzają strumieniami trybu wyłącznego, mogą kontrolować poziomy głośności tych strumieni za pośrednictwem interfejsu IAudioEndpointVolum e. Ten interfejs steruje poziomem głośności urządzenia punktu końcowego audio . Używa sprzętowego sterowania głośnością dla urządzenia punktu końcowego, jeśli sprzęt audio implementuje taką kontrolę. W przeciwnym razie interfejs IAudioEndpointVolume implementuje sterowanie głośnością w oprogramowaniu.
Jeśli urządzenie ma sprzętową kontrolę głośności, zmiany wprowadzone w kontrolce za pośrednictwem interfejsu IAudioEndpointVolume wpływają na poziom głośności zarówno w trybie udostępnionym, jak i w trybie wyłącznym. Jeśli urządzenie nie ma sprzętowych kontrolek głośności i wyciszenia, zmiany wprowadzone w woluminie oprogramowania i kontrolki wyciszenia za pośrednictwem tego interfejsu wpływają na poziom głośności w trybie udostępnionym, ale nie w trybie wyłącznym. W trybie wyłącznym aplikacja i sprzęt audio wymieniają dane audio bezpośrednio, pomijając kontrolki oprogramowania.
Ogólnie rzecz biorąc, aplikacje powinny unikać korzystania z interfejsu IAudioEndpointVolume w celu kontrolowania poziomów głośności strumieni w trybie udostępnionym. Zamiast tego aplikacje powinny używać interfejsu ISimpleAudioVolume, IChannelAudioVolumelub interfejsu IAudioStreamVolume.
Jeśli aplikacja wyświetla kontrolkę głośności, która używa interfejsu IAudioEndpointVolume do sterowania poziomem głośności urządzenia punktu końcowego audio, ta kontrolka głośności powinna odzwierciedlać sterowanie woluminem punktu końcowego wyświetlane przez systemowy program sterowania woluminami, Sndvol. Jak wyjaśniono wcześniej, kontrolka woluminu punktu końcowego jest wyświetlana po lewej stronie okna Sndvol w polu grupy z etykietą Device. Jeśli użytkownik zmieni wolumin punktu końcowego urządzenia za pośrednictwem kontrolki głośności w usłudze Sndvol, odpowiednia kontrolka woluminu punktu końcowego w aplikacji powinna zostać przeniesiona w zgodzie z kontrolką w usłudze Sndvol. Podobnie, jeśli użytkownik zmieni poziom woluminu za pośrednictwem kontrolki woluminu punktu końcowego w oknie aplikacji, odpowiednia kontrolka woluminu w usłudze Sndvol powinna zostać przeniesiona w zgodzie z kontrolką głośności aplikacji.
Aby upewnić się, że kontrolka woluminu punktu końcowego w oknie aplikacji odzwierciedla kontrolkę woluminu punktu końcowego w usłudze Sndvol, aplikacja powinna zaimplementować IAudioEndpointVolumeCallback interfejs i zarejestrować ten interfejs w celu odbierania powiadomień. Następnie za każdym razem, gdy użytkownik zmienia poziom woluminu punktu końcowego w usłudze Sndvol, aplikacja odbiera wywołanie powiadomienia za pośrednictwem IAudioEndpointVolumeCallback::OnNotify metody. Podczas tego wywołania metoda OnNotify może zaktualizować kontrolkę woluminu punktu końcowego w oknie aplikacji, aby dopasować ustawienie kontrolki wyświetlane w Sndvol. Podobnie za każdym razem, gdy użytkownik zmienia poziom woluminu punktu końcowego za pomocą sterowania woluminem w oknie aplikacji, usługa Sndvol otrzymuje powiadomienie i natychmiast aktualizuje jego kontrolkę woluminu punktu końcowego, aby wyświetlić nowy poziom woluminu.
Poniższy przykład kodu to plik nagłówkowy, który pokazuje możliwą implementację interfejsuIAudioEndpointVolumeCallback:
// 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;
}
};
Klasa CAudioEndpointVolumeCallback w poprzednim przykładzie kodu to implementacja interfejsu IAudioEndpointVolumeCall back. Ponieważ IAudioEndpointVolumeCallback dziedziczy z IUnknown, definicja klasy zawiera implementacje metod IUnknownAddRef, Releasei QueryInterface. Metoda OnNotify w definicji klasy jest wywoływana za każdym razem, gdy jedna z następujących metod zmienia poziom woluminu punktu końcowego:
- IAudioEndpointVolume::SetChannelVolumeLevel
- IAudioEndpointVolume::SetChannelVolumeLevelScalar
- IAudioEndpointVolume::SetMasterVolumeLevel
- IAudioEndpointVolume::SetMasterVolumeLevelScalar
- IAudioEndpointVolume::SetMute
- IAudioEndpointVolume::VolumeStepDown
- IAudioEndpointVolume::VolumeStepUp
Implementacja metody OnNotify w poprzednim przykładzie kodu wysyła komunikaty do kontrolki woluminu w oknie aplikacji w celu zaktualizowania wyświetlanego poziomu woluminu.
Aplikacja wywołuje metodę IAudioEndpointVolume::RegisterControlChangeNotify w celu zarejestrowania interfejsu IAudioEndpointVolumeCallback w celu odbierania powiadomień. Gdy aplikacja nie wymaga już powiadomień, wywołuje metodę IAudioEndpointVolume::UnregisterControlChangeNotify, aby usunąć rejestrację.
Poniższy przykład kodu to aplikacja systemu Windows, która wywołuje RegisterControlChangeNotify i UnregisterControlChangeNotify metod rejestrowania i wyrejestrowania klasy CAudioEndpointVolumeCallback w poprzednim przykładzie kodu:
// 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;
}
W poprzednim przykładzie kodu funkcja WinMain wywołuje funkcję CoCreateInstance, aby utworzyć wystąpienie interfejsu IMMDeviceEnumerator i wywołuje IMMDeviceEnumerator::GetDefaultAudioEndpoint metodę uzyskiwania interfejsu IMMDevice domyślnego urządzenia renderowania. WinMain wywołuje metodę IMMDevice::Activate w celu uzyskania interfejsu IAudioEndpointVolume urządzenia i wywołuje RegisterControlChangeNotify, aby zarejestrować aplikację w celu otrzymywania powiadomień o zmianach woluminu punktu końcowego. Następnie WinMain otwiera okno dialogowe, aby wyświetlić kontrolkę woluminu punktu końcowego dla urządzenia. W oknie dialogowym zostanie również wyświetlone pole wyboru wskazujące, czy urządzenie jest wyciszone. Kontrolka woluminu punktu końcowego i wyciszenie pole wyboru w oknie dialogowym odzwierciedla ustawienia kontrolki woluminu punktu końcowego i wyciszenie pola wyboru wyświetlane przez Sndvol. Aby uzyskać więcej informacji na temat WinMain i CoCreateInstance, zobacz dokumentację zestawu Windows SDK. Aby uzyskać więcej informacji na temat IMMDeviceEnumerator i IMMDevice, zobacz Wyliczanie urządzeń audio.
Procedura okna dialogowego DlgProc w poprzednim przykładzie kodu obsługuje zmiany wprowadzone przez użytkownika do ustawień woluminu i wyciszania za pomocą kontrolek w oknie dialogowym. Gdy dlgProc wywołuje SetMasterVolumeLevelScalar lub SetMute, Sndvol otrzymuje powiadomienie o zmianie i aktualizuje odpowiednią kontrolkę w oknie, aby odzwierciedlić nowe ustawienie woluminu lub wyciszenia. Jeśli zamiast używać okna dialogowego, użytkownik aktualizuje ustawienia woluminu i wyciszenia za pomocą kontrolek w oknie Sndvol, OnNotify metody w klasie CAudioEndpointVolumeCallback aktualizuje kontrolki w oknie dialogowym, aby wyświetlić nowe ustawienia.
Jeśli użytkownik zmieni wolumin za pomocą kontrolek w oknie dialogowym, OnNotify metody w klasie CAudioEndpointVolumeCallback nie wysyła komunikatów w celu zaktualizowania kontrolek w oknie dialogowym. W tym celu byłoby nadmiarowe. OnNotify aktualizuje kontrolki w oknie dialogowym tylko wtedy, gdy zmiana woluminu pochodzi z Sndvol lub w innej aplikacji. Drugi parametr w SetMasterVolumeLevelScalar i wywołania metody SetMute w funkcji DlgProc jest wskaźnikiem do identyfikatora GUID kontekstu zdarzenia, który przekazuje jedną z metod do OnNotify. OnNotify sprawdza wartość identyfikatora GUID kontekstu zdarzenia, aby określić, czy okno dialogowe jest źródłem zmiany woluminu. Aby uzyskać więcej informacji na temat identyfikatorów GUID kontekstu zdarzenia, zobacz IAudioEndpointVolumeCallback::OnNotify.
Gdy użytkownik zakończy okno dialogowe, UnregisterControlChangeNotify wywołanie w poprzednim przykładzie kodu usuwa rejestrację klasy CAudioEndpointVolumeCallback przed zakończeniem programu.
Możesz łatwo zmodyfikować poprzedni przykładowy kod, aby wyświetlić kontrolki woluminu i wyciszenia dla domyślnego urządzenia przechwytywania. W funkcji WinMain zmień wartość pierwszego parametru w wywołaniu metody IMMDeviceEnumerator::GetDefaultAudioEndpoint metody z eRender na eCapture.
Poniższy przykład kodu to skrypt zasobu, który definiuje kontrolki woluminu i wyciszenia, które są wyświetlane w poprzednim przykładzie kodu:
// 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
Poniższy przykład kodu to plik nagłówka zasobu, który definiuje identyfikatory kontrolek, które są wyświetlane w poprzednich przykładach kodu:
// 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
Powyższe przykłady kodu łączą się w celu utworzenia prostej aplikacji do kontrolowania i monitorowania woluminu punktu końcowego domyślnego urządzenia renderowania. Bardziej przydatna aplikacja może dodatkowo powiadomić użytkownika o zmianie stanu urządzenia. Na przykład urządzenie może być wyłączone, odłączone lub usunięte. Aby uzyskać więcej informacji na temat monitorowania tego typu zdarzeń, zobacz Device Events.
Tematy pokrewne