Source code of Windows XP (NT5)
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.

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