Zdarzenia audio dla starszych aplikacji audio
Starsze interfejsy API audio, takie jak DirectSound, DirectShow i funkcje waveOutXxx umożliwiają aplikacjom uzyskiwanie i ustawianie poziomów głośności strumieni audio. Aplikacje mogą używać funkcji sterowania woluminami w tych interfejsach API do wyświetlania suwaków głośności w oknach aplikacji.
W systemie Windows Vista systemowy program sterowania woluminami, Sndvol, umożliwia użytkownikom kontrolowanie poziomów głośności audio dla poszczególnych aplikacji. Suwaki głośności wyświetlane przez aplikacje powinny być połączone z odpowiednimi suwakami głośności w narzędziu Sndvol. Jeśli użytkownik dostosuje wolumin aplikacji za pomocą suwaka głośności w oknie aplikacji, wówczas odpowiedni suwak głośności w Sndvol natychmiast zostanie przeniesiony, aby wskazać nowy poziom woluminu. Z drugiej strony, jeśli użytkownik dostosuje wolumin aplikacji za pomocą Sndvol, suwaki głośności w oknie aplikacji powinny zostać przeniesione, aby wskazać nowy poziom woluminu.
W systemie Windows Vista funkcja Sndvol natychmiast odzwierciedla zmiany woluminu, które aplikacja wykonuje za pośrednictwem wywołań funkcji IDirectSoundBuffer::SetVolume lub waveOutSetVolume funkcji. Jednak starsze interfejsy API audio, takie jak DirectSound lub waveOutXxx, nie zapewniają możliwości powiadamiania aplikacji, gdy użytkownik zmienia wolumin aplikacji za pośrednictwem Sndvol. Jeśli aplikacja wyświetla suwak głośności, ale nie otrzymuje powiadomień o zmianach woluminu, suwak nie będzie odzwierciedlać zmian wprowadzonych przez użytkownika w aplikacji Sndvol. Aby zaimplementować odpowiednie zachowanie, projektant aplikacji musi w jakiś sposób zrekompensować brak powiadomień przez starszy interfejs API audio.
Jednym z rozwiązań może być ustawienie czasomierza, aby okresowo przypominać o tym, aby sprawdzić poziom woluminu, aby sprawdzić, czy uległ zmianie.
Bardziej eleganckim rozwiązaniem jest użycie przez aplikację funkcji powiadamiania o zdarzeniach podstawowych interfejsów API audio. W szczególności aplikacja może zarejestrować interfejs IAudioSessionEvents w celu odbierania wywołań zwrotnych w przypadku wystąpienia zmian głośności lub innych typów zdarzeń dźwiękowych. Gdy wolumin się zmieni, rutyna wywołania zwrotnego zmiany woluminu może natychmiast zaktualizować suwak głośności aplikacji, aby odzwierciedlić zmianę.
Poniższy przykład kodu pokazuje, jak aplikacja może zarejestrować się w celu odbierania powiadomień o zmianach woluminu i innych zdarzeniach dźwiękowych:
//-----------------------------------------------------------
// Register the application to receive notifications when the
// volume level changes on the default process-specific audio
// session (with session GUID value GUID_NULL) on the audio
// endpoint device with the specified data-flow direction
// (eRender or eCapture) and device role.
//-----------------------------------------------------------
#define EXIT_ON_ERROR(hr) \
if (FAILED(hr)) { goto Exit; }
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) \
{ (punk)->Release(); (punk) = NULL; }
class AudioVolumeEvents
{
HRESULT _hrStatus;
IAudioSessionManager *_pManager;
IAudioSessionControl *_pControl;
IAudioSessionEvents *_pAudioEvents;
public:
AudioVolumeEvents(EDataFlow, ERole, IAudioSessionEvents*);
~AudioVolumeEvents();
HRESULT GetStatus() { return _hrStatus; };
};
// Constructor
AudioVolumeEvents::AudioVolumeEvents(EDataFlow flow, ERole role,
IAudioSessionEvents *pAudioEvents)
{
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
_hrStatus = S_OK;
_pManager = NULL;
_pControl = NULL;
_pAudioEvents = pAudioEvents;
if (_pAudioEvents == NULL)
{
_hrStatus = E_POINTER;
return;
}
_pAudioEvents->AddRef();
// Get the enumerator for the audio endpoint devices
// on this system.
_hrStatus = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(void**)&pEnumerator);
EXIT_ON_ERROR(_hrStatus)
// Get the audio endpoint device with the specified data-flow
// direction (eRender or eCapture) and device role.
_hrStatus = pEnumerator->GetDefaultAudioEndpoint(flow, role,
&pDevice);
EXIT_ON_ERROR(_hrStatus)
// Get the session manager for the endpoint device.
_hrStatus = pDevice->Activate(__uuidof(IAudioSessionManager),
CLSCTX_INPROC_SERVER, NULL,
(void**)&_pManager);
EXIT_ON_ERROR(_hrStatus)
// Get the control interface for the process-specific audio
// session with session GUID = GUID_NULL. This is the session
// that an audio stream for a DirectSound, DirectShow, waveOut,
// or PlaySound application stream belongs to by default.
_hrStatus = _pManager->GetAudioSessionControl(NULL, 0, &_pControl);
EXIT_ON_ERROR(_hrStatus)
_hrStatus = _pControl->RegisterAudioSessionNotification(_pAudioEvents);
EXIT_ON_ERROR(_hrStatus)
Exit:
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pDevice)
}
// Destructor
AudioVolumeEvents::~AudioVolumeEvents()
{
if (_pControl != NULL)
{
_pControl->UnregisterAudioSessionNotification(_pAudioEvents);
}
SAFE_RELEASE(_pManager)
SAFE_RELEASE(_pControl)
SAFE_RELEASE(_pAudioEvents)
};
Powyższy przykład kodu implementuje klasę o nazwie AudioVolumeEvents. Podczas inicjowania programu aplikacja audio umożliwia wysyłanie powiadomień audio zdarzeń przez utworzenie obiektu AudioVolumeEvents. Konstruktor dla tej klasy przyjmuje trzy parametry wejściowe:
- przepływ— kierunek przepływu danych urządzenia punktu końcowego audio (wartość wyliczeniaEDataFlow).
- rola— bieżąca rola urządzenia urządzenia punktu końcowego (wartość wyliczeniaERole).
- pAudioEvents — wskaźnik do obiektu (IAudioSessionEvents wystąpienia interfejsu), który zawiera zestaw procedur wywołania zwrotnego implementowanych przez aplikację.
Konstruktor dostarcza wartości przepływu i roli jako parametry wejściowe do metody IMMDeviceEnumerator::GetDefaultAudioEndpoint. Metoda tworzy obiekt IMMDevice, który hermetyzuje urządzenie punktu końcowego audio z określonym kierunkiem przepływu danych i rolą urządzenia.
Aplikacja implementuje obiekt wskazywany przez pAudioEvents. (Implementacja nie jest pokazana w poprzednim przykładzie kodu. Aby zapoznać się z przykładem kodu, który implementuje interfejs IAudioSessionEvents, zobacz zdarzenia sesji audio). Każda metoda w tym interfejsie odbiera powiadomienia o konkretnym typie zdarzenia audio. Jeśli aplikacja nie jest zainteresowana określonym typem zdarzenia, metoda dla tego typu zdarzenia nie powinna nic robić, ale zwracać S_OK.
Metoda IAudioSessionEvents::OnSimpleVolumeChanged odbiera powiadomienia o zmianach woluminu. Zazwyczaj ta metoda aktualizuje suwak głośności aplikacji.
W poprzednim przykładzie kodu konstruktor klasy AudioVolumeEvents rejestruje powiadomienia na temat sesji audio specyficznej dla procesu sesji audio, która jest identyfikowana przez wartość identyfikatora GUID sesji GUID_NULL. Domyślnie starsze interfejsy API audio, takie jak DirectSound, DirectShow i funkcje waveOutXxx przypisują strumienie do tej sesji. Jednak aplikacja DirectSound lub DirectShow może, jako opcja, zastąpić domyślne zachowanie i przypisać swoje strumienie do sesji między procesami lub do sesji, która jest identyfikowana przez wartość identyfikatora GUID inną niż GUID_NULL. (Obecnie nie podano żadnego mechanizmu dla aplikacji waveOutXxx w celu zastąpienia domyślnego zachowania w podobny sposób). Aby zapoznać się z przykładem kodu aplikacji DirectShow z tym zachowaniem, zobacz Role urządzeń dla aplikacji DirectShow. Aby obsłużyć taką aplikację, można zmodyfikować konstruktor w poprzednim przykładzie kodu tak, aby akceptował dwa dodatkowe parametry wejściowe — identyfikator GUID sesji i flagę wskazującą, czy sesja, która ma być monitorowana, jest sesją specyficzną dla procesu krzyżowego lub specyficznego dla procesu. Przekaż te parametry do wywołania metody IAudioSessionManager::GetAudioSessionControl w konstruktorze.
Po wywołaniu konstruktora IAudioSessionControl::RegisterAudioSessionNotification metody rejestrowania powiadomień aplikacja będzie nadal otrzymywać powiadomienia tylko tak długo, jak istnieje interfejs IAudioSessionControl lub IAudioSessionManager. Obiekt AudioVolumeEvents w poprzednim przykładzie kodu przechowuje odwołania do tych interfejsów do momentu wywołania jego destruktora. To zachowanie gwarantuje, że aplikacja będzie nadal otrzymywać powiadomienia o okresie istnienia obiektu AudioVolumeEvents.
Zamiast niejawnie wybierać urządzenie audio na podstawie jego roli urządzenia, aplikacja multimedialna DirectSound lub starsza wersja systemu Windows może zezwolić użytkownikowi na jawne wybranie urządzenia z listy dostępnych urządzeń, które są identyfikowane przez przyjazne nazwy. Aby obsługiwać to zachowanie, należy zmodyfikować powyższy przykład kodu w celu wygenerowania powiadomień audio-event dla wybranego urządzenia. Wymagane są dwie modyfikacje. Najpierw zmień definicję konstruktora, aby zaakceptować ciąg identyfikatora punktu końcowego jako parametr wejściowy (zamiast parametrów przepływu i roli w przykładzie kodu). Ten ciąg identyfikuje urządzenie punktu końcowego audio odpowiadające wybranemu urządzeniu DirectSound lub starszemu urządzeniu waveform. Następnie zastąp wywołanie metody IMMDeviceEnumerator::GetDefaultAudioEndpoint metodą wywołaniem metody IMMDeviceEnumerator::GetDevice. Wywołanie GetDevice przyjmuje ciąg identyfikatora punktu końcowego jako parametr wejściowy i tworzy wystąpienie urządzenia punktu końcowego identyfikowanego przez ciąg.
Technika uzyskiwania ciągu identyfikatora punktu końcowego dla urządzenia DirectSound lub starszego urządzenia waveform jest następująca.
Najpierw podczas wyliczania urządzenia funkcja DirectSound dostarcza ciąg identyfikatora punktu końcowego dla każdego wyliczonego urządzenia. Aby rozpocząć wyliczanie urządzenia, aplikacja przekazuje wskaźnik funkcji wywołania zwrotnego jako parametr wejściowy do funkcji DirectSoundCreate lub DirectSoundCaptureCreate. Definicja funkcji wywołania zwrotnego to:
BOOL DSEnumCallback(
LPGUID lpGuid,
LPCSTR lpcstrDescription,
LPCSTR lpcstrModule,
LPVOID lpContext
);
W systemie Windows Vista parametr lpcstrModule wskazuje ciąg identyfikatora punktu końcowego. (We wcześniejszych wersjach systemu Windows, w tym Windows Server 2003, Windows XP i Windows 2000, lpcstrModule parametr wskazuje nazwę modułu sterownika dla urządzenia). Parametr lpcstrDescription wskazuje ciąg zawierający przyjazną nazwę urządzenia. Aby uzyskać więcej informacji na temat wyliczania urządzeń DirectSound, zobacz dokumentację zestawu Windows SDK.
Po drugie, aby uzyskać ciąg identyfikatora punktu końcowego dla starszego urządzenia waveform, użyj waveOutMessage lub funkcji waveInMessage, aby wysłać komunikat DRV_QUERYFUNCTIONINSTANCEID do sterownika urządzenia waveform. Aby zapoznać się z przykładem kodu pokazującym użycie tego komunikatu, zobacz Role urządzeń dla starszych aplikacji multimedialnych systemu Windows.
Tematy pokrewne