2025-11-28 00:35:46 +09:00

388 lines
9.3 KiB
C++

//------------------------------------------------------------------------------
//
// Manages the audio session.
//
// The CAudioSessionVolume class performs two functions:
//
// - Enables the application to set the volume on the audio session that
// MFPlay uses for audio playback.
//
// - Notifies the application when the session volume is changed externally
// (eg through SndVol application)
//
// This class uses two WASAPI interfaces:
//
// - IAudioSessionControl
// - ISimpleAudioVolume
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
#include "MFPlayer.h"
#include "AudioSessionVolume.h"
// {2715279F-4139-4ba0-9CB1-B351F1B58A4A}
static const GUID AudioSessionVolumeCtx =
{ 0x2715279f, 0x4139, 0x4ba0, { 0x9c, 0xb1, 0xb3, 0x51, 0xf1, 0xb5, 0x8a, 0x4a } };
//-------------------------------------------------------------------
// Constructor
//-------------------------------------------------------------------
CAudioSessionVolume::CAudioSessionVolume(
UINT uNotificationMessage,
HWND hwndNotification
)
: m_cRef(1),
m_uNotificationMessage(uNotificationMessage),
m_hwndNotification(hwndNotification),
m_bNotificationsEnabled(FALSE),
m_pAudioSession(NULL),
m_pSimpleAudioVolume(NULL)
{
}
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
CAudioSessionVolume::~CAudioSessionVolume()
{
EnableNotifications(FALSE);
SafeRelease(&m_pAudioSession);
SafeRelease(&m_pSimpleAudioVolume);
};
//-------------------------------------------------------------------
// CreateInstance
//
// Creates an instance of the CAudioSessionVolume object.
//-------------------------------------------------------------------
/* static */
HRESULT CAudioSessionVolume::CreateInstance(
UINT uNotificationMessage,
HWND hwndNotification,
CAudioSessionVolume **ppAudioSessionVolume
)
{
HRESULT hr = S_OK;
CAudioSessionVolume *pAudioSessionVolume = NULL;
pAudioSessionVolume = new (std::nothrow) CAudioSessionVolume(
uNotificationMessage, hwndNotification);
if (pAudioSessionVolume == NULL)
{
hr = E_OUTOFMEMORY;
goto done;
}
hr = pAudioSessionVolume->Initialize();
if (FAILED(hr)) { goto done; }
*ppAudioSessionVolume = pAudioSessionVolume;
(*ppAudioSessionVolume)->AddRef();
done:
SafeRelease(&pAudioSessionVolume);
return hr;
}
//-------------------------------------------------------------------
// Initialize
//
// 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;
}
/* IUnknown methods */
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 c = InterlockedDecrement( &m_cRef );
if (c == 0)
{
delete this;
}
return c;
}
//-------------------------------------------------------------------
// EnableNotifications
//
// Enables or disables notifications from the audio session. For
// example, if the user mutes the audio through the system volume-
// control program (Sndvol), the application will be notified.
//
//-------------------------------------------------------------------
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;
}
//-------------------------------------------------------------------
// GetVolume
//
// Gets the session volume level.
//
//-------------------------------------------------------------------
HRESULT CAudioSessionVolume::GetVolume(float *pflVolume)
{
HRESULT hr = S_OK;
if ( m_pSimpleAudioVolume == NULL)
{
hr = E_FAIL;
}
else
{
hr = m_pSimpleAudioVolume->GetMasterVolume(pflVolume);
}
return hr;
}
//-------------------------------------------------------------------
// SetVolume
//
// Sets the session volume level.
//
// flVolume: Ranges from 0 (silent) to 1 (full volume)
//-------------------------------------------------------------------
HRESULT CAudioSessionVolume::SetVolume(float flVolume)
{
HRESULT hr = S_OK;
if (m_pSimpleAudioVolume == NULL)
{
hr = E_FAIL;
}
else
{
hr = m_pSimpleAudioVolume->SetMasterVolume(
flVolume,
&AudioSessionVolumeCtx // Event context.
);
}
return hr;
}
//-------------------------------------------------------------------
// GetMute
//
// Gets the muting state of the session.
//
//-------------------------------------------------------------------
HRESULT CAudioSessionVolume::GetMute(BOOL *pbMute)
{
HRESULT hr = S_OK;
if (m_pSimpleAudioVolume == NULL)
{
hr = E_FAIL;
}
else
{
hr = m_pSimpleAudioVolume->GetMute(pbMute);
}
return hr;
}
//-------------------------------------------------------------------
// SetMute
//
// Mutes or unmutes the session audio.
//
//-------------------------------------------------------------------
HRESULT CAudioSessionVolume::SetMute(BOOL bMute)
{
HRESULT hr = S_OK;
if (m_pSimpleAudioVolume == NULL)
{
hr = E_FAIL;
}
else
{
hr = m_pSimpleAudioVolume->SetMute(
bMute,
&AudioSessionVolumeCtx // Event context.
);
}
return hr;
}
//-------------------------------------------------------------------
// SetDisplayName
//
// Sets the display name for the session audio.
//
//-------------------------------------------------------------------
HRESULT CAudioSessionVolume::SetDisplayName(const WCHAR *wszName)
{
HRESULT hr = S_OK;
if (m_pAudioSession == NULL)
{
hr = E_FAIL;
}
else
{
hr = m_pAudioSession->SetDisplayName(wszName, NULL);
}
return hr;
}
//-------------------------------------------------------------------
// OnSimpleVolumeChanged
//
// Callback 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;
}