Leaked source code of windows server 2003
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.

2790 lines
85 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dvserverengine.cpp
  6. * Content: Implements the CDirectVoiceServerEngine class.
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 07/18/99 rodtoll Created It
  12. * 07/22/99 rodtoll Added multiple reader/single writer guard to class
  13. * Added use of new player information handlers
  14. * Added additional error checks
  15. * 07/23/99 rodtoll Completed client/server support
  16. * Bugfixes to client/server
  17. * Multicast support to the server
  18. * 07/26/99 rodtoll Updated to use new method for communicating with
  19. * the transport.
  20. * 07/29/99 pnewson Updated call to CInputQueue2 constructor
  21. * 08/03/99 pnewson Cleanup of Frame and Queue classes
  22. * 08/03/99 rodtoll Removed async flag from send calls, not needed
  23. * 08/05/99 rodtoll Fixed locking, was causing deadlock w/DirectPlay
  24. * 08/10/99 rodtoll Removed TODO pragmas
  25. * 08/18/99 rodtoll Modified speech transmission behaviour from server.
  26. * To allow server to distinguish bounced speech from
  27. * client speech, server now sends SPEECHBOUNCED
  28. * message types.
  29. * 08/25/99 rodtoll Fixed speech receive so it records target of audio
  30. * 08/25/99 rodtoll General Cleanup/Modifications to support new
  31. * compression sub-system.
  32. * Added parameters to GetCompression func
  33. * 08/26/99 rodtoll Added more debug statements & shutdown call on session stop
  34. * 08/30/99 rodtoll Updated to allow client/server mode Mixing/Multicast sessions
  35. * 09/01/99 rodtoll Added check for valid pointers in func calls
  36. * 09/02/99 rodtoll Added checks to handle case no local player created
  37. * 09/04/99 rodtoll Added new "echo server" mode to the server
  38. * 09/07/99 rodtoll Implemented SetTransmitTarget and GetTransmitTarget
  39. * 09/10/99 rodtoll Fixed bug with StartSession parameter validation
  40. * rodtoll Bug w/check for current status in StartSession
  41. * 09/14/99 rodtoll Added new SetNotifyMask function
  42. * rodtoll Updated Iniitalize parameters to take notification masks.
  43. * rodtoll Implemented notification masks. (Allows user to choose which notifications to receive)
  44. * 09/15/99 rodtoll Fixed bug with target set proper usage checking and client/server mode checking
  45. * 09/20/99 rodtoll Added more memory alloc failure checks
  46. * rodtoll Added error handling for client/server mixing thread
  47. * rodtoll Updated error handling so when session lost send session lost message
  48. * rodtoll Tightened checks for valid Notify Masks
  49. * rodtoll Added proper error checking to SetNotifyMask
  50. * 09/28/99 rodtoll Fixed StopSession for host migration. Won't send SessionLost messages to players
  51. * if stopping and host migration is available
  52. * 10/04/99 rodtoll Added usage of the DVPROTOCOL_VERSION_XXX macros
  53. * rodtoll Additional documentation/DPFs
  54. * 10/18/99 rodtoll Fix: Calling Initialize twice doesn't fail
  55. * 10/20/99 rodtoll Fix: Bug #114114 - StartSession takes invalid parameters
  56. * 10/25/99 rodtoll Fix: Bug #114684 - GetCaps causes lockup on shutdown
  57. * rodtoll Fix: Bug #114682 - SetSessionDesc crashes when you specify NULL
  58. * rodtoll Fix: Bug #114223 - Debug messages being printed at error level when inappropriate
  59. * 10/29/99 rodtoll Bug #113726 - Integrate Voxware Codecs, updating to use new
  60. * pluggable codec architecture.
  61. * 11/17/99 rodtoll Fix: Bug #115538 - dwSize members of > sizeof struct were accepted
  62. * rodtoll Fix: Bug #115823 - Passing NULL for buffer size in GetCompressionTypes crashes
  63. * rodtoll Fix: Bug #115827 - Calling SetNotifyMask when there is no callback should fail
  64. * rodtoll Fix: Bug #116440 - Remove unused flags
  65. * rodtoll Fix: Bug #117447 - GetTransmitTarget has problems
  66. * 11/22/99 rodtoll Fixed Initialize() would fail incorrectly
  67. * 11/23/99 rodtoll Updated Initialize/SetNotifyMask so error checking behaviour is consistant
  68. * rodtoll Updated GetTransmitTarget to release lock while calling into dplay
  69. * 11/23/99 rodtoll Split CheckForValid into Group and Player
  70. * 12/06/99 rodtoll Bumped playback/record threads to time critical priority
  71. * 12/16/99 rodtoll Fix: Bug #122629 - Host migration broken in unusual configurations.
  72. * Updated to use new algorithm described in dvprot.h
  73. * - Generate and added host order IDs to player table messages
  74. * - Added send of new hostmigrateleave message when shutting down and
  75. * host should migrate
  76. * - Sends session lost when shutting down if no one available to take over hosting
  77. * - Added new player list message
  78. * - Fixed handling of refusing player connections
  79. * 01/14/2000 rodtoll Updated to allow multiple targets for a single player
  80. * rodtoll Updated to use FPM for managing memory for Multicast mode
  81. * rodtoll Updated to use new callback semantics
  82. * rodtoll Removed DVFLAGS_SYNC as a valid flag for StartSession/StopSession
  83. * rodtoll Removed DVMSGID_STARTSESSIONRESULT / DVMSGID_STOPSESSIONRESULT
  84. * 03/29/2000 rodtoll Updated to use new nametable / more efficient locking
  85. * rodtoll Modified calls to ConfirmValidEntity to check the nametable instead
  86. * 04/07/2000 rodtoll Bug #32179 - Prevent registration of > 1 interface
  87. * rodtoll Updated to use no copy sends, so handles pooling frames to be sent, proper
  88. * pulling of frames from pools and returns.
  89. * 05/31/2000 rodtoll Bug #35860 - Fix VC6 compile errors for instrumented builds
  90. * 06/02/2000 rodtoll Moved host migration so it is keyed off voice message and transport messages.
  91. * More reliable this way.
  92. * 06/15/2000 rodtoll Bug #36794 - dwIndex build error with old compiler fixed
  93. * 06/21/2000 rodtoll Bug #36820 - Host migration failure when local client is next host.
  94. * Updated shutdown sequence to deregister server before sending out hostmigrateleave
  95. * 06/27/2000 rodtoll Bug #37604 - Voice objects don't get SESSION_LOST when transport session is closed
  96. * Added send of session lost message in this case.
  97. * rodtoll Fixed window which would cause crash when outstanding sends are completed after we
  98. * have deregistered -- we now wait.
  99. * 06/28/2000 rodtoll Prefix Bug #38022
  100. * 07/01/2000 rodtoll Bug #38280 - DVMSGID_DELETEVOICEPLAYER messages are being sent in non-peer to peer sessions
  101. * 07/09/2000 rodtoll Added signature bytes
  102. * 07/22/2000 rodtoll Bug #40284 - Initialize() and SetNotifyMask() should return invalidparam instead of invalidpointer
  103. * rodtoll Bug #40296, 38858 - Crashes due to shutdown race condition
  104. * Now ensures that all threads from transport have left and that
  105. * all notificatinos have been processed before shutdown is complete.
  106. * rodtoll Bug #39586 - Trap 14 in DPVVOX.DLL during session of voicegroup, adding guards for overwrites
  107. * 07/26/2000 rodtoll Bug #40607 - DPVoice: Problems with Mixing serer when there are more then 3 clients connected to a server and 2 of the transmit
  108. * Logic bug caused all people reusing mix to get garbage
  109. * 08/03/2000 rodtoll Bug #41320 - DirectPlayVoice servers will reject connections from newer clients
  110. * 08/08/2000 rodtoll Was missing a DNLeaveCriticalSection during shutdown
  111. * 08/25/2000 rodtoll Bug #43485 - Memory leak -- Session Lost case leaks one buffer
  112. * 08/28/2000 masonb Voice Merge: DNet FPOOLs use DNCRITICAL_SECTION, modified m_pBufferDescPool usage
  113. * 09/01/2000 masonb Modified Mixer to call _endthread to clean up thread handle
  114. * 09/14/2000 rodtoll Bug #45001 - DVOICE: AV if client has targetted > 10 players
  115. * 09/28/2000 rodtoll Fix Again: Bug #45541 - DPVOICE: Client gets DVERR_TIMEOUT message when disconnecting (Server always confirms disconnect)
  116. * 11/16/2000 rodtoll Bug #40587 - DPVOICE: Mixing server needs to use multi-processors
  117. * 11/28/2000 rodtoll Bug #47333 - DPVOICE: Server controlled targetting - invalid targets are not removed automatically
  118. * 04/02/2001 simonpow Bug #354859 - Fixes for PREfast spotted problems. (HRESULT to BOOL casting)
  119. * 04/06/2001 kareemc Added Voice Defense
  120. * 04/09/2001 rodtoll WINBUG #364126 - DPVoice : Memory leak when Initializing 2 Voice Servers with same DPlay transport
  121. * 09/05/2001 simonpow Bug #463972. Added constuct/destruct methods to initialisation
  122. * calls on m_fpPlayers for CVoicePlayer and CDVCSPlayer
  123. * 02/28/2002 rodtoll WINBUG #549959 - SECURITY: DPVOICE: Voice server trusts client's target list
  124. * - Update receive path to use server's copy of client target list when server controlled targetting enabled
  125. * rodtoll WINBUG #549943 - SECURITY: DPVOICE: Possible corruption of voice server state
  126. * - Harden receive paths - i.e. ensure host migration processing only when host migration available,
  127. * prevent double disconnects from crashing server
  128. * rodtoll WINBUG #550124 - SECURITY: DPVOICE: Shared memory region with NULL DACL
  129. * - Remove performance statistics dumping to shared memory
  130. * 03/01/2002 simonpow Bug #549974 Added anti-hack check for incoming packet
  131. * rate to HandleSpeechWithTarget method
  132. * 06/13/2002 simonpow BUG #59944 Switched over to using Threadpool based timers rather than multimedia
  133. ***************************************************************************/
  134. #include "dxvoicepch.h"
  135. #define SERVER_POOLS_NUM 3
  136. #define SERVER_POOLS_SIZE_MESSAGE (sizeof(DVPROTOCOLMSG_FULLMESSAGE))
  137. #define SERVER_POOLS_SIZE_PLAYERLIST DVPROTOCOL_PLAYERLIST_MAXSIZE
  138. #undef DPF_MODNAME
  139. #define DPF_MODNAME "CDirectVoiceServerEngine::CDirectVoiceServerEngine"
  140. //
  141. // Constructor
  142. //
  143. // Initializes the object into the uninitialized state
  144. //
  145. CDirectVoiceServerEngine::CDirectVoiceServerEngine( DIRECTVOICESERVEROBJECT *lpObject
  146. ): m_dwSignature(VSIG_SERVERENGINE),
  147. m_lpMessageHandler(NULL),
  148. m_lpUserContext(NULL),
  149. m_lpObject(lpObject),
  150. m_dvidLocal(0),
  151. m_dwCurrentState(DVSSTATE_NOTINITIALIZED),
  152. m_lpSessionTransport(NULL),
  153. m_lpdwMessageElements(NULL),
  154. m_dwNumMessageElements(0),
  155. m_dwNextHostOrderID(0),
  156. m_pBufferPools(NULL),
  157. m_pdwBufferPoolSizes(NULL),
  158. m_hMixerControlThread(NULL),
  159. m_dwMixerControlThreadID(0),
  160. m_pStats(NULL),
  161. m_fCritSecInited(FALSE),
  162. m_fHostMigrationEnabled(FALSE)
  163. {
  164. memset( &m_dvCaps, 0x00, sizeof( DVCAPS ) );
  165. m_dvCaps.dwSize = sizeof( DVCAPS );
  166. m_dvCaps.dwFlags = 0;
  167. }
  168. #undef DPF_MODNAME
  169. #define DPF_MODNAME "CDirectVoiceServerEngine::InitClass"
  170. CDirectVoiceServerEngine::InitClass( )
  171. {
  172. if (!DNInitializeCriticalSection( &m_csMixingAddList ))
  173. {
  174. return FALSE;
  175. }
  176. if (!DNInitializeCriticalSection( &m_csPlayerActiveList ))
  177. {
  178. DNDeleteCriticalSection( &m_csMixingAddList );
  179. return FALSE;
  180. }
  181. if (!DNInitializeCriticalSection( &m_csHostOrderLock ))
  182. {
  183. DNDeleteCriticalSection( &m_csPlayerActiveList );
  184. DNDeleteCriticalSection( &m_csMixingAddList );
  185. return FALSE;
  186. }
  187. if (!DNInitializeCriticalSection( &m_csBufferLock ))
  188. {
  189. DNDeleteCriticalSection( &m_csHostOrderLock );
  190. DNDeleteCriticalSection( &m_csPlayerActiveList );
  191. DNDeleteCriticalSection( &m_csMixingAddList );
  192. return FALSE;
  193. }
  194. if (!DNInitializeCriticalSection( &m_csClassLock ))
  195. {
  196. DNDeleteCriticalSection( &m_csBufferLock );
  197. DNDeleteCriticalSection( &m_csHostOrderLock );
  198. DNDeleteCriticalSection( &m_csPlayerActiveList );
  199. DNDeleteCriticalSection( &m_csMixingAddList );
  200. return FALSE;
  201. }
  202. if (!DNInitializeCriticalSection( &m_csStats ))
  203. {
  204. DNDeleteCriticalSection( &m_csClassLock );
  205. DNDeleteCriticalSection( &m_csBufferLock );
  206. DNDeleteCriticalSection( &m_csHostOrderLock );
  207. DNDeleteCriticalSection( &m_csPlayerActiveList );
  208. DNDeleteCriticalSection( &m_csMixingAddList );
  209. return FALSE;
  210. }
  211. if (!DNInitializeCriticalSection( &m_csNotifyLock ))
  212. {
  213. DNDeleteCriticalSection( &m_csStats );
  214. DNDeleteCriticalSection( &m_csClassLock );
  215. DNDeleteCriticalSection( &m_csBufferLock );
  216. DNDeleteCriticalSection( &m_csHostOrderLock );
  217. DNDeleteCriticalSection( &m_csPlayerActiveList );
  218. DNDeleteCriticalSection( &m_csMixingAddList );
  219. return FALSE;
  220. }
  221. m_fCritSecInited = TRUE;
  222. return TRUE;
  223. }
  224. #undef DPF_MODNAME
  225. #define DPF_MODNAME "CDirectVoiceServerEngine::~CDirectVoiceServerEngine"
  226. //
  227. // Destructor
  228. //
  229. // Frees the resources associated with the server. Shuts the server down
  230. // if it is running.
  231. //
  232. // Server objects should never be destructed directly, the COM Release
  233. // method should be used.
  234. //
  235. // Called By:
  236. // DVS_Release (When reference count reaches 0)
  237. //
  238. // Locks Required:
  239. // - Global Write Lock
  240. //
  241. CDirectVoiceServerEngine::~CDirectVoiceServerEngine()
  242. {
  243. HRESULT hr;
  244. // Stop the session if it's running.
  245. hr = StopSession(0, FALSE , DV_OK );
  246. if( hr != DV_OK && hr != DVERR_NOTHOSTING )
  247. {
  248. DPFX(DPFPREP, DVF_ERRORLEVEL, "StopSession Failed hr=0x%x", hr );
  249. }
  250. DNEnterCriticalSection( &m_csClassLock );
  251. if( m_lpdwMessageElements != NULL )
  252. delete [] m_lpdwMessageElements;
  253. DNLeaveCriticalSection( &m_csClassLock );
  254. if (m_fCritSecInited)
  255. {
  256. DNDeleteCriticalSection( &m_csMixingAddList );
  257. DNDeleteCriticalSection( &m_csHostOrderLock );
  258. DNDeleteCriticalSection( &m_csPlayerActiveList );
  259. DNDeleteCriticalSection( &m_csBufferLock );
  260. DNDeleteCriticalSection( &m_csClassLock );
  261. DNDeleteCriticalSection( &m_csNotifyLock );
  262. DNDeleteCriticalSection( &m_csStats );
  263. }
  264. m_dwSignature = VSIG_SERVERENGINE_FREE;
  265. }
  266. #undef DPF_MODNAME
  267. #define DPF_MODNAME "CDirectVoiceServerEngine::TransmitMessage"
  268. //
  269. // TransmitMessage
  270. //
  271. // This function sends a notification to the notification handler. Before transmitting
  272. // it, the notify elements are checked to ensure the specified notification is activated.
  273. // (or notification array is NULL).
  274. //
  275. // Called By:
  276. // - Multiple locations throughout dvsereng.cpp
  277. //
  278. // Locks Required:
  279. // - m_csNotifyLock - The notification lock
  280. //
  281. void CDirectVoiceServerEngine::TransmitMessage( DWORD dwMessageType, LPVOID lpdvData, DWORD dwSize )
  282. {
  283. if( m_lpMessageHandler != NULL )
  284. {
  285. BFCSingleLock slLock( &m_csNotifyLock );
  286. slLock.Lock();
  287. BOOL fSend = FALSE;
  288. if( m_dwNumMessageElements == 0 )
  289. {
  290. fSend = TRUE;
  291. }
  292. else
  293. {
  294. for( DWORD dwIndex = 0; dwIndex < m_dwNumMessageElements; dwIndex++ )
  295. {
  296. if( m_lpdwMessageElements[dwIndex] == dwMessageType )
  297. {
  298. fSend = TRUE;
  299. break;
  300. }
  301. }
  302. }
  303. if( fSend )
  304. {
  305. (*m_lpMessageHandler)( m_lpUserContext, dwMessageType,lpdvData );
  306. }
  307. }
  308. }
  309. // Handles initializing a server object for host migration
  310. #undef DPF_MODNAME
  311. #define DPF_MODNAME "CDirectVoiceServerEngine::HostMigrateStart"
  312. //
  313. // HostMigrateStart
  314. //
  315. // This function is called on the object which is to become the new host when
  316. // the host migrates. It is used instead of the traditional startup to
  317. // ensure that the object is initialized correctly in the migration case.
  318. //
  319. // Called By:
  320. // - DV_HostMigrate
  321. //
  322. // Locks Required:
  323. // - None
  324. //
  325. HRESULT CDirectVoiceServerEngine::HostMigrateStart(LPDVSESSIONDESC lpSessionDesc, DWORD dwHostOrderIDSeed )
  326. {
  327. HRESULT hr;
  328. DPFX(DPFPREP, DVF_ENTRYLEVEL, "DVSE::HostMigrateStart() Begin" );
  329. // Start
  330. hr = StartSession( lpSessionDesc, 0, dwHostOrderIDSeed );
  331. // Fail
  332. if( hr != DV_OK )
  333. {
  334. DPFX(DPFPREP, DVF_ERRORLEVEL, "CDirectVoiceServerEngine::HostMigrateStart Failed Hr=0x%x", hr );
  335. return hr;
  336. }
  337. hr = InformClientsOfMigrate();
  338. if( FAILED( hr ) )
  339. {
  340. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to inform users of host migration hr=0x%x", hr );
  341. }
  342. return hr;
  343. }
  344. #undef DPF_MODNAME
  345. #define DPF_MODNAME "CDirectVoiceServerEngine::InformClientsOfMigrate"
  346. //
  347. //
  348. // This function will
  349. //
  350. HRESULT CDirectVoiceServerEngine::InformClientsOfMigrate()
  351. {
  352. DPFX(DPFPREP, DVF_ERRORLEVEL, "Informing clients of migration" );
  353. return Send_HostMigrated();
  354. }
  355. #undef DPF_MODNAME
  356. #define DPF_MODNAME "CDirectVoiceServerEngine::StartSession"
  357. //
  358. // StartSession
  359. //
  360. // This function handles starting the directplayvoice session in the associated directplay/net
  361. // session. It also handles startup for a new host when the host migrates. (Called by
  362. // HostMigrateStart in this case).
  363. //
  364. // Called By:
  365. // - DV_StartSession
  366. // - HostMigrateStart
  367. //
  368. // Locks Required:
  369. // - Global Write Lock
  370. //
  371. HRESULT CDirectVoiceServerEngine::StartSession(LPDVSESSIONDESC lpSessionDesc, DWORD dwFlags, DWORD dwHostOrderIDSeed )
  372. {
  373. HRESULT hr;
  374. BOOL fPoolsInit = FALSE;
  375. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter" );
  376. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  377. DPFX(DPFPREP, DVF_APIPARAM, "Param: lpSessionDesc = 0x%p dwFlags = 0x%x", lpSessionDesc, dwFlags );
  378. if( dwFlags !=0 )
  379. {
  380. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid flags specified" );
  381. return DVERR_INVALIDFLAGS;
  382. }
  383. hr = DV_ValidSessionDesc( lpSessionDesc );
  384. if( FAILED( hr ) )
  385. {
  386. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error validating session description. hr=0x%x", hr );
  387. return hr;
  388. }
  389. DV_DUMP_SD( lpSessionDesc );
  390. CDVCSLock guardLock(&m_csClassLock);
  391. guardLock.Lock();
  392. switch( m_dwCurrentState )
  393. {
  394. case DVSSTATE_SHUTDOWN:
  395. case DVSSTATE_RUNNING:
  396. case DVSSTATE_STARTUP:
  397. DPFX(DPFPREP, DVF_ERRORLEVEL, "Session is already in progress." );
  398. return DVERR_HOSTING;
  399. case DVSSTATE_NOTINITIALIZED:
  400. DPFX(DPFPREP, DVF_ERRORLEVEL, "Object not initialized" );
  401. return DVERR_NOTINITIALIZED;
  402. }
  403. if( m_lpSessionTransport == NULL )
  404. {
  405. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid transport" );
  406. return DVERR_INVALIDOBJECT;
  407. }
  408. m_pTimer = NULL;
  409. m_hTickSemaphore = NULL;
  410. m_hShutdownMixerEvent = NULL;
  411. m_hMixerDoneEvent = NULL;
  412. m_prWorkerControl = NULL;
  413. m_pFramePool = NULL;
  414. // Retrieve the information about the dplay/dnet session
  415. hr = m_lpSessionTransport->GetTransportSettings( &m_dwTransportSessionType, &m_dwTransportFlags );
  416. if( FAILED( hr ) )
  417. {
  418. DPFX(DPFPREP, DVF_ERRORLEVEL, "Could not retrieve transport settings hr=0x%x", hr );
  419. return hr;
  420. }
  421. // Peer-to-peer mode not available in client/server mode
  422. if( m_dwTransportSessionType == DVTRANSPORT_SESSION_CLIENTSERVER &&
  423. (lpSessionDesc->dwSessionType == DVSESSIONTYPE_PEER) )
  424. {
  425. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot host peer session in client/server transport" );
  426. return DVERR_NOTSUPPORTED;
  427. }
  428. // Server control target not available if host migration is enabled
  429. if( (m_dwTransportFlags & DVTRANSPORT_MIGRATEHOST) &&
  430. (lpSessionDesc->dwFlags & DVSESSION_SERVERCONTROLTARGET) )
  431. {
  432. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot support host migration with server controlled targetting" );
  433. return DVERR_NOTSUPPORTED;
  434. }
  435. if( m_dwTransportFlags & DVTRANSPORT_MIGRATEHOST &&
  436. (lpSessionDesc->dwSessionType == DVSESSIONTYPE_MIXING ||
  437. lpSessionDesc->dwSessionType == DVSESSIONTYPE_ECHO) )
  438. {
  439. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot support host migration for mixing or echo servers" );
  440. return DVERR_NOTSUPPORTED;
  441. }
  442. hr = DVCDB_GetCompressionInfo( lpSessionDesc->guidCT, &m_lpdvfCompressionInfo );
  443. if( FAILED( hr ) )
  444. {
  445. DPFX(DPFPREP, DVF_ERRORLEVEL, "Compression type not supported. hr=0x%x", hr );
  446. return DVERR_COMPRESSIONNOTSUPPORTED;
  447. }
  448. m_dwCompressedFrameSize = m_lpdvfCompressionInfo->dwFrameLength;
  449. SetCurrentState( DVSSTATE_STARTUP );
  450. // Scrub the session description
  451. memcpy( &m_dvSessionDesc, lpSessionDesc, sizeof( DVSESSIONDESC ) );
  452. // Needs to be here, AFTER the memcpy of the sessiondesc
  453. m_fHostMigrationEnabled = IsHostMigrationEnabled();
  454. if( m_dvSessionDesc.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  455. {
  456. m_dvSessionDesc.dwBufferAggressiveness = s_dwDefaultBufferAggressiveness;
  457. }
  458. if( m_dvSessionDesc.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  459. {
  460. m_dvSessionDesc.dwBufferQuality = s_dwDefaultBufferQuality;
  461. }
  462. m_dwNextHostOrderID = dwHostOrderIDSeed;
  463. m_pStats = &m_statMixingFixed;
  464. m_pServerStats = &m_dvsServerStatsFixed;
  465. // Reset statistics
  466. ZeroMemory( m_pStats, sizeof( MixingServerStats ) );
  467. ZeroMemory( m_pServerStats, sizeof( ServerStats ) );
  468. memcpy( &m_pServerStats->m_dvSessionDesc, &m_dvSessionDesc, sizeof( DVSESSIONDESC ) );
  469. hr = SetupBuffers();
  470. if( FAILED( hr ) )
  471. {
  472. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to setup buffer pools hr=0x%x", hr );
  473. goto STARTSESSION_FAILURE;
  474. }
  475. if( lpSessionDesc->dwSessionType == DVSESSIONTYPE_FORWARDING )
  476. {
  477. hr = StartupMulticast();
  478. if( FAILED( hr ) )
  479. {
  480. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to initializing multicast hr=0x%x", hr );
  481. goto STARTSESSION_FAILURE;
  482. }
  483. }
  484. // Setup name table
  485. hr = m_voiceNameTable.Initialize();
  486. if( FAILED( hr ) )
  487. {
  488. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to initialize nametable hr=0x%x", hr );
  489. goto STARTSESSION_FAILURE;
  490. }
  491. // Initialize player allocation pools
  492. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  493. {
  494. fPoolsInit = m_fpPlayers.Initialize(sizeof(CDVCSPlayer),
  495. CDVCSPlayer::PoolAllocFunction, NULL, NULL, CDVCSPlayer::PoolDeallocFunction);
  496. }
  497. else
  498. {
  499. fPoolsInit = m_fpPlayers.Initialize(sizeof(CVoicePlayer),
  500. CVoicePlayer::PoolAllocFunction, NULL, NULL, CVoicePlayer::PoolDeallocFunction);
  501. }
  502. m_blPlayerActiveList.Initialize();
  503. SetCurrentState( DVSSTATE_RUNNING );
  504. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  505. {
  506. hr = StartupClientServer();
  507. if( FAILED( hr ) )
  508. {
  509. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to startup client/server hr=0x%x", hr );
  510. goto STARTSESSION_FAILURE;
  511. }
  512. }
  513. // Tell DirectPlay we're alive and want to see incoming traffic
  514. hr = m_lpSessionTransport->EnableReceiveHook( m_lpObject, DVTRANSPORT_OBJECTTYPE_SERVER );
  515. if( FAILED( hr ) )
  516. {
  517. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed on call to EnableReceiveHook hr=0x%x", hr );
  518. goto STARTSESSION_FAILURE;
  519. }
  520. STARTSESSION_RETURN:
  521. guardLock.Unlock();
  522. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Success" );
  523. return hr;
  524. STARTSESSION_FAILURE:
  525. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  526. {
  527. ShutdownClientServer();
  528. }
  529. else if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_FORWARDING )
  530. {
  531. ShutdownMulticast();
  532. }
  533. m_voiceNameTable.DeInitialize(TRUE, m_lpUserContext,m_lpMessageHandler);
  534. // Initialize player allocation pools
  535. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  536. {
  537. delete m_pFramePool;
  538. m_pFramePool = NULL;
  539. }
  540. if( fPoolsInit )
  541. {
  542. m_fpPlayers.DeInitialize();
  543. }
  544. FreeBuffers();
  545. SetCurrentState( DVSSTATE_IDLE );
  546. goto STARTSESSION_RETURN;
  547. }
  548. #undef DPF_MODNAME
  549. #define DPF_MODNAME "CDirectVoiceServerEngine::CheckForMigrate"
  550. BOOL CDirectVoiceServerEngine::CheckForMigrate( DWORD dwFlags, BOOL fSilent )
  551. {
  552. // We should shutdown the session if:
  553. //
  554. // 1. We're not in peer to peer mode
  555. // 2. "No host migration" flag was specified in session description
  556. // 3. "No host migrate" flag was specified on call to StopSession
  557. // 4. We were not asked to be silent
  558. // 5. There isn't a host migrate
  559. //
  560. if( (m_dvSessionDesc.dwSessionType != DVSESSIONTYPE_PEER ) ||
  561. (m_dvSessionDesc.dwFlags & DVSESSION_NOHOSTMIGRATION) ||
  562. (dwFlags & DVFLAGS_NOHOSTMIGRATE) ||
  563. fSilent ||
  564. !(m_dwTransportFlags & DVTRANSPORT_MIGRATEHOST) )
  565. {
  566. DPFX(DPFPREP, DVF_ERRORLEVEL, "Destroying session." );
  567. return FALSE;
  568. }
  569. // A migration is possible
  570. else
  571. {
  572. return TRUE;
  573. /*
  574. THIS IS DISABLED BECAUSE OF a race condition where the server has not yet
  575. received notifications from all players in the session and therefore may
  576. think (incorrectly) that there is no one left.
  577. // We look for at least one client who hasn't marked themselves
  578. // as notpeerhost
  579. //
  580. DVID dvidNewHost;
  581. DWORD dwNewHostOrder = m_voiceNameTable.GetLowestHostOrderID(&dvidNewHost);
  582. if( dwNewHostOrder != DVPROTOCOL_HOSTORDER_INVALID )
  583. {
  584. DPFX(DPFPREP, DVF_ERRORLEVEL, "Found at least one client who can become host. (It's 0x%x)", dvidNewHost );
  585. return TRUE;
  586. }
  587. else
  588. {
  589. DPFX(DPFPREP, DVF_ERRORLEVEL, "Could not find a client to become host" );
  590. return FALSE;
  591. }
  592. */
  593. }
  594. }
  595. #undef DPF_MODNAME
  596. #define DPF_MODNAME "CDirectVoiceServerEngine::StopSession"
  597. //
  598. // StopSession
  599. //
  600. // This function is responsible for shutting down the directplayvoice session. In sessions
  601. // without host migration, this function will simply cleanup the memory and detach itself
  602. // from directplay. This way directplay will take care of the host migration. To use this
  603. // option, specify fSilent = TRUE.
  604. //
  605. // In addition, this function is called when an fatal error occurs while the session is
  606. // running.
  607. //
  608. // It is also called when the user calls StopSession.
  609. //
  610. // Called By:
  611. // - HandleMixerThreadError
  612. // - HandleStopTransportSession
  613. // - DVS_StopSession
  614. //
  615. // Locks Required:
  616. // - Global Write Lock
  617. //
  618. HRESULT CDirectVoiceServerEngine::StopSession(DWORD dwFlags, BOOL fSilent, HRESULT hrResult )
  619. {
  620. DPFX(DPFPREP, DVF_ENTRYLEVEL, "DVSE::StopSession() Begin" );
  621. DPFX(DPFPREP, DVF_APIPARAM, "Param: dwFlags = 0x%x", dwFlags );
  622. if( dwFlags & ~(DVFLAGS_NOHOSTMIGRATE) )
  623. {
  624. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid flags specified" );
  625. return DVERR_INVALIDFLAGS;
  626. }
  627. CDVCSLock guardLock(&m_csClassLock);
  628. guardLock.Lock();
  629. // We need to be initialized
  630. if( m_dwCurrentState == DVSSTATE_NOTINITIALIZED )
  631. {
  632. DPFX(DPFPREP, DVF_ERRORLEVEL, "Not Initialized" );
  633. return DVERR_NOTINITIALIZED;
  634. }
  635. if( m_dwCurrentState != DVSSTATE_RUNNING )
  636. {
  637. DPFX(DPFPREP, DVF_ERRORLEVEL, "Session is not running" );
  638. return DVERR_NOTHOSTING;
  639. }
  640. // If no host migrate has been specified
  641. if( dwFlags & DVFLAGS_NOHOSTMIGRATE )
  642. m_fHostMigrationEnabled = FALSE;
  643. // Stop client/server thread
  644. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  645. {
  646. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Shutting down client/server" );
  647. ShutdownClientServer();
  648. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Shutting down client/server" );
  649. }
  650. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Waiting for buffer returns." );
  651. // Wait until all the outstanding sends have completed
  652. WaitForBufferReturns();
  653. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Waiting for buffer returns." );
  654. // Disable receives
  655. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Unhook transport." );
  656. m_lpSessionTransport->DisableReceiveHook( );
  657. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Unhook transport." );
  658. // Waits for transport threads to be done inside our layer
  659. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Awaiting detach." );
  660. m_lpSessionTransport->WaitForDetachCompletion();
  661. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Awaiting detach." );
  662. // Check to see if there is migration going on. If a migration should
  663. // happen then we do not transmit a session lost message
  664. //
  665. if( !FAILED( hrResult ) )
  666. {
  667. if( !CheckForMigrate( dwFlags, fSilent ) )
  668. {
  669. DPFX(DPFPREP, DVF_INFOLEVEL, "Host migration not possible. Sending lost session." );
  670. Send_SessionLost( DVERR_SESSIONLOST );
  671. }
  672. // Host is migrating. Inform the users
  673. else if( m_dwTransportFlags & DVTRANSPORT_MIGRATEHOST )
  674. {
  675. DPFX(DPFPREP, DVF_INFOLEVEL, "Host migration begin." );
  676. Send_HostMigrateLeave();
  677. }
  678. }
  679. SetCurrentState( DVSSTATE_SHUTDOWN );
  680. // Disable sends
  681. //m_lpSessionTransport->DestroyTransport();
  682. // Kill name table
  683. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Destroying nametable" );
  684. m_voiceNameTable.DeInitialize(TRUE,m_lpUserContext,m_lpMessageHandler);
  685. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Destroying nametable" );
  686. // Cleanup the active list
  687. CleanupActiveList();
  688. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  689. {
  690. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Cleanup mixing" );
  691. delete m_pFramePool;
  692. m_pFramePool = NULL;
  693. }
  694. else
  695. {
  696. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Cleanup.." );
  697. }
  698. // Kill the FPM
  699. m_fpPlayers.DeInitialize();
  700. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_FORWARDING )
  701. {
  702. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Shutdown forwarding" );
  703. ShutdownMulticast();
  704. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Shutdown forwarding" );
  705. }
  706. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Final cleanup" );
  707. FreeBuffers();
  708. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Final cleanup" );
  709. m_fHostMigrationEnabled = FALSE;
  710. SetCurrentState( DVSSTATE_IDLE );
  711. guardLock.Unlock();
  712. // Check to see if the transport session was closed
  713. if( hrResult == DVERR_SESSIONLOST )
  714. {
  715. DVMSG_SESSIONLOST dvMsgLost;
  716. dvMsgLost.dwSize = sizeof( DVMSG_SESSIONLOST );
  717. dvMsgLost.hrResult = hrResult;
  718. TransmitMessage( DVMSGID_SESSIONLOST, &dvMsgLost, sizeof( DVPROTOCOLMSG_SESSIONLOST ) );
  719. }
  720. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done" );
  721. return DV_OK;
  722. }
  723. // WaitForBufferReturns
  724. //
  725. // This function waits until oustanding sends have completed before continuing
  726. // we use this to ensure we don't deregister with outstanding sends.
  727. //
  728. #undef DPF_MODNAME
  729. #define DPF_MODNAME "CDirectVoiceServerEngine::WaitForBufferReturns"
  730. void CDirectVoiceServerEngine::WaitForBufferReturns()
  731. {
  732. DPFX(DPFPREP, DVF_INFOLEVEL, ">> Waiting for buffer returns. %d remaining", m_BufferDescPool.GetInUseCount() );
  733. while( 1 )
  734. {
  735. if( m_BufferDescPool.GetInUseCount() == 0 )
  736. {
  737. break;
  738. }
  739. Sleep( 20 );
  740. }
  741. DPFX(DPFPREP, DVF_INFOLEVEL, "<< Waiting complete." );
  742. return;
  743. }
  744. #undef DPF_MODNAME
  745. #define DPF_MODNAME "CDirectVoiceServerEngine::GetSessionDesc"
  746. //
  747. // GetSessionDesc
  748. //
  749. // Called to retrieve the description of the current session.
  750. //
  751. // Called By:
  752. // - DVS_GetSessionDesc
  753. //
  754. // Locks Required:
  755. // - Global Read Lock
  756. //
  757. HRESULT CDirectVoiceServerEngine::GetSessionDesc( LPDVSESSIONDESC lpSessionDesc )
  758. {
  759. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter" );
  760. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  761. DPFX(DPFPREP, DVF_APIPARAM, "Param: lpSessionDesc = 0x%p", lpSessionDesc );
  762. if( lpSessionDesc == NULL || !DNVALID_WRITEPTR(lpSessionDesc,sizeof( DVSESSIONDESC )) )
  763. {
  764. DPFX(DPFPREP, DVF_ERRORLEVEL, "Session desc pointer bad" );
  765. return DVERR_INVALIDPOINTER;
  766. }
  767. if( lpSessionDesc->dwSize != sizeof( DVSESSIONDESC ) )
  768. {
  769. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid size on session desc" );
  770. return DVERR_INVALIDPARAM;
  771. }
  772. CDVCSLock guardLock(&m_csClassLock);
  773. guardLock.Lock();
  774. // We need to be initialized
  775. if( m_dwCurrentState == DVSSTATE_NOTINITIALIZED )
  776. {
  777. DPFX(DPFPREP, DVF_ERRORLEVEL, "Not Initialized" );
  778. return DVERR_NOTINITIALIZED;
  779. }
  780. if( m_dwCurrentState != DVSSTATE_RUNNING )
  781. {
  782. DPFX(DPFPREP, DVF_ERRORLEVEL, "No host running" );
  783. return DVERR_NOTHOSTING;
  784. }
  785. memcpy( lpSessionDesc, &m_dvSessionDesc, sizeof( DVSESSIONDESC ) );
  786. DV_DUMP_SD( (LPDVSESSIONDESC) lpSessionDesc );
  787. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done, Returning DV_OK" );
  788. return DV_OK;
  789. }
  790. #undef DPF_MODNAME
  791. #define DPF_MODNAME "CDirectVoiceServerEngine::SetSessionDesc"
  792. //
  793. // SetSessionDesc
  794. //
  795. // Used to set session parameters. The only parameters that can be set are the
  796. // buffer quality and buffer aggresiveness.
  797. //
  798. // Called By:
  799. // - DVS_SetSessionDesc
  800. //
  801. // Locks Required:
  802. // - Global Write Lock
  803. //
  804. HRESULT CDirectVoiceServerEngine::SetSessionDesc(LPDVSESSIONDESC lpSessionDesc )
  805. {
  806. DPFX(DPFPREP, DVF_ENTRYLEVEL, "DVSE::SetSessionDesc() Begin" );
  807. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  808. DPFX(DPFPREP, DVF_APIPARAM, "Param: lpSessionDesc = 0x%p", lpSessionDesc);
  809. if( lpSessionDesc == NULL ||
  810. !DNVALID_READPTR( lpSessionDesc, sizeof(DVSESSIONDESC)) )
  811. {
  812. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid pointer" );
  813. return DVERR_INVALIDPOINTER;
  814. }
  815. DV_DUMP_SD( lpSessionDesc );
  816. if( lpSessionDesc->dwSize != sizeof( DVSESSIONDESC ) )
  817. {
  818. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid size of session desc" );
  819. return DVERR_INVALIDPARAM;
  820. }
  821. if( !DV_ValidBufferAggresiveness( lpSessionDesc->dwBufferAggressiveness ) ||
  822. !DV_ValidBufferQuality( lpSessionDesc->dwBufferQuality) )
  823. {
  824. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid buffer settings" );
  825. return DVERR_INVALIDPARAM;
  826. }
  827. CDVCSLock guardLock(&m_csClassLock);
  828. guardLock.Lock();
  829. // We need to be initialized
  830. if( m_dwCurrentState == DVSSTATE_NOTINITIALIZED )
  831. {
  832. DPFX(DPFPREP, DVF_ERRORLEVEL, "Not Initialized" );
  833. return DVERR_NOTINITIALIZED;
  834. }
  835. if( m_dwCurrentState != DVSSTATE_RUNNING )
  836. {
  837. DPFX(DPFPREP, DVF_ERRORLEVEL, "No session running" );
  838. return DVERR_NOTHOSTING;
  839. }
  840. if( m_dvSessionDesc.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  841. {
  842. m_dvSessionDesc.dwBufferAggressiveness = s_dwDefaultBufferAggressiveness;
  843. }
  844. else
  845. {
  846. m_dvSessionDesc.dwBufferAggressiveness = lpSessionDesc->dwBufferAggressiveness;
  847. }
  848. if( m_dvSessionDesc.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  849. {
  850. m_dvSessionDesc.dwBufferQuality = s_dwDefaultBufferQuality;
  851. }
  852. else
  853. {
  854. m_dvSessionDesc.dwBufferQuality = lpSessionDesc->dwBufferQuality;
  855. }
  856. DPFX(DPFPREP, DVF_ENTRYLEVEL, "End" );
  857. return S_OK;
  858. }
  859. #undef DPF_MODNAME
  860. #define DPF_MODNAME "CDirectVoiceServerEngine::GetCaps"
  861. //
  862. // GetCaps
  863. //
  864. // Retrieves the caps for the DirectPlayVoiceServer object.
  865. //
  866. // Called By:
  867. // - DVS_GetCaps
  868. //
  869. // Locks Required:
  870. //
  871. HRESULT CDirectVoiceServerEngine::GetCaps(LPDVCAPS lpdvCaps)
  872. {
  873. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Begin" );
  874. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  875. DPFX(DPFPREP, DVF_APIPARAM, "Param: lpdvCaps = 0x%p", lpdvCaps );
  876. if( lpdvCaps == NULL ||
  877. !DNVALID_WRITEPTR(lpdvCaps,sizeof(DVCAPS)) )
  878. {
  879. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid pointer" );
  880. return DVERR_INVALIDPOINTER;
  881. }
  882. DV_DUMP_CAPS( lpdvCaps );
  883. if( lpdvCaps->dwSize != sizeof( DVCAPS ) )
  884. {
  885. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid size" );
  886. return DVERR_INVALIDPARAM;
  887. }
  888. CDVCSLock guardLock(&m_csClassLock);
  889. guardLock.Lock();
  890. memcpy( lpdvCaps, &m_dvCaps, sizeof( DVCAPS ) );
  891. guardLock.Unlock();
  892. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done" );
  893. return DV_OK;
  894. }
  895. #undef DPF_MODNAME
  896. #define DPF_MODNAME "CDirectVoiceServerEngine::GetCompressionTypes"
  897. //
  898. // GetCompressionTypes
  899. //
  900. // This function retrieves a list of the current compression types.
  901. //
  902. // Called By:
  903. // - DVS_GetCompressionTypes
  904. //
  905. // Locks Required:
  906. // NONE
  907. //
  908. HRESULT CDirectVoiceServerEngine::GetCompressionTypes( LPVOID lpBuffer, LPDWORD lpdwBufferSize, LPDWORD lpdwNumElements, DWORD dwFlags)
  909. {
  910. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Begin" );
  911. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  912. DPFX(DPFPREP, DVF_APIPARAM, "Param: lpBuffer = 0x%p lpdwBufferSize = 0x%p lpdwNumElements = 0x%p dwFlags = 0x%x", lpBuffer, lpdwBufferSize, lpdwNumElements, dwFlags);
  913. HRESULT hres = DVCDB_CopyCompressionArrayToBuffer( lpBuffer, lpdwBufferSize, lpdwNumElements, dwFlags );
  914. if( hres == DV_OK )
  915. {
  916. DV_DUMP_CI( (LPDVCOMPRESSIONINFO) lpBuffer, *lpdwNumElements );
  917. }
  918. DPFX(DPFPREP, DVF_ENTRYLEVEL, "End" );
  919. return hres;
  920. }
  921. #undef DPF_MODNAME
  922. #define DPF_MODNAME "CDirectVoiceServerEngine::SetTransmitTarget"
  923. //
  924. // SetTransmitTarget
  925. //
  926. // This function sets the transmit target for the specified user. Only available in sessions with the
  927. // DVSESSION_SERVERCONTROLTARGET flag specified.
  928. //
  929. // Called By:
  930. // - DVS_SetTransmitTarget
  931. //
  932. // Locks Required:
  933. // - Global Write Lock
  934. //
  935. HRESULT CDirectVoiceServerEngine::SetTransmitTarget(DVID dvidSource, PDVID pdvidTargets, DWORD dwNumTargets, DWORD dwFlags)
  936. {
  937. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Begin" );
  938. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  939. DPFX(DPFPREP, DVF_APIPARAM, "Param: dvidSource: 0x%x pdvidTargets: 0x%p dwNumTargets: %d dwFlags: 0x%x", dvidSource, pdvidTargets, dwNumTargets, dwFlags );
  940. HRESULT hr;
  941. hr = DV_ValidTargetList( pdvidTargets, dwNumTargets );
  942. if( FAILED( hr ) )
  943. {
  944. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid target list hr=0x%x", hr );
  945. return hr;
  946. }
  947. // Flags must be 0.
  948. if( dwFlags != 0 )
  949. {
  950. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid flags" );
  951. return DVERR_INVALIDFLAGS;
  952. }
  953. // We need to be initialized
  954. if( m_dwCurrentState == DVSSTATE_NOTINITIALIZED )
  955. {
  956. DPFX(DPFPREP, DVF_ERRORLEVEL, "Not Initialized" );
  957. return DVERR_NOTINITIALIZED;
  958. }
  959. // We need to be running
  960. if( m_dwCurrentState != DVSSTATE_RUNNING )
  961. {
  962. DPFX(DPFPREP, DVF_ERRORLEVEL, "Not hosting" );
  963. return DVERR_NOTCONNECTED;
  964. }
  965. // Only if servercontroltarget is active
  966. if( !(m_dvSessionDesc.dwFlags & DVSESSION_SERVERCONTROLTARGET) )
  967. {
  968. DPFX(DPFPREP, DVF_ERRORLEVEL, "Only available with the DVSESSION_SERVERCONTROLTARGET session flag" );
  969. return DVERR_NOTALLOWED;
  970. }
  971. // Parameter checks
  972. if( !m_voiceNameTable.IsEntry( dvidSource ) )
  973. {
  974. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid source player" );
  975. return DVERR_INVALIDPLAYER;
  976. }
  977. if( dwNumTargets > 0 )
  978. {
  979. for( DWORD dwIndex = 0; dwIndex < dwNumTargets; dwIndex++ )
  980. {
  981. if( !m_voiceNameTable.IsEntry( pdvidTargets[dwIndex] ) )
  982. {
  983. if( !m_lpSessionTransport->ConfirmValidGroup( pdvidTargets[dwIndex] ) )
  984. {
  985. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid target player/group" );
  986. return DVERR_INVALIDTARGET;
  987. }
  988. }
  989. }
  990. }
  991. if( dvidSource == DVID_ALLPLAYERS )
  992. {
  993. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot set the target for all or none" );
  994. return DVERR_INVALIDPLAYER;
  995. }
  996. // Grab the player and set the target field
  997. CDVCSPlayer *pPlayerInfo;
  998. hr = m_voiceNameTable.GetEntry( dvidSource, (CVoicePlayer **) &pPlayerInfo, TRUE );
  999. if( FAILED( hr ) || pPlayerInfo == NULL )
  1000. {
  1001. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to lookup player entry. hr=0x%x", hr );
  1002. return DVERR_INVALIDPLAYER;
  1003. }
  1004. ASSERT_VPLAYER(pPlayerInfo);
  1005. // We have to ensure that updates to the player's target list do not
  1006. // happen simulatenously between a call to this function and a removal
  1007. // of a player because of a player leaving the session.
  1008. pPlayerInfo->Lock();
  1009. hr = pPlayerInfo->SetPlayerTargets( pdvidTargets, dwNumTargets );
  1010. if( FAILED( hr ) )
  1011. {
  1012. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to set player target hr=0x%x", hr );
  1013. pPlayerInfo->Release();
  1014. return hr;
  1015. }
  1016. hr = BuildAndSendTargetUpdate( dvidSource, pPlayerInfo );
  1017. pPlayerInfo->UnLock();
  1018. pPlayerInfo->Release();
  1019. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done" );
  1020. return hr;
  1021. }
  1022. #undef DPF_MODNAME
  1023. #define DPF_MODNAME "CDirectVoiceServerEngine::BuildAndSendTargetUpdate"
  1024. //
  1025. // BuildAndSendTargetUpdate
  1026. //
  1027. // This function builds and sends a message with a target list to the specified
  1028. // user.
  1029. //
  1030. HRESULT CDirectVoiceServerEngine::BuildAndSendTargetUpdate( DVID dvidSource,CVoicePlayer *pPlayerInfo )
  1031. {
  1032. // Grab the player and set the target field
  1033. HRESULT hr;
  1034. PDVTRANSPORT_BUFFERDESC pBufferDesc;
  1035. // Protect target information
  1036. pPlayerInfo->Lock();
  1037. DWORD dwTransmitSize;
  1038. PDVPROTOCOLMSG_SETTARGET pSetTargetMsg;
  1039. PVOID pvSendContext;
  1040. dwTransmitSize = sizeof( DVPROTOCOLMSG_SETTARGET ) + (pPlayerInfo->GetNumTargets()*sizeof(DVID));
  1041. pBufferDesc = GetTransmitBuffer( dwTransmitSize, &pvSendContext );
  1042. if( pBufferDesc == NULL )
  1043. {
  1044. pPlayerInfo->UnLock();
  1045. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to alloc memory" );
  1046. return DVERR_BUFFERTOOSMALL;
  1047. }
  1048. pSetTargetMsg = (PDVPROTOCOLMSG_SETTARGET) pBufferDesc->pBufferData;
  1049. // Send the message to the player
  1050. pSetTargetMsg->dwType = DVMSGID_SETTARGETS;
  1051. pSetTargetMsg->dwNumTargets = pPlayerInfo->GetNumTargets();
  1052. memcpy( &pSetTargetMsg[1], pPlayerInfo->GetTargetList(), sizeof( DVID ) * pPlayerInfo->GetNumTargets() );
  1053. pPlayerInfo->UnLock();
  1054. hr = m_lpSessionTransport->SendToIDS( &dvidSource, 1, pBufferDesc, pvSendContext, DVTRANSPORT_SEND_GUARANTEED );
  1055. if( hr == DVERR_PENDING )
  1056. {
  1057. hr = DV_OK;
  1058. }
  1059. else if( FAILED( hr ) )
  1060. {
  1061. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to send target set message hr=0x%x", hr );
  1062. }
  1063. return hr;
  1064. }
  1065. #undef DPF_MODNAME
  1066. #define DPF_MODNAME "CDirectVoiceServerEngine::GetTransmitTarget"
  1067. //
  1068. // GetTransmitTarget
  1069. //
  1070. // This function returns the current transmission target of the specified user.
  1071. //
  1072. // Only available in sessions with the DVSESSION_SERVERCONTROLTARGET flag.
  1073. //
  1074. // Called By:
  1075. // - DVS_GetTransmitTarget
  1076. //
  1077. // Locks Required:
  1078. // - Global Read Lock
  1079. //
  1080. HRESULT CDirectVoiceServerEngine::GetTransmitTarget(DVID dvidSource, LPDVID lpdvidTargets, PDWORD pdwNumElements, DWORD dwFlags )
  1081. {
  1082. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Begin" );
  1083. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  1084. DPFX(DPFPREP, DVF_APIPARAM, "Param: dvidSource = 0x%x lpdvidTargets = 0x%p pdwNumElements = 0x%p dwFlags = 0x%x", dvidSource, lpdvidTargets, pdwNumElements, dwFlags );
  1085. if( pdwNumElements == NULL ||
  1086. !DNVALID_WRITEPTR( pdwNumElements, sizeof( DWORD ) ) )
  1087. {
  1088. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid pointer" );
  1089. return DVERR_INVALIDPOINTER;
  1090. }
  1091. if( pdwNumElements != NULL &&
  1092. *pdwNumElements > 0 &&
  1093. !DNVALID_WRITEPTR( lpdvidTargets, (*pdwNumElements)*sizeof(DVID) ) )
  1094. {
  1095. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid target list buffer specified" );
  1096. return DVERR_INVALIDPOINTER;
  1097. }
  1098. if( pdwNumElements == NULL )
  1099. {
  1100. DPFX(DPFPREP, DVF_ERRORLEVEL, "You must provider a ptr # of elements" );
  1101. return DVERR_INVALIDPARAM;
  1102. }
  1103. // Flags must be 0.
  1104. if( dwFlags != 0 )
  1105. {
  1106. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid flags specified" );
  1107. return DVERR_INVALIDFLAGS;
  1108. }
  1109. // We need to be initialized
  1110. if( m_dwCurrentState == DVSSTATE_NOTINITIALIZED )
  1111. {
  1112. DPFX(DPFPREP, DVF_ERRORLEVEL, "Object not initialized" );
  1113. return DVERR_NOTINITIALIZED;
  1114. }
  1115. // We need to be running
  1116. if( m_dwCurrentState != DVSSTATE_RUNNING )
  1117. {
  1118. DPFX(DPFPREP, DVF_ERRORLEVEL, "No session running" );
  1119. return DVERR_NOTCONNECTED;
  1120. }
  1121. // Only if servercontroltarget is active
  1122. if( !(m_dvSessionDesc.dwFlags & DVSESSION_SERVERCONTROLTARGET) )
  1123. {
  1124. DPFX(DPFPREP, DVF_ERRORLEVEL, "Only available with the DVSESSION_SERVERCONTROLTARGET session flag" );
  1125. return DVERR_NOTALLOWED;
  1126. }
  1127. if( dvidSource == DVID_ALLPLAYERS )
  1128. {
  1129. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot get target for all or none" );
  1130. return DVERR_INVALIDPLAYER;
  1131. }
  1132. // Parameter checks
  1133. if( !m_voiceNameTable.IsEntry( dvidSource ) )
  1134. {
  1135. DPFX(DPFPREP, DVF_ERRORLEVEL, "Specified player does not exist" );
  1136. return DVERR_INVALIDPLAYER;
  1137. }
  1138. HRESULT hr;
  1139. // Grab the player and set the target field
  1140. CDVCSPlayer *pPlayerInfo;
  1141. hr = m_voiceNameTable.GetEntry( dvidSource, (CVoicePlayer **) &pPlayerInfo, TRUE );
  1142. if( FAILED( hr ) || pPlayerInfo == NULL )
  1143. {
  1144. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to lookup player entry. hr=0x%x", hr );
  1145. return DVERR_INVALIDPLAYER;
  1146. }
  1147. ASSERT_VPLAYER(pPlayerInfo);
  1148. pPlayerInfo->Lock();
  1149. if( *pdwNumElements < pPlayerInfo->GetNumTargets() )
  1150. {
  1151. hr = DVERR_BUFFERTOOSMALL;
  1152. }
  1153. else
  1154. {
  1155. memcpy( lpdvidTargets, pPlayerInfo->GetTargetList(), pPlayerInfo->GetNumTargets()*sizeof(DVID) );
  1156. }
  1157. *pdwNumElements = pPlayerInfo->GetNumTargets();
  1158. pPlayerInfo->UnLock();
  1159. pPlayerInfo->Release();
  1160. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done" );
  1161. return hr;
  1162. }
  1163. #undef DPF_MODNAME
  1164. #define DPF_MODNAME "CDirectVoiceServerEngine::Initialize"
  1165. //
  1166. // Initialize
  1167. //
  1168. // This function is responsible for connecting the DirectPlayVoiceServer object
  1169. // to the associated transport session. It sets up the object and makes
  1170. // it ready for a call to StartSession.
  1171. //
  1172. // Called By:
  1173. // - DV_Initialize
  1174. //
  1175. // Locks Required:
  1176. // - Global Write Lock
  1177. //
  1178. HRESULT CDirectVoiceServerEngine::Initialize( CDirectVoiceTransport *lpTransport, LPDVMESSAGEHANDLER lpdvHandler, LPVOID lpUserContext, LPDWORD lpdwMessages, DWORD dwNumElements )
  1179. {
  1180. HRESULT hr;
  1181. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Begin" );
  1182. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  1183. DPFX(DPFPREP, DVF_APIPARAM, "Param: lpTransport = 0x%p lpdvHandler = 0x%p lpUserContext = 0x%p ", lpTransport, lpdvHandler, lpUserContext );
  1184. if( lpTransport == NULL )
  1185. {
  1186. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid pointer" );
  1187. return E_POINTER;
  1188. }
  1189. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter" );
  1190. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  1191. DPFX(DPFPREP, DVF_APIPARAM, "lpdwMessages = 0x%p dwNumElements = %d", lpdwMessages, dwNumElements );
  1192. hr = DV_ValidMessageArray( lpdwMessages, dwNumElements, TRUE );
  1193. if( FAILED( hr ) )
  1194. {
  1195. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid message array hr=0x%x", hr );
  1196. return hr;
  1197. }
  1198. DPFX(DPFPREP, DVF_APIPARAM, "Message IDs=%d", dwNumElements );
  1199. if( lpdwMessages != NULL )
  1200. {
  1201. for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  1202. {
  1203. DPFX(DPFPREP, DVF_APIPARAM, "MessageIDs[%d] = %d", dwIndex, lpdwMessages[dwIndex] );
  1204. }
  1205. }
  1206. CDVCSLock guardLock(&m_csClassLock);
  1207. guardLock.Lock();
  1208. if( m_dwCurrentState != DVSSTATE_NOTINITIALIZED )
  1209. {
  1210. DPFX(DPFPREP, DVF_ERRORLEVEL, "Already Initialized" );
  1211. return DVERR_INITIALIZED;
  1212. }
  1213. if( lpdvHandler == NULL && lpdwMessages != NULL )
  1214. {
  1215. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot specify message mask there is no callback function" );
  1216. return DVERR_NOCALLBACK;
  1217. }
  1218. SetCurrentState( DVSSTATE_IDLE );
  1219. BFCSingleLock slLock( &m_csNotifyLock );
  1220. slLock.Lock();
  1221. m_lpMessageHandler = lpdvHandler;
  1222. hr = InternalSetNotifyMask( lpdwMessages, dwNumElements );
  1223. if( FAILED( hr ) )
  1224. {
  1225. SetCurrentState( DVSSTATE_NOTINITIALIZED );
  1226. DPFX(DPFPREP, DVF_ERRORLEVEL, "SetNotifyMask Failed hr=0x%x", hr );
  1227. return hr;
  1228. }
  1229. m_lpSessionTransport = lpTransport;
  1230. m_lpUserContext = lpUserContext;
  1231. m_dvidLocal = m_lpSessionTransport->GetLocalID();
  1232. DPFX(DPFPREP, DVF_ENTRYLEVEL, "DVSE::Initialize() End" );
  1233. return DV_OK;
  1234. }
  1235. #undef DPF_MODNAME
  1236. #define DPF_MODNAME "CDirectVoiceServerEngine::ReceiveSpeechMessage"
  1237. //
  1238. // ReceiveSpeechMessage
  1239. //
  1240. // Responsible for processing a speech message when it is received.
  1241. //
  1242. // Called By:
  1243. // - DV_ReceiveSpeechMessage
  1244. //
  1245. // Locks Required:
  1246. // - None
  1247. //
  1248. BOOL CDirectVoiceServerEngine::ReceiveSpeechMessage( DVID dvidSource, LPVOID lpMessage, DWORD dwSize )
  1249. {
  1250. PDVPROTOCOLMSG_FULLMESSAGE lpdvFullMessage;
  1251. // if we dont' have at least one byte then we are going to bail
  1252. if ( dwSize < 1 )
  1253. {
  1254. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::ReceiveSpeechMessage() Ignoring zero-byte sized message from=0x%x",
  1255. dvidSource );
  1256. return FALSE;
  1257. }
  1258. lpdvFullMessage = (PDVPROTOCOLMSG_FULLMESSAGE) lpMessage;
  1259. if( !ValidatePacketType( lpdvFullMessage ) )
  1260. {
  1261. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::ReceiveSpeechMessage() Ignoring message with invalid packet type, type=0x%x, from=0x%x",
  1262. lpdvFullMessage->dvGeneric.dwType, dvidSource );
  1263. return FALSE;
  1264. }
  1265. switch( lpdvFullMessage->dvGeneric.dwType )
  1266. {
  1267. case DVMSGID_SPEECHBOUNCE:
  1268. // Ignore speech bounces, only reason we get is because we're sending to all or targetting
  1269. // a client on the same ID as us.
  1270. return TRUE;
  1271. case DVMSGID_CONNECTREQUEST:
  1272. return HandleConnectRequest( dvidSource, static_cast<PDVPROTOCOLMSG_CONNECTREQUEST>(lpMessage), dwSize );
  1273. case DVMSGID_DISCONNECT:
  1274. return HandleDisconnect( dvidSource, static_cast<PDVPROTOCOLMSG_GENERIC>(lpMessage), dwSize);
  1275. case DVMSGID_SETTINGSCONFIRM:
  1276. return HandleSettingsConfirm( dvidSource, static_cast<PDVPROTOCOLMSG_SETTINGSCONFIRM>(lpMessage), dwSize );
  1277. case DVMSGID_SETTINGSREJECT:
  1278. return HandleSettingsReject( dvidSource, static_cast<PDVPROTOCOLMSG_GENERIC>(lpMessage), dwSize );
  1279. case DVMSGID_SPEECHWITHTARGET:
  1280. return HandleSpeechWithTarget( dvidSource, static_cast<PDVPROTOCOLMSG_SPEECHWITHTARGET>(lpMessage), dwSize );
  1281. case DVMSGID_SPEECH:
  1282. return HandleSpeech( dvidSource, static_cast<PDVPROTOCOLMSG_SPEECHHEADER>(lpMessage), dwSize );
  1283. default:
  1284. DPFX(DPFPREP, DVF_WARNINGLEVEL, "DVSE::ReceiveSpeechMessage() Ignoring Non-Speech Message id=0x%x from=0x%x",
  1285. lpdvFullMessage->dvGeneric.dwType, dvidSource );
  1286. return FALSE;
  1287. }
  1288. }
  1289. #undef DPF_MODNAME
  1290. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleSpeech"
  1291. // HandleSpeech
  1292. //
  1293. // Handles processing of incoming speech packets (in echo server mode).
  1294. //
  1295. // How speech is handled depends on session type. If the session is client/server, the
  1296. // packet is buffered in the appropriate user's queue. If the session is multicast,
  1297. // the packet is forwarded to the packet's target.
  1298. //
  1299. BOOL CDirectVoiceServerEngine::HandleSpeech( DVID dvidSource, PDVPROTOCOLMSG_SPEECHHEADER lpdvSpeech, DWORD dwSize )
  1300. {
  1301. HRESULT hr = DV_OK;
  1302. if ( dwSize < sizeof( DVPROTOCOLMSG_SPEECHHEADER ) )
  1303. {
  1304. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSpeech() Ignoring incorrectly sized message, size=0x%x, from=0x%x",
  1305. dwSize, dvidSource );
  1306. return FALSE;
  1307. }
  1308. if( !ValidateSpeechPacketSize( m_lpdvfCompressionInfo, dwSize - sizeof( DVPROTOCOLMSG_SPEECHHEADER ) ) )
  1309. {
  1310. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSpeech() Ignoring message with invalid speech size, size=0x%x, from=0x%x",
  1311. dwSize, dvidSource );
  1312. return FALSE;
  1313. }
  1314. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_ECHO )
  1315. {
  1316. // Bounce speech back to the user
  1317. PDVTRANSPORT_BUFFERDESC pBufferDesc;
  1318. PVOID pvSendContext;
  1319. PDVPROTOCOLMSG_SPEECHHEADER pvSpeechHeader;
  1320. pBufferDesc = GetTransmitBuffer( dwSize, &pvSendContext );
  1321. if( pBufferDesc == NULL )
  1322. {
  1323. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error allocating transmit buffer" );
  1324. return FALSE;
  1325. }
  1326. pvSpeechHeader = (PDVPROTOCOLMSG_SPEECHHEADER) pBufferDesc->pBufferData;
  1327. memcpy( pvSpeechHeader, lpdvSpeech, dwSize );
  1328. pvSpeechHeader->dwType = DVMSGID_SPEECHBOUNCE;
  1329. hr = m_lpSessionTransport->SendToIDS( &dvidSource, 1, pBufferDesc, pvSendContext, 0 );
  1330. if( hr == DVERR_PENDING )
  1331. {
  1332. hr = DV_OK;
  1333. }
  1334. else if( FAILED( hr ) )
  1335. {
  1336. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed sending to ID hr=0x%x", hr );
  1337. }
  1338. return (hr==DV_OK);
  1339. }
  1340. return TRUE;
  1341. }
  1342. #undef DPF_MODNAME
  1343. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleSpeechWithTarget"
  1344. // HandleSpeechWithTarget
  1345. //
  1346. // Handles processing of incoming speech packets.
  1347. //
  1348. // How speech is handled depends on session type. If the session is client/server, the
  1349. // packet is buffered in the appropriate user's queue. If the session is multicast,
  1350. // the packet is forwarded to the packet's target.
  1351. //
  1352. BOOL CDirectVoiceServerEngine::HandleSpeechWithTarget( DVID dvidSource, PDVPROTOCOLMSG_SPEECHWITHTARGET lpdvSpeech, DWORD dwSize )
  1353. {
  1354. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter");
  1355. DWORD dwSpeechSize; // Size of speech portion in bytes
  1356. DWORD dwTargetSize; // Size of targetting info in bytes
  1357. PBYTE pSourceSpeech; // Pointer to speech within the packet
  1358. HRESULT hr = DV_OK;
  1359. CVoicePlayer *pTargetPlayer;
  1360. if ( dwSize < sizeof( DVPROTOCOLMSG_SPEECHWITHTARGET ) || dwSize < sizeof(DVPROTOCOLMSG_SPEECHWITHTARGET) + lpdvSpeech->dwNumTargets*sizeof(DVID) )
  1361. {
  1362. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSpeechWithFrom() Ignoring incorrectly sized message, size=0x%x, from=0x%x",
  1363. dwSize, dvidSource );
  1364. return FALSE;
  1365. }
  1366. if( lpdvSpeech->dwNumTargets > DV_MAX_TARGETS )
  1367. {
  1368. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSpeechWithTarget() Ignoring message with too many targets, targets=0x%x, from=0x%x",
  1369. lpdvSpeech->dwNumTargets, dvidSource );
  1370. return FALSE;
  1371. }
  1372. if( !ValidateSpeechPacketSize( m_lpdvfCompressionInfo, dwSize - (sizeof(DVPROTOCOLMSG_SPEECHWITHTARGET) + lpdvSpeech->dwNumTargets*sizeof( DVID ) ) ) )
  1373. {
  1374. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSpeechWithFrom() Ignoring message with invalid speech size, size=0x%x, from=0x%x",
  1375. dwSize, dvidSource );
  1376. return FALSE;
  1377. }
  1378. hr = m_voiceNameTable.GetEntry( dvidSource, &pTargetPlayer, TRUE );
  1379. if( FAILED( hr ) )
  1380. {
  1381. DPFX(DPFPREP, 1, "Ignoring speech from unknown source hr=0x%x", hr );
  1382. return FALSE;
  1383. }
  1384. ASSERT_VPLAYER(pTargetPlayer);
  1385. if (!pTargetPlayer->ValidateSpeechPacketForDataRate())
  1386. {
  1387. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSpeechWithTarget() "
  1388. "Ignoring message as data exceeded. targets=0x%x from=0x%x",
  1389. lpdvSpeech->dwNumTargets, dvidSource );
  1390. return FALSE;
  1391. }
  1392. dwTargetSize = lpdvSpeech->dwNumTargets*sizeof(DVID);
  1393. dwSpeechSize = dwSize - sizeof( DVPROTOCOLMSG_SPEECHWITHTARGET ) - dwTargetSize;
  1394. pSourceSpeech = (PBYTE) lpdvSpeech;
  1395. pSourceSpeech += sizeof( DVPROTOCOLMSG_SPEECHWITHTARGET ) + dwTargetSize;
  1396. // We're a mixing server, queue up the speech.
  1397. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  1398. {
  1399. hr = HandleMixingReceive( (CDVCSPlayer *) pTargetPlayer, lpdvSpeech, dwSpeechSize, pSourceSpeech );
  1400. }
  1401. else if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_FORWARDING )
  1402. {
  1403. hr = HandleForwardingReceive( pTargetPlayer, lpdvSpeech, dwSpeechSize, pSourceSpeech );
  1404. }
  1405. if( FAILED( hr ) )
  1406. {
  1407. DPFX(DPFPREP, 1, "Unable to receive audio hr=0x%x", hr );
  1408. pTargetPlayer->Release();
  1409. return FALSE;
  1410. }
  1411. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Exit");
  1412. pTargetPlayer->Release();
  1413. return TRUE;
  1414. }
  1415. #undef DPF_MODNAME
  1416. #define DPF_MODNAME "CDirectVoiceServerEngine::DoPlayerDisconnect"
  1417. //
  1418. // Performs the work of removing the specified player from the session.
  1419. //
  1420. // Optionally informs the specified player of their disconnection.
  1421. //
  1422. // Called By:
  1423. // - HandleDisconnect (Player requests disconnect)
  1424. // - RemovePlayer (Dplay tells us player disconnected)
  1425. //
  1426. // Locks Required:
  1427. // - Global Write Lock
  1428. //
  1429. void CDirectVoiceServerEngine::DoPlayerDisconnect( DVID dvidPlayer, BOOL bInformPlayer )
  1430. {
  1431. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Disconnecting player 0x%x", dvidPlayer );
  1432. if( m_dwCurrentState != DVSSTATE_RUNNING )
  1433. {
  1434. DPFX(DPFPREP, DVF_ERRORLEVEL, "Player disconnect ignored, not running" );
  1435. return;
  1436. }
  1437. CVoicePlayer *pPlayerInfo = NULL;
  1438. HRESULT hr;
  1439. // Prevents double simultaneous deletes from crashing server.
  1440. //
  1441. // Retrieve and remove from the nametable the specified player.
  1442. hr = m_voiceNameTable.DeleteAndReturnEntry( dvidPlayer, &pPlayerInfo );
  1443. if( FAILED( hr ) )
  1444. {
  1445. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Error retrieving player entry. hr=0x%x Player may have dropped.", hr );
  1446. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Or we may have encountered disconnect during host migration" );
  1447. // If we're peer to peer session, inform players of disconnection
  1448. // Clients will ignore disconnects for players who are not in the session
  1449. //
  1450. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_PEER )
  1451. {
  1452. hr = Send_DeletePlayer( dvidPlayer );
  1453. if( FAILED( hr ) )
  1454. {
  1455. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error sending deleteplayer to all hr=0x%x", hr );
  1456. }
  1457. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Sent player Quit to all" );
  1458. }
  1459. // If specified, send a message to the user to inform them of the disconnection
  1460. // This will prevent client from timing out.
  1461. if( bInformPlayer )
  1462. {
  1463. hr = Send_DisconnectConfirm( dvidPlayer, DV_OK );
  1464. if( FAILED( hr ) )
  1465. {
  1466. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error sending disconnect confirm hr=0x%x", hr );
  1467. }
  1468. else
  1469. {
  1470. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Sent disconnect confirm to player" );
  1471. }
  1472. }
  1473. return;
  1474. }
  1475. else
  1476. {
  1477. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Retrieved record" );
  1478. }
  1479. ASSERT_VPLAYER(pPlayerInfo);
  1480. // Mark record as disconnected
  1481. pPlayerInfo->SetDisconnected();
  1482. // Remove player from the "active" list!
  1483. DNEnterCriticalSection( &m_csPlayerActiveList );
  1484. pPlayerInfo->RemoveFromNotifyList();
  1485. pPlayerInfo->Release();
  1486. DNLeaveCriticalSection( &m_csPlayerActiveList );
  1487. // If we're peer to peer session, inform players of disconnection
  1488. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_PEER )
  1489. {
  1490. hr = Send_DeletePlayer( dvidPlayer );
  1491. if( FAILED( hr ) )
  1492. {
  1493. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error sending deleteplayer to all hr=0x%x", hr );
  1494. }
  1495. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Sent player Quit to all" );
  1496. }
  1497. // If specified, send a message to the user to inform them of the disconnection
  1498. if( bInformPlayer )
  1499. {
  1500. hr = Send_DisconnectConfirm( dvidPlayer, DV_OK );
  1501. if( FAILED( hr ) )
  1502. {
  1503. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error sending disconnect confirm hr=0x%x", hr );
  1504. }
  1505. else
  1506. {
  1507. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Sent disconnect confirm to player" );
  1508. }
  1509. }
  1510. DVMSG_DELETEVOICEPLAYER dvDeletePlayer;
  1511. dvDeletePlayer.dvidPlayer = dvidPlayer;
  1512. dvDeletePlayer.dwSize = sizeof( DVMSG_DELETEVOICEPLAYER );
  1513. dvDeletePlayer.pvPlayerContext = pPlayerInfo->GetContext();
  1514. pPlayerInfo->SetContext( NULL );
  1515. // Release reference for find
  1516. pPlayerInfo->Release();
  1517. TransmitMessage( DVMSGID_DELETEVOICEPLAYER, &dvDeletePlayer, sizeof( DVMSG_DELETEVOICEPLAYER ) );
  1518. // Remove this player from everyone's target lists
  1519. FindAndRemoveDeadTarget( dvidPlayer );
  1520. }
  1521. #undef DPF_MODNAME
  1522. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleDisconnect"
  1523. //
  1524. // HandleDisconnect
  1525. //
  1526. // Called when a DVMSGID_DISCONNECT message is received.
  1527. //
  1528. // Called By:
  1529. // - ReceiveSpeechMessage
  1530. //
  1531. // Locks Required:
  1532. // - None
  1533. //
  1534. BOOL CDirectVoiceServerEngine::HandleDisconnect( DVID dvidSource, PDVPROTOCOLMSG_GENERIC lpdvDisconnect, DWORD dwSize )
  1535. {
  1536. if ( dwSize != sizeof( DVPROTOCOLMSG_GENERIC ) )
  1537. {
  1538. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleDisconnect() Ignoring incorrectly sized message, size=0x%x, from=0x%x",
  1539. dwSize, dvidSource );
  1540. return FALSE;
  1541. }
  1542. DoPlayerDisconnect( dvidSource, TRUE );
  1543. return TRUE;
  1544. }
  1545. #undef DPF_MODNAME
  1546. #define DPF_MODNAME "CDirectVoiceServerEngine::CreatePlayerEntry"
  1547. //
  1548. // CreatePlayerEntry
  1549. //
  1550. // Performs the actual work of creating a player entity. The work performed depends on the
  1551. // type of session.
  1552. //
  1553. // Called By:
  1554. // - HandleSettingsConfirm
  1555. //
  1556. // Locks Required:
  1557. // - None
  1558. //
  1559. HRESULT CDirectVoiceServerEngine::CreatePlayerEntry( DVID dvidSource, PDVPROTOCOLMSG_SETTINGSCONFIRM lpdvSettingsConfirm, DWORD dwHostOrderID, CVoicePlayer **ppPlayer )
  1560. {
  1561. HRESULT hr;
  1562. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Requesting create [ID=0x%x]",dvidSource );
  1563. CVoicePlayer *pNewPlayer;
  1564. // Complicated.
  1565. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  1566. {
  1567. CDVCSPlayer *pNewMixingPlayer = (CDVCSPlayer*)m_fpPlayers.Get();
  1568. ASSERT_VPLAYER(pNewMixingPlayer);
  1569. hr = pNewMixingPlayer->Initialize( dvidSource, dwHostOrderID,
  1570. lpdvSettingsConfirm->dwFlags, NULL,
  1571. m_dwCompressedFrameSize, m_dwUnCompressedFrameSize,
  1572. &m_fpPlayers, m_dwNumMixingThreads );
  1573. if( FAILED( hr ) )
  1574. {
  1575. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error initializing new player record hr=0x%x", hr );
  1576. return hr;
  1577. }
  1578. QUEUE_PARAMS queueParams;
  1579. queueParams.wFrameSize = m_dwCompressedFrameSize;
  1580. queueParams.bInnerQueueSize = m_lpdvfCompressionInfo->wInnerQueueSize;
  1581. queueParams.bMaxHighWaterMark = m_lpdvfCompressionInfo->wMaxHighWaterMark,
  1582. queueParams.iQuality = m_dvSessionDesc.dwBufferQuality;
  1583. queueParams.iHops = 2;
  1584. queueParams.iAggr = m_dvSessionDesc.dwBufferAggressiveness;
  1585. queueParams.bInitHighWaterMark = 2;
  1586. queueParams.wQueueId = dvidSource;
  1587. queueParams.wMSPerFrame = m_lpdvfCompressionInfo->dwTimeout,
  1588. queueParams.pFramePool = m_pFramePool;
  1589. hr = pNewMixingPlayer->CreateQueue( &queueParams );
  1590. if( FAILED( hr ) )
  1591. {
  1592. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to create inputqueue hr=0x%x", hr );
  1593. pNewMixingPlayer->Release();
  1594. return hr;
  1595. }
  1596. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Created mixing player" );
  1597. pNewPlayer = (CVoicePlayer *) pNewMixingPlayer;
  1598. }
  1599. // Otherwise.. not so complicated
  1600. else
  1601. {
  1602. pNewPlayer = (CVoicePlayer*)m_fpPlayers.Get();
  1603. if( pNewPlayer == NULL )
  1604. {
  1605. DPFX(DPFPREP, DVF_ERRORLEVEL, "CDirectVoiceServerEngine::CreatePlayerEntry() Alloc failure on player struct" );
  1606. return DVERR_OUTOFMEMORY;
  1607. }
  1608. ASSERT_VPLAYER(pNewPlayer);
  1609. hr = pNewPlayer->Initialize( dvidSource, dwHostOrderID, lpdvSettingsConfirm->dwFlags, NULL, &m_fpPlayers );
  1610. if( FAILED( hr ) )
  1611. {
  1612. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error initializing new player record hr=0x%x", hr );
  1613. return hr;
  1614. }
  1615. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Created regular player" );
  1616. }
  1617. hr = m_voiceNameTable.AddEntry( dvidSource, pNewPlayer );
  1618. // Add failed.. release our entry, destroying player
  1619. if( FAILED( hr ) )
  1620. {
  1621. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Error adding player to nametable hr=0x%x", hr );
  1622. pNewPlayer->Release();
  1623. return hr;
  1624. }
  1625. // If we're mixing session add this player to the mixing server "add queue"
  1626. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  1627. {
  1628. AddPlayerToMixingAddList( pNewPlayer );
  1629. }
  1630. // Add player to the "active" list!
  1631. DNEnterCriticalSection( &m_csPlayerActiveList );
  1632. pNewPlayer->AddToNotifyList(&m_blPlayerActiveList);
  1633. pNewPlayer->AddRef();
  1634. DNLeaveCriticalSection( &m_csPlayerActiveList );
  1635. *ppPlayer = pNewPlayer;
  1636. return DV_OK;
  1637. }
  1638. #undef DPF_MODNAME
  1639. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleSettingsConfirm"
  1640. //
  1641. // HandleSettingsConfirm
  1642. //
  1643. // Called to handle the DVMSGID_SETTINGSCONFIRM message. Creates a player entry for
  1644. // the specified player and optionally informs all players in the session.
  1645. //
  1646. // Called By:
  1647. // - ReceiveSpeechMessage
  1648. //
  1649. // Locks Required:
  1650. // - Global Write Lock
  1651. //
  1652. BOOL CDirectVoiceServerEngine::HandleSettingsConfirm( DVID dvidSource, PDVPROTOCOLMSG_SETTINGSCONFIRM lpdvSettingsConfirm, DWORD dwSize )
  1653. {
  1654. HRESULT hr;
  1655. CVoicePlayer *pPlayer;
  1656. if ( dwSize != sizeof( DVPROTOCOLMSG_SETTINGSCONFIRM ) )
  1657. {
  1658. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSettingsConfirm() Ignoring incorrectly sized message, size=0x%x, from=0x%x",
  1659. dwSize, dvidSource );
  1660. return FALSE;
  1661. }
  1662. if( !ValidateSettingsFlags( lpdvSettingsConfirm->dwFlags ) )
  1663. {
  1664. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleSettingsConfirm() Ignoring message with invalid client flags, flags=0x%x, from=0x%x",
  1665. lpdvSettingsConfirm->dwFlags, dvidSource );
  1666. return FALSE;
  1667. }
  1668. DPFX(DPFPREP, DVF_ENTRYLEVEL, "HandleSettingsConfirm: Start [ID=0x%x]", dvidSource );
  1669. if( m_dwCurrentState != DVSSTATE_RUNNING )
  1670. {
  1671. DPFX(DPFPREP, DVF_ERRORLEVEL, "Ignoring settings confirm message, not hosting" );
  1672. return TRUE;
  1673. }
  1674. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Received settings confirm [ID=0x%x]", dvidSource );
  1675. // See if specified player already exists. If they do then we need to do nothing, not even
  1676. // host migration code below. This prevents duplicate create player messages from causing
  1677. // changes to host migration code.
  1678. if( m_voiceNameTable.IsEntry( dvidSource ) )
  1679. {
  1680. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Error creating player entry. [ID=0x%x]", dvidSource );
  1681. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Normal during host migration" );
  1682. return TRUE;
  1683. }
  1684. DWORD dwHostOrderID = 0;
  1685. // Only run host migration code if host migration is available.
  1686. if( m_fHostMigrationEnabled )
  1687. {
  1688. DNEnterCriticalSection( &m_csHostOrderLock );
  1689. // This is a host migration version of this message, so re-use existing
  1690. // host order ID
  1691. //
  1692. if( lpdvSettingsConfirm->dwHostOrderID != DVPROTOCOL_HOSTORDER_INVALID )
  1693. {
  1694. dwHostOrderID = lpdvSettingsConfirm->dwHostOrderID;
  1695. // Further reduce chances of duplicate ID, if we received a host order ID > then
  1696. // the last ID offset the next value by offset again.
  1697. if( dwHostOrderID > m_dwNextHostOrderID )
  1698. {
  1699. m_dwNextHostOrderID += DVMIGRATE_ORDERID_OFFSET;
  1700. }
  1701. }
  1702. else
  1703. {
  1704. dwHostOrderID = m_dwNextHostOrderID;
  1705. m_dwNextHostOrderID++;
  1706. }
  1707. DNLeaveCriticalSection( &m_csHostOrderLock );
  1708. }
  1709. hr = CreatePlayerEntry( dvidSource, lpdvSettingsConfirm, dwHostOrderID, &pPlayer );
  1710. if( FAILED( hr ) )
  1711. {
  1712. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Error creating player entry. [ID=0x%x] hr=0x%x", dvidSource, hr );
  1713. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Normal during host migration" );
  1714. return TRUE;
  1715. }
  1716. else
  1717. {
  1718. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Player Created [ID=0x%x]", dvidSource );
  1719. }
  1720. ASSERT_VPLAYER(pPlayer);
  1721. if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_PEER )
  1722. {
  1723. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Sending current player list [ID=0x%x]", dvidSource );
  1724. hr = SendPlayerList( dvidSource, dwHostOrderID );
  1725. if( FAILED( hr ) )
  1726. {
  1727. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to send player list to player [ID=0x%x] hr=0x%x", dvidSource, hr );
  1728. }
  1729. else
  1730. {
  1731. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Playerlist sent [[ID=0x%x]", dvidSource );
  1732. }
  1733. hr = Send_CreatePlayer( DVID_ALLPLAYERS, pPlayer );
  1734. if( FAILED( hr ) )
  1735. {
  1736. DPFX(DPFPREP, DVF_ERRORLEVEL, "Send to all for new player failed hr=0x%x", hr );
  1737. }
  1738. else
  1739. {
  1740. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Informed players of join of [ID=0x%x]", dvidSource );
  1741. }
  1742. }
  1743. else if( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING )
  1744. {
  1745. hr = Send_CreatePlayer( dvidSource, pPlayer );
  1746. if( FAILED( hr ) )
  1747. {
  1748. DPFX(DPFPREP, DVF_ERRORLEVEL, "Send to player for new player failed hr=0x%x", hr );
  1749. }
  1750. else
  1751. {
  1752. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Informed player of their own join [ID=0x%x]", dvidSource );
  1753. }
  1754. }
  1755. DVMSG_CREATEVOICEPLAYER dvCreatePlayer;
  1756. dvCreatePlayer.dvidPlayer = dvidSource;
  1757. dvCreatePlayer.dwFlags = lpdvSettingsConfirm->dwFlags;
  1758. dvCreatePlayer.dwSize = sizeof( DVMSG_CREATEVOICEPLAYER );
  1759. dvCreatePlayer.pvPlayerContext = NULL;
  1760. TransmitMessage( DVMSGID_CREATEVOICEPLAYER, &dvCreatePlayer, sizeof( DVMSG_CREATEVOICEPLAYER ) );
  1761. pPlayer->SetContext( dvCreatePlayer.pvPlayerContext );
  1762. // Release our reference to the player
  1763. pPlayer->Release();
  1764. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done processing [ID=0x%x]", dvidSource );
  1765. return TRUE;
  1766. }
  1767. #undef DPF_MODNAME
  1768. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleSettingsReject"
  1769. //
  1770. // HandleSettingsReject
  1771. //
  1772. // This message type is ignored.
  1773. //
  1774. BOOL CDirectVoiceServerEngine::HandleSettingsReject( DVID dvidSource, PDVPROTOCOLMSG_GENERIC lpdvGeneric, DWORD dwSize )
  1775. {
  1776. return TRUE;
  1777. }
  1778. #undef DPF_MODNAME
  1779. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleConnectRequest"
  1780. //
  1781. // HandleConnectRequest
  1782. //
  1783. // This function is responsible for responding to user connect requests. It is the server's
  1784. // oportunity to reject or accept players. Called in response to a DVMSGID_CONNECTREQUEST
  1785. // message.
  1786. //
  1787. // Called By:
  1788. // - ReceiveSpeechMessage
  1789. //
  1790. // Locks Required:
  1791. // - Global Read Lock
  1792. //
  1793. BOOL CDirectVoiceServerEngine::HandleConnectRequest( DVID dvidSource, PDVPROTOCOLMSG_CONNECTREQUEST lpdvConnectRequest, DWORD dwSize )
  1794. {
  1795. HRESULT hr;
  1796. if ( dwSize != sizeof( DVPROTOCOLMSG_CONNECTREQUEST ) )
  1797. {
  1798. DPFX( DPFPREP, DVF_ANTIHACK_DEBUG_LEVEL, "DVSE::HandleConnectRequest() Ignoring incorrectly sized message, size=0x%x, from=0x%x",
  1799. dwSize, dvidSource );
  1800. return FALSE;
  1801. }
  1802. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Receive Connect Request.. From [ID=0x%x]", dvidSource );
  1803. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Processing Request.. [ID=0x%x]", dvidSource );
  1804. // Handle case where we've shutdown or starting up and we
  1805. // receive this message
  1806. //
  1807. if( m_dwCurrentState != DVSSTATE_RUNNING )
  1808. {
  1809. hr = Send_ConnectRefuse( dvidSource, DVERR_NOTHOSTING );
  1810. if( FAILED( hr ) )
  1811. {
  1812. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Error! Failed on internal send hr=0x%x", hr );
  1813. }
  1814. return TRUE;
  1815. }
  1816. if( !CheckProtocolCompatible( lpdvConnectRequest->ucVersionMajor,
  1817. lpdvConnectRequest->ucVersionMinor,
  1818. lpdvConnectRequest->dwVersionBuild ) )
  1819. {
  1820. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Protocol is not compatible. [ID=0x%x] Current=%d.%d b%d User=%d.%d b%d", dvidSource,
  1821. DVPROTOCOL_VERSION_MAJOR,
  1822. DVPROTOCOL_VERSION_MINOR,
  1823. DVPROTOCOL_VERSION_BUILD,
  1824. lpdvConnectRequest->ucVersionMajor,
  1825. lpdvConnectRequest->ucVersionMinor,
  1826. lpdvConnectRequest->dwVersionBuild );
  1827. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Rejecting connection request. [ID=0x%x]", dvidSource );
  1828. hr = Send_ConnectRefuse( dvidSource, DVERR_INCOMPATIBLEVERSION );
  1829. if( FAILED( hr ) )
  1830. {
  1831. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Error! Failed on internal send hr=0x%x", hr );
  1832. }
  1833. return TRUE;
  1834. }
  1835. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Processing Request..2 [ID=0x%x]", dvidSource );
  1836. hr = Send_ConnectAccept( dvidSource );
  1837. if( FAILED( hr ) )
  1838. {
  1839. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error sending player's connect request: hr=0x%x", hr );
  1840. //// TODO: Handle this case better
  1841. }
  1842. else
  1843. {
  1844. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Sent connect request [ID=0x%x]", dvidSource );
  1845. }
  1846. DPFX(DPFPREP, DVF_PLAYERMANAGE_DEBUG_LEVEL, "Processing Request..4 [ID=0x%x]", dvidSource );
  1847. return TRUE;
  1848. }
  1849. #undef DPF_MODNAME
  1850. #define DPF_MODNAME "CDirectVoiceServerEngine::StopTransportSession"
  1851. //
  1852. // StopTransportSession
  1853. //
  1854. // This function is called by the transport when the transport session
  1855. // is stopped.
  1856. //
  1857. // Called By:
  1858. // - DV_NotifyEvent
  1859. //
  1860. // Locks Required:
  1861. // - None
  1862. //
  1863. HRESULT CDirectVoiceServerEngine::StopTransportSession()
  1864. {
  1865. StopSession(0,FALSE,DVERR_SESSIONLOST);
  1866. return S_OK;
  1867. }
  1868. #undef DPF_MODNAME
  1869. #define DPF_MODNAME "CDirectVoiceServerEngine::StartTransportSession"
  1870. HRESULT CDirectVoiceServerEngine::StartTransportSession( )
  1871. {
  1872. return S_OK;
  1873. }
  1874. #undef DPF_MODNAME
  1875. #define DPF_MODNAME "CDirectVoiceServerEngine::AddPlayer"
  1876. HRESULT CDirectVoiceServerEngine::AddPlayer( DVID dvID )
  1877. {
  1878. return S_OK;
  1879. }
  1880. #undef DPF_MODNAME
  1881. #define DPF_MODNAME "CDirectVoiceServerEngine::RemovePlayer"
  1882. HRESULT CDirectVoiceServerEngine::RemovePlayer( DVID dvID )
  1883. {
  1884. if( m_voiceNameTable.IsEntry( dvID ) )
  1885. {
  1886. DoPlayerDisconnect( dvID, FALSE );
  1887. }
  1888. return S_OK;
  1889. }
  1890. #undef DPF_MODNAME
  1891. #define DPF_MODNAME "CDirectVoiceServerEngine::CreateGroup"
  1892. HRESULT CDirectVoiceServerEngine::CreateGroup( DVID dvID )
  1893. {
  1894. return S_OK;
  1895. }
  1896. #undef DPF_MODNAME
  1897. #define DPF_MODNAME "CDirectVoiceServerEngine::DeleteGroup"
  1898. HRESULT CDirectVoiceServerEngine::DeleteGroup( DVID dvID )
  1899. {
  1900. FindAndRemoveDeadTarget( dvID );
  1901. return S_OK;
  1902. }
  1903. #undef DPF_MODNAME
  1904. #define DPF_MODNAME "CDirectVoiceServerEngine::AddPlayerToGroup"
  1905. HRESULT CDirectVoiceServerEngine::AddPlayerToGroup( DVID dvidGroup, DVID dvidPlayer )
  1906. {
  1907. return S_OK;
  1908. }
  1909. #undef DPF_MODNAME
  1910. #define DPF_MODNAME "CDirectVoiceServerEngine::RemovePlayerFromGroup"
  1911. HRESULT CDirectVoiceServerEngine::RemovePlayerFromGroup( DVID dvidGroup, DVID dvidPlayer )
  1912. {
  1913. return S_OK;
  1914. }
  1915. #undef DPF_MODNAME
  1916. #define DPF_MODNAME "CDirectVoiceServerEngine::SetCurrentState"
  1917. // SetCurrentState
  1918. //
  1919. // Sets the current state of the client engine
  1920. //
  1921. void CDirectVoiceServerEngine::SetCurrentState( DWORD dwState )
  1922. {
  1923. m_dwCurrentState = dwState;
  1924. }
  1925. #undef DPF_MODNAME
  1926. #define DPF_MODNAME "CDirectVoiceServerEngine::MigrateHost"
  1927. //
  1928. // MigrateHost
  1929. //
  1930. // This function is responsible for stoping the host in the case where the host
  1931. // suddenly migrates from this client.
  1932. //
  1933. // In most cases the session will be lost before this occurs on the local object
  1934. // and this will never get called.
  1935. //
  1936. HRESULT CDirectVoiceServerEngine::MigrateHost( DVID dvidNewHost, LPDIRECTPLAYVOICESERVER lpdvServer )
  1937. {
  1938. // Cleanup...
  1939. // return StopSession( DVFLAGS_SYNC, TRUE );
  1940. return DV_OK;
  1941. }
  1942. #undef DPF_MODNAME
  1943. #define DPF_MODNAME "CDirectVoiceClientEngine::InternalSetNotifyMask"
  1944. //
  1945. // SetNotifyMask
  1946. //
  1947. HRESULT CDirectVoiceServerEngine::InternalSetNotifyMask( LPDWORD lpdwMessages, DWORD dwNumElements )
  1948. {
  1949. BFCSingleLock slLock( &m_csNotifyLock );
  1950. slLock.Lock();
  1951. if( m_lpdwMessageElements != NULL )
  1952. {
  1953. delete [] m_lpdwMessageElements;
  1954. }
  1955. m_dwNumMessageElements = dwNumElements;
  1956. // Make copies of the message elements into our own message array.
  1957. if( m_dwNumMessageElements > 0 )
  1958. {
  1959. m_lpdwMessageElements = new DWORD[m_dwNumMessageElements];
  1960. if( m_lpdwMessageElements == NULL )
  1961. {
  1962. DPFX(DPFPREP, DVF_ERRORLEVEL, "Initialize: Error allocating memory" );
  1963. return DVERR_OUTOFMEMORY;
  1964. }
  1965. memcpy( m_lpdwMessageElements, lpdwMessages, sizeof(DWORD)*m_dwNumMessageElements );
  1966. }
  1967. else
  1968. {
  1969. m_lpdwMessageElements = NULL;
  1970. }
  1971. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done" );
  1972. return DV_OK;
  1973. }
  1974. #undef DPF_MODNAME
  1975. #define DPF_MODNAME "CDirectVoiceClientEngine::SetNotifyMask"
  1976. //
  1977. // SetNotifyMask
  1978. //
  1979. // This function sets the notification mask for the DirectPlayVoice object.
  1980. //
  1981. // The array passed in lpdwMessages specify the ID's of the notifications the user wishes to
  1982. // receive. This or specifying NULL for the array turns on all notifications.
  1983. //
  1984. // Called By:
  1985. // - DVS_SetNotifyMask
  1986. //
  1987. // Locks Required:
  1988. // - m_csNotifyLock (Notification array lock)
  1989. //
  1990. HRESULT CDirectVoiceServerEngine::SetNotifyMask( LPDWORD lpdwMessages, DWORD dwNumElements )
  1991. {
  1992. HRESULT hr;
  1993. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter" );
  1994. // 7/31/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers, addresses, and handles.
  1995. DPFX(DPFPREP, DVF_APIPARAM, "lpdwMessages = 0x%p dwNumElements = %d", lpdwMessages, dwNumElements );
  1996. hr = DV_ValidMessageArray( lpdwMessages, dwNumElements, TRUE );
  1997. if( FAILED( hr ) )
  1998. {
  1999. DPFX(DPFPREP, DVF_ERRORLEVEL, "Invalid message array hr=0x%x", hr);
  2000. return hr;
  2001. }
  2002. DPFX(DPFPREP, DVF_APIPARAM, "Message IDs=%d", dwNumElements );
  2003. if( lpdwMessages != NULL )
  2004. {
  2005. for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  2006. {
  2007. DPFX(DPFPREP, DVF_APIPARAM, "MessageIDs[%d] = %d", dwIndex, lpdwMessages[dwIndex] );
  2008. }
  2009. }
  2010. if( m_dwCurrentState == DVSSTATE_NOTINITIALIZED )
  2011. {
  2012. DPFX(DPFPREP, DVF_ERRORLEVEL, "Not initialized" );
  2013. return DVERR_NOTINITIALIZED;
  2014. }
  2015. BFCSingleLock slLock( &m_csNotifyLock );
  2016. slLock.Lock();
  2017. if( m_lpMessageHandler == NULL )
  2018. {
  2019. DPFX(DPFPREP, DVF_ERRORLEVEL, "Cannot specify message mask there is no callback function" );
  2020. return DVERR_NOCALLBACK;
  2021. }
  2022. hr = InternalSetNotifyMask( lpdwMessages, dwNumElements );
  2023. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Done" );
  2024. return hr;
  2025. }
  2026. #undef DPF_MODNAME
  2027. #define DPF_MODNAME "CDirectVoiceClientEngine::CleanupActiveList"
  2028. void CDirectVoiceServerEngine::CleanupActiveList()
  2029. {
  2030. CBilink *pblSearch;
  2031. CVoicePlayer *pVoicePlayer;
  2032. DNEnterCriticalSection( &m_csPlayerActiveList );
  2033. pblSearch = m_blPlayerActiveList.GetNext();
  2034. while( pblSearch != &m_blPlayerActiveList )
  2035. {
  2036. pVoicePlayer = CONTAINING_RECORD( pblSearch, CVoicePlayer, m_blNotifyList );
  2037. ASSERT_VPLAYER(pVoicePlayer);
  2038. pblSearch = pblSearch->GetNext();
  2039. pVoicePlayer->RemoveFromNotifyList();
  2040. pVoicePlayer->Release();
  2041. }
  2042. DNLeaveCriticalSection( &m_csPlayerActiveList );
  2043. }
  2044. #undef DPF_MODNAME
  2045. #define DPF_MODNAME "CDirectVoiceServerEngine::GetTransmitBuffer"
  2046. PDVTRANSPORT_BUFFERDESC CDirectVoiceServerEngine::GetTransmitBuffer( DWORD dwSize, LPVOID *ppvSendContext )
  2047. {
  2048. PDVTRANSPORT_BUFFERDESC pNewBuffer = NULL;
  2049. DWORD dwFPMIndex = 0xFFFFFFFF;
  2050. DWORD dwWastedSpace = 0xFFFFFFFF;
  2051. DWORD dwSearchFPMIndex;
  2052. DNEnterCriticalSection( &m_csBufferLock );
  2053. pNewBuffer = (PDVTRANSPORT_BUFFERDESC) m_BufferDescPool.Get( );
  2054. DNLeaveCriticalSection( &m_csBufferLock );
  2055. DPFX(DPFPREP, DVF_BUFFERDESC_DEBUG_LEVEL, "BUFFERDESC: Got a buffer desc address 0x%p", (void *) pNewBuffer );
  2056. if( pNewBuffer == NULL )
  2057. {
  2058. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error getting transmit buffer" );
  2059. goto GETTRANSMITBUFFER_ERROR;
  2060. }
  2061. pNewBuffer->lRefCount = 0;
  2062. pNewBuffer->dwObjectType = DVTRANSPORT_OBJECTTYPE_SERVER;
  2063. pNewBuffer->dwFlags = 0;
  2064. pNewBuffer->pBufferData = NULL;
  2065. for( dwSearchFPMIndex = 0; dwSearchFPMIndex < m_dwNumPools; dwSearchFPMIndex++ )
  2066. {
  2067. // Potential pool
  2068. if( m_pdwBufferPoolSizes[dwSearchFPMIndex] >= dwSize )
  2069. {
  2070. if( m_pdwBufferPoolSizes[dwSearchFPMIndex] - dwSize < dwWastedSpace )
  2071. {
  2072. dwWastedSpace = m_pdwBufferPoolSizes[dwSearchFPMIndex] - dwSize;
  2073. dwFPMIndex = dwSearchFPMIndex;
  2074. }
  2075. }
  2076. }
  2077. if( dwFPMIndex == 0xFFFFFFFF )
  2078. {
  2079. DNASSERT( FALSE );
  2080. DPFX(DPFPREP, 0, "Could not find pool large enough for buffer" );
  2081. goto GETTRANSMITBUFFER_ERROR;
  2082. }
  2083. pNewBuffer->pvContext = &m_pBufferPools[dwFPMIndex];
  2084. DNEnterCriticalSection( &m_csBufferLock );
  2085. pNewBuffer->pBufferData = (PBYTE) m_pBufferPools[dwFPMIndex].Get();
  2086. DNLeaveCriticalSection( &m_csBufferLock );
  2087. DPFX(DPFPREP, DVF_BUFFERDESC_DEBUG_LEVEL, "BUFFERDESC: Got a buffer value at address 0x%p", (void *) pNewBuffer->pBufferData );
  2088. DPFX(DPFPREP, DVF_BUFFERDESC_DEBUG_LEVEL, "BUFFERDESC: nInUse = %i", m_BufferDescPool.GetInUseCount() );
  2089. if( pNewBuffer->pBufferData == NULL )
  2090. {
  2091. DPFX(DPFPREP, 0, "Error getting buffer for buffer desc" );
  2092. goto GETTRANSMITBUFFER_ERROR;
  2093. }
  2094. pNewBuffer->dwBufferSize = dwSize;
  2095. *ppvSendContext = pNewBuffer;
  2096. return pNewBuffer;
  2097. GETTRANSMITBUFFER_ERROR:
  2098. DNEnterCriticalSection( &m_csBufferLock );
  2099. if( pNewBuffer != NULL && pNewBuffer->pBufferData != NULL )
  2100. {
  2101. ((CFixedPool*) pNewBuffer->pvContext)->Release( pNewBuffer->pBufferData );
  2102. }
  2103. if( pNewBuffer != NULL )
  2104. {
  2105. m_BufferDescPool.Release( pNewBuffer );
  2106. }
  2107. DNLeaveCriticalSection( &m_csBufferLock );
  2108. return NULL;
  2109. }
  2110. #undef DPF_MODNAME
  2111. #define DPF_MODNAME "CDirectVoiceServerEngine::ReturnTransmitBuffer"
  2112. // ReturnTransmitBuffer
  2113. //
  2114. // PDVTRANSPORT_BUFFERDESC pBufferDesc - Buffer description of buffer to return
  2115. // LPVOID lpvContext - Context value to be used when returning the buffer
  2116. //
  2117. void CDirectVoiceServerEngine::ReturnTransmitBuffer( PVOID pvContext )
  2118. {
  2119. PDVTRANSPORT_BUFFERDESC pBufferDesc = (PDVTRANSPORT_BUFFERDESC) pvContext;
  2120. CFixedPool* pPool = (CFixedPool*) pBufferDesc->pvContext;
  2121. DPFX(DPFPREP, DVF_BUFFERDESC_DEBUG_LEVEL, "BUFFERDESC: Returning a buffer desc at address 0x%p", (void *) pBufferDesc );
  2122. DPFX(DPFPREP, DVF_BUFFERDESC_DEBUG_LEVEL, "BUFFERDESC: Returning a buffer at address 0x%p", (void *) pBufferDesc->pBufferData );
  2123. DNEnterCriticalSection( &m_csBufferLock );
  2124. // Release memory
  2125. pPool->Release( pBufferDesc->pBufferData );
  2126. // Release buffer description
  2127. m_BufferDescPool.Release( pvContext );
  2128. DPFX(DPFPREP, DVF_BUFFERDESC_DEBUG_LEVEL, "BUFFERDESC: nInUse = %i", m_BufferDescPool.GetInUseCount() );
  2129. DNLeaveCriticalSection( &m_csBufferLock );
  2130. }
  2131. #undef DPF_MODNAME
  2132. #define DPF_MODNAME "CDirectVoiceServerEngine::SendComplete"
  2133. HRESULT CDirectVoiceServerEngine::SendComplete( PDVEVENTMSG_SENDCOMPLETE pSendComplete )
  2134. {
  2135. ReturnTransmitBuffer( pSendComplete->pvUserContext );
  2136. return DV_OK;
  2137. }
  2138. #undef DPF_MODNAME
  2139. #define DPF_MODNAME "CDirectVoiceServerEngine::SetupBuffers"
  2140. HRESULT CDirectVoiceServerEngine::SetupBuffers()
  2141. {
  2142. HRESULT hr = DV_OK;
  2143. DWORD dwIndex = 0;
  2144. m_dwNumPools = SERVER_POOLS_NUM;
  2145. if (!m_BufferDescPool.Initialize( sizeof(DVTRANSPORT_BUFFERDESC), NULL, NULL, NULL, NULL ))
  2146. {
  2147. DPFX(DPFPREP, 0, "Error allocating memory" );
  2148. hr = DVERR_OUTOFMEMORY;
  2149. goto SETUPBUFFERS_ERROR;
  2150. }
  2151. m_pBufferPools = new CFixedPool[m_dwNumPools];
  2152. if( m_pBufferPools == NULL )
  2153. {
  2154. DPFX(DPFPREP, 0, "Error allocating memory" );
  2155. hr = DVERR_OUTOFMEMORY;
  2156. goto SETUPBUFFERS_ERROR;
  2157. }
  2158. memset( m_pBufferPools, 0x00, sizeof( CFixedPool ) * m_dwNumPools );
  2159. m_pdwBufferPoolSizes = new DWORD[m_dwNumPools];
  2160. if( m_pdwBufferPoolSizes == NULL )
  2161. {
  2162. DPFX(DPFPREP, 0, "Error allocating memory" );
  2163. hr = DVERR_OUTOFMEMORY;
  2164. goto SETUPBUFFERS_ERROR;
  2165. }
  2166. m_pdwBufferPoolSizes[0] = SERVER_POOLS_SIZE_MESSAGE;
  2167. m_pdwBufferPoolSizes[1] = SERVER_POOLS_SIZE_PLAYERLIST;
  2168. m_pdwBufferPoolSizes[2] = sizeof( DVPROTOCOLMSG_SPEECHWITHFROM )+m_dwCompressedFrameSize+COMPRESSION_SLUSH;
  2169. for( dwIndex = 0; dwIndex < m_dwNumPools; dwIndex++ )
  2170. {
  2171. if(!m_pBufferPools[dwIndex].Initialize( m_pdwBufferPoolSizes[dwIndex], NULL, NULL, NULL, NULL))
  2172. {
  2173. DPFX(DPFPREP, 0, "Error creating transmit buffers" );
  2174. goto SETUPBUFFERS_ERROR;
  2175. }
  2176. }
  2177. return DV_OK;
  2178. SETUPBUFFERS_ERROR:
  2179. FreeBuffers();
  2180. return hr;
  2181. }
  2182. #undef DPF_MODNAME
  2183. #define DPF_MODNAME "CDirectVoiceServerEngine::FreeBuffers"
  2184. HRESULT CDirectVoiceServerEngine::FreeBuffers()
  2185. {
  2186. DWORD dwIndex;
  2187. if( m_pBufferPools != NULL )
  2188. {
  2189. for( dwIndex = 0; dwIndex < m_dwNumPools; dwIndex++ )
  2190. {
  2191. m_pBufferPools[dwIndex].DeInitialize();
  2192. }
  2193. delete [] m_pBufferPools;
  2194. m_pBufferPools = NULL;
  2195. }
  2196. if( m_pdwBufferPoolSizes != NULL )
  2197. {
  2198. delete [] m_pdwBufferPoolSizes;
  2199. m_pdwBufferPoolSizes = 0;
  2200. }
  2201. m_BufferDescPool.DeInitialize();
  2202. m_dwNumPools = 0;
  2203. return DV_OK;
  2204. }
  2205. #undef DPF_MODNAME
  2206. #define DPF_MODNAME "CDirectVoiceServerEngine::FindAndRemoveDeadTargets"
  2207. //
  2208. // FindAndRemoveDeadTargets
  2209. //
  2210. // This function when called with the server controlled targetting flag active
  2211. // scans the list of players and for each player checks to see if the specified
  2212. // DVID is in their target list. If the player IS in the target list the target
  2213. // list for the player is updated and and update is sent to the client.
  2214. //
  2215. // Parameters:
  2216. // dvidID - ID of the player who has been removed for some reason.
  2217. //
  2218. void CDirectVoiceServerEngine::FindAndRemoveDeadTarget( DVID dvidID )
  2219. {
  2220. if( !(m_dvSessionDesc.dwFlags & DVSESSION_SERVERCONTROLTARGET) )
  2221. return;
  2222. DPFX(DPFPREP, DVF_INFOLEVEL, "Player/Group ID [0x%x] was removed, checking player target lists", dvidID );
  2223. // Grab the active player list lock so we can run the list
  2224. DNEnterCriticalSection( &m_csPlayerActiveList );
  2225. CBilink *pblSearch = NULL;
  2226. CVoicePlayer *pPlayer = NULL;
  2227. HRESULT hr = DV_OK;
  2228. pblSearch = m_blPlayerActiveList.GetNext();
  2229. while( pblSearch != &m_blPlayerActiveList )
  2230. {
  2231. pPlayer = CONTAINING_RECORD(pblSearch, CVoicePlayer, m_blNotifyList);
  2232. ASSERT_VPLAYER(pPlayer);
  2233. // Lock the specified player -- we have to to ensure that we don't get another
  2234. // simultaneous taregtting update that races this one.
  2235. pPlayer->Lock();
  2236. // Specified target was in this player's target list
  2237. if( pPlayer->FindAndRemovePlayerTarget(dvidID) )
  2238. {
  2239. // Send an update to the client
  2240. hr = BuildAndSendTargetUpdate( pPlayer->GetPlayerID(),pPlayer );
  2241. if( FAILED( hr ) )
  2242. {
  2243. DPFX(DPFPREP, DVF_INFOLEVEL, "Unable to send target update to player [0x%x] hr=[0x%x]", pPlayer->GetPlayerID(), hr );
  2244. }
  2245. }
  2246. pPlayer->UnLock();
  2247. pblSearch = pblSearch->GetNext();
  2248. }
  2249. DNLeaveCriticalSection( &m_csPlayerActiveList );
  2250. }
  2251. #undef DPF_MODNAME
  2252. #define DPF_MODNAME "CDirectVoiceServerEngine::ValidateSettingsFlags"
  2253. BOOL CDirectVoiceServerEngine::ValidateSettingsFlags( DWORD dwFlags )
  2254. {
  2255. return ((dwFlags == 0) || (dwFlags == DVPLAYERCAPS_HALFDUPLEX));
  2256. }
  2257. #undef DPF_MODNAME
  2258. #define DPF_MODNAME "CDirectVoiceServerEngine::ValidatePacketType"
  2259. BOOL CDirectVoiceServerEngine::ValidatePacketType( const DVPROTOCOLMSG_FULLMESSAGE* lpdvFullMessage ) const
  2260. {
  2261. switch( lpdvFullMessage->dvGeneric.dwType )
  2262. {
  2263. case DVMSGID_SPEECHWITHTARGET:
  2264. return ( ( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_FORWARDING ) ||
  2265. ( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING ) );
  2266. break;
  2267. case DVMSGID_SPEECH:
  2268. return ( ( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_MIXING ) ||
  2269. ( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_PEER ) ||
  2270. ( m_dvSessionDesc.dwSessionType == DVSESSIONTYPE_ECHO ) );
  2271. break;
  2272. }
  2273. return TRUE;
  2274. }
  2275. #undef DPF_MODNAME
  2276. #define DPF_MODNAME "CDirectVoiceServerEngine::IsHostMigrationAllowed"
  2277. //
  2278. // This function checks to see if host migration is enabled. Host migration is available
  2279. // if we're in peer-to-peer mode.
  2280. //
  2281. BOOL CDirectVoiceServerEngine::IsHostMigrationEnabled( ) const
  2282. {
  2283. // If it's disabled, it's off.
  2284. if( m_dvSessionDesc.dwFlags & DVSESSION_NOHOSTMIGRATION )
  2285. return FALSE;
  2286. // Only migrate in peer-to-peer
  2287. if( m_dvSessionDesc.dwSessionType != DVSESSIONTYPE_PEER )
  2288. return FALSE;
  2289. // Only migrate in peer-to-peer transport
  2290. if( m_dwTransportSessionType != DVTRANSPORT_SESSION_PEERTOPEER )
  2291. return FALSE;
  2292. // No host migration allowed on transport, so none on our session.
  2293. if( !(m_dwTransportFlags & DVTRANSPORT_MIGRATEHOST) )
  2294. return FALSE;
  2295. return TRUE;
  2296. }