Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1247 lines
42 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999, 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: mixserver.cpp
  6. * Content: Implements the mixing server portion of the server class
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 11/01/2000 rodtoll Split out from dvsereng.cpp
  12. * 12/14/2000 rodtoll DPVOICE: [Mixing Server] Mixer may create infinite loop
  13. * 02/20/2001 rodtoll WINBUG #321297 - DPVOICE: Access violation in DPVoice.dll while running DVSalvo server
  14. * 04/09/2001 rodtoll WINBUG #364126 - DPVoice : Memory leak when Initializing 2 Voice Servers with same DPlay transport
  15. * 02/28/2002 rodtoll WINBUG #549959 - SECURITY: DPVOICE: Voice server trusts client's target list
  16. * - Update receive path to use server's copy of client target list when server controlled targetting enabled
  17. * 06/13/2002 simonpow BUG #59944 Switched over to using Threadpool based timers rather than multimedia
  18. ***************************************************************************/
  19. #include "dxvoicepch.h"
  20. #undef DPF_MODNAME
  21. #define DPF_MODNAME "CDirectVoiceServerEngine::AddPlayerToMixingAddList"
  22. void CDirectVoiceServerEngine::AddPlayerToMixingAddList( CVoicePlayer *pPlayer )
  23. {
  24. CDVCSPlayer *pVoicePlayer = (CDVCSPlayer *) pPlayer;
  25. ASSERT_VPLAYER( pVoicePlayer );
  26. for( DWORD dwIndex = 0; dwIndex < m_dwNumMixingThreads; dwIndex++ )
  27. {
  28. DNEnterCriticalSection( &m_prWorkerControl[dwIndex].m_csMixingAddList );
  29. pVoicePlayer->AddToMixingList( dwIndex, &m_prWorkerControl[dwIndex].m_blMixingAddPlayers );
  30. pVoicePlayer->AddRef();
  31. DNLeaveCriticalSection( &m_prWorkerControl[dwIndex].m_csMixingAddList );
  32. }
  33. }
  34. #undef DPF_MODNAME
  35. #define DPF_MODNAME "CDirectVoiceServerEngine::StartWorkerThreads"
  36. // StartWorkerThreads
  37. //
  38. // This function starts mixer worker threads. The number started is based on the
  39. // m_dwNumMixingThreads variable which must be initialized before this is called.
  40. //
  41. HRESULT CDirectVoiceServerEngine::StartWorkerThreads()
  42. {
  43. HRESULT hr = DV_OK;
  44. DWORD dwIndex;
  45. m_prWorkerControl = new MIXERTHREAD_CONTROL[m_dwNumMixingThreads];
  46. if( m_prWorkerControl == NULL )
  47. {
  48. DPFX(DPFPREP, DVF_ERRORLEVEL, "Out of memory!" );
  49. return DVERR_OUTOFMEMORY;
  50. }
  51. // Zero memory so everything is initialized.
  52. ZeroMemory( m_prWorkerControl, sizeof( MIXERTHREAD_CONTROL )*m_dwNumMixingThreads );
  53. for( dwIndex = 0; dwIndex < m_dwNumMixingThreads; dwIndex++ )
  54. {
  55. m_prWorkerControl[dwIndex].dwThreadIndex = dwIndex;
  56. m_prWorkerControl[dwIndex].hThreadDone = CreateEvent( NULL, FALSE, FALSE, NULL );
  57. m_prWorkerControl[dwIndex].hThreadDoWork = CreateEvent( NULL, FALSE, FALSE, NULL );
  58. m_prWorkerControl[dwIndex].hThreadIdle = CreateEvent( NULL, FALSE, FALSE, NULL );
  59. m_prWorkerControl[dwIndex].hThreadQuit = CreateEvent( NULL, FALSE, FALSE, NULL );
  60. m_prWorkerControl[dwIndex].m_pServerObject = this;
  61. m_prWorkerControl[dwIndex].m_blMixingAddPlayers.Initialize();
  62. m_prWorkerControl[dwIndex].m_blMixingActivePlayers.Initialize();
  63. m_prWorkerControl[dwIndex].m_blMixingSpeakingPlayers.Initialize();
  64. m_prWorkerControl[dwIndex].m_blMixingHearingPlayers.Initialize();
  65. if (!DNInitializeCriticalSection( &m_prWorkerControl[dwIndex].m_csMixingAddList ))
  66. {
  67. hr = DVERR_OUTOFMEMORY;
  68. goto EXIT_ERROR;
  69. }
  70. if( m_prWorkerControl[dwIndex].hThreadDone == NULL ||
  71. m_prWorkerControl[dwIndex].hThreadDoWork == NULL ||
  72. m_prWorkerControl[dwIndex].hThreadIdle == NULL ||
  73. m_prWorkerControl[dwIndex].hThreadQuit == NULL )
  74. {
  75. hr = GetLastError();
  76. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error creating events hr=0x%x", hr );
  77. hr = DVERR_GENERIC;
  78. goto EXIT_ERROR;
  79. }
  80. m_prWorkerControl[dwIndex].m_mixerBuffer = new BYTE[m_dwUnCompressedFrameSize];
  81. m_prWorkerControl[dwIndex].m_realMixerBuffer = new LONG[m_dwMixerSize];
  82. if( m_prWorkerControl[dwIndex].m_mixerBuffer == NULL ||
  83. m_prWorkerControl[dwIndex].m_realMixerBuffer == NULL )
  84. {
  85. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error allocating memory" );
  86. hr = DVERR_OUTOFMEMORY;
  87. goto EXIT_ERROR;
  88. }
  89. m_prWorkerControl[dwIndex].hThread = (HANDLE) CreateThread( NULL, 0, MixerWorker, &m_prWorkerControl[dwIndex], 0, &m_prWorkerControl[dwIndex].dwThreadID );
  90. if( m_prWorkerControl[dwIndex].hThread == NULL )
  91. {
  92. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error creating events/thread" );
  93. hr = DVERR_GENERIC;
  94. goto EXIT_ERROR;
  95. }
  96. ::SetThreadPriority( m_prWorkerControl[dwIndex].hThread, THREAD_PRIORITY_TIME_CRITICAL );
  97. }
  98. return DV_OK;
  99. EXIT_ERROR:
  100. ShutdownWorkerThreads();
  101. return hr;
  102. }
  103. HRESULT CDirectVoiceServerEngine::ShutdownWorkerThreads()
  104. {
  105. DWORD dwIndex;
  106. if( m_prWorkerControl )
  107. {
  108. for( dwIndex = 0; dwIndex < m_dwNumMixingThreads; dwIndex++ )
  109. {
  110. if( m_prWorkerControl[dwIndex].hThread )
  111. {
  112. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "[%d]: Shutting down ID=[0x%x]", dwIndex, m_prWorkerControl[dwIndex].dwThreadID );
  113. SetEvent( m_prWorkerControl[dwIndex].hThreadQuit );
  114. WaitForSingleObject( m_prWorkerControl[dwIndex].hThreadDone, INFINITE );
  115. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "[%d]: Shutting down complete", dwIndex );
  116. CloseHandle( m_prWorkerControl[dwIndex].hThread );
  117. m_prWorkerControl[dwIndex].hThread = NULL;
  118. DNDeleteCriticalSection( &m_prWorkerControl[dwIndex].m_csMixingAddList );
  119. }
  120. if( m_prWorkerControl[dwIndex].hThreadDone )
  121. CloseHandle( m_prWorkerControl[dwIndex].hThreadDone );
  122. if( m_prWorkerControl[dwIndex].hThreadDoWork )
  123. CloseHandle( m_prWorkerControl[dwIndex].hThreadDoWork );
  124. if( m_prWorkerControl[dwIndex].hThreadIdle )
  125. CloseHandle( m_prWorkerControl[dwIndex].hThreadIdle );
  126. if( m_prWorkerControl[dwIndex].hThreadQuit )
  127. CloseHandle( m_prWorkerControl[dwIndex].hThreadQuit );
  128. if( m_prWorkerControl[dwIndex].m_mixerBuffer )
  129. delete [] m_prWorkerControl[dwIndex].m_mixerBuffer;
  130. if( m_prWorkerControl[dwIndex].m_realMixerBuffer )
  131. delete [] m_prWorkerControl[dwIndex].m_realMixerBuffer;
  132. DNASSERT( m_prWorkerControl[dwIndex].m_blMixingAddPlayers.IsEmpty() );
  133. DNASSERT( m_prWorkerControl[dwIndex].m_blMixingActivePlayers.IsEmpty() );
  134. }
  135. delete [] m_prWorkerControl;
  136. m_prWorkerControl = NULL;
  137. }
  138. return 0;
  139. }
  140. #undef DPF_MODNAME
  141. #define DPF_MODNAME "CDirectVoiceServerEngine::StartupClientServer"
  142. //
  143. // StartupClientServer
  144. //
  145. // This function is called to initialize the Mixer portion of the server object.
  146. // Only called for Mixing Sessions. Initialization includes the startup of
  147. // the mixing thread and startup of the mixer multimedia timer.
  148. //
  149. // Called By:
  150. // - StartSession
  151. //
  152. // Locks Required:
  153. // - None
  154. //
  155. HRESULT CDirectVoiceServerEngine::StartupClientServer()
  156. {
  157. HRESULT hr;
  158. HANDLE tmpThreadHandle;
  159. SYSTEM_INFO sysInfo;
  160. DWORD dwIndex;
  161. m_pFramePool = NULL;
  162. m_dwCompressedFrameSize = m_lpdvfCompressionInfo->dwFrameLength;
  163. m_dwUnCompressedFrameSize = DVCDB_CalcUnCompressedFrameSize( m_lpdvfCompressionInfo, s_lpwfxMixerFormat );
  164. m_dwNumPerBuffer = m_lpdvfCompressionInfo->dwFramesPerBuffer;
  165. m_pFramePool = new CFramePool( m_dwCompressedFrameSize );
  166. if( m_pFramePool == NULL )
  167. {
  168. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to allocate frame pool" );
  169. return DVERR_OUTOFMEMORY;
  170. }
  171. if (!m_pFramePool->Init())
  172. {
  173. delete m_pFramePool;
  174. m_pFramePool = NULL;
  175. return DVERR_OUTOFMEMORY;
  176. }
  177. m_mixerEightBit = (s_lpwfxMixerFormat->wBitsPerSample==8) ? TRUE : FALSE;
  178. GetSystemInfo( &sysInfo );
  179. m_dwNumMixingThreads = sysInfo.dwNumberOfProcessors;
  180. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXER: There will be %d worker threads", m_dwNumMixingThreads );
  181. if( m_mixerEightBit )
  182. {
  183. m_dwMixerSize = m_dwUnCompressedFrameSize;
  184. }
  185. else
  186. {
  187. // Mixer size is / 2 because 16-bit samples, only need 1 LONG for
  188. // each 16-bit sample = 2 * 8bit.
  189. m_dwMixerSize = m_dwUnCompressedFrameSize / 2;
  190. }
  191. m_pStats->m_dwNumMixingThreads = m_dwNumMixingThreads;
  192. hr = StartWorkerThreads();
  193. if( FAILED( hr ) )
  194. {
  195. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed starting worker threads hr=0x%x", hr );
  196. goto EXIT_CLIENTSERVERSTARTUP;
  197. }
  198. // General info
  199. m_pTimer = new DvTimer;
  200. if( m_pTimer == NULL )
  201. {
  202. DPFX(DPFPREP, DVF_ERRORLEVEL, "Out of memory!" );
  203. hr = DVERR_OUTOFMEMORY;
  204. goto EXIT_CLIENTSERVERSTARTUP;
  205. }
  206. m_hTickSemaphore = CreateSemaphore( NULL, 0, 0xFFFFFF, NULL );
  207. if( m_hTickSemaphore == NULL )
  208. {
  209. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to create semaphore" );
  210. hr = DVERR_GENERIC;
  211. goto EXIT_CLIENTSERVERSTARTUP;
  212. }
  213. m_hShutdownMixerEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  214. m_hMixerDoneEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  215. if( m_hShutdownMixerEvent == NULL ||
  216. m_hMixerDoneEvent == NULL )
  217. {
  218. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to create events" );
  219. hr = DVERR_GENERIC;
  220. goto EXIT_CLIENTSERVERSTARTUP;
  221. }
  222. m_hMixerControlThread = CreateThread( NULL, 0, MixerControl, this, 0, &m_dwMixerControlThreadID );
  223. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXER: Controller Started: ID=0x%x", m_dwMixerControlThreadID );
  224. if( m_hMixerControlThread == NULL )
  225. {
  226. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error creating events/thread" );
  227. hr = DVERR_GENERIC;
  228. goto EXIT_CLIENTSERVERSTARTUP;
  229. }
  230. ::SetThreadPriority( m_hMixerControlThread, THREAD_PRIORITY_TIME_CRITICAL );
  231. if( !m_pTimer->Create( m_lpdvfCompressionInfo->dwTimeout, &m_hTickSemaphore, MixingServerWakeupProc ) )
  232. {
  233. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to create multimedia timer" );
  234. hr = DVERR_GENERIC;
  235. goto EXIT_CLIENTSERVERSTARTUP;
  236. }
  237. return DV_OK;
  238. EXIT_CLIENTSERVERSTARTUP:
  239. ShutdownClientServer();
  240. return hr;
  241. }
  242. #undef DPF_MODNAME
  243. #define DPF_MODNAME "CDirectVoiceServerEngine::ShutdownClientServer"
  244. //
  245. // ShutdownClientServer
  246. //
  247. // This function is responsible for shutting down the mixer portion of the
  248. // server object. This function should only be called for mixing sessions.
  249. //
  250. // This function will stop the mixer thread and the mixer multimedia timer.
  251. //
  252. // Called By:
  253. // - StopSession
  254. //
  255. // Locks Required:
  256. // - None
  257. //
  258. HRESULT CDirectVoiceServerEngine::ShutdownClientServer()
  259. {
  260. if( m_hMixerControlThread )
  261. {
  262. SetEvent( m_hShutdownMixerEvent );
  263. WaitForSingleObject( m_hMixerDoneEvent, INFINITE );
  264. CloseHandle( m_hMixerControlThread );
  265. m_hMixerControlThread = NULL;
  266. // Cleanup the mixing list
  267. CleanupMixingList();
  268. }
  269. if( m_hShutdownMixerEvent )
  270. {
  271. CloseHandle( m_hShutdownMixerEvent );
  272. m_hShutdownMixerEvent = NULL;
  273. }
  274. if( m_hMixerDoneEvent )
  275. {
  276. CloseHandle( m_hMixerDoneEvent );
  277. m_hMixerDoneEvent = NULL;
  278. }
  279. ShutdownWorkerThreads();
  280. if( m_pTimer )
  281. {
  282. delete m_pTimer;
  283. m_pTimer = NULL;
  284. }
  285. if( m_hTickSemaphore )
  286. {
  287. CloseHandle( m_hTickSemaphore );
  288. m_hTickSemaphore = NULL;
  289. }
  290. return DV_OK;
  291. }
  292. #undef DPF_MODNAME
  293. #define DPF_MODNAME "CDirectVoiceServerEngine::Mixer_Buffer_Reset"
  294. // Mixer_Buffer_Reset
  295. //
  296. // This function resets the mixer buffer back to silence.
  297. void CDirectVoiceServerEngine::Mixer_Buffer_Reset( DWORD dwThreadIndex )
  298. {
  299. FillBufferWithSilence( m_prWorkerControl[dwThreadIndex].m_realMixerBuffer,
  300. m_prWorkerControl[dwThreadIndex].m_pServerObject->m_mixerEightBit,
  301. m_prWorkerControl[dwThreadIndex].m_pServerObject->m_dwUnCompressedFrameSize );
  302. }
  303. #undef DPF_MODNAME
  304. #define DPF_MODNAME "CDirectVoiceServerEngine::Mixer_Buffer_MixBuffer"
  305. // Mixer_Buffer_MixBuffer
  306. //
  307. // This function mixes the speech pointed to by the source parameter
  308. // into the mixer buffer.
  309. //
  310. // Parameters:
  311. // unsigned char *source -
  312. // Pointer to source data in uncompressed format
  313. void CDirectVoiceServerEngine::Mixer_Buffer_MixBuffer( DWORD dwThreadIndex, const unsigned char *source )
  314. {
  315. MixInBuffer( m_prWorkerControl[dwThreadIndex].m_realMixerBuffer, source,
  316. m_prWorkerControl[dwThreadIndex].m_pServerObject->m_mixerEightBit,
  317. m_prWorkerControl[dwThreadIndex].m_pServerObject->m_dwUnCompressedFrameSize );
  318. }
  319. #undef DPF_MODNAME
  320. #define DPF_MODNAME "CDirectVoiceServerEngine::Mixer_Buffer_Normalize"
  321. // Mixer_Buffer_Normalize
  322. //
  323. // This function takes the mixed audio data from the mixer
  324. // buffer and transfers it back to the mixer format
  325. // and places it into the m_mixerBuffer buffer.
  326. //
  327. void CDirectVoiceServerEngine::Mixer_Buffer_Normalize( DWORD dwThreadIndex )
  328. {
  329. NormalizeBuffer( m_prWorkerControl[dwThreadIndex].m_mixerBuffer,
  330. m_prWorkerControl[dwThreadIndex].m_realMixerBuffer,
  331. m_prWorkerControl[dwThreadIndex].m_pServerObject->m_mixerEightBit,
  332. m_prWorkerControl[dwThreadIndex].m_pServerObject->m_dwUnCompressedFrameSize );
  333. }
  334. #undef DPF_MODNAME
  335. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleMixerThreadError"
  336. //
  337. // HandleMixerThreadError
  338. //
  339. // This function is called by the mixer when an unrecoverable error
  340. // occurs.
  341. //
  342. void CDirectVoiceServerEngine::HandleMixerThreadError( HRESULT hr )
  343. {
  344. DPFX(DPFPREP, DVF_ERRORLEVEL, "Mixer Thread Encountered an error. hr=0x%x", hr );
  345. SetEvent( m_hMixerDoneEvent );
  346. StopSession( 0, FALSE, hr );
  347. }
  348. #undef DPF_MODNAME
  349. #define DPF_MODNAME "CDirectVoiceServerEngine::MixerControl"
  350. DWORD WINAPI CDirectVoiceServerEngine::MixerControl( void *pvContext )
  351. {
  352. CDirectVoiceServerEngine *This = (CDirectVoiceServerEngine *) pvContext;
  353. HANDLE hEvents[3];
  354. HANDLE *hIdleEvents = new HANDLE[This->m_dwNumMixingThreads+1];
  355. DWORD dwIndex = 0;
  356. LONG lFreeThreadIndex = 0;
  357. DWORD dwNumToMix = 0;
  358. DWORD dwTickCountStart;
  359. LONG lWaitResult;
  360. if( !hIdleEvents )
  361. {
  362. DPFX(DPFPREP, DVF_ERRORLEVEL, "MIXCTRL: Error allocating array" );
  363. DNASSERT( FALSE );
  364. SetEvent( This->m_hMixerDoneEvent );
  365. return 0;
  366. }
  367. hEvents[0] = This->m_hShutdownMixerEvent;
  368. hEvents[1] = This->m_hTickSemaphore;
  369. hEvents[2] = (HANDLE) ((DWORD_PTR) 0xFFFFFFFF);
  370. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXCTRL: Starting up" );
  371. for( dwIndex = 0; dwIndex < This->m_dwNumMixingThreads; dwIndex++ )
  372. {
  373. hIdleEvents[dwIndex] = This->m_prWorkerControl[dwIndex].hThreadIdle;
  374. }
  375. hIdleEvents[This->m_dwNumMixingThreads] = (HANDLE) ((DWORD_PTR) 0xFFFFFFFF);
  376. // Wait for tick or for quit command
  377. while( (lWaitResult = WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE )) != WAIT_OBJECT_0 )
  378. {
  379. // On Win9X we may occationally over run the end of the wait list
  380. // and the result is we hit the FFFFFFFFF which will cause
  381. // a failure.
  382. if( lWaitResult == WAIT_FAILED )
  383. continue;
  384. // Update statistics block
  385. InterlockedIncrement( &This->m_pStats->m_dwNumMixingPasses );
  386. dwTickCountStart = GetTickCount();
  387. // On Win95 you may occasionally encounter a situation where the waitformultiple runs
  388. // off the end of the list and ends up with the invalid handle above. Just continue
  389. // in this case.
  390. lFreeThreadIndex = WAIT_FAILED;
  391. while( lFreeThreadIndex == WAIT_FAILED )
  392. {
  393. // Wait for a single mixing thread to be free
  394. lFreeThreadIndex = WaitForMultipleObjects( This->m_dwNumMixingThreads, hIdleEvents, FALSE, INFINITE );
  395. //// TODO: Error checking!
  396. }
  397. lFreeThreadIndex -= WAIT_OBJECT_0;
  398. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXCTRL: Worker [%d] is elected to do work", lFreeThreadIndex );
  399. This->SpinWorkToThread( lFreeThreadIndex );
  400. }
  401. delete [] hIdleEvents;
  402. SetEvent( This->m_hMixerDoneEvent );
  403. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXCTRL: Shutting down" );
  404. return 0;
  405. }
  406. #undef DPF_MODNAME
  407. #define DPF_MODNAME "CDirectVoiceServerEngine::MixerWorker"
  408. DWORD WINAPI CDirectVoiceServerEngine::MixerWorker( void *pvContext )
  409. {
  410. PMIXERTHREAD_CONTROL This = (PMIXERTHREAD_CONTROL) pvContext;
  411. HANDLE hEvents[3];
  412. CBilink *pblSearch, *pblSubSearch;
  413. CDVCSPlayer *pCurrentPlayer = NULL, *pTmpPlayer = NULL;
  414. DWORD dwNumTargets = 0;
  415. DWORD dwTargetIndex = 0;
  416. DWORD dwResultSize = 0;
  417. DWORD dwIndex = 0;
  418. DWORD dwThreadIndex = This->dwThreadIndex;
  419. HRESULT hr;
  420. CDVCSPlayer **ppThreadHearList = NULL;
  421. PDVPROTOCOLMSG_SPEECHHEADER pdvmSpeechHeader = NULL;
  422. PDVTRANSPORT_BUFFERDESC pdvbTransmitBufferDesc = NULL;
  423. PVOID pvSendContext = NULL;
  424. DVID dvidSendTarget;
  425. DWORD dwTickCountStart;
  426. DWORD dwTickCountDecStart;
  427. DWORD dwTickCountMixStart;
  428. DWORD dwTickCountDupStart;
  429. DWORD dwTickCountRetStart;
  430. DWORD dwStatIndex;
  431. DWORD dwTickCountEnd;
  432. DWORD dwTotalMix, dwForwardMix, dwReuseMix, dwOriginalMix;
  433. LONG lWaitResult;
  434. MixingServerStats *pStats = This->m_pServerObject->m_pStats;
  435. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: [%d] Started [0x%x] Thread", This->dwThreadIndex, GetCurrentThreadId() );
  436. hEvents[0] = This->hThreadQuit;
  437. hEvents[1] = This->hThreadDoWork;
  438. hEvents[2] = (HANDLE) ((DWORD_PTR) 0xFFFFFFFF);
  439. SetEvent( This->hThreadIdle );
  440. while( (lWaitResult = WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE )) != WAIT_OBJECT_0 )
  441. {
  442. // On Win95 it may occationally move off the end of the list and hit the guard value
  443. if( lWaitResult == WAIT_FAILED )
  444. continue;
  445. // Statistics update
  446. dwTickCountStart = GetTickCount();
  447. InterlockedIncrement( &pStats->m_dwNumMixingThreadsActive );
  448. pStats->m_dwNumMixingPassesPerThread[dwThreadIndex]++;
  449. if( pStats->m_dwNumMixingThreadsActive >
  450. pStats->m_dwMaxMixingThreadsActive )
  451. {
  452. pStats->m_dwMaxMixingThreadsActive = pStats->m_dwNumMixingThreadsActive;
  453. }
  454. dwStatIndex = pStats->m_dwCurrentMixingHistoryLoc[dwThreadIndex];
  455. pStats->m_lCurrentPlayerCount[dwThreadIndex][dwStatIndex] = This->dwNumToMix;
  456. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: [%d] Starting work", This->dwThreadIndex );
  457. if( This->dwNumToMix == 0 )
  458. {
  459. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: No players to process!" );
  460. goto WORK_COMPLETE;
  461. }
  462. dwTickCountDecStart = GetTickCount();
  463. pStats->m_lCurrentDecCountHistory[dwThreadIndex][dwStatIndex] = 0;
  464. // Pass through player list and decompress those who need decompression
  465. //
  466. pblSearch = This->m_blMixingSpeakingPlayers.GetNext();
  467. while( pblSearch != &This->m_blMixingSpeakingPlayers )
  468. {
  469. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  470. pCurrentPlayer = pRealBilink->m_pPlayer;
  471. ASSERT_VPLAYER( pCurrentPlayer );
  472. // Dereference the array of can hear players for this player
  473. ppThreadHearList = pCurrentPlayer->m_pppCanHear[dwThreadIndex];
  474. // Player needs to have their voice decompressed
  475. if( pCurrentPlayer->m_pfNeedsDecompression[dwThreadIndex] )
  476. {
  477. DNASSERT( pCurrentPlayer );
  478. DNASSERT( pCurrentPlayer->m_pSourceFrame[dwThreadIndex] );
  479. DNASSERT( !pCurrentPlayer->m_pSourceFrame[dwThreadIndex]->GetIsSilence() );
  480. dwResultSize = This->m_pServerObject->m_dwUnCompressedFrameSize;
  481. hr = pCurrentPlayer->DeCompressInBound(
  482. pCurrentPlayer->m_pSourceFrame[dwThreadIndex],
  483. &pCurrentPlayer->m_sourceUnCompressed[pCurrentPlayer->m_pdwUnCompressedBufferOffset[dwThreadIndex]],
  484. &dwResultSize );
  485. pStats->m_lCurrentDecCountHistory[dwThreadIndex][dwStatIndex]++;
  486. if( FAILED( hr ) )
  487. {
  488. DNASSERT( FALSE );
  489. // TODO: ERROR Handling for failed decompression
  490. }
  491. else
  492. {
  493. pCurrentPlayer->m_pfDecompressed[dwThreadIndex] = TRUE;
  494. }
  495. DNASSERT( dwResultSize == This->m_pServerObject->m_dwUnCompressedFrameSize );
  496. }
  497. // Integrity checks
  498. //
  499. // Check to ensure that each player who this person can hear is supposed to be decompressed
  500. #ifdef _DEBUG
  501. DNASSERT( pCurrentPlayer->m_pdwHearCount[dwThreadIndex] < This->dwNumToMix );
  502. if( pCurrentPlayer->m_pdwHearCount[dwThreadIndex] > 1 )
  503. {
  504. for( dwIndex; dwIndex < pCurrentPlayer->m_pdwHearCount[dwThreadIndex]; dwIndex++ )
  505. {
  506. DNASSERT( ppThreadHearList[dwIndex] );
  507. DNASSERT( ppThreadHearList[dwIndex]->m_pfNeedsDecompression[dwThreadIndex] );
  508. }
  509. }
  510. #endif
  511. pblSearch = pblSearch->GetNext();
  512. }
  513. dwTickCountDupStart = GetTickCount();
  514. pStats->m_lCurrentDecTimeHistory[dwThreadIndex][dwStatIndex] = dwTickCountDupStart - dwTickCountDecStart;
  515. // Check for duplicates in the sending. If there is duplicates then we need
  516. // to setup the reuse
  517. pblSearch = This->m_blMixingHearingPlayers.GetNext();
  518. while( pblSearch != &This->m_blMixingHearingPlayers )
  519. {
  520. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  521. pCurrentPlayer = pRealBilink->m_pPlayer;
  522. ASSERT_VPLAYER( pCurrentPlayer );
  523. // If we don't hear anybody, this step is irrelevant
  524. if( pCurrentPlayer->m_pdwHearCount[dwThreadIndex] < 2 )
  525. goto DUPLICATE_CHECK_LOOP_DONE;
  526. // Dereference the array of can hear players for this player
  527. ppThreadHearList = pCurrentPlayer->m_pppCanHear[dwThreadIndex];
  528. pblSubSearch = This->m_blMixingHearingPlayers.GetNext();
  529. // Only do the people who come before them.
  530. while( pblSubSearch != pblSearch )
  531. {
  532. CBilinkPlusObject* pRealSubBilink = CONTAINING_OBJECT( pblSubSearch, CBilinkPlusObject, m_bl );
  533. pTmpPlayer = pRealSubBilink->m_pPlayer;
  534. ASSERT_VPLAYER( pTmpPlayer );
  535. // This person's mix is the same, re-use it!
  536. if( pTmpPlayer->ComparePlayerMix( dwThreadIndex, pCurrentPlayer ) )
  537. {
  538. pCurrentPlayer->m_pReuseMixFromThisPlayer[dwThreadIndex] = pTmpPlayer;
  539. pTmpPlayer->m_pfMixToBeReused[dwThreadIndex] = TRUE;
  540. break;
  541. }
  542. pblSubSearch = pblSubSearch->GetNext();
  543. }
  544. DUPLICATE_CHECK_LOOP_DONE:
  545. pblSearch = pblSearch->GetNext();
  546. }
  547. dwTickCountMixStart = GetTickCount();
  548. pStats->m_lCurrentDupTimeHistory[dwThreadIndex][dwStatIndex] = dwTickCountMixStart - dwTickCountDupStart;
  549. dwTotalMix = 0;
  550. dwForwardMix = 0;
  551. dwReuseMix = 0;
  552. dwOriginalMix = 0;
  553. // Pass through player list and compress and send mixes as appropriate
  554. pblSearch = This->m_blMixingHearingPlayers.GetNext();
  555. while( pblSearch != &This->m_blMixingHearingPlayers )
  556. {
  557. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  558. pCurrentPlayer = pRealBilink->m_pPlayer;
  559. ASSERT_VPLAYER( pCurrentPlayer );
  560. // Dereference the array of can hear players for this player
  561. ppThreadHearList = pCurrentPlayer->m_pppCanHear[dwThreadIndex];
  562. // Pre-set next so we can continue() below and still go to next item
  563. pblSearch = pblSearch->GetNext();
  564. if( !pCurrentPlayer->m_pdwHearCount[dwThreadIndex] )
  565. {
  566. continue;
  567. }
  568. dwTotalMix++;
  569. // Get a transmission buffer and description
  570. pdvbTransmitBufferDesc = This->m_pServerObject->GetTransmitBuffer( This->m_pServerObject->m_dwCompressedFrameSize+sizeof(DVPROTOCOLMSG_SPEECHHEADER)+COMPRESSION_SLUSH,
  571. &pvSendContext );
  572. if( pdvbTransmitBufferDesc == NULL )
  573. {
  574. // TODO: Error handling for out of memory condition
  575. DNASSERT( FALSE );
  576. }
  577. // Setup the packet header
  578. pdvmSpeechHeader = (PDVPROTOCOLMSG_SPEECHHEADER) pdvbTransmitBufferDesc->pBufferData;
  579. pdvmSpeechHeader->dwType = DVMSGID_SPEECHBOUNCE;
  580. pdvmSpeechHeader->bMsgNum = pCurrentPlayer->m_pbMsgNumToSend[dwThreadIndex];
  581. pdvmSpeechHeader->bSeqNum = pCurrentPlayer->m_pbSeqNumToSend[dwThreadIndex];
  582. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: [%d] Sending Packet to 0x%x Msg=0x%x Seq=0x%x",
  583. dwThreadIndex,
  584. pCurrentPlayer->GetPlayerID(),
  585. pdvmSpeechHeader->bMsgNum,
  586. pdvmSpeechHeader->bSeqNum );
  587. // If this player hears something they will be getting a packet
  588. //
  589. // Only hear one person -- forward the packet
  590. //
  591. if( pCurrentPlayer->m_pdwHearCount[dwThreadIndex] == 1)
  592. {
  593. dwResultSize = ppThreadHearList[0]->m_pSourceFrame[dwThreadIndex]->GetFrameLength();
  594. memcpy( &pdvmSpeechHeader[1],
  595. ppThreadHearList[0]->m_pSourceFrame[dwThreadIndex]->GetDataPointer(),
  596. dwResultSize );
  597. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: [%d] Forwarding already compressed packet", dwThreadIndex );
  598. pCurrentPlayer->m_pfMixed[dwThreadIndex] = TRUE;
  599. dwForwardMix++;
  600. }
  601. else if( pCurrentPlayer->m_pdwHearCount[dwThreadIndex] > 1)
  602. {
  603. pTmpPlayer = pCurrentPlayer->m_pReuseMixFromThisPlayer[dwThreadIndex];
  604. // We are re-using a previous player's mix
  605. if( pTmpPlayer )
  606. {
  607. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXERWORKER: [%d] Forwarding pre-built mix", dwThreadIndex );
  608. ASSERT_VPLAYER( pTmpPlayer );
  609. DNASSERT( pTmpPlayer->m_pfMixed[dwThreadIndex] );
  610. DNASSERT( pTmpPlayer->m_pfMixToBeReused[dwThreadIndex] );
  611. DNASSERT( pTmpPlayer->m_pdwResultLength[dwThreadIndex] );
  612. dwResultSize = pTmpPlayer->m_pdwResultLength[dwThreadIndex];
  613. memcpy( &pdvmSpeechHeader[1],
  614. &pTmpPlayer->m_targetCompressed[pTmpPlayer->m_pdwCompressedBufferOffset[dwThreadIndex]],
  615. dwResultSize );
  616. dwReuseMix++;
  617. }
  618. else
  619. {
  620. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXERWORKER: [%d] Creating original mix", dwThreadIndex );
  621. dwOriginalMix++;
  622. dwResultSize = This->m_pServerObject->m_dwCompressedFrameSize;
  623. // Reset the high resolution mixer buffer
  624. This->m_pServerObject->Mixer_Buffer_Reset(dwThreadIndex);
  625. // Mix in specified player's audio.
  626. for( dwIndex = 0; dwIndex < pCurrentPlayer->m_pdwHearCount[dwThreadIndex]; dwIndex++ )
  627. {
  628. DNASSERT( !ppThreadHearList[dwIndex]->m_pfSilence[dwThreadIndex] );
  629. This->m_pServerObject->Mixer_Buffer_MixBuffer(dwThreadIndex,ppThreadHearList[dwIndex]->m_sourceUnCompressed );
  630. }
  631. // Normalize the buffer back to the thread's mix buffer
  632. This->m_pServerObject->Mixer_Buffer_Normalize(dwThreadIndex);
  633. hr = pCurrentPlayer->CompressOutBound( This->m_mixerBuffer,
  634. This->m_pServerObject->m_dwUnCompressedFrameSize,
  635. (BYTE *) &pdvmSpeechHeader[1],
  636. &dwResultSize );
  637. if( FAILED( hr ) )
  638. {
  639. DNASSERT( FALSE );
  640. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed compressing outbound audio" );
  641. }
  642. pCurrentPlayer->m_pfMixed[dwThreadIndex] = TRUE;
  643. pCurrentPlayer->m_pdwResultLength[dwThreadIndex] = dwResultSize;
  644. // This player's mix will be re-used, ensure that we cache it
  645. if( pCurrentPlayer->m_pfMixToBeReused[dwThreadIndex] )
  646. {
  647. memcpy( &pCurrentPlayer->m_targetCompressed[pCurrentPlayer->m_pdwCompressedBufferOffset[dwThreadIndex]],
  648. &pdvmSpeechHeader[1],
  649. pCurrentPlayer->m_pdwResultLength[dwThreadIndex] );
  650. }
  651. }
  652. }
  653. else
  654. {
  655. DNASSERT(FALSE);
  656. }
  657. dvidSendTarget = pCurrentPlayer->GetPlayerID();
  658. pdvbTransmitBufferDesc->dwBufferSize= dwResultSize + sizeof( DVPROTOCOLMSG_SPEECHHEADER );
  659. hr = This->m_pServerObject->m_lpSessionTransport->SendToIDS( &dvidSendTarget, 1, pdvbTransmitBufferDesc, pvSendContext, 0 );
  660. if( hr == DVERR_PENDING )
  661. hr = DV_OK;
  662. if( FAILED( hr ) )
  663. {
  664. DPFX(DPFPREP, DVF_ERRORLEVEL, "MIXWORKER: [%d] Unable to transmit to target [0x%x]", pCurrentPlayer->GetPlayerID() );
  665. }
  666. }
  667. dwTickCountRetStart = GetTickCount();
  668. pStats->m_lCurrentMixTimeHistory[dwThreadIndex][dwStatIndex] = dwTickCountRetStart - dwTickCountMixStart;
  669. pStats->m_lCurrentMixCountTotalHistory[dwThreadIndex][dwStatIndex] = dwTotalMix;
  670. pStats->m_lCurrentMixCountFwdHistory[dwThreadIndex][dwStatIndex] = dwForwardMix;
  671. pStats->m_lCurrentMixCountReuseHistory[dwThreadIndex][dwStatIndex] = dwReuseMix;
  672. pStats->m_lCurrentMixCountOriginalHistory[dwThreadIndex][dwStatIndex] = dwOriginalMix;
  673. WORK_COMPLETE:
  674. // Pass through player list and return frames
  675. pblSearch = This->m_blMixingActivePlayers.GetNext();
  676. while( pblSearch != &This->m_blMixingActivePlayers )
  677. {
  678. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  679. pCurrentPlayer = pRealBilink->m_pPlayer;
  680. ASSERT_VPLAYER( pCurrentPlayer );
  681. DNASSERT( pCurrentPlayer->m_pSourceFrame[dwThreadIndex] );
  682. pCurrentPlayer->CompleteRun( dwThreadIndex );
  683. pblSearch = pblSearch->GetNext();
  684. }
  685. dwTickCountEnd = GetTickCount();
  686. pStats->m_lCurrentRetTimeHistory[dwThreadIndex][dwStatIndex] = dwTickCountEnd - dwTickCountRetStart;
  687. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: [%d] Work complete", This->dwThreadIndex );
  688. // Statistics update
  689. InterlockedDecrement( &This->m_pServerObject->m_pStats->m_dwNumMixingThreadsActive );
  690. SetEvent( This->hThreadIdle );
  691. // Statistics update
  692. pStats->m_dwMixingPassesTimeHistory[dwThreadIndex][dwStatIndex] = dwTickCountEnd - dwTickCountStart;
  693. pStats->m_dwCurrentMixingHistoryLoc[dwThreadIndex]++;
  694. pStats->m_dwCurrentMixingHistoryLoc[dwThreadIndex] %= MIXING_HISTORY;
  695. }
  696. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "MIXWORKER: [%d] Shutting down", This->dwThreadIndex );
  697. SetEvent( This->hThreadDone );
  698. return 0;
  699. }
  700. #undef DPF_MODNAME
  701. #define DPF_MODNAME "CDirectVoiceServerEngine::SpinWorkToThread"
  702. //
  703. // SpinWorkToThread
  704. //
  705. // This function performs the first step of a mixing server pass and then
  706. // passes the work off to the specified thread
  707. //
  708. // Responsible for:
  709. // 1. Updating the
  710. // 2. running the list of players, determinging who they can hear
  711. //
  712. void CDirectVoiceServerEngine::SpinWorkToThread( LONG lThreadIndex )
  713. {
  714. CBilink *pblSearch = NULL, *pblSubSearch = NULL;
  715. CDVCSPlayer *pCurrentPlayer = NULL, *pTmpPlayer = NULL, *pComparePlayer = NULL;
  716. HRESULT hr;
  717. PDVID pdvidTargets = NULL;
  718. DWORD dwNumTargets = 0;
  719. DWORD dwTargetIndex = 0;
  720. DWORD dwTickCountStart = GetTickCount();
  721. // Update the list of players from the pending lists to the individual bilinks
  722. UpdateActiveMixingPendingList( lThreadIndex, &m_prWorkerControl[lThreadIndex].dwNumToMix );
  723. // Pass 1 through player list.
  724. //
  725. // Reset state variables for specified thread, create any converters that need creating
  726. pblSearch = m_prWorkerControl[lThreadIndex].m_blMixingActivePlayers.GetNext();
  727. while( pblSearch != &m_prWorkerControl[lThreadIndex].m_blMixingActivePlayers )
  728. {
  729. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  730. pTmpPlayer = pRealBilink->m_pPlayer;
  731. ASSERT_VPLAYER( pTmpPlayer );
  732. pblSearch = pblSearch->GetNext();
  733. // Reset for the next pass
  734. pTmpPlayer->ResetForNextRun(lThreadIndex,TRUE);
  735. // Resize the can hear array
  736. pTmpPlayer->ResizeIfRequired( lThreadIndex, m_prWorkerControl[lThreadIndex].dwNumToMix );
  737. // Lock the player -- only one person should be creating converter at a time
  738. pTmpPlayer->Lock();
  739. // Create outbound converter if required
  740. if( !pTmpPlayer->IsOutBoundConverterInitialized() )
  741. {
  742. hr = pTmpPlayer->CreateOutBoundConverter( s_lpwfxMixerFormat, m_dvSessionDesc.guidCT );
  743. if( FAILED( hr ) )
  744. {
  745. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to create outbound converter hr=0x%x", hr );
  746. DNASSERT( FALSE );
  747. }
  748. }
  749. // Create inbound converter if required
  750. if( !pTmpPlayer->IsInBoundConverterInitialized() )
  751. {
  752. hr = pTmpPlayer->CreateInBoundConverter( m_dvSessionDesc.guidCT, s_lpwfxMixerFormat );
  753. if( FAILED( hr ) )
  754. {
  755. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to create converter" );
  756. DNASSERT( FALSE );
  757. }
  758. }
  759. pTmpPlayer->UnLock();
  760. }
  761. DNASSERT(m_prWorkerControl[lThreadIndex].m_blMixingSpeakingPlayers.IsEmpty());
  762. DNASSERT(m_prWorkerControl[lThreadIndex].m_blMixingHearingPlayers.IsEmpty());
  763. m_prWorkerControl[lThreadIndex].m_blMixingSpeakingPlayers.Initialize();
  764. m_prWorkerControl[lThreadIndex].m_blMixingHearingPlayers.Initialize();
  765. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "SST: 2" );
  766. // Pass 2.
  767. //
  768. // For each player:
  769. // 1. Figure out who they hear.
  770. // 2. TODO: If they hear anyone, add them to the "to send to" list of people
  771. // 3. TODO: If they hear > 1, add the people they hear to the "to decompress" list of people.
  772. // 4. Setup the appropriate sequence # / msg # for the transmission
  773. //
  774. pblSearch = m_prWorkerControl[lThreadIndex].m_blMixingActivePlayers.GetNext();
  775. while( pblSearch != &m_prWorkerControl[lThreadIndex].m_blMixingActivePlayers )
  776. {
  777. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  778. pCurrentPlayer = pRealBilink->m_pPlayer;
  779. ASSERT_VPLAYER( pCurrentPlayer );
  780. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "0x%x Can hear: ", pCurrentPlayer->GetPlayerID() );
  781. pblSearch = pblSearch->GetNext();
  782. pblSubSearch = m_prWorkerControl[lThreadIndex].m_blMixingActivePlayers.GetNext();
  783. // Search the list of people in the session
  784. while( pblSubSearch != &m_prWorkerControl[lThreadIndex].m_blMixingActivePlayers )
  785. {
  786. CBilinkPlusObject* pRealSubBilink = CONTAINING_OBJECT( pblSubSearch, CBilinkPlusObject, m_bl );
  787. pComparePlayer = pRealSubBilink->m_pPlayer;
  788. ASSERT_VPLAYER( pComparePlayer );
  789. pblSubSearch = pblSubSearch->GetNext();
  790. // This record contains a silent record -- ignore
  791. if( pComparePlayer->m_pfSilence[lThreadIndex] )
  792. continue;
  793. // If this isn't the player themselves
  794. if( pblSearch != pblSubSearch )
  795. {
  796. DNASSERT( pComparePlayer->m_pSourceFrame[lThreadIndex] );
  797. pdvidTargets = pComparePlayer->m_pSourceFrame[lThreadIndex]->GetTargetList();
  798. dwNumTargets = pComparePlayer->m_pSourceFrame[lThreadIndex]->GetNumTargets();
  799. // The target of the subIndex user's frame is this user OR
  800. // The user is in the group which is target of subIndex user's frame
  801. for( dwTargetIndex = 0; dwTargetIndex < dwNumTargets; dwTargetIndex++ )
  802. {
  803. if( pCurrentPlayer->GetPlayerID() == pdvidTargets[dwTargetIndex] ||
  804. m_lpSessionTransport->IsPlayerInGroup( pdvidTargets[dwTargetIndex], pCurrentPlayer->GetPlayerID() ) )
  805. {
  806. *((*(pCurrentPlayer->m_pppCanHear+lThreadIndex))+pCurrentPlayer->m_pdwHearCount[lThreadIndex]) = pComparePlayer;
  807. pCurrentPlayer->m_pdwHearCount[lThreadIndex]++;
  808. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "0x%x", pComparePlayer->GetPlayerID() );
  809. // Setup the appropriate msg num / sequence number so when it's sent
  810. // we ensure it gets re-assembled on the other side in the right order
  811. if( pCurrentPlayer->m_pdwHearCount[lThreadIndex] == 1 )
  812. {
  813. if( pCurrentPlayer->m_bLastSent == FALSE )
  814. {
  815. pCurrentPlayer->m_bMsgNum++;
  816. pCurrentPlayer->m_bSeqNum = 0;
  817. pCurrentPlayer->m_bLastSent = TRUE;
  818. }
  819. else
  820. {
  821. pCurrentPlayer->m_bSeqNum++;
  822. }
  823. pCurrentPlayer->m_pbMsgNumToSend[lThreadIndex] = pCurrentPlayer->m_bMsgNum;
  824. pCurrentPlayer->m_pbSeqNumToSend[lThreadIndex] = pCurrentPlayer->m_bSeqNum;
  825. pCurrentPlayer->AddToHearingList( lThreadIndex, &m_prWorkerControl[lThreadIndex].m_blMixingHearingPlayers );
  826. }
  827. // We can hear > 1 person, we need to mark each person as needing decompression
  828. else if( pCurrentPlayer->m_pdwHearCount[lThreadIndex] > 1 )
  829. {
  830. if( !pComparePlayer->m_pfNeedsDecompression[lThreadIndex] )
  831. {
  832. // Add this player to the list of people who need to be decompressed
  833. pComparePlayer->AddToSpeakingList( lThreadIndex, &m_prWorkerControl[lThreadIndex].m_blMixingSpeakingPlayers );
  834. pComparePlayer->m_pfNeedsDecompression[lThreadIndex] = TRUE;
  835. }
  836. // Special case, we just transitioned to having > 1 people heard by this player,
  837. // we should mark the first person we can hear for decompression as well
  838. if( pCurrentPlayer->m_pdwHearCount[lThreadIndex] == 2 )
  839. {
  840. pTmpPlayer = (pCurrentPlayer->m_pppCanHear[lThreadIndex])[0];
  841. ASSERT_VPLAYER( pTmpPlayer );
  842. if( !pTmpPlayer->m_pfNeedsDecompression[lThreadIndex] )
  843. {
  844. pTmpPlayer->AddToSpeakingList( lThreadIndex, &m_prWorkerControl[lThreadIndex].m_blMixingSpeakingPlayers );
  845. pTmpPlayer->m_pfNeedsDecompression[lThreadIndex] = TRUE;
  846. }
  847. }
  848. }
  849. // We need to break out of the loop as we only need to add an individual player once to the
  850. // list of people a player can hear.
  851. break;
  852. }
  853. }
  854. }
  855. }
  856. if( !pCurrentPlayer->m_pdwHearCount[lThreadIndex] )
  857. {
  858. pCurrentPlayer->m_bLastSent = FALSE;
  859. }
  860. else
  861. {
  862. pCurrentPlayer->m_bLastSent = TRUE;
  863. }
  864. }
  865. m_pStats->m_dwPreMixingPassTimeHistoryLoc++;
  866. m_pStats->m_dwPreMixingPassTimeHistoryLoc %= MIXING_HISTORY;
  867. m_pStats->m_dwPreMixingPassTimeHistory[m_pStats->m_dwPreMixingPassTimeHistoryLoc] = GetTickCount() - dwTickCountStart;
  868. SetEvent( m_prWorkerControl[lThreadIndex].hThreadDoWork );
  869. }
  870. #undef DPF_MODNAME
  871. #define DPF_MODNAME "CDirectVoiceServerEngine::MixingServerWakeupProc"
  872. // MixingServerWakeupProc
  873. //
  874. // This function is called by the windows timer used by this
  875. // class each time the timer goes off. The function signals
  876. // a semaphore provided by the creator of the timer.
  877. //
  878. // Parameters:
  879. // DWORD param - A recast pointer to a HANDLE
  880. void CDirectVoiceServerEngine::MixingServerWakeupProc( void * pvUserData )
  881. {
  882. ReleaseSemaphore( *((HANDLE * ) pvUserData), 1, NULL );
  883. }
  884. #undef DPF_MODNAME
  885. #define DPF_MODNAME "CDirectVoiceServerEngine::HandleMixingReceive"
  886. HRESULT CDirectVoiceServerEngine::HandleMixingReceive( CDVCSPlayer *pTargetPlayer, PDVPROTOCOLMSG_SPEECHWITHTARGET pdvSpeechWithtarget, DWORD dwSpeechSize, PBYTE pSourceSpeech )
  887. {
  888. HRESULT hr;
  889. DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "Mixing Server Speech Handler" );
  890. ASSERT_VPLAYER(pTargetPlayer);
  891. hr = pTargetPlayer->HandleMixingReceive( &pdvSpeechWithtarget->dvHeader, pSourceSpeech, dwSpeechSize, (PDVID) &pdvSpeechWithtarget[1], pdvSpeechWithtarget->dwNumTargets, m_dvSessionDesc.dwFlags & DVSESSION_SERVERCONTROLTARGET );
  892. DPFX(DPFPREP, DVF_CLIENT_SEQNUM_DEBUG_LEVEL, "SEQ: Receive: Msg [%d] Seq [%d]", pdvSpeechWithtarget->dvHeader.bMsgNum, pdvSpeechWithtarget->dvHeader.bSeqNum );
  893. return hr;
  894. }
  895. #undef DPF_MODNAME
  896. #define DPF_MODNAME "CDirectVoiceClientEngine::UpdateActiveMixingPendingList"
  897. void CDirectVoiceServerEngine::UpdateActiveMixingPendingList( DWORD dwThreadIndex, DWORD *pdwNumActive)
  898. {
  899. CBilink *pblSearch;
  900. CDVCSPlayer *pVoicePlayer;
  901. DNEnterCriticalSection( &m_prWorkerControl[dwThreadIndex].m_csMixingAddList );
  902. // Add players who are pending
  903. pblSearch = m_prWorkerControl[dwThreadIndex].m_blMixingAddPlayers.GetNext();
  904. while( pblSearch != &m_prWorkerControl[dwThreadIndex].m_blMixingAddPlayers )
  905. {
  906. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  907. pVoicePlayer = pRealBilink->m_pPlayer;
  908. ASSERT_VPLAYER(pVoicePlayer);
  909. pVoicePlayer->RemoveFromMixingList(dwThreadIndex);
  910. pVoicePlayer->AddToMixingList( dwThreadIndex, &m_prWorkerControl[dwThreadIndex].m_blMixingActivePlayers );
  911. pblSearch = m_prWorkerControl[dwThreadIndex].m_blMixingAddPlayers.GetNext();
  912. }
  913. DNASSERT( m_prWorkerControl[dwThreadIndex].m_blMixingAddPlayers.IsEmpty() );
  914. DNLeaveCriticalSection( &m_prWorkerControl[dwThreadIndex].m_csMixingAddList );
  915. *pdwNumActive = 0;
  916. // Remove players who have disconnected
  917. pblSearch = m_prWorkerControl[dwThreadIndex].m_blMixingActivePlayers.GetNext();
  918. while( pblSearch != &m_prWorkerControl[dwThreadIndex].m_blMixingActivePlayers )
  919. {
  920. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  921. pVoicePlayer = pRealBilink->m_pPlayer;
  922. ASSERT_VPLAYER(pVoicePlayer);
  923. pblSearch = pblSearch->GetNext();
  924. // If current player has disconnected, remove them from active list
  925. // and release the reference the list has
  926. if( pVoicePlayer->IsDisconnected() )
  927. {
  928. // Because players are removed from active list here, but not from hearing and/or speaking
  929. // list you may end up in a situation where a player is talking, drops and during removal
  930. // ends up in a state where they are not on the mixing list, but they are on the hearing
  931. // and speaking lists. Except, the hearing and speaking lists are initialized for the
  932. // next run in the spinworktothread. The result is when you go to delete the player
  933. // object and attempt to release the player it will assert and/or crash because player
  934. // still points to next person in the list (even though they don't point back). Causes
  935. // bilink corruption.
  936. pVoicePlayer->RemoveFromMixingList(dwThreadIndex);
  937. pVoicePlayer->RemoveFromHearingList(dwThreadIndex);
  938. pVoicePlayer->RemoveFromSpeakingList(dwThreadIndex);
  939. pVoicePlayer->Release();
  940. }
  941. else
  942. {
  943. (*pdwNumActive)++;
  944. }
  945. }
  946. }
  947. #undef DPF_MODNAME
  948. #define DPF_MODNAME "CDirectVoiceClientEngine::CleanupMixingList"
  949. void CDirectVoiceServerEngine::CleanupMixingList()
  950. {
  951. CBilink *pblSearch;
  952. CDVCSPlayer *pVoicePlayer;
  953. for( DWORD dwIndex = 0; dwIndex < m_dwNumMixingThreads; dwIndex++ )
  954. {
  955. DNEnterCriticalSection( &m_prWorkerControl[dwIndex].m_csMixingAddList );
  956. // Add players who are pending
  957. pblSearch = m_prWorkerControl[dwIndex].m_blMixingAddPlayers.GetNext();
  958. while( pblSearch != &m_prWorkerControl[dwIndex].m_blMixingAddPlayers )
  959. {
  960. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  961. pVoicePlayer = pRealBilink->m_pPlayer;
  962. ASSERT_VPLAYER(pVoicePlayer);
  963. pblSearch = pblSearch->GetNext();
  964. pVoicePlayer->RemoveFromMixingList(dwIndex);
  965. pVoicePlayer->Release();
  966. }
  967. DNLeaveCriticalSection( &m_prWorkerControl[dwIndex].m_csMixingAddList );
  968. DNASSERT( m_prWorkerControl[dwIndex].m_blMixingAddPlayers.IsEmpty() );
  969. pblSearch = m_prWorkerControl[dwIndex].m_blMixingActivePlayers.GetNext();
  970. while( pblSearch != &m_prWorkerControl[dwIndex].m_blMixingActivePlayers )
  971. {
  972. CBilinkPlusObject* pRealBilink = CONTAINING_OBJECT( pblSearch, CBilinkPlusObject, m_bl );
  973. pVoicePlayer = pRealBilink->m_pPlayer;
  974. ASSERT_VPLAYER(pVoicePlayer);
  975. pblSearch = pblSearch->GetNext();
  976. pVoicePlayer->RemoveFromMixingList(dwIndex);
  977. pVoicePlayer->RemoveFromHearingList(dwIndex);
  978. pVoicePlayer->RemoveFromSpeakingList(dwIndex);
  979. pVoicePlayer->Release();
  980. }
  981. }
  982. }