You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
504 lines
15 KiB
504 lines
15 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dvdxtran.cpp
|
|
* Content: Implementation of transport class providing DirectXVoice transport
|
|
* through the IDirectXVoiceTransport interface.
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 07/23/99 rodtoll Modified from dvdptran.cpp
|
|
* 08/03/99 rodtoll Modified to conform to new base class and minor fixes
|
|
* for dplay integration.
|
|
* 08/04/99 rodtoll Modified to allow group targets
|
|
* 08/10/99 rodtoll Removed TODO pragmas
|
|
* 08/25/99 rodtoll Fixed group membership check
|
|
* 08/30/99 rodtoll Modified SendToServer to send to the server player in
|
|
* client/server sessions.
|
|
* 08/31/99 rodtoll Updated to use new debug libs
|
|
* 09/01/99 rodtoll Updated so that constructor no longer calls into dplay
|
|
* rodtoll Added check for valid pointers in func calls
|
|
* 09/02/99 rodtoll Added checks to handle case no local player created
|
|
* 09/20/99 rodtoll Added memory alloc failure checks
|
|
* 09/21/99 rodtoll Fixed memory leak
|
|
* 10/05/99 rodtoll Additional comments and DPF_MODNAMEs
|
|
* 11/23/99 rodtoll Split CheckForValid into Group and Player
|
|
* 12/16/99 rodtoll Bug #122629 - As part of new host migration update how
|
|
* sends to server before first response are sent.
|
|
* 01/14/2000 rodtoll Renamed SendToID to SendToIDS and updated parameter list
|
|
* to accept multiple targets.
|
|
* rodtoll Added GetNumPlayers call
|
|
* 01/17/2000 rodtoll Debug statement removed that limited max players to 30
|
|
* 03/28/2000 rodtoll Moved nametable from here to upper level classes
|
|
* rodtoll Removed uneeded functions/members
|
|
* 04/07/2000 rodtoll Updated to support new DP <--> DPV interface
|
|
* rodtoll Updated to support no copy sends
|
|
* rodtoll Bug #32179 - Prevent multiple client/server registrations on transport
|
|
* 06/21/2000 rodtoll Bug #36820 - Host migrates to wrong client when client/server are on same interface
|
|
* Condition exists where host sends leave message, client attempts to start new host
|
|
* which fails because old host still registered. Now deregistering is two step
|
|
* process DisableReceiveHook then DestroyTransport.
|
|
* 07/22/20000 rodtoll Bug #40296, 38858 - Crashes due to shutdown race condition
|
|
* Now ensures that all threads from transport have left and that
|
|
* all notificatinos have been processed before shutdown is complete.
|
|
* 01/04/2001 rodtoll WinBug #94200 - Remove stray comments
|
|
* 01/22/2001 rodtoll WINBUG #288437 - IA64 Pointer misalignment due to wire packets
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "dxvoicepch.h"
|
|
|
|
|
|
#define DVF_SEND_DEBUG_LEVEL DVF_INFOLEVEL
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::CDirectVoiceDirectXTransport"
|
|
CDirectVoiceDirectXTransport::CDirectVoiceDirectXTransport( LPDIRECTPLAYVOICETRANSPORT lpTransport
|
|
): m_lpTransport(NULL),
|
|
m_dpidServer(DPID_ALLPLAYERS),
|
|
m_dpidLocalPlayer(0),
|
|
m_bLocalServer(TRUE),
|
|
m_bActiveSession(TRUE),
|
|
m_dwTransportFlags(0),
|
|
m_lpVoiceEngine(NULL),
|
|
m_dwMaxPlayers(0),
|
|
m_initialized(FALSE),
|
|
m_dwObjectType(0),
|
|
m_fAdvised(FALSE)
|
|
{
|
|
lpTransport->QueryInterface( IID_IDirectPlayVoiceTransport, (void **) &m_lpTransport );
|
|
|
|
m_dvTransportInfo.dwSize = sizeof( DVTRANSPORTINFO );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::~CDirectVoiceDirectXTransport"
|
|
CDirectVoiceDirectXTransport::~CDirectVoiceDirectXTransport()
|
|
{
|
|
if( m_lpTransport != NULL )
|
|
m_lpTransport->Release();
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::DestroyTransport"
|
|
// DestroyTransport
|
|
//
|
|
// This method is used to remove last references to transport that transport
|
|
// layer has. There was a memory leak where
|
|
//
|
|
//
|
|
void CDirectVoiceDirectXTransport::DestroyTransport()
|
|
{
|
|
if( m_lpTransport != NULL )
|
|
{
|
|
m_lpTransport->Release();
|
|
m_lpTransport = NULL;
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::Initialize"
|
|
//
|
|
// Initialize
|
|
//
|
|
// Called from the transport when Advise is called.
|
|
//
|
|
// Used to initialize this object.
|
|
//
|
|
HRESULT CDirectVoiceDirectXTransport::Initialize( )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = m_lpTransport->GetSessionInfo( &m_dvTransportInfo );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, 0, "DXVT::Initialize: GetSessionInfo() failed! hr=0x%x", hr );
|
|
return hr;
|
|
}
|
|
|
|
m_dwMaxPlayers = (m_dvTransportInfo.dwMaxPlayers==0) ? 255 : m_dvTransportInfo.dwMaxPlayers;
|
|
|
|
|
|
m_dpidLocalPlayer = m_dvTransportInfo.dvidLocalID;
|
|
|
|
// No longer needed, the server may not bee the host of the dplay session
|
|
// m_dpidServer = m_dvTransportInfo.dvidSessionHost;
|
|
m_dpidServer = DPID_ALLPLAYERS;
|
|
|
|
m_initialized = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::GetMaxPlayers"
|
|
DWORD CDirectVoiceDirectXTransport::GetMaxPlayers( )
|
|
{
|
|
return m_dwMaxPlayers;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::SendHelper"
|
|
HRESULT CDirectVoiceDirectXTransport::SendHelper( UNALIGNED DVID * pdvidTargets, DWORD dwNumTargets, PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if( dwNumTargets > 1 )
|
|
{
|
|
DNASSERT(pdvidTargets);
|
|
DEBUG_ONLY( for( DWORD dwIndex = 0; dwIndex < dwNumTargets; dwIndex++ ) { )
|
|
DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Using multitargetted send [From=0x%x To=0x%x]", m_dpidLocalPlayer, pdvidTargets[dwIndex] );
|
|
DEBUG_ONLY( } )
|
|
|
|
hr = m_lpTransport->SendSpeechEx( m_dpidLocalPlayer, dwNumTargets, pdvidTargets, pBufferDesc, pvContext, dwFlags );
|
|
}
|
|
else if (dwNumTargets==1)
|
|
{
|
|
DNASSERT(pdvidTargets);
|
|
DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Single target for send [From=0x%x To=0x%x]", m_dpidLocalPlayer, pdvidTargets[0] );
|
|
hr = m_lpTransport->SendSpeech( m_dpidLocalPlayer, *pdvidTargets, pBufferDesc, pvContext, dwFlags );
|
|
}
|
|
else
|
|
{
|
|
//no targets specified, so simply return the send buffer and do nothing
|
|
DVEVENTMSG_SENDCOMPLETE sendCompleteEvent;
|
|
sendCompleteEvent.pvUserContext=pvContext;
|
|
sendCompleteEvent.hrSendResult=DPN_OK;
|
|
m_lpVoiceEngine->SendComplete(&sendCompleteEvent);
|
|
DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Ignoring send from 0x%x, as dwNumTargets==0", m_dpidLocalPlayer);
|
|
hr=DPN_OK;
|
|
}
|
|
|
|
/*
|
|
DNASSERT( pdpidTargets != NULL );
|
|
|
|
for( DWORD dwIndex = 0; dwIndex < dwNumTargets; dwIndex++ )
|
|
{
|
|
hr = m_lpTransport->SendSpeech( m_dpidLocalPlayer, pdpidTargets[dwIndex], lpBuffer, dwSize, dwFlags );
|
|
} */
|
|
|
|
return hr;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::SendToServer"
|
|
HRESULT CDirectVoiceDirectXTransport::SendToServer( PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
|
|
{
|
|
if( m_dvTransportInfo.dwSessionType == DVTRANSPORT_SESSION_CLIENTSERVER )
|
|
{
|
|
DVID dvidTmp = DVID_SERVERPLAYER;
|
|
|
|
DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Sending to standard server player" );
|
|
|
|
return SendHelper( &dvidTmp, 1, pBufferDesc, pvContext, dwFlags );
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Sending to server ID [ID=0x%x]", m_dpidServer );
|
|
return SendHelper( &m_dpidServer, 1, pBufferDesc, pvContext, dwFlags );
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::SendToIDS"
|
|
HRESULT CDirectVoiceDirectXTransport::SendToIDS( UNALIGNED DVID * pdvidTargets, DWORD dwNumTargets, PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
|
|
{
|
|
return SendHelper( pdvidTargets, dwNumTargets, pBufferDesc, pvContext, dwFlags );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::SendToAll"
|
|
HRESULT CDirectVoiceDirectXTransport::SendToAll( PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
|
|
{
|
|
DVID dvidTmp = DPID_ALLPLAYERS;
|
|
|
|
return SendHelper( &dvidTmp, 1, pBufferDesc, pvContext, dwFlags );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmValidGroup"
|
|
BOOL CDirectVoiceDirectXTransport::ConfirmValidGroup( DVID dvid )
|
|
{
|
|
if( dvid == DVID_ALLPLAYERS )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if( m_dvTransportInfo.dwSessionType == DVTRANSPORT_SESSION_CLIENTSERVER )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
BOOL fResult;
|
|
HRESULT hr;
|
|
|
|
hr = m_lpTransport->IsValidGroup( dvid, &fResult );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Error confirming valid group hr=0x%x", hr );
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return fResult;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmValidEntity"
|
|
//
|
|
// ConfirmValidEntity
|
|
//
|
|
// Checks to ensure that the ID passed is a valid one for the session.
|
|
//
|
|
// Will return TRUE if the player iD is one of:
|
|
// DVID_ALLPLAYERS, DVID_NOTARGET, (any value in client/server mode),
|
|
// a player in the map, or a valid Transport group.
|
|
//
|
|
BOOL CDirectVoiceDirectXTransport::ConfirmValidEntity( DVID dvid )
|
|
{
|
|
if( m_dvTransportInfo.dwSessionType == DVTRANSPORT_SESSION_CLIENTSERVER )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
BOOL fResult;
|
|
m_lpTransport->IsValidEntity( dvid, &fResult );
|
|
return fResult;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::EnableReceiveHook"
|
|
//
|
|
// EnableReceiveHook
|
|
//
|
|
// This is used to activate the connection between the transport
|
|
// and the transport class.
|
|
//
|
|
// We call advise, which will cause Initialize to be called on this
|
|
// class before we return from Advise.
|
|
//
|
|
HRESULT CDirectVoiceDirectXTransport::EnableReceiveHook( LPDIRECTVOICEOBJECT dvObject, DWORD dwObjectType )
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_lpVoiceEngine = dvObject->lpDVEngine;
|
|
m_dwObjectType = dwObjectType;
|
|
|
|
// The transport will call Initialize on our notification interface
|
|
// before returning from this function.
|
|
//
|
|
// Once we've returned from this function we should be ok.
|
|
// FYI: This is safe, but using QueryInterface would be more "correct". However, we would
|
|
// need to determine if this is a client or a server and call the appropriate QueryInterface.
|
|
hr = m_lpTransport->Advise( (LPUNKNOWN) dvObject, m_dwObjectType );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Advise failed. hr=0x%x", hr );
|
|
m_fAdvised = FALSE;
|
|
}
|
|
else
|
|
{
|
|
m_fAdvised = TRUE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::DisableReceiveHook"
|
|
HRESULT CDirectVoiceDirectXTransport::WaitForDetachCompletion()
|
|
{
|
|
DPFX(DPFPREP, DVF_DISCONNECT_PROCEDURE_DEBUG_LEVEL, "# of threads remaining: %d", m_lRefCount );
|
|
|
|
// Loop until all threads are done inside our layer
|
|
while( m_lRefCount > 0 )
|
|
Sleep( 5 );
|
|
|
|
return DV_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::DisableReceiveHook"
|
|
//
|
|
// DisableReceiveHook
|
|
//
|
|
// Removes the hooks into the transport and releases the interface
|
|
// reference this object holds for the transport.
|
|
//
|
|
// Also responsible for destroying the list of players maintained
|
|
// by this object.
|
|
//
|
|
HRESULT CDirectVoiceDirectXTransport::DisableReceiveHook( )
|
|
{
|
|
if( m_fAdvised )
|
|
{
|
|
m_lpTransport->UnAdvise( m_dwObjectType );
|
|
|
|
m_fAdvised = FALSE;
|
|
|
|
m_initialized = FALSE;
|
|
|
|
DPFX(DPFPREP, DVF_DISCONNECT_PROCEDURE_DEBUG_LEVEL, "Unhooking Transport" );
|
|
}
|
|
|
|
// When this is done no more indications will be waiting.
|
|
|
|
return DV_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmLocalHost"
|
|
BOOL CDirectVoiceDirectXTransport::ConfirmLocalHost( )
|
|
{
|
|
if( !m_initialized )
|
|
m_lpTransport->GetSessionInfo( &m_dvTransportInfo );
|
|
|
|
if( m_dvTransportInfo.dwFlags & DVTRANSPORT_LOCALHOST )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmSessionActive"
|
|
BOOL CDirectVoiceDirectXTransport::ConfirmSessionActive( )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::GetTransportSettings"
|
|
HRESULT CDirectVoiceDirectXTransport::GetTransportSettings( LPDWORD lpdwSessionType, LPDWORD lpdwFlags )
|
|
{
|
|
HRESULT hr = DV_OK;
|
|
|
|
if( !m_initialized )
|
|
hr = m_lpTransport->GetSessionInfo( &m_dvTransportInfo );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to retrieve transport settings" );
|
|
return hr;
|
|
}
|
|
|
|
*lpdwSessionType = m_dvTransportInfo.dwSessionType;
|
|
*lpdwFlags = m_dvTransportInfo.dwFlags;
|
|
|
|
return DV_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::AddPlayerEntry"
|
|
HRESULT CDirectVoiceDirectXTransport::AddPlayerEntry( DVID dvidPlayer, LPVOID lpData )
|
|
{
|
|
return DVERR_NOTSUPPORTED;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::DeletePlayerEntry"
|
|
HRESULT CDirectVoiceDirectXTransport::DeletePlayerEntry( DVID dvidPlayer )
|
|
{
|
|
return DVERR_NOTSUPPORTED;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::GetPlayerEntry"
|
|
//
|
|
// GetPlayerEntry
|
|
//
|
|
// Retrieves the player record for the specified player (if it exists).
|
|
//
|
|
HRESULT CDirectVoiceDirectXTransport::GetPlayerEntry( DVID dvidPlayer, CVoicePlayer **lplpPlayer )
|
|
{
|
|
return DVERR_NOTSUPPORTED;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// USEFUL FOR REMOTE VOICE SESSIONS
|
|
//
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::CreateGroup"
|
|
HRESULT CDirectVoiceDirectXTransport::CreateGroup( LPDVID dvidGroup )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::DeleteGroup"
|
|
HRESULT CDirectVoiceDirectXTransport::DeleteGroup( DVID dvidGroup )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::AddPlayerToGroup"
|
|
HRESULT CDirectVoiceDirectXTransport::AddPlayerToGroup( LPDVID dvidGroup, DVID dvidPlayer )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::RemovePlayerFromGroup"
|
|
HRESULT CDirectVoiceDirectXTransport::RemovePlayerFromGroup( DVID dvidGroup, DVID dvidPlayer )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::IsPlayerInGroup"
|
|
BOOL CDirectVoiceDirectXTransport::IsPlayerInGroup( DVID dvidGroup, DVID dvidPlayer )
|
|
{
|
|
if( dvidGroup == DVID_ALLPLAYERS )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if( dvidGroup == dvidPlayer )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return (m_lpTransport->IsGroupMember( dvidGroup, dvidPlayer )==DV_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::MigrateHost"
|
|
//
|
|
// MigrateHost
|
|
//
|
|
// Updates server DPID to match new host
|
|
//
|
|
HRESULT CDirectVoiceDirectXTransport::MigrateHost( DVID dvidNewHost )
|
|
{
|
|
DPFX(DPFPREP, DVF_HOSTMIGRATE_DEBUG_LEVEL, "HOST MIGRATION: Setting host to 0x%x", dvidNewHost );
|
|
m_dpidServer = dvidNewHost;
|
|
|
|
return DV_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirectVoiceDirectXTransport::MigrateHost"
|
|
DVID CDirectVoiceDirectXTransport::GetLocalID()
|
|
{
|
|
m_dwDuumy = m_dpidLocalPlayer;
|
|
return m_dpidLocalPlayer;
|
|
}
|
|
|
|
|