Gerenciar a sessão de áudio
[O recurso associado a esta página, MFPlay, é um recurso herdado. Foi substituído pelo MediaPlayer e IMFMediaEngine. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda enfaticamente que o novo código use o MediaPlayer and IMFMediaEngine em vez de DirectShow quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito, se possível, para usar as novas APIs.
Este tópico descreve como controlar o volume de áudio ao usar o MFPlay para reprodução de áudio/vídeo.
O MFPlay fornece os seguintes métodos para controlar o volume do áudio durante a reprodução.
Método | Descrição |
---|---|
IMFPMediaPlayer::SetBalance | Define o equilíbrio entre os canais esquerdo e direito. |
IMFPMediaPlayer::SetMute | Silencia ou ativa o som do áudio. |
IMFPMediaPlayer::SetVolume | Define o nível de volume. |
Para entender o comportamento desses métodos, você deve conhecer a terminologia da API de Sessão de Áudio do Windows (WASAPI), que implementa a funcionalidade de áudio de baixo nível usada pelo MFPlay.
Na WASAPI, cada fluxo de áudio pertence a exatamente uma sessão de áudio, que é um grupo de fluxos de áudio relacionados. Normalmente, um aplicativo mantém uma única sessão de áudio, embora os aplicativos possam criar mais de uma sessão. O programa de controle de volume do sistema (Sndvol) exibe um controle de volume para cada sessão de áudio. Por meio do Sndvol, um usuário pode ajustar o volume de uma sessão de áudio de fora do aplicativo. O imagem a seguir ilustra esse processo.
No MFPlay, um item de mídia pode ter um ou mais fluxos de áudio ativos (normalmente apenas um). Internamente, o MFPlay usa o SAR (Renderizador de Áudio de Streaming) para renderizar os fluxos de áudio. A menos que você o configure de outra forma, o SAR ingressa na sessão de áudio padrão do aplicativo.
Os métodos de áudio MFPlay controlam apenas os fluxos que pertencem ao item de mídia atual. Eles não afetam o volume de nenhum outro fluxo pertencente à mesma sessão de áudio. Em termos de WASAPI, os métodos MFPlay controlam os níveis de volume por canal, não o nível de volume mestre. O imagem a seguir ilustra esse processo.
É importante entender algumas implicações desse recurso do MFPlay. Primeiro, um aplicativo pode ajustar o volume de reprodução sem afetar outros fluxos de áudio. Você poderá usar esse recurso no caso do MFPlay para implementar a transição com desvanecimento de áudio, criando duas instâncias do objeto MFPlay e ajustando o volume separadamente.
Se você usar métodos MFPlay para alterar o volume ou o estado mudo, as alterações não aparecerão no Sndvol. Por exemplo, você pode chamar SetMute para silenciar o áudio, mas o Sndvol não mostrará a sessão como silenciada. Por outro lado, se SndVol for usado para ajustar o volume da sessão, as alterações não serão refletidas nos valores retornados por IMFPMediaPlayer::GetVolume ou IMFPMediaPlayer::GetMute.
Para cada instância do objeto de player MFPlay, o nível de volume efetivo é igual a fPlayerVolume × fSessionVolume, onde fPlayerVolume é o valor retornado por GetVolume, e fSessionVolume é o volume mestre da sessão.
Para cenários de reprodução simples, poderá ser preferível usar a WASAPI para controlar o volume de áudio de toda a sessão, em vez de usar os métodos MFPlay.
Código de exemplo
O que se segue é uma classe C++ que lida com as tarefas básicas na WASAPI:
- Controlando o volume e o estado mudo da sessão.
- Recebendo notificações sempre que o volume ou o estado mudo mudarem.
Declaração de classe
A declaração de classe CAudioSessionVolume
implementa a interface IAudioSessionEvents, que é a interface de retorno de chamada para eventos de sessão de áudio.
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;
};
Quando o objeto CAudioSessionVolume
recebe um evento de sessão de áudio, ele publica uma mensagem de janela privada no aplicativo. O identificador da janela e a mensagem da janela são fornecidos como parâmetros para o método CAudioSessionVolume::CreateInstance
estático.
Obter os ponteiros de interface da WASAPI
CAudioSessionVolume
usa duas interfaces WASAPI principais:
- IAudioSessionControl gerencia a sessão de áudio.
- ISimpleAudioVolume controla o nível de volume e o estado mudo da sessão.
Para obter essas interfaces, você deve enumerar o ponto de extremidade de áudio usado pelo SAR. Um ponto de extremidade de áudio é um dispositivo de hardware que captura ou consome dados de áudio. Para reprodução de áudio, um endpoint é simplesmente um alto-falante ou outra saída de áudio. Por padrão, o SAR usa o ponto de extremidade padrão para a função de dispositivo eConsole. Uma função de dispositivo é uma função atribuída a um ponto de extremidade. As funções de dispositivo são especificadas pela enumeração ERole, que é documentada mas APIs Core Audio.
O código a seguir mostra como enumerar o ponto de extremidade e obter as interfaces WASAPI.
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;
}
Controlar o volume
Os métodos CAudioSessionVolume
que controlam o volume de áudio chamam os métodos ISimpleAudioVolume equivalentes. Por exemplo, CAudioSessionVolume::SetVolume
chama ISimpleAudioVolume::SetMasterVolume, conforme mostrado no código a seguir.
HRESULT CAudioSessionVolume::SetVolume(float flVolume)
{
if (m_pSimpleAudioVolume == NULL)
{
return E_FAIL;
}
else
{
return m_pSimpleAudioVolume->SetMasterVolume(
flVolume,
&AudioSessionVolumeCtx // Event context.
);
}
}
Código CAudioSessionVolume completo
Veja a lista completa dos métodos da classe CAudioSessionVolume
.
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;
}
Requisitos
A MFPlay requer o Windows 7.
Tópicos relacionados