Ljudhändelser för äldre ljudprogram
Äldre ljud-API:er som DirectSound, DirectShow och funktionerna waveOutXxx gör det möjligt för program att hämta och ange volymnivåerna för ljudströmmar. Program kan använda volymkontrollfunktionerna i dessa API:er för att visa volymreglage i sina programfönster.
I Windows Vista gör systemets volymkontrollprogram, Sndvol, att användarna kan styra ljudvolymnivåerna för enskilda program. De volymreglage som visas av program ska länkas till motsvarande volymreglage i Sndvol. Om en användare justerar programvolymen via ett volymreglage i ett programfönster flyttas motsvarande volymreglage i Sndvol omedelbart för att indikera den nya volymnivån. Om användaren däremot justerar programvolymen via Sndvol bör volymreglagen i programfönstret flyttas för att indikera den nya volymnivån.
I Windows Vista återspeglar Sndvol omedelbart volymändringar som ett program gör via anrop till IDirectSoundBuffer::SetVolume-metoden eller waveOutSetVolume-funktionen. Ett äldre ljud-API som DirectSound eller waveOutXxx-funktioner ger dock inget sätt att meddela ett program när användaren ändrar programvolymen via Sndvol. Om ett program visar ett volymreglage men inte tar emot meddelanden om volymändringar kan skjutreglaget inte återspegla ändringar som gjorts av användaren i Sndvol. För att implementera rätt beteende måste programdesignern på något sätt kompensera för bristen på meddelanden från det äldre ljud-API:et.
En lösning kan vara att programmet ställer in en timer för att regelbundet påminna den om att kontrollera volymnivån för att se om den har ändrats.
En mer elegant lösning är att programmet använder funktionerna för händelsemeddelanden i kärnljud-API:erna. I synnerhet kan programmet registrera ett IAudioSessionEvents- gränssnitt för att ta emot återanrop när volymändringar eller andra typer av ljudhändelser inträffar. När volymen ändras kan återanropsrutinen för volymändring omedelbart uppdatera programmets volymreglage för att återspegla ändringen.
Följande kodexempel visar hur ett program kan registrera sig för att ta emot meddelanden om volymändringar och andra ljudhändelser:
//-----------------------------------------------------------
// 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)
};
I föregående kodexempel implementeras en klass med namnet AudioVolumeEvents. Under programinitieringen aktiverar ljudprogrammet ljudhändelsemeddelanden genom att skapa ett AudioVolumeEvents-objekt. Konstruktorn för den här klassen tar tre indataparametrar:
- flöde– dataflödesriktningen för ljudslutpunktsenhet (ett EDataFlow- uppräkningsvärde).
- roll– den aktuella enhetsrollen för slutpunktsenheten (ett ERole- uppräkningsvärde).
- pAudioEvents– pekare mot ett objekt (en IAudioSessionEvents gränssnittsinstans) som innehåller en uppsättning återanropsrutiner som implementeras av programmet.
Konstruktorn tillhandahåller flödes- och rollvärdena som indataparametrar till metoden IMMDeviceEnumerator::GetDefaultAudioEndpoint. Metoden skapar ett IMMDevice- objekt som kapslar in ljudslutpunktsenheten med den angivna dataflödesriktningen och enhetsrollen.
Programmet implementerar objektet som pekas på av pAudioEvents. (Implementeringen visas inte i föregående kodexempel. Ett kodexempel som implementerar ett IAudioSessionEvents--gränssnitt finns i Ljudsessionshändelser.) Varje metod i det här gränssnittet tar emot meddelanden om en viss typ av ljudhändelse. Om programmet inte är intresserat av en viss händelsetyp bör metoden för den händelsetypen inte göra något annat än att returnera S_OK.
Metoden IAudioSessionEvents::OnSimpleVolumeChanged tar emot meddelanden om volymändringar. Den här metoden uppdaterar vanligtvis programmets volymreglage.
I föregående kodexempel registrerar konstruktorn för klassen AudioVolumeEvents för meddelanden på den processspecifika ljudsession som identifieras av sessions-GUID-värdet GUID_NULL. Som standard tilldelar äldre ljud-API:er som DirectSound, DirectShow och funktionerna waveOutXxx sina strömmar till den här sessionen. Ett DirectSound- eller DirectShow-program kan dock som ett alternativ åsidosätta standardbeteendet och tilldela dess strömmar till en korsprocesssession eller till en session som identifieras av ett annat GUID-värde än GUID_NULL. (Ingen mekanism tillhandahålls för närvarande för ett waveOutXxx- program för att åsidosätta standardbeteendet på ett liknande sätt.) Ett kodexempel på ett DirectShow-program med det här beteendet finns i Enhetsroller för DirectShow-program. För att hantera ett sådant program kan du ändra konstruktorn i föregående kodexempel för att acceptera ytterligare två indataparametrar– ett sessions-GUID och en flagga för att ange om sessionen som ska övervakas är en korsprocess eller processspecifik session. Skicka dessa parametrar till anropet till metoden IAudioSessionManager::GetAudioSessionControl i konstruktorn.
När konstruktorn anropar IAudioSessionControl::RegisterAudioSessionNotification metod för att registrera sig för meddelanden, fortsätter programmet att ta emot meddelanden endast så länge antingen IAudioSessionControl eller IAudioSessionManager gränssnitt finns. Objektet AudioVolumeEvents i föregående kodexempel innehåller referenser till dessa gränssnitt tills dess destruktor anropas. Det här beteendet säkerställer att programmet fortsätter att ta emot meddelanden under livslängden för AudioVolumeEvents-objektet.
I stället för att implicit välja en ljudenhet baserat på dess enhetsroll kan ett DirectSound- eller äldre Multimedieprogram i Windows göra det möjligt för användaren att uttryckligen välja en enhet från en lista över tillgängliga enheter som identifieras med sina egna namn. För att stödja det här beteendet måste föregående kodexempel ändras för att generera ljudhändelsemeddelanden för den valda enheten. Två ändringar krävs. Ändra först konstruktorns definition så att den accepterar en slutpunkts-ID-sträng som en indataparameter (i stället för flödes- och rollparametrarna i kodexemplet). Den här strängen identifierar den ljudslutpunktsenhet som motsvarar den valda DirectSound- eller äldre vågformsenheten. För det andra ersätter du anropet till metoden IMMDeviceEnumerator::GetDefaultAudioEndpoint med ett anrop till metoden IMMDeviceEnumerator::GetDevice. Anropet GetDevice tar slutpunkts-ID-strängen som indataparameter och skapar en instans av slutpunktsenheten som identifieras av strängen.
Metoden för att hämta slutpunkts-ID-strängen för en DirectSound-enhet eller äldre vågformsenhet är följande.
Under enhetsuppräkning tillhandahåller DirectSound först slutpunkts-ID-strängen för varje uppräknad enhet. För att påbörja enhetsuppräkning skickar programmet en motringningsfunktionspekare som indataparameter till funktionen DirectSoundCreate eller DirectSoundCaptureCreate. Definitionen av återanropsfunktionen är:
BOOL DSEnumCallback(
LPGUID lpGuid,
LPCSTR lpcstrDescription,
LPCSTR lpcstrModule,
LPVOID lpContext
);
I Windows Vista pekar parametern lpcstrModule på slutpunkts-ID-strängen. (I tidigare versioner av Windows, inklusive Windows Server 2003, Windows XP och Windows 2000, pekar parametern lpcstrModule på namnet på drivrutinsmodulen för enheten.) Parametern lpcstrDescription pekar på en sträng som innehåller enhetens eget namn. Mer information om DirectSound-enhetsuppräkning finns i Windows SDK-dokumentationen.
För att hämta slutpunkts-ID-strängen för en äldre vågformsenhet använder du funktionen waveOutMessage eller waveInMessage för att skicka ett DRV_QUERYFUNCTIONINSTANCEID meddelande till drivrutinen för waveform-enheten. Ett kodexempel som visar användningen av det här meddelandet finns i Enhetsroller för äldre Windows Multimedia-program.
Relaterade ämnen