Freigeben über


Verwalten der Audiositzung

[Bei dem auf dieser Seite gezeigten Feature MFPlay handelt es sich um ein Legacyfeature. Es wurde durch MediaPlayer und IMFMediaEngine abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass in neuem Code wenn möglich MediaPlayer und IMFMediaEngine anstelle von DirectShow verwendet wird. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, wenn möglich umgeschrieben wird, um die neuen APIs zu verwenden.]

In diesem Thema wird beschrieben, wie Sie die Audiolautstärke bei Verwendung von MFPlay für die Audio-/Videowiedergabe steuern.

MFPlay bietet die folgenden Methoden zum Steuern der Audiolautstärke während der Wiedergabe.

Methode Beschreibung
IMFPMediaPlayer::SetBalance Legt die Balance zwischen dem linken und dem rechten Kanal fest.
IMFPMediaPlayer::SetMute Schaltet die Audiowiedergabe stumm oder hebt die Stummschaltung der Audiowiedergabe auf.
IMFPMediaPlayer::SetVolume Legt die Lautstärke fest.

 

Um das Verhalten dieser Methoden zu verstehen, müssen Sie Terminologie aus der Windows-Audiositzungs-API (WASAPI) kennen, die die von MFPlay verwendete Audiofunktionalität auf niedriger Ebene implementiert.

In WASAPI gehört jeder Audiostream zu genau einer Audiositzung, bei der es sich um eine Gruppe verwandter Audiostreams handelt. In der Regel verwaltet eine Anwendung eine einzelne Audiositzung, obwohl Anwendungen mehrere Sitzungen erstellen können. Das Programm zur Steuerung der Systemlautstärke (Sndvol) zeigt eine Lautstärkeregelung für jede Audiositzung an. Über Sndvol kann ein Benutzer die Lautstärke einer Audiositzung von außerhalb der Anwendung anpassen. Das folgende Bild zeigt diesen Prozess.

Diagramm mit Audiostreams, die auf dem Weg zu den Lautsprechern die Lautstärkeregelung passieren. Anwendung und sndvol zeigen auf die Lautstärkesteuerung.

In MFPlay kann ein Medienelement einen oder mehrere aktive Audiostreams aufweisen (in der Regel nur einen). Intern verwendet MFPlay den Streaming-Audiorenderer (SAR), um die Audiostreams zu rendern. Sofern Sie diese Einstellung nicht anders konfigurieren, verknüpft der SAR die Standardaudiositzung der Anwendung.

Die MFPlay-Audiomethoden steuern nur die Streams, die zum aktuellen Medienelement gehören. Sie wirken sich nicht auf die Lautstärke anderer Streams aus, zur selben Audiositzung gehören. In Bezug auf die WASAPI steuern die MFPlay-Methoden die Lautstärke pro Kanal und nicht die allgemeine Lautstärke. Das folgende Bild zeigt diesen Prozess.

Diagramm ähnlich dem vorherigen, allerdings beginnt der zweite Stream beim Medienelement, und die Anwendung zeigt auf den zweiten Stream und auf die Lautstärkesteuerung.

Es ist wichtig, einige Auswirkungen dieses Features von MFPlay zu verstehen. Zunächst kann eine Anwendung die Wiedergabelautstärke anpassen, ohne dass sich dies auf andere Audiostreams auswirkt. Sie können dieses Feature verwenden, wenn MFPlay Audioüberblenden implementiert, indem Sie zwei Instanzen des MFPlay-Objekts erstellen und die Lautstärke separat anpassen.

Wenn Sie MFPlay-Methoden verwenden, um den Lautstärke- oder Stummschaltungszustand zu ändern, werden die Änderungen nicht in Sndvol angezeigt. Sie können beispielsweise SetMute aufrufen, um Audio stummzuschalten, aber Sndvol zeigt die Sitzung nicht als stummgeschaltet an. Wenn SndVol dagegen verwendet wird, um die Sitzungslautstärke anzupassen, werden die Änderungen nicht in den von IMFPMediaPlayer::GetVolume oder IMFPMediaPlayer::GetMute zurückgegebenen Werten widergespiegelt.

Für jede Instanz des MFPlay-Playerobjekts entspricht der effektive Lautstärkepegel fPlayerVolume × fSessionVolume. Dabei ist fPlayerVolume der von GetVolume zurückgegebene Wert, und fSessionVolume ist die allgemeine Lautstärke für die Sitzung.

In manchen Wiedergabeszenarien ist es möglicherweise vorteilhafter, anstelle der MFPlay-Methoden die WASAPI zum Steuern der Audiolautstärke für die gesamte Sitzung zu verwenden.

Beispielcode

Es folgt eine C++-Klasse, die die grundlegenden Aufgaben in WASAPI behandelt:

  • Steuern des Lautstärke- und Stummschaltungszustands für die Sitzung
  • Erhalten von Benachrichtigungen, wenn sich der Lautstärke- oder Stummschaltungszustand ändert

Klassendeklaration

Die Klassendeklaration CAudioSessionVolume implementiert die IAudioSessionEvents-Schnittstelle, die die Rückrufschnittstelle für Audiositzungsereignisse ist.

class CAudioSessionVolume : public IAudioSessionEvents
{
public:
    // Static method to create an instance of the object.
    static HRESULT CreateInstance(
        UINT uNotificationMessage,
        HWND hwndNotification,
        CAudioSessionVolume **ppAudioSessionVolume
    );

    // IUnknown methods.
    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    // IAudioSessionEvents methods.

    STDMETHODIMP OnSimpleVolumeChanged(
        float NewVolume,
        BOOL NewMute,
        LPCGUID EventContext
        );

    // The remaining audio session events do not require any action.
    STDMETHODIMP OnDisplayNameChanged(LPCWSTR,LPCGUID)
    {
        return S_OK;
    }

    STDMETHODIMP OnIconPathChanged(LPCWSTR,LPCGUID)
    {
        return S_OK;
    }

    STDMETHODIMP OnChannelVolumeChanged(DWORD,float[],DWORD,LPCGUID)
    {
        return S_OK;
    }

    STDMETHODIMP OnGroupingParamChanged(LPCGUID,LPCGUID)
    {
        return S_OK;
    }

    STDMETHODIMP OnStateChanged(AudioSessionState)
    {
        return S_OK;
    }

    STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason)
    {
        return S_OK;
    }

    // Other methods
    HRESULT EnableNotifications(BOOL bEnable);
    HRESULT GetVolume(float *pflVolume);
    HRESULT SetVolume(float flVolume);
    HRESULT GetMute(BOOL *pbMute);
    HRESULT SetMute(BOOL bMute);
    HRESULT SetDisplayName(const WCHAR *wszName);

protected:
    CAudioSessionVolume(UINT uNotificationMessage, HWND hwndNotification);
    ~CAudioSessionVolume();

    HRESULT Initialize();

protected:
    LONG m_cRef;                        // Reference count.
    UINT m_uNotificationMessage;        // Window message to send when an audio event occurs.
    HWND m_hwndNotification;            // Window to receives messages.
    BOOL m_bNotificationsEnabled;       // Are audio notifications enabled?

    IAudioSessionControl    *m_pAudioSession;
    ISimpleAudioVolume      *m_pSimpleAudioVolume;
};

Wenn das CAudioSessionVolume-Objekt ein Audiositzungsereignis empfängt, sendet es eine Nachricht in einem privaten Fenster an die Anwendung. Das Fensterhandle und die Fenstermeldung werden als Parameter an die statische CAudioSessionVolume::CreateInstance-Methode übergeben.

Abrufen der WASAPI-Schnittstellenzeiger

CAudioSessionVolume verwendet zwei WASAPI-Hauptschnittstellen:

Um diese Schnittstellen abzurufen, müssen Sie den vom SAR verwendeten Audioendpunkt auflisten. Ein Audioendpunkt ist ein Hardwaregerät, das Audiodaten aufzeichnet oder nutzt. Bei der Audiowiedergabe ist ein Endpunkt einfach ein Lautsprecher oder eine andere Audioausgabe. Standardmäßig verwendet der SAR den Standardendpunkt für die eConsole-Geräterolle. Eine Geräterolle ist eine zugewiesene Rolle für einen Endpunkt. Geräterollen werden durch die ERole-Enumeration angegeben, die unter Kernaudio-APIs dokumentiert ist.

Der folgende Code zeigt, wie der Endpunkt aufgelistet wird und die WASAPI-Schnittstellen abgerufen werden.

HRESULT CAudioSessionVolume::Initialize()
{
    HRESULT hr = S_OK;

    IMMDeviceEnumerator *pDeviceEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    IAudioSessionManager *pAudioSessionManager = NULL;

    // Get the enumerator for the audio endpoint devices.
    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator),
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pDeviceEnumerator)
        );

    if (FAILED(hr))
    {
        goto done;
    }

    // Get the default audio endpoint that the SAR will use.
    hr = pDeviceEnumerator->GetDefaultAudioEndpoint(
        eRender,
        eConsole,   // The SAR uses 'eConsole' by default.
        &pDevice
        );

    if (FAILED(hr))
    {
        goto done;
    }

    // Get the session manager for this device.
    hr = pDevice->Activate(
        __uuidof(IAudioSessionManager),
        CLSCTX_INPROC_SERVER,
        NULL,
        (void**) &pAudioSessionManager
        );

    if (FAILED(hr))
    {
        goto done;
    }

    // Get the audio session.
    hr = pAudioSessionManager->GetAudioSessionControl(
        &GUID_NULL,     // Get the default audio session.
        FALSE,          // The session is not cross-process.
        &m_pAudioSession
        );


    if (FAILED(hr))
    {
        goto done;
    }

    hr = pAudioSessionManager->GetSimpleAudioVolume(
        &GUID_NULL, 0, &m_pSimpleAudioVolume
        );

done:
    SafeRelease(&pDeviceEnumerator);
    SafeRelease(&pDevice);
    SafeRelease(&pAudioSessionManager);
    return hr;
}

Steuern der Lautstärke

Die CAudioSessionVolume-Methoden zum Steuern der Audiolautstärke rufen die entsprechenden ISimpleAudioVolume-Methoden auf. CAudioSessionVolume::SetVolume ruft beispielsweise ISimpleAudioVolume::SetMasterVolume auf, wie im folgenden Code gezeigt:

HRESULT CAudioSessionVolume::SetVolume(float flVolume)
{
    if (m_pSimpleAudioVolume == NULL)
    {
        return E_FAIL;
    }
    else
    {
        return m_pSimpleAudioVolume->SetMasterVolume(
            flVolume,
            &AudioSessionVolumeCtx  // Event context.
            );
    }
}

Vollständiger CAudioSessionVolume-Code

Hier sehen Sie die vollständige Auflistung für die Methoden der CAudioSessionVolume-Klasse:

static const GUID AudioSessionVolumeCtx =
{ 0x2715279f, 0x4139, 0x4ba0, { 0x9c, 0xb1, 0xb3, 0x51, 0xf1, 0xb5, 0x8a, 0x4a } };


CAudioSessionVolume::CAudioSessionVolume(
    UINT uNotificationMessage,
    HWND hwndNotification
    )
    : m_cRef(1),
      m_uNotificationMessage(uNotificationMessage),
      m_hwndNotification(hwndNotification),
      m_bNotificationsEnabled(FALSE),
      m_pAudioSession(NULL),
      m_pSimpleAudioVolume(NULL)
{
}

CAudioSessionVolume::~CAudioSessionVolume()
{
    EnableNotifications(FALSE);

    SafeRelease(&m_pAudioSession);
    SafeRelease(&m_pSimpleAudioVolume);
};


//  Creates an instance of the CAudioSessionVolume object.

/* static */
HRESULT CAudioSessionVolume::CreateInstance(
    UINT uNotificationMessage,
    HWND hwndNotification,
    CAudioSessionVolume **ppAudioSessionVolume
    )
{

    CAudioSessionVolume *pAudioSessionVolume = new (std::nothrow)
        CAudioSessionVolume(uNotificationMessage, hwndNotification);

    if (pAudioSessionVolume == NULL)
    {
        return E_OUTOFMEMORY;
    }

    HRESULT hr = pAudioSessionVolume->Initialize();
    if (SUCCEEDED(hr))
    {
        *ppAudioSessionVolume = pAudioSessionVolume;
    }
    else
    {
        pAudioSessionVolume->Release();
    }

    return hr;
}


//  Initializes the CAudioSessionVolume object.

HRESULT CAudioSessionVolume::Initialize()
{
    HRESULT hr = S_OK;

    IMMDeviceEnumerator *pDeviceEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    IAudioSessionManager *pAudioSessionManager = NULL;

    // Get the enumerator for the audio endpoint devices.
    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator),
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pDeviceEnumerator)
        );

    if (FAILED(hr))
    {
        goto done;
    }

    // Get the default audio endpoint that the SAR will use.
    hr = pDeviceEnumerator->GetDefaultAudioEndpoint(
        eRender,
        eConsole,   // The SAR uses 'eConsole' by default.
        &pDevice
        );

    if (FAILED(hr))
    {
        goto done;
    }

    // Get the session manager for this device.
    hr = pDevice->Activate(
        __uuidof(IAudioSessionManager),
        CLSCTX_INPROC_SERVER,
        NULL,
        (void**) &pAudioSessionManager
        );

    if (FAILED(hr))
    {
        goto done;
    }

    // Get the audio session.
    hr = pAudioSessionManager->GetAudioSessionControl(
        &GUID_NULL,     // Get the default audio session.
        FALSE,          // The session is not cross-process.
        &m_pAudioSession
        );


    if (FAILED(hr))
    {
        goto done;
    }

    hr = pAudioSessionManager->GetSimpleAudioVolume(
        &GUID_NULL, 0, &m_pSimpleAudioVolume
        );

done:
    SafeRelease(&pDeviceEnumerator);
    SafeRelease(&pDevice);
    SafeRelease(&pAudioSessionManager);
    return hr;
}

STDMETHODIMP CAudioSessionVolume::QueryInterface(REFIID riid, void **ppv)
{
    static const QITAB qit[] =
    {
        QITABENT(CAudioSessionVolume, IAudioSessionEvents),
        { 0 },
    };
    return QISearch(this, qit, riid, ppv);
}

STDMETHODIMP_(ULONG) CAudioSessionVolume::AddRef()
{
    return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CAudioSessionVolume::Release()
{
    LONG cRef = InterlockedDecrement( &m_cRef );
    if (cRef == 0)
    {
        delete this;
    }
    return cRef;
}


// Enables or disables notifications from the audio session. For example, the
// application is notified if the user mutes the audio through the system
// volume-control program (Sndvol).

HRESULT CAudioSessionVolume::EnableNotifications(BOOL bEnable)
{
    HRESULT hr = S_OK;

    if (m_hwndNotification == NULL || m_pAudioSession == NULL)
    {
        return E_FAIL;
    }

    if (m_bNotificationsEnabled == bEnable)
    {
        // No change.
        return S_OK;
    }

    if (bEnable)
    {
        hr = m_pAudioSession->RegisterAudioSessionNotification(this);
    }
    else
    {
        hr = m_pAudioSession->UnregisterAudioSessionNotification(this);
    }

    if (SUCCEEDED(hr))
    {
        m_bNotificationsEnabled = bEnable;
    }

    return hr;
}


// Gets the session volume level.

HRESULT CAudioSessionVolume::GetVolume(float *pflVolume)
{
    if ( m_pSimpleAudioVolume == NULL)
    {
        return E_FAIL;
    }
    else
    {
        return m_pSimpleAudioVolume->GetMasterVolume(pflVolume);
    }
}

//  Sets the session volume level.
//
//  flVolume: Ranges from 0 (silent) to 1 (full volume)

HRESULT CAudioSessionVolume::SetVolume(float flVolume)
{
    if (m_pSimpleAudioVolume == NULL)
    {
        return E_FAIL;
    }
    else
    {
        return m_pSimpleAudioVolume->SetMasterVolume(
            flVolume,
            &AudioSessionVolumeCtx  // Event context.
            );
    }
}


//  Gets the muting state of the session.

HRESULT CAudioSessionVolume::GetMute(BOOL *pbMute)
{
    if (m_pSimpleAudioVolume == NULL)
    {
        return E_FAIL;
    }
    else
    {
        return m_pSimpleAudioVolume->GetMute(pbMute);
    }
}

//  Mutes or unmutes the session audio.

HRESULT CAudioSessionVolume::SetMute(BOOL bMute)
{
    if (m_pSimpleAudioVolume == NULL)
    {
        return E_FAIL;
    }
    else
    {
        return m_pSimpleAudioVolume->SetMute(
            bMute,
            &AudioSessionVolumeCtx  // Event context.
            );
    }
}

//  Sets the display name for the session audio.

HRESULT CAudioSessionVolume::SetDisplayName(const WCHAR *wszName)
{
    if (m_pAudioSession == NULL)
    {
        return E_FAIL;
    }
    else
    {
        return m_pAudioSession->SetDisplayName(wszName, NULL);
    }
}


//  Called when the session volume level or muting state changes.
//  (Implements IAudioSessionEvents::OnSimpleVolumeChanged.)

HRESULT CAudioSessionVolume::OnSimpleVolumeChanged(
    float NewVolume,
    BOOL NewMute,
    LPCGUID EventContext
    )
{
    // Check if we should post a message to the application.

    if ( m_bNotificationsEnabled &&
        (*EventContext != AudioSessionVolumeCtx) &&
        (m_hwndNotification != NULL)
        )
    {
        // Notifications are enabled, AND
        // We did not trigger the event ourselves, AND
        // We have a valid window handle.

        // Post the message.
        ::PostMessage(
            m_hwndNotification,
            m_uNotificationMessage,
            *((WPARAM*)(&NewVolume)),  // Coerce the float.
            (LPARAM)NewMute
            );
    }
    return S_OK;
}

Anforderungen

MFPlay erfordert Windows 7.

Verwenden von MFPlay für die Audio-/Videowiedergabe