Team Fortress 2 Source Code as on 22/4/2020
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.

871 lines
23 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: X360 XAudio Version
  4. //
  5. //=====================================================================================//
  6. #include "audio_pch.h"
  7. #include "snd_dev_xaudio.h"
  8. #include "UtlLinkedList.h"
  9. #include "session.h"
  10. #include "server.h"
  11. #include "client.h"
  12. #include "matchmaking.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. // The outer code mixes in PAINTBUFFER_SIZE (# of samples) chunks (see MIX_PaintChannels), we will never need more than
  16. // that many samples in a buffer. This ends up being about 20ms per buffer
  17. #define XAUDIO2_BUFFER_SAMPLES 8192
  18. // buffer return has a latency, so need a decent pool
  19. #define MAX_XAUDIO2_BUFFERS 32
  20. #define SURROUND_HEADPHONES 0
  21. #define SURROUND_STEREO 2
  22. #define SURROUND_DIGITAL5DOT1 5
  23. // 5.1 means there are a max of 6 channels
  24. #define MAX_DEVICE_CHANNELS 6
  25. ConVar snd_xaudio_spew_packets( "snd_xaudio_spew_packets", "0", 0, "Spew XAudio packet delivery" );
  26. //-----------------------------------------------------------------------------
  27. // Implementation of XAudio
  28. //-----------------------------------------------------------------------------
  29. class CAudioXAudio : public CAudioDeviceBase
  30. {
  31. public:
  32. ~CAudioXAudio( void );
  33. bool IsActive( void ) { return true; }
  34. bool Init( void );
  35. void Shutdown( void );
  36. void Pause( void );
  37. void UnPause( void );
  38. int PaintBegin( float mixAheadTime, int soundtime, int paintedtime );
  39. int GetOutputPosition( void );
  40. void ClearBuffer( void );
  41. void TransferSamples( int end );
  42. const char *DeviceName( void );
  43. int DeviceChannels( void ) { return m_deviceChannels; }
  44. int DeviceSampleBits( void ) { return m_deviceSampleBits; }
  45. int DeviceSampleBytes( void ) { return m_deviceSampleBits/8; }
  46. int DeviceDmaSpeed( void ) { return m_deviceDmaSpeed; }
  47. int DeviceSampleCount( void ) { return m_deviceSampleCount; }
  48. void XAudioPacketCallback( int hCompletedBuffer );
  49. static CAudioXAudio *m_pSingleton;
  50. CXboxVoice *GetVoiceData( void ) { return &m_VoiceData; }
  51. IXAudio2 *GetXAudio2( void ) { return m_pXAudio2; }
  52. private:
  53. int TransferStereo( const portable_samplepair_t *pFront, int paintedTime, int endTime, char *pOutptuBuffer );
  54. int TransferSurroundInterleaved( const portable_samplepair_t *pFront, const portable_samplepair_t *pRear, const portable_samplepair_t *pCenter, int paintedTime, int endTime, char *pOutputBuffer );
  55. int m_deviceChannels; // channels per hardware output buffer (1 for quad/5.1, 2 for stereo)
  56. int m_deviceSampleBits; // bits per sample (16)
  57. int m_deviceSampleCount; // count of mono samples in output buffer
  58. int m_deviceDmaSpeed; // samples per second per output buffer
  59. int m_clockDivider;
  60. IXAudio2 *m_pXAudio2;
  61. IXAudio2MasteringVoice *m_pMasteringVoice;
  62. IXAudio2SourceVoice *m_pSourceVoice;
  63. XAUDIO2_BUFFER m_Buffers[MAX_XAUDIO2_BUFFERS];
  64. BYTE *m_pOutputBuffer;
  65. int m_bufferSizeBytes; // size of a single hardware output buffer, in bytes
  66. CInterlockedUInt m_BufferTail;
  67. CInterlockedUInt m_BufferHead;
  68. CXboxVoice m_VoiceData;
  69. };
  70. CAudioXAudio *CAudioXAudio::m_pSingleton = NULL;
  71. //-----------------------------------------------------------------------------
  72. // XAudio packet completion callback
  73. //-----------------------------------------------------------------------------
  74. class XAudio2VoiceCallback : public IXAudio2VoiceCallback
  75. {
  76. public:
  77. XAudio2VoiceCallback() {}
  78. ~XAudio2VoiceCallback() {}
  79. void OnStreamEnd() {}
  80. void OnVoiceProcessingPassEnd() {}
  81. void OnVoiceProcessingPassStart( UINT32 SamplesRequired ) {}
  82. void OnBufferEnd( void *pBufferContext )
  83. {
  84. CAudioXAudio::m_pSingleton->XAudioPacketCallback( (int)pBufferContext );
  85. }
  86. void OnBufferStart( void *pBufferContext ) {}
  87. void OnLoopEnd( void *pBufferContext ) {}
  88. void OnVoiceError( void *pBufferContext, HRESULT Error ) {}
  89. };
  90. XAudio2VoiceCallback s_XAudio2VoiceCallback;
  91. //-----------------------------------------------------------------------------
  92. // Create XAudio Device
  93. //-----------------------------------------------------------------------------
  94. IAudioDevice *Audio_CreateXAudioDevice( void )
  95. {
  96. MEM_ALLOC_CREDIT();
  97. if ( !CAudioXAudio::m_pSingleton )
  98. {
  99. CAudioXAudio::m_pSingleton = new CAudioXAudio;
  100. }
  101. if ( !CAudioXAudio::m_pSingleton->Init() )
  102. {
  103. delete CAudioXAudio::m_pSingleton;
  104. CAudioXAudio::m_pSingleton = NULL;
  105. }
  106. return CAudioXAudio::m_pSingleton;
  107. }
  108. CXboxVoice *Audio_GetXVoice( void )
  109. {
  110. if ( CAudioXAudio::m_pSingleton )
  111. {
  112. return CAudioXAudio::m_pSingleton->GetVoiceData();
  113. }
  114. return NULL;
  115. }
  116. IXAudio2 *Audio_GetXAudio2( void )
  117. {
  118. if ( CAudioXAudio::m_pSingleton )
  119. {
  120. return CAudioXAudio::m_pSingleton->GetXAudio2();
  121. }
  122. return NULL;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Destructor
  126. //-----------------------------------------------------------------------------
  127. CAudioXAudio::~CAudioXAudio( void )
  128. {
  129. m_pSingleton = NULL;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Initialize XAudio
  133. //-----------------------------------------------------------------------------
  134. bool CAudioXAudio::Init( void )
  135. {
  136. XAUDIOSPEAKERCONFIG xAudioConfig = 0;
  137. XAudioGetSpeakerConfig( &xAudioConfig );
  138. snd_surround.SetValue( ( xAudioConfig & XAUDIOSPEAKERCONFIG_DIGITAL_DOLBYDIGITAL ) ? SURROUND_DIGITAL5DOT1 : SURROUND_STEREO );
  139. m_bHeadphone = false;
  140. m_bSurround = false;
  141. m_bSurroundCenter = false;
  142. switch ( snd_surround.GetInt() )
  143. {
  144. case SURROUND_HEADPHONES:
  145. m_bHeadphone = true;
  146. m_deviceChannels = 2;
  147. break;
  148. default:
  149. case SURROUND_STEREO:
  150. m_deviceChannels = 2;
  151. break;
  152. case SURROUND_DIGITAL5DOT1:
  153. m_bSurround = true;
  154. m_bSurroundCenter = true;
  155. m_deviceChannels = 6;
  156. break;
  157. }
  158. m_deviceSampleBits = 16;
  159. m_deviceDmaSpeed = SOUND_DMA_SPEED;
  160. // initialize the XAudio Engine
  161. // Both threads on core 2
  162. m_pXAudio2 = NULL;
  163. HRESULT hr = XAudio2Create( &m_pXAudio2, 0, XboxThread5 );
  164. if ( FAILED( hr ) )
  165. return false;
  166. // create the mastering voice, this will upsample to the devices target hw output rate
  167. m_pMasteringVoice = NULL;
  168. hr = m_pXAudio2->CreateMasteringVoice( &m_pMasteringVoice );
  169. if ( FAILED( hr ) )
  170. return false;
  171. // 16 bit PCM
  172. WAVEFORMATEX waveFormatEx = { 0 };
  173. waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
  174. waveFormatEx.nChannels = m_deviceChannels;
  175. waveFormatEx.nSamplesPerSec = m_deviceDmaSpeed;
  176. waveFormatEx.wBitsPerSample = 16;
  177. waveFormatEx.nBlockAlign = ( waveFormatEx.nChannels * waveFormatEx.wBitsPerSample ) / 8;
  178. waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * waveFormatEx.nBlockAlign;
  179. waveFormatEx.cbSize = 0;
  180. m_pSourceVoice = NULL;
  181. hr = m_pXAudio2->CreateSourceVoice(
  182. &m_pSourceVoice,
  183. &waveFormatEx,
  184. 0,
  185. XAUDIO2_DEFAULT_FREQ_RATIO,
  186. &s_XAudio2VoiceCallback,
  187. NULL,
  188. NULL );
  189. if ( FAILED( hr ) )
  190. return false;
  191. float volumes[MAX_DEVICE_CHANNELS];
  192. for ( int i = 0; i < MAX_DEVICE_CHANNELS; i++ )
  193. {
  194. if ( !m_bSurround && i >= 2 )
  195. {
  196. volumes[i] = 0;
  197. }
  198. else
  199. {
  200. volumes[i] = 1.0;
  201. }
  202. }
  203. m_pSourceVoice->SetChannelVolumes( m_deviceChannels, volumes );
  204. m_bufferSizeBytes = XAUDIO2_BUFFER_SAMPLES * (m_deviceSampleBits/8) * m_deviceChannels;
  205. m_pOutputBuffer = new BYTE[MAX_XAUDIO2_BUFFERS * m_bufferSizeBytes];
  206. ClearBuffer();
  207. V_memset( m_Buffers, 0, MAX_XAUDIO2_BUFFERS * sizeof( XAUDIO2_BUFFER ) );
  208. for ( int i = 0; i < MAX_XAUDIO2_BUFFERS; i++ )
  209. {
  210. m_Buffers[i].pAudioData = m_pOutputBuffer + i*m_bufferSizeBytes;
  211. m_Buffers[i].pContext = (LPVOID)i;
  212. }
  213. m_BufferHead = 0;
  214. m_BufferTail = 0;
  215. // number of mono samples output buffer may hold
  216. m_deviceSampleCount = MAX_XAUDIO2_BUFFERS * (m_bufferSizeBytes/(DeviceSampleBytes()));
  217. // NOTE: This really shouldn't be tied to the # of bufferable samples.
  218. // This just needs to be large enough so that it doesn't fake out the sampling in
  219. // GetSoundTime(). Basically GetSoundTime() assumes a cyclical time stamp and finds wraparound cases
  220. // but that means it needs to get called much more often than once per cycle. So this number should be
  221. // much larger than the framerate in terms of output time
  222. m_clockDivider = m_deviceSampleCount / DeviceChannels();
  223. // not really part of XAudio2, but mixer xma lacks one-time init, so doing it here
  224. XMAPlaybackInitialize();
  225. hr = m_pSourceVoice->Start( 0 );
  226. if ( FAILED( hr ) )
  227. return false;
  228. DevMsg( "XAudio Device Initialized:\n" );
  229. DevMsg( " %s\n"
  230. " %d channel(s)\n"
  231. " %d bits/sample\n"
  232. " %d samples/sec\n", DeviceName(), DeviceChannels(), DeviceSampleBits(), DeviceDmaSpeed() );
  233. m_VoiceData.VoiceInit();
  234. // success
  235. return true;
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Shutdown XAudio
  239. //-----------------------------------------------------------------------------
  240. void CAudioXAudio::Shutdown( void )
  241. {
  242. if ( m_pSourceVoice )
  243. {
  244. m_pSourceVoice->Stop( 0 );
  245. m_pSourceVoice->DestroyVoice();
  246. m_pSourceVoice = NULL;
  247. delete[] m_pOutputBuffer;
  248. }
  249. if ( m_pMasteringVoice )
  250. {
  251. m_pMasteringVoice->DestroyVoice();
  252. m_pMasteringVoice = NULL;
  253. }
  254. // need to release ref to XAudio2
  255. m_VoiceData.VoiceShutdown();
  256. if ( m_pXAudio2 )
  257. {
  258. m_pXAudio2->Release();
  259. m_pXAudio2 = NULL;
  260. }
  261. if ( this == CAudioXAudio::m_pSingleton )
  262. {
  263. CAudioXAudio::m_pSingleton = NULL;
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. // XAudio has completed a packet. Assuming these are sequential
  268. //-----------------------------------------------------------------------------
  269. void CAudioXAudio::XAudioPacketCallback( int hCompletedBuffer )
  270. {
  271. // packet completion expected to be sequential
  272. Assert( hCompletedBuffer == (int)( m_PacketTail % MAX_XAUDIO2_BUFFERS ) );
  273. m_BufferTail++;
  274. if ( snd_xaudio_spew_packets.GetBool() )
  275. {
  276. if ( m_BufferTail == m_BufferHead )
  277. {
  278. Warning( "XAudio: Starved\n" );
  279. }
  280. else
  281. {
  282. Msg( "XAudio: Packet Callback, Submit: %2d, Free: %2d\n", m_BufferHead - m_BufferTail, MAX_XAUDIO2_BUFFERS - ( m_BufferHead - m_BufferTail ) );
  283. }
  284. }
  285. if ( m_BufferTail == m_BufferHead )
  286. {
  287. // very bad, out of packets, xaudio is starving
  288. // mix thread didn't keep up with audio clock and submit packets
  289. // submit a silent buffer to keep stream playing and audio clock running
  290. int head = m_BufferHead++;
  291. XAUDIO2_BUFFER *pBuffer = &m_Buffers[head % MAX_XAUDIO2_BUFFERS];
  292. V_memset( pBuffer->pAudioData, 0, m_bufferSizeBytes );
  293. pBuffer->AudioBytes = m_bufferSizeBytes;
  294. m_pSourceVoice->SubmitSourceBuffer( pBuffer );
  295. }
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Return the "write" cursor. Used to clock the audio mixing.
  299. // The actual hw write cursor and the number of samples it fetches is unknown.
  300. //-----------------------------------------------------------------------------
  301. int CAudioXAudio::GetOutputPosition( void )
  302. {
  303. XAUDIO2_VOICE_STATE state;
  304. state.SamplesPlayed = 0;
  305. m_pSourceVoice->GetState( &state );
  306. return ( state.SamplesPlayed % m_clockDivider );
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Pause playback
  310. //-----------------------------------------------------------------------------
  311. void CAudioXAudio::Pause( void )
  312. {
  313. if ( m_pSourceVoice )
  314. {
  315. m_pSourceVoice->Stop( 0 );
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Resume playback
  320. //-----------------------------------------------------------------------------
  321. void CAudioXAudio::UnPause( void )
  322. {
  323. if ( m_pSourceVoice )
  324. {
  325. m_pSourceVoice->Start( 0 );
  326. }
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Calc the paint position
  330. //-----------------------------------------------------------------------------
  331. int CAudioXAudio::PaintBegin( float mixAheadTime, int soundtime, int paintedtime )
  332. {
  333. // soundtime = total full samples that have been played out to hardware at dmaspeed
  334. // paintedtime = total full samples that have been mixed at speed
  335. // endtime = target for full samples in mixahead buffer at speed
  336. int mixaheadtime = mixAheadTime * DeviceDmaSpeed();
  337. int endtime = soundtime + mixaheadtime;
  338. if ( endtime <= paintedtime )
  339. {
  340. return endtime;
  341. }
  342. int fullsamps = DeviceSampleCount() / DeviceChannels();
  343. if ( ( endtime - soundtime ) > fullsamps )
  344. {
  345. endtime = soundtime + fullsamps;
  346. }
  347. if ( ( endtime - paintedtime ) & 0x03 )
  348. {
  349. // The difference between endtime and painted time should align on
  350. // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
  351. endtime -= ( endtime - paintedtime ) & 0x03;
  352. }
  353. return endtime;
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Fill the output buffers with silence
  357. //-----------------------------------------------------------------------------
  358. void CAudioXAudio::ClearBuffer( void )
  359. {
  360. V_memset( m_pOutputBuffer, 0, MAX_XAUDIO2_BUFFERS * m_bufferSizeBytes );
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Fill the output buffer with L/R samples
  364. //-----------------------------------------------------------------------------
  365. int CAudioXAudio::TransferStereo( const portable_samplepair_t *pFrontBuffer, int paintedTime, int endTime, char *pOutputBuffer )
  366. {
  367. int linearCount;
  368. int i;
  369. int val;
  370. int volumeFactor = S_GetMasterVolume() * 256;
  371. int *pFront = (int *)pFrontBuffer;
  372. short *pOutput = (short *)pOutputBuffer;
  373. // get size of output buffer in full samples (LR pairs)
  374. // number of sequential sample pairs that can be wrriten
  375. linearCount = g_AudioDevice->DeviceSampleCount() >> 1;
  376. // clamp output count to requested number of samples
  377. if ( linearCount > endTime - paintedTime )
  378. {
  379. linearCount = endTime - paintedTime;
  380. }
  381. // linearCount is now number of mono 16 bit samples (L and R) to xfer.
  382. linearCount <<= 1;
  383. // transfer mono 16bit samples multiplying each sample by volume.
  384. for ( i=0; i<linearCount; i+=2 )
  385. {
  386. // L Channel
  387. val = ( pFront[i] * volumeFactor ) >> 8;
  388. *pOutput++ = CLIP( val );
  389. // R Channel
  390. val = ( pFront[i+1] * volumeFactor ) >> 8;
  391. *pOutput++ = CLIP( val );
  392. }
  393. return linearCount * DeviceSampleBytes();
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Fill the output buffer with interleaved surround samples
  397. //-----------------------------------------------------------------------------
  398. int CAudioXAudio::TransferSurroundInterleaved( const portable_samplepair_t *pFrontBuffer, const portable_samplepair_t *pRearBuffer, const portable_samplepair_t *pCenterBuffer, int paintedTime, int endTime, char *pOutputBuffer )
  399. {
  400. int linearCount;
  401. int i, j;
  402. int val;
  403. int volumeFactor = S_GetMasterVolume() * 256;
  404. int *pFront = (int *)pFrontBuffer;
  405. int *pRear = (int *)pRearBuffer;
  406. int *pCenter = (int *)pCenterBuffer;
  407. short *pOutput = (short *)pOutputBuffer;
  408. // number of mono samples per channel
  409. // number of sequential samples that can be wrriten
  410. linearCount = m_bufferSizeBytes/( DeviceSampleBytes() * DeviceChannels() );
  411. // clamp output count to requested number of samples
  412. if ( linearCount > endTime - paintedTime )
  413. {
  414. linearCount = endTime - paintedTime;
  415. }
  416. for ( i = 0, j = 0; i < linearCount; i++, j += 2 )
  417. {
  418. // FL
  419. val = ( pFront[j] * volumeFactor ) >> 8;
  420. *pOutput++ = CLIP( val );
  421. // FR
  422. val = ( pFront[j+1] * volumeFactor ) >> 8;
  423. *pOutput++ = CLIP( val );
  424. // Center
  425. val = ( pCenter[j] * volumeFactor) >> 8;
  426. *pOutput++ = CLIP( val );
  427. // Let the hardware mix the sub from the main channels since
  428. // we don't have any sub-specific sounds, or direct sub-addressing
  429. *pOutput++ = 0;
  430. // RL
  431. val = ( pRear[j] * volumeFactor ) >> 8;
  432. *pOutput++ = CLIP( val );
  433. // RR
  434. val = ( pRear[j+1] * volumeFactor ) >> 8;
  435. *pOutput++ = CLIP( val );
  436. }
  437. return linearCount * DeviceSampleBytes() * DeviceChannels();
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Transfer up to a full paintbuffer (PAINTBUFFER_SIZE) of samples out to the xaudio buffer(s).
  441. //-----------------------------------------------------------------------------
  442. void CAudioXAudio::TransferSamples( int endTime )
  443. {
  444. XAUDIO2_BUFFER *pBuffer;
  445. if ( m_BufferHead - m_BufferTail >= MAX_XAUDIO2_BUFFERS )
  446. {
  447. DevWarning( "XAudio: No Free Buffers!\n" );
  448. return;
  449. }
  450. int sampleCount = endTime - g_paintedtime;
  451. if ( sampleCount > XAUDIO2_BUFFER_SAMPLES )
  452. {
  453. DevWarning( "XAudio: Overflowed mix buffer!\n" );
  454. endTime = g_paintedtime + XAUDIO2_BUFFER_SAMPLES;
  455. }
  456. unsigned int nBuffer = m_BufferHead++;
  457. pBuffer = &m_Buffers[nBuffer % MAX_XAUDIO2_BUFFERS];
  458. if ( !m_bSurround )
  459. {
  460. pBuffer->AudioBytes = TransferStereo( PAINTBUFFER, g_paintedtime, endTime, (char *)pBuffer->pAudioData );
  461. }
  462. else
  463. {
  464. pBuffer->AudioBytes = TransferSurroundInterleaved( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, g_paintedtime, endTime, (char *)pBuffer->pAudioData );
  465. }
  466. // submit buffer
  467. m_pSourceVoice->SubmitSourceBuffer( pBuffer );
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Get our device name
  471. //-----------------------------------------------------------------------------
  472. const char *CAudioXAudio::DeviceName( void )
  473. {
  474. if ( m_bSurround )
  475. {
  476. return "XAudio: 5.1 Channel Surround";
  477. }
  478. return "XAudio: Stereo";
  479. }
  480. CXboxVoice::CXboxVoice()
  481. {
  482. m_pXHVEngine = NULL;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Initialize Voice
  486. //-----------------------------------------------------------------------------
  487. void CXboxVoice::VoiceInit( void )
  488. {
  489. if ( !m_pXHVEngine )
  490. {
  491. // Set the processing modes
  492. XHV_PROCESSING_MODE rgMode = XHV_VOICECHAT_MODE;
  493. // Set up parameters for the voice chat engine
  494. XHV_INIT_PARAMS xhvParams = {0};
  495. xhvParams.dwMaxRemoteTalkers = MAX_PLAYERS;
  496. xhvParams.dwMaxLocalTalkers = XUSER_MAX_COUNT;
  497. xhvParams.localTalkerEnabledModes = &rgMode;
  498. xhvParams.remoteTalkerEnabledModes = &rgMode;
  499. xhvParams.dwNumLocalTalkerEnabledModes = 1;
  500. xhvParams.dwNumRemoteTalkerEnabledModes = 1;
  501. xhvParams.pXAudio2 = CAudioXAudio::m_pSingleton->GetXAudio2();
  502. // Create the engine
  503. HRESULT hr = XHV2CreateEngine( &xhvParams, NULL, &m_pXHVEngine );
  504. if ( hr != S_OK )
  505. {
  506. Warning( "Couldn't load XHV engine!\n" );
  507. }
  508. }
  509. VoiceResetLocalData( );
  510. }
  511. void CXboxVoice::VoiceShutdown( void )
  512. {
  513. if ( !m_pXHVEngine )
  514. return;
  515. m_pXHVEngine->Release();
  516. m_pXHVEngine = NULL;
  517. }
  518. void CXboxVoice::AddPlayerToVoiceList( CClientInfo *pClient, bool bLocal )
  519. {
  520. XHV_PROCESSING_MODE local_proc_mode = XHV_VOICECHAT_MODE;
  521. for ( int i = 0; i < pClient->m_cPlayers; ++i )
  522. {
  523. if ( pClient->m_xuids[i] == 0 )
  524. continue;
  525. if ( bLocal == true )
  526. {
  527. if ( m_pXHVEngine->RegisterLocalTalker( pClient->m_iControllers[i] ) == S_OK )
  528. {
  529. m_pXHVEngine->StartLocalProcessingModes( pClient->m_iControllers[i], &local_proc_mode, 1 );
  530. }
  531. }
  532. else
  533. {
  534. if ( m_pXHVEngine->RegisterRemoteTalker( pClient->m_xuids[i], NULL, NULL, NULL ) == S_OK )
  535. {
  536. m_pXHVEngine->StartRemoteProcessingModes( pClient->m_xuids[i], &local_proc_mode, 1 );
  537. }
  538. }
  539. }
  540. }
  541. void CXboxVoice::RemovePlayerFromVoiceList( CClientInfo *pClient, bool bLocal )
  542. {
  543. for ( int i = 0; i < pClient->m_cPlayers; ++i )
  544. {
  545. if ( pClient->m_xuids[i] == 0 )
  546. continue;
  547. if ( bLocal == true )
  548. {
  549. m_pXHVEngine->UnregisterLocalTalker( pClient->m_iControllers[i] );
  550. }
  551. else
  552. {
  553. m_pXHVEngine->UnregisterRemoteTalker( pClient->m_xuids[i] );
  554. }
  555. }
  556. }
  557. void CXboxVoice::PlayIncomingVoiceData( XUID xuid, const byte *pbData, DWORD pdwSize )
  558. {
  559. XUID localXUID;
  560. XUserGetXUID( XBX_GetPrimaryUserId(), &localXUID );
  561. //Hack: Don't play stuff that comes from ourselves.
  562. if ( localXUID == xuid )
  563. return;
  564. m_pXHVEngine->SubmitIncomingChatData( xuid, pbData, &pdwSize );
  565. }
  566. void CXboxVoice::UpdateHUDVoiceStatus( void )
  567. {
  568. for ( int iClient = 0; iClient < cl.m_nMaxClients; iClient++ )
  569. {
  570. bool bSelf = (cl.m_nPlayerSlot == iClient);
  571. int iIndex = iClient + 1;
  572. XUID id = g_pMatchmaking->PlayerIdToXuid( iIndex );
  573. if ( id != 0 )
  574. {
  575. bool bTalking = false;
  576. if ( bSelf == true )
  577. {
  578. //Make sure the player's own label is not on.
  579. g_pSoundServices->OnChangeVoiceStatus( iIndex, false );
  580. iIndex = -1;
  581. if ( IsPlayerTalking( XBX_GetPrimaryUserId(), true ) )
  582. {
  583. bTalking = true;
  584. }
  585. }
  586. else
  587. {
  588. if ( IsPlayerTalking( id, false ) )
  589. {
  590. bTalking = true;
  591. }
  592. }
  593. g_pSoundServices->OnChangeVoiceStatus( iIndex, bTalking );
  594. }
  595. else
  596. {
  597. g_pSoundServices->OnChangeVoiceStatus( iIndex, false );
  598. }
  599. }
  600. }
  601. bool CXboxVoice::VoiceUpdateData( void )
  602. {
  603. DWORD dwNumPackets = 0;
  604. DWORD dwBytes = 0;
  605. WORD wVoiceBytes = 0;
  606. bool bShouldSend = false;
  607. DWORD dwVoiceFlags = m_pXHVEngine->GetDataReadyFlags();
  608. //Update UI stuff.
  609. UpdateHUDVoiceStatus();
  610. for ( uint i = 0; i < XUSER_MAX_COUNT; ++i )
  611. {
  612. // We currently only allow one player per console
  613. if ( i != XBX_GetPrimaryUserId() )
  614. {
  615. continue;
  616. }
  617. if ( IsHeadsetPresent( i ) == false )
  618. continue;
  619. if ( !(dwVoiceFlags & ( 1 << i )) )
  620. continue;
  621. dwBytes = m_ChatBufferSize - m_wLocalDataSize;
  622. if( dwBytes < XHV_VOICECHAT_MODE_PACKET_SIZE )
  623. {
  624. bShouldSend = true;
  625. }
  626. else
  627. {
  628. m_pXHVEngine->GetLocalChatData( i, m_ChatBuffer + m_wLocalDataSize, &dwBytes, &dwNumPackets );
  629. m_wLocalDataSize += ((WORD)dwBytes) & MAXWORD;
  630. if( m_wLocalDataSize > ( ( m_ChatBufferSize * 7 ) / 10 ) )
  631. {
  632. bShouldSend = true;
  633. }
  634. }
  635. wVoiceBytes += m_wLocalDataSize & MAXWORD;
  636. break;
  637. }
  638. return bShouldSend ||
  639. ( wVoiceBytes &&
  640. ( GetTickCount() - m_dwLastVoiceSend ) > MAX_VOICE_BUFFER_TIME );
  641. }
  642. void CXboxVoice::SetPlaybackPriority( XUID remoteTalker, DWORD dwUserIndex, XHV_PLAYBACK_PRIORITY playbackPriority )
  643. {
  644. m_pXHVEngine->SetPlaybackPriority( remoteTalker, dwUserIndex, playbackPriority );
  645. }
  646. void CXboxVoice::GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers )
  647. {
  648. m_pXHVEngine->GetRemoteTalkers( (DWORD*)pNumTalkers, pRemoteTalkers );
  649. }
  650. void CXboxVoice::GetVoiceData( CLC_VoiceData *pMessage )
  651. {
  652. byte *puchVoiceData = NULL;
  653. pMessage->m_nLength = m_wLocalDataSize;
  654. XUserGetXUID( XBX_GetPrimaryUserId(), &pMessage->m_xuid );
  655. puchVoiceData = m_ChatBuffer;
  656. pMessage->m_DataOut.StartWriting( puchVoiceData, pMessage->m_nLength );
  657. pMessage->m_nLength *= 8;
  658. pMessage->m_DataOut.SeekToBit( pMessage->m_nLength ); // set correct writing position
  659. }
  660. void CXboxVoice::VoiceSendData( INetChannel *pChannel )
  661. {
  662. CLC_VoiceData voiceMsg;
  663. GetVoiceData( &voiceMsg );
  664. if ( pChannel )
  665. {
  666. pChannel->SendNetMsg( voiceMsg, false, true );
  667. VoiceResetLocalData();
  668. }
  669. }
  670. void CXboxVoice::VoiceResetLocalData( void )
  671. {
  672. m_wLocalDataSize = 0;
  673. m_dwLastVoiceSend = GetTickCount();
  674. Q_memset( m_ChatBuffer, 0, m_ChatBufferSize );
  675. }
  676. bool CXboxVoice::IsPlayerTalking( XUID uid, bool bLocal )
  677. {
  678. if ( bLocal == true )
  679. {
  680. return m_pXHVEngine->IsLocalTalking( XBX_GetPrimaryUserId() );
  681. }
  682. else
  683. {
  684. return !g_pMatchmaking->IsPlayerMuted( XBX_GetPrimaryUserId(), uid ) && m_pXHVEngine->IsRemoteTalking( uid );
  685. }
  686. return false;
  687. }
  688. bool CXboxVoice::IsHeadsetPresent( int id )
  689. {
  690. return m_pXHVEngine->IsHeadsetPresent( id );
  691. }
  692. void CXboxVoice::RemoveAllTalkers( CClientInfo *pLocal )
  693. {
  694. int numRemoteTalkers;
  695. XUID remoteTalkers[MAX_PLAYERS];
  696. GetRemoteTalkers( &numRemoteTalkers, remoteTalkers );
  697. for ( int iRemote = 0; iRemote < numRemoteTalkers; iRemote++ )
  698. {
  699. m_pXHVEngine->UnregisterRemoteTalker( remoteTalkers[iRemote] );
  700. }
  701. if ( pLocal )
  702. {
  703. for ( int i = 0; i < pLocal->m_cPlayers; ++i )
  704. {
  705. if ( pLocal->m_xuids[i] == 0 )
  706. continue;
  707. m_pXHVEngine->UnregisterLocalTalker( pLocal->m_iControllers[i] );
  708. }
  709. }
  710. }