Freigeben über


Audioereignisse für Legacyaudioanwendungen

Ältere Audio-APIs wie DirectSound, DirectShow und die waveOutXxx--Funktionen ermöglichen Anwendungen das Abrufen und Festlegen der Lautstärke von Audiodatenströmen. Anwendungen können die Volumensteuerungsfunktionen in diesen APIs verwenden, um Lautstärkeregler in ihren Anwendungsfenstern anzuzeigen.

In Windows Vista ermöglicht das Systemlautstärkesteuerungsprogramm Sndvol benutzern die Steuerung der Audiolautstärken für einzelne Anwendungen. Die Lautstärkeregler, die von Anwendungen angezeigt werden, sollten mit den entsprechenden Lautstärkereglern in Sndvol verknüpft werden. Wenn ein Benutzer die Anwendungslautstärke über einen Volumeschieberegler in einem Anwendungsfenster anpasst, wird der entsprechende Lautstärkeregler in Sndvol sofort verschoben, um die neue Lautstärkeebene anzugeben. Wenn der Benutzer die Anwendungslautstärke hingegen über Sndvol anpasst, sollten die Lautstärkeregler im Anwendungsfenster verschoben werden, um die neue Lautstärkeebene anzugeben.

In Windows Vista spiegelt Sndvol sofort Volumeänderungen wider, die eine Anwendung über Aufrufe an die IDirectSoundBuffer::SetVolume--Methode oder waveOutSetVolume--Funktion erfolgt. Eine ältere Audio-API wie DirectSound oder die waveOutXxx- Funktionen bieten jedoch keine Möglichkeit, eine Anwendung zu benachrichtigen, wenn der Benutzer das Anwendungsvol ändert. Wenn eine Anwendung einen Volumeschieberegler anzeigt, aber keine Benachrichtigungen über Volumeänderungen empfängt, schlägt der Schieberegler die vom Benutzer in Sndvol vorgenommenen Änderungen nicht wider. Um das entsprechende Verhalten zu implementieren, muss der Anwendungsdesigner irgendwie das Fehlen von Benachrichtigungen durch die legacy-Audio-API ausgleichen.

Eine Lösung kann für die Anwendung sein, um einen Timer festzulegen, um ihn regelmäßig daran zu erinnern, die Lautstärke zu überprüfen, um festzustellen, ob sie geändert wurde.

Eine elegantere Lösung ist die Verwendung der Ereignisbenachrichtigungsfunktionen der wichtigsten Audio-APIs für die Anwendung. Insbesondere kann die Anwendung ein IAudioSessionEvents- Schnittstelle registrieren, um Rückrufe zu empfangen, wenn Lautstärkeänderungen oder andere Arten von Audioereignissen auftreten. Wenn sich das Volume ändert, kann die Rückrufroutine für die Volumeänderung sofort den Lautstärkeregler der Anwendung aktualisieren, um die Änderung widerzuspiegeln.

Das folgende Codebeispiel zeigt, wie eine Anwendung registrieren kann, um Benachrichtigungen über Volumeänderungen und andere Audioereignisse zu erhalten:

//-----------------------------------------------------------
// 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)
};

Im vorherigen Codebeispiel wird eine Klasse namens "AudioVolumeEvents" implementiert. Während der Programminitialisierung ermöglicht die Audioanwendung Audioereignisbenachrichtigungen durch Erstellen eines AudioVolumeEvents-Objekts. Der Konstruktor für diese Klasse akzeptiert drei Eingabeparameter:

  • Fluss– die Datenflussrichtung des Audioendpunktgeräts (ein EDataFlow Enumerationswert).
  • Rolle– die aktuelle Geräterolle des Endpunktgeräts (ein ERole Enumerationswert).
  • pAudioEvents-– Zeiger auf ein Objekt (eine IAudioSessionEvents Schnittstelleninstanz), die eine Reihe von Rückrufroutinen enthält, die von der Anwendung implementiert werden.

Der Konstruktor stellt die Fluss- und Rollenwerte als Eingabeparameter für die IMMDeviceEnumerator::GetDefaultAudioEndpoint-Methode bereit. Die Methode erstellt ein IMMDevice--Objekt, das das Audioendpunktgerät mit der angegebenen Datenflussrichtung und Geräterolle kapselt.

Die Anwendung implementiert das Objekt, auf das von pAudioEventsverwiesen wird. (Die Implementierung wird im vorherigen Codebeispiel nicht angezeigt. Ein Codebeispiel, das eine IAudioSessionEvents- Schnittstelle implementiert, finden Sie unter Audiositzungsereignisse.) Jede Methode in dieser Schnittstelle empfängt Benachrichtigungen über einen bestimmten Audioereignistyp. Wenn die Anwendung nicht an einem bestimmten Ereignistyp interessiert ist, sollte die Methode für diesen Ereignistyp nichts tun, sondern S_OK zurückgeben.

Die IAudioSessionEvents::OnSimpleVolumeChanged Methode empfängt Benachrichtigungen über Volumeänderungen. In der Regel aktualisiert diese Methode den Lautstärkeregler der Anwendung.

Im vorherigen Codebeispiel registriert der Konstruktor für die AudioVolumeEvents-Klasse Benachrichtigungen für die prozessspezifische Audiositzung, die durch den Sitzungs-GUID-Wert GUID_NULL identifiziert wird. Standardmäßig weisen ältere Audio-APIs wie DirectSound, DirectShow und die waveOutXxx--Funktionen dieser Sitzung ihre Datenströme zu. Eine DirectSound- oder DirectShow-Anwendung kann jedoch als Option das Standardverhalten außer Kraft setzen und die Datenströme einer prozessübergreifenden Sitzung oder einer Sitzung zuweisen, die durch einen anderen GUID-Wert als GUID_NULL identifiziert wird. (Es wird derzeit kein Mechanismus für eine waveOutXxx- Anwendung bereitgestellt, um das Standardverhalten auf ähnliche Weise außer Kraft zu setzen.) Ein Codebeispiel für eine DirectShow-Anwendung mit diesem Verhalten finden Sie unter Geräterollen für DirectShow-Anwendungen. Um eine solche Anwendung aufzunehmen, können Sie den Konstruktor im vorherigen Codebeispiel so ändern, dass zwei zusätzliche Eingabeparameter akzeptiert werden: eine Sitzungs-GUID und ein Flag, um anzugeben, ob es sich bei der zu überwachenden Sitzung um eine prozessübergreifende oder prozessspezifische Sitzung handelt. Übergeben Sie diese Parameter an den Aufruf der IAudioSessionManager::GetAudioSessionControl--Methode im Konstruktor.

Nachdem der Konstruktor die IAudioSessionControl::RegisterAudioSessionNotification Methode zum Registrieren für Benachrichtigungen aufruft, empfängt die Anwendung weiterhin nur Benachrichtigungen, solange entweder die IAudioSessionControl oder IAudioSessionManager Schnittstelle vorhanden ist. Das AudioVolumeEvents-Objekt im vorherigen Codebeispiel enthält Verweise auf diese Schnittstellen, bis der Destruktor aufgerufen wird. Dieses Verhalten stellt sicher, dass die Anwendung weiterhin Benachrichtigungen für die Lebensdauer des AudioVolumeEvents-Objekts empfängt.

Anstatt implizit ein Audiogerät basierend auf seiner Geräterolle auszuwählen, kann eine DirectSound- oder ältere Windows-Multimediaanwendung dem Benutzer erlauben, ein Gerät explizit aus einer Liste der verfügbaren Geräte auszuwählen, die durch ihre Anzeigenamen identifiziert werden. Um dieses Verhalten zu unterstützen, muss das vorherige Codebeispiel geändert werden, um Audioereignisbenachrichtigungen für das ausgewählte Gerät zu generieren. Es sind zwei Änderungen erforderlich. Ändern Sie zunächst die Konstruktordefinition so, dass eine Endpunkt-ID-Zeichenfolge als Eingabeparameter akzeptiert wird (anstelle des Fluss- und Rollenparameters im Codebeispiel). Diese Zeichenfolge identifiziert das Audioendpunktgerät, das dem ausgewählten DirectSound- oder legacy Waveform-Gerät entspricht. Ersetzen Sie zweitens den Aufruf der IMMDeviceEnumerator::GetDefaultAudioEndpoint-Methode durch einen Aufruf der IMMDeviceEnumerator::GetDevice-Methode. Der GetDevice Aufruf verwendet die Endpunkt-ID-Zeichenfolge als Eingabeparameter und erstellt eine Instanz des Endpunktgeräts, das durch die Zeichenfolge identifiziert wird.

Die Methode zum Abrufen der Endpunkt-ID-Zeichenfolge für ein DirectSound-Gerät oder ein älteres Waveform-Gerät lautet wie folgt.

Zuerst stellt DirectSound während der Geräteaufzählung die Endpunkt-ID-Zeichenfolge für jedes aufgezählte Gerät bereit. Um mit der Geräteenumeration zu beginnen, übergibt die Anwendung einen Rückruffunktionspunkt als Eingabeparameter an die DirectSoundCreate oder DirectSoundCaptureCreate-Funktion. Die Definition der Rückruffunktion lautet:

BOOL DSEnumCallback(
  LPGUID  lpGuid,
  LPCSTR  lpcstrDescription,
  LPCSTR  lpcstrModule,
  LPVOID  lpContext
);

In Windows Vista verweist der lpcstrModule Parameter auf die Endpunkt-ID-Zeichenfolge. (In früheren Versionen von Windows, einschließlich Windows Server 2003, Windows XP und Windows 2000, verweist der lpcstrModule Parameter auf den Namen des Treibermoduls für das Gerät.) Der lpcstrDescription Parameter verweist auf eine Zeichenfolge, die den Anzeigenamen des Geräts enthält. Weitere Informationen zur DirectSound-Geräteenumeration finden Sie in der Windows SDK-Dokumentation.

Verwenden Sie zum Abrufen der Endpunkt-ID-Zeichenfolge für ein älteres Waveform-Gerät die waveOutMessage- oder waveInMessage--Funktion, um eine DRV_QUERYFUNCTIONINSTANCEID Nachricht an den Waveform-Gerätetreiber zu senden. Ein Codebeispiel, das die Verwendung dieser Meldung zeigt, finden Sie unter Geräterollen für Ältere Windows Multimedia-Anwendungen.

Interoperabilität mit älteren Audio-APIs