414 lines
14 KiB
C++
414 lines
14 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: XHVVoiceManager.cpp
|
|
//
|
|
// Desc: Wraps the XHV voice engine and provides a simple interface to the
|
|
// game
|
|
//
|
|
// Hist: 05.06.03 - New for the June 2003 XDK
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
#include "XHVVoiceManager.h"
|
|
#include <assert.h>
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CXHVVoiceManager (ctor)
|
|
// Desc: Initializes member variables
|
|
//-----------------------------------------------------------------------------
|
|
CXHVVoiceManager::CXHVVoiceManager()
|
|
{
|
|
m_pXHVEngine = NULL;
|
|
m_dwNumLocalTalkers = 0;
|
|
m_dwMaxRemoteTalkers = 0;
|
|
m_dwNumRemoteTalkers = 0;
|
|
// m_pPlayerVoiceInfo = NULL;
|
|
m_bVoiceThroughSpeakers = FALSE;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ~CXHVVoiceManager (dtor)
|
|
// Desc: Performs any final cleanup that is needed
|
|
//-----------------------------------------------------------------------------
|
|
CXHVVoiceManager::~CXHVVoiceManager()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Initialize
|
|
// Desc: Initializes the XHV voice manager
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::Initialize( XHV_RUNTIME_PARAMS* pXHVParams )
|
|
{
|
|
assert( pXHVParams );
|
|
|
|
// Create the engine
|
|
HRESULT hr = XHVEngineCreate( pXHVParams, &m_pXHVEngine );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
// Enable voicechat and loopback modes only
|
|
m_pXHVEngine->EnableProcessingMode( XHV_LOOPBACK_MODE );
|
|
m_pXHVEngine->EnableProcessingMode( XHV_VOICECHAT_MODE );
|
|
// m_pXHVEngine->EnableProcessingMode( XHV_SR_MODE );
|
|
|
|
m_dwNumLocalTalkers = pXHVParams->dwMaxLocalTalkers;
|
|
m_dwMaxRemoteTalkers = pXHVParams->dwMaxRemoteTalkers;
|
|
|
|
// Register each local talker immediately, but leave them inactive
|
|
for( DWORD i = 0; i < m_dwNumLocalTalkers; i++ )
|
|
{
|
|
m_pXHVEngine->RegisterLocalTalker( i );
|
|
m_pXHVEngine->SetProcessingMode( i, XHV_INACTIVE_MODE );
|
|
}
|
|
|
|
// Allocate space for the PlayerVoiceInfo structs
|
|
// m_pPlayerVoiceInfo = new PlayerVoiceInfo[ m_dwMaxRemoteTalkers ];
|
|
// if( NULL == m_pPlayerVoiceInfo )
|
|
// {
|
|
// Shutdown();
|
|
// return E_OUTOFMEMORY;
|
|
// }
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Shutdown
|
|
// Desc: Shuts down the object
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::Shutdown()
|
|
{
|
|
if( m_pXHVEngine )
|
|
{
|
|
m_pXHVEngine->Release();
|
|
m_pXHVEngine = NULL;
|
|
}
|
|
|
|
// if( m_pPlayerVoiceInfo )
|
|
// {
|
|
// delete[] m_pPlayerVoiceInfo;
|
|
// m_pPlayerVoiceInfo = NULL;
|
|
// }
|
|
|
|
m_dwNumLocalTalkers = 0;
|
|
m_dwMaxRemoteTalkers = 0;
|
|
m_dwNumRemoteTalkers = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: RegisterRemoteTalker
|
|
// Desc: Registers a new remote talker
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::RegisterRemoteTalker( XUID xuidRemoteTalker )
|
|
{
|
|
// XHV allows you to call RegisterRemoteTalker more than once with the
|
|
// same XUID. For convenience, we'll emulate that behavior
|
|
if( SUCCEEDED( FindPlayerVoiceInfo( xuidRemoteTalker, NULL ) ) )
|
|
return S_OK;
|
|
|
|
// Verify we're within our limits
|
|
assert( m_dwNumRemoteTalkers < m_dwMaxRemoteTalkers );
|
|
|
|
// Register the remote talker with XHV
|
|
HRESULT hr;
|
|
hr = m_pXHVEngine->RegisterRemoteTalker( xuidRemoteTalker );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
// Set up a new PlayerVoiceInfo struct for the player
|
|
PlayerVoiceInfo* pRemoteTalker = &m_pPlayerVoiceInfo[ m_dwNumRemoteTalkers ];
|
|
pRemoteTalker->xuid = xuidRemoteTalker;
|
|
for( DWORD i = 0; i < XGetPortCount(); i++ )
|
|
{
|
|
pRemoteTalker->bMuted[ i ] = FALSE;
|
|
pRemoteTalker->bRemoteMuted[ i ] = FALSE;
|
|
pRemoteTalker->priority[ i ] = XHV_PLAYBACK_PRIORITY_NEVER;
|
|
}
|
|
|
|
++m_dwNumRemoteTalkers;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: UnregisterRemoteTalker
|
|
// Desc: Unregisters an existing remote talker
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::UnregisterRemoteTalker( XUID xuidRemoteTalker )
|
|
{
|
|
// Find the entry to remove from our PlayerVoiceInfo list
|
|
DWORD dwEntry;
|
|
if( FAILED( FindPlayerVoiceInfo( xuidRemoteTalker, &dwEntry ) ) )
|
|
return E_FAIL;
|
|
|
|
// Remove the entry by overwriting it with the last entry in the list
|
|
memcpy( &m_pPlayerVoiceInfo[ dwEntry ],
|
|
&m_pPlayerVoiceInfo[ m_dwNumRemoteTalkers - 1 ],
|
|
sizeof( PlayerVoiceInfo ) );
|
|
--m_dwNumRemoteTalkers;
|
|
|
|
// Unregister the remote talker with XHV
|
|
HRESULT hr = m_pXHVEngine->UnregisterRemoteTalker( xuidRemoteTalker );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ClearRemoteTalkers
|
|
// Desc: Unregisters all remaining remote talkers
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::ClearRemoteTalkers()
|
|
{
|
|
for( DWORD i = 0; i < m_dwNumRemoteTalkers; i++ )
|
|
{
|
|
m_pXHVEngine->UnregisterRemoteTalker( m_pPlayerVoiceInfo[ i ].xuid );
|
|
}
|
|
m_dwNumRemoteTalkers = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetRemoteTalkerPriority
|
|
// Desc: Sets the priority of a remote talker.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::SetRemoteTalkerPriority( XUID xuidRemoteTalker,
|
|
DWORD dwPort,
|
|
XHV_PLAYBACK_PRIORITY priority )
|
|
{
|
|
DWORD dwEntry;
|
|
if( FAILED( FindPlayerVoiceInfo( xuidRemoteTalker, &dwEntry ) ) )
|
|
return E_FAIL;
|
|
|
|
// Set our copy of the priority
|
|
PlayerVoiceInfo* pInfo = &m_pPlayerVoiceInfo[ dwEntry ];
|
|
pInfo->priority[ dwPort ] = priority;
|
|
|
|
// Recalculate priorities for the remote talker
|
|
if( FAILED( RecalculatePriorities( pInfo ) ) )
|
|
return E_FAIL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: RecalculatePriorities
|
|
// Desc: Calculates and sets the appropriate priorities of the remote talker.
|
|
// If Voice Through Speakers is disabled, it sets the priority for each
|
|
// local talker based upon their priority for the remote talker and
|
|
// their mute settings, and sets speaker priority to NEVER.
|
|
// If Voice Through Speakers is enabled, it sets the priority for each
|
|
// local talker to NEVER, and sets speaker priority based on the
|
|
// following rules:
|
|
// 1) If any local talker has muted the remote talker, set to NEVER
|
|
// 2) If the remote talker has muted any local talker, set to NEVER
|
|
// 3) Otherwise, priority is the max of each local talker's priority
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::RecalculatePriorities( PlayerVoiceInfo* pInfo )
|
|
{
|
|
if( !m_bVoiceThroughSpeakers )
|
|
{
|
|
// Set appropriate local talker priorities
|
|
for( DWORD dwPort = 0; dwPort < m_dwNumLocalTalkers; dwPort++ )
|
|
{
|
|
XHV_PLAYBACK_PRIORITY priority = pInfo->priority[ dwPort ];
|
|
if( pInfo->bMuted[ dwPort ] || pInfo->bRemoteMuted[ dwPort ] )
|
|
{
|
|
priority = XHV_PLAYBACK_PRIORITY_NEVER;
|
|
}
|
|
|
|
m_pXHVEngine->SetPlaybackPriority( pInfo->xuid,
|
|
dwPort,
|
|
priority );
|
|
}
|
|
|
|
// Set speaker priority to NEVER
|
|
m_pXHVEngine->SetPlaybackPriority( pInfo->xuid,
|
|
XHV_PLAYBACK_TO_SPEAKERS,
|
|
XHV_PLAYBACK_PRIORITY_NEVER );
|
|
}
|
|
else
|
|
{
|
|
XHV_PLAYBACK_PRIORITY priority = XHV_PLAYBACK_PRIORITY_NEVER;
|
|
|
|
// Turn off local talker headphone output, and calculate
|
|
// maximum priority while accounting for muting
|
|
for( DWORD dwPort = 0; dwPort < m_dwNumLocalTalkers; dwPort++ )
|
|
{
|
|
m_pXHVEngine->SetPlaybackPriority( pInfo->xuid,
|
|
dwPort,
|
|
XHV_PLAYBACK_PRIORITY_NEVER );
|
|
|
|
// If anyone has muted or been muted by the remote talker,
|
|
// must set priority to NEVER
|
|
if( pInfo->bMuted[ dwPort ] || pInfo->bRemoteMuted[ dwPort ] )
|
|
{
|
|
priority = XHV_PLAYBACK_PRIORITY_NEVER;
|
|
break;
|
|
}
|
|
|
|
// Calculate maximum priority - lower values correspond
|
|
// to higher priority
|
|
if( pInfo->priority[ dwPort ] < priority )
|
|
priority = pInfo->priority[ dwPort ];
|
|
}
|
|
|
|
m_pXHVEngine->SetPlaybackPriority( pInfo->xuid,
|
|
XHV_PLAYBACK_TO_SPEAKERS,
|
|
priority );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetVoiceThroughSpeakers
|
|
// Desc: Turns voice-through-speakers mode off and on
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::SetVoiceThroughSpeakers( BOOL bVoiceThroughSpeakers )
|
|
{
|
|
m_bVoiceThroughSpeakers = bVoiceThroughSpeakers;
|
|
|
|
// Recalculate the priorities for each remote talker
|
|
for( DWORD i = 0; i < m_dwNumRemoteTalkers; i++ )
|
|
{
|
|
RecalculatePriorities( &m_pPlayerVoiceInfo[ i ] );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetVoiceThroughSpeakers
|
|
// Desc: Turns voice-through-speakers mode off and on
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CXHVVoiceManager::GetVoiceThroughSpeakers( VOID )
|
|
{
|
|
return m_bVoiceThroughSpeakers;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetMute
|
|
// Desc: Mutes/UnMutes a remote talker for a given local talker
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::SetMute( XUID xuidRemoteTalker, DWORD dwPort, BOOL bMuted )
|
|
{
|
|
DWORD dwEntry;
|
|
if( FAILED( FindPlayerVoiceInfo( xuidRemoteTalker, &dwEntry ) ) )
|
|
return E_FAIL;
|
|
|
|
PlayerVoiceInfo* pInfo = &m_pPlayerVoiceInfo[ dwEntry ];
|
|
pInfo->bMuted[ dwPort ] = bMuted;
|
|
RecalculatePriorities( pInfo );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetRemoteMute
|
|
// Desc: RemoteMutes/RemoteUnMutes a remote talker for a given local talker
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::SetRemoteMute( XUID xuidRemoteTalker, DWORD dwPort, BOOL bRemoteMuted )
|
|
{
|
|
DWORD dwEntry;
|
|
if( FAILED( FindPlayerVoiceInfo( xuidRemoteTalker, &dwEntry ) ) )
|
|
return E_FAIL;
|
|
|
|
PlayerVoiceInfo* pInfo = &m_pPlayerVoiceInfo[ dwEntry ];
|
|
pInfo->bRemoteMuted[ dwPort ] = bRemoteMuted;
|
|
RecalculatePriorities( pInfo );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: IsTalking
|
|
// Desc: Determines whether a remote talker is currently talking to a local
|
|
// talker.
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CXHVVoiceManager::IsTalking( XUID xuidRemoteTalker, DWORD dwPort )
|
|
{
|
|
// First, see if the remote talker is currently talking
|
|
BOOL bIsTalking = m_pXHVEngine->IsTalking( xuidRemoteTalker );
|
|
|
|
// Although they're talking, a local player may not hear them due to
|
|
// muting - possibly even another local talker being muted, if Voice
|
|
// Through Speakers is on.
|
|
if( bIsTalking )
|
|
{
|
|
DWORD dwEntry;
|
|
if( FAILED( FindPlayerVoiceInfo( xuidRemoteTalker, &dwEntry ) ) )
|
|
return FALSE;
|
|
PlayerVoiceInfo* pInfo = &m_pPlayerVoiceInfo[ dwEntry ];
|
|
|
|
if( !m_bVoiceThroughSpeakers )
|
|
{
|
|
// Voice Through Speakers OFF - check this local talker's
|
|
// mute settings
|
|
if( pInfo->bMuted[ dwPort ] || pInfo->bRemoteMuted[ dwPort ] )
|
|
bIsTalking = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Voice Through Speakers ON - check every local talker's
|
|
// mute settings
|
|
for( DWORD i = 0; i < m_dwNumLocalTalkers; i++ )
|
|
{
|
|
if( pInfo->bMuted[ i ] || pInfo->bRemoteMuted[ i ] )
|
|
bIsTalking = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bIsTalking;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: FindPlayerVoiceInfo
|
|
// Desc: Helper function to find an entry in the player voice info list
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CXHVVoiceManager::FindPlayerVoiceInfo( XUID xuidRemoteTalker, DWORD* pdwEntry )
|
|
{
|
|
for( DWORD i = 0; i < m_dwNumRemoteTalkers; i++ )
|
|
{
|
|
if( XOnlineAreUsersIdentical( &m_pPlayerVoiceInfo[i].xuid,
|
|
&xuidRemoteTalker ) )
|
|
{
|
|
if( pdwEntry )
|
|
{
|
|
*pdwEntry = i;
|
|
}
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|