Files
Jedi-Academy/codemp/xbox/XHVVoiceManager.cpp
2013-04-04 14:32:05 -07:00

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