Counter Strike : Global Offensive Source Code
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.

1067 lines
30 KiB

  1. //========= Copyright � 1996-2005, 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 "server.h"
  10. #include "client.h"
  11. #include "matchmaking/imatchframework.h"
  12. #include "tier2/tier2.h"
  13. #include "smartptr.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. // The outer code mixes in PAINTBUFFER_SIZE (# of samples) chunks (see MIX_PaintChannels), we will never need more than
  17. // that many samples in a buffer. This ends up being about 20ms per buffer
  18. #define XAUDIO2_BUFFER_SAMPLES PAINTBUFFER_SIZE
  19. // buffer return has a latency, so need a decent pool
  20. #define MAX_XAUDIO2_BUFFERS 32
  21. #define SURROUND_HEADPHONES 0
  22. #define SURROUND_STEREO 2
  23. #define SURROUND_DIGITAL5DOT1 5
  24. // 5.1 means there are a max of 6 channels
  25. #define MAX_DEVICE_CHANNELS 6
  26. ConVar snd_xaudio_spew_buffers( "snd_xaudio_spew_buffers", "0", 0, "Spew XAudio buffer delivery" );
  27. extern IVEngineClient *engineClient;
  28. //-----------------------------------------------------------------------------
  29. // Implementation of XAudio
  30. //-----------------------------------------------------------------------------
  31. class CAudioXAudio : public CAudioDeviceBase
  32. {
  33. public:
  34. CAudioXAudio() : m_pXAudio2(NULL), m_pMasteringVoice(NULL), m_pSourceVoice(NULL), m_pOutputBuffer(NULL)
  35. {
  36. memset( m_Buffers, 0, sizeof(m_Buffers) ); // COMPILE_TIME_ASSERT( sizeof(m_Buffers) == sizeof(XAUDIO2_BUFFER)*MAX_XAUDIO2_BUFFERS );
  37. m_pName = "XAudio2 Device";
  38. m_nChannels = 2;
  39. m_nSampleBits = 16;
  40. m_nSampleRate = 44100;
  41. m_bIsActive = true;
  42. }
  43. ~CAudioXAudio( void );
  44. bool IsActive( void ) { return true; }
  45. bool Init( void );
  46. void Shutdown( void );
  47. void Pause( void );
  48. void UnPause( void );
  49. int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
  50. int GetOutputPosition( void );
  51. void ClearBuffer( void );
  52. void TransferSamples( int64 end );
  53. const char *DeviceName( void );
  54. int DeviceDmaSpeed( void ) { return m_nSampleRate; }
  55. int DeviceSampleCount( void ) { return m_deviceSampleCount; }
  56. void XAudio2BufferCallback( int hCompletedBuffer );
  57. static CAudioXAudio *m_pSingleton;
  58. CXboxVoice *GetVoiceData( void ) { return &m_VoiceData; }
  59. IXAudio2 *GetXAudio2( void ) { return m_pXAudio2; }
  60. private:
  61. int TransferStereo( const portable_samplepair_t *pFront, int paintedTime, int endTime, char *pOutptuBuffer );
  62. int TransferSurroundInterleaved( const portable_samplepair_t *pFront, const portable_samplepair_t *pRear, const portable_samplepair_t *pCenter, int paintedTime, int endTime, char *pOutputBuffer );
  63. int m_deviceSampleCount; // count of mono samples in output buffer
  64. int m_clockDivider;
  65. IXAudio2 *m_pXAudio2;
  66. IXAudio2MasteringVoice *m_pMasteringVoice;
  67. IXAudio2SourceVoice *m_pSourceVoice;
  68. XAUDIO2_BUFFER m_Buffers[MAX_XAUDIO2_BUFFERS];
  69. BYTE *m_pOutputBuffer;
  70. int m_bufferSizeBytes; // size of a single hardware output buffer, in bytes
  71. CInterlockedUInt m_BufferTail;
  72. CInterlockedUInt m_BufferHead;
  73. CXboxVoice m_VoiceData;
  74. };
  75. CAudioXAudio *CAudioXAudio::m_pSingleton = NULL;
  76. class XAudio2VoiceCallback : public IXAudio2VoiceCallback
  77. {
  78. public:
  79. XAudio2VoiceCallback() {}
  80. ~XAudio2VoiceCallback() {}
  81. void OnStreamEnd() {}
  82. void OnVoiceProcessingPassEnd() {}
  83. void OnVoiceProcessingPassStart( UINT32 SamplesRequired ) {}
  84. void OnBufferEnd( void *pBufferContext )
  85. {
  86. CAudioXAudio::m_pSingleton->XAudio2BufferCallback( (int)pBufferContext );
  87. }
  88. void OnBufferStart( void *pBufferContext ) {}
  89. void OnLoopEnd( void *pBufferContext ) {}
  90. void OnVoiceError( void *pBufferContext, HRESULT Error ) {}
  91. };
  92. XAudio2VoiceCallback s_XAudio2VoiceCallback;
  93. //-----------------------------------------------------------------------------
  94. // Create XAudio Device
  95. //-----------------------------------------------------------------------------
  96. IAudioDevice *Audio_CreateXAudioDevice( bool bInitVoice )
  97. {
  98. MEM_ALLOC_CREDIT();
  99. if ( CommandLine()->CheckParm( "-nosound" ) )
  100. {
  101. // respect forced lack of audio
  102. return NULL;
  103. }
  104. if ( !CAudioXAudio::m_pSingleton )
  105. {
  106. CAudioXAudio::m_pSingleton = new CAudioXAudio;
  107. if ( !CAudioXAudio::m_pSingleton->Init() )
  108. {
  109. AssertMsg( false, "Failed to init CAudioXAudio\n" );
  110. delete CAudioXAudio::m_pSingleton;
  111. CAudioXAudio::m_pSingleton = NULL;
  112. }
  113. }
  114. // need to support early init of XAudio (for bink startup video) without the voice
  115. // voice requires matchmaking which is not available at this early point
  116. // this defers the voice init to a later engine init mark
  117. if ( bInitVoice && CAudioXAudio::m_pSingleton )
  118. {
  119. CAudioXAudio::m_pSingleton->GetVoiceData()->VoiceInit();
  120. }
  121. return CAudioXAudio::m_pSingleton;
  122. }
  123. CXboxVoice *Audio_GetXVoice( void )
  124. {
  125. if ( CAudioXAudio::m_pSingleton )
  126. {
  127. return CAudioXAudio::m_pSingleton->GetVoiceData();
  128. }
  129. return NULL;
  130. }
  131. IXAudio2 *Audio_GetXAudio2( void )
  132. {
  133. if ( CAudioXAudio::m_pSingleton )
  134. {
  135. return CAudioXAudio::m_pSingleton->GetXAudio2();
  136. }
  137. return NULL;
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Destructor
  141. //-----------------------------------------------------------------------------
  142. CAudioXAudio::~CAudioXAudio( void )
  143. {
  144. m_pSingleton = NULL;
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Initialize XAudio
  148. //-----------------------------------------------------------------------------
  149. bool CAudioXAudio::Init( void )
  150. {
  151. XAUDIOSPEAKERCONFIG xAudioConfig = 0;
  152. XGetSpeakerConfig( &xAudioConfig );
  153. snd_surround.SetValue( ( xAudioConfig & XAUDIOSPEAKERCONFIG_DIGITAL_DOLBYDIGITAL ) ? SURROUND_DIGITAL5DOT1 : SURROUND_STEREO );
  154. m_bHeadphone = false;
  155. m_bSurround = false;
  156. m_bSurroundCenter = false;
  157. switch ( snd_surround.GetInt() )
  158. {
  159. case SURROUND_HEADPHONES:
  160. m_bHeadphone = true;
  161. m_nChannels = 2;
  162. break;
  163. default:
  164. case SURROUND_STEREO:
  165. m_nChannels = 2;
  166. break;
  167. case SURROUND_DIGITAL5DOT1:
  168. m_bSurround = true;
  169. m_bSurroundCenter = true;
  170. m_nChannels = 6;
  171. break;
  172. }
  173. Assert( m_nChannels <= MAX_DEVICE_CHANNELS );
  174. m_nSampleBits = 16;
  175. m_nSampleRate = SOUND_DMA_SPEED;
  176. // initialize the XAudio Engine
  177. // Both threads on core 2
  178. m_pXAudio2 = NULL;
  179. HRESULT hr = XAudio2Create( &m_pXAudio2, 0, XboxThread5 );
  180. if ( FAILED( hr ) )
  181. return false;
  182. // create the mastering voice, this will upsample to the devices target hw output rate
  183. m_pMasteringVoice = NULL;
  184. hr = m_pXAudio2->CreateMasteringVoice( &m_pMasteringVoice );
  185. if ( FAILED( hr ) )
  186. return false;
  187. // 16 bit PCM
  188. WAVEFORMATEX waveFormatEx = { 0 };
  189. waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
  190. waveFormatEx.nChannels = m_nChannels;
  191. waveFormatEx.nSamplesPerSec = m_nSampleRate;
  192. waveFormatEx.wBitsPerSample = 16;
  193. waveFormatEx.nBlockAlign = ( waveFormatEx.nChannels * waveFormatEx.wBitsPerSample ) / 8;
  194. waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * waveFormatEx.nBlockAlign;
  195. waveFormatEx.cbSize = 0;
  196. m_pSourceVoice = NULL;
  197. hr = m_pXAudio2->CreateSourceVoice(
  198. &m_pSourceVoice,
  199. &waveFormatEx,
  200. 0,
  201. XAUDIO2_DEFAULT_FREQ_RATIO,
  202. &s_XAudio2VoiceCallback,
  203. NULL,
  204. NULL );
  205. if ( FAILED( hr ) )
  206. return false;
  207. float volumes[MAX_DEVICE_CHANNELS];
  208. for ( int i = 0; i < MAX_DEVICE_CHANNELS; i++ )
  209. {
  210. if ( !m_bSurround && i >= 2 )
  211. {
  212. volumes[i] = 0;
  213. }
  214. else
  215. {
  216. volumes[i] = 1.0;
  217. }
  218. }
  219. m_pSourceVoice->SetChannelVolumes( m_nChannels, volumes );
  220. m_bufferSizeBytes = XAUDIO2_BUFFER_SAMPLES * (m_nSampleBits/8) * m_nChannels;
  221. m_pOutputBuffer = new BYTE[MAX_XAUDIO2_BUFFERS * m_bufferSizeBytes];
  222. ClearBuffer();
  223. V_memset( m_Buffers, 0, MAX_XAUDIO2_BUFFERS * sizeof( XAUDIO2_BUFFER ) );
  224. for ( int i = 0; i < MAX_XAUDIO2_BUFFERS; i++ )
  225. {
  226. m_Buffers[i].pAudioData = m_pOutputBuffer + i*m_bufferSizeBytes;
  227. m_Buffers[i].pContext = (LPVOID)i;
  228. }
  229. m_BufferHead = 0;
  230. m_BufferTail = 0;
  231. // number of mono samples output buffer may hold
  232. m_deviceSampleCount = MAX_XAUDIO2_BUFFERS * (m_bufferSizeBytes/(DeviceSampleBytes()));
  233. // NOTE: This really shouldn't be tied to the # of bufferable samples.
  234. // This just needs to be large enough so that it doesn't fake out the sampling in
  235. // GetSoundTime(). Basically GetSoundTime() assumes a cyclical time stamp and finds wraparound cases
  236. // but that means it needs to get called much more often than once per cycle. So this number should be
  237. // much larger than the framerate in terms of output time
  238. m_clockDivider = m_deviceSampleCount / ChannelCount();
  239. // not really part of XAudio2, but mixer xma lacks one-time init, so doing it here
  240. XMAPlaybackInitialize();
  241. hr = m_pSourceVoice->Start( 0 );
  242. if ( FAILED( hr ) )
  243. return false;
  244. DevMsg( "XAudio Device Initialized:\n" );
  245. DevMsg( " %s\n"
  246. " %d channel(s)\n"
  247. " %d bits/sample\n"
  248. " %d samples/sec\n", DeviceName(), ChannelCount(), BitsPerSample(), DeviceDmaSpeed() );
  249. // success
  250. return true;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Shutdown XAudio
  254. //-----------------------------------------------------------------------------
  255. void CAudioXAudio::Shutdown( void )
  256. {
  257. if ( m_pSourceVoice )
  258. {
  259. m_pSourceVoice->Stop( 0 );
  260. m_pSourceVoice->DestroyVoice();
  261. m_pSourceVoice = NULL;
  262. delete[] m_pOutputBuffer;
  263. }
  264. if ( m_pMasteringVoice )
  265. {
  266. m_pMasteringVoice->DestroyVoice();
  267. m_pMasteringVoice = NULL;
  268. }
  269. // need to release ref to XAudio2
  270. m_VoiceData.VoiceShutdown();
  271. if ( m_pXAudio2 )
  272. {
  273. m_pXAudio2->Release();
  274. m_pXAudio2 = NULL;
  275. }
  276. if ( this == CAudioXAudio::m_pSingleton )
  277. {
  278. CAudioXAudio::m_pSingleton = NULL;
  279. }
  280. }
  281. //-----------------------------------------------------------------------------
  282. // XAudio has completed a buffer. Assuming these are sequential
  283. //-----------------------------------------------------------------------------
  284. void CAudioXAudio::XAudio2BufferCallback( int hCompletedBuffer )
  285. {
  286. // buffer completion expected to be sequential
  287. Assert( hCompletedBuffer == (int)( m_BufferTail % MAX_XAUDIO2_BUFFERS ) );
  288. m_BufferTail++;
  289. if ( snd_xaudio_spew_buffers.GetBool() )
  290. {
  291. if ( m_BufferTail == m_BufferHead )
  292. {
  293. Warning( "XAudio: Starved\n" );
  294. }
  295. else
  296. {
  297. Msg( "XAudio: Buffer Callback, Submit: %2d, Free: %2d\n", m_BufferHead - m_BufferTail, MAX_XAUDIO2_BUFFERS - ( m_BufferHead - m_BufferTail ) );
  298. }
  299. }
  300. if ( m_BufferTail == m_BufferHead )
  301. {
  302. // very bad, out of buffers, xaudio is starving
  303. // mix thread didn't keep up with audio clock and submit buffers
  304. // submit a silent buffer to keep stream playing and audio clock running
  305. int head = m_BufferHead++;
  306. XAUDIO2_BUFFER *pBuffer = &m_Buffers[head % MAX_XAUDIO2_BUFFERS];
  307. V_memset( (void *)pBuffer->pAudioData, 0, m_bufferSizeBytes );
  308. pBuffer->AudioBytes = m_bufferSizeBytes;
  309. m_pSourceVoice->SubmitSourceBuffer( pBuffer );
  310. }
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Return the "write" cursor. Used to clock the audio mixing.
  314. // The actual hw write cursor and the number of samples it fetches is unknown.
  315. //-----------------------------------------------------------------------------
  316. int CAudioXAudio::GetOutputPosition( void )
  317. {
  318. XAUDIO2_VOICE_STATE state;
  319. state.SamplesPlayed = 0;
  320. m_pSourceVoice->GetState( &state );
  321. return ( state.SamplesPlayed % m_clockDivider );
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Pause playback
  325. //-----------------------------------------------------------------------------
  326. void CAudioXAudio::Pause( void )
  327. {
  328. if ( m_pSourceVoice )
  329. {
  330. m_pSourceVoice->Stop( 0 );
  331. }
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Resume playback
  335. //-----------------------------------------------------------------------------
  336. void CAudioXAudio::UnPause( void )
  337. {
  338. if ( m_pSourceVoice )
  339. {
  340. m_pSourceVoice->Start( 0 );
  341. }
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Calc the paint position
  345. //-----------------------------------------------------------------------------
  346. int64 CAudioXAudio::PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime )
  347. {
  348. // soundtime = total full samples that have been played out to hardware at dmaspeed
  349. // paintedtime = total full samples that have been mixed at speed
  350. // endtime = target for full samples in mixahead buffer at speed
  351. int mixaheadtime = mixAheadTime * DeviceDmaSpeed();
  352. int64 endtime = soundtime + mixaheadtime;
  353. if ( endtime <= paintedtime )
  354. {
  355. return endtime;
  356. }
  357. int fullsamps = MAX_XAUDIO2_BUFFERS * (m_bufferSizeBytes /( DeviceSampleBytes() * ChannelCount() ));
  358. if ( ( endtime - soundtime ) > fullsamps )
  359. {
  360. endtime = soundtime + fullsamps;
  361. }
  362. if ( ( endtime - paintedtime ) & 0x03 )
  363. {
  364. // The difference between endtime and painted time should align on
  365. // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
  366. endtime -= ( endtime - paintedtime ) & 0x03;
  367. }
  368. return endtime;
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Fill the output buffers with silence
  372. //-----------------------------------------------------------------------------
  373. void CAudioXAudio::ClearBuffer( void )
  374. {
  375. V_memset( m_pOutputBuffer, 0, MAX_XAUDIO2_BUFFERS * m_bufferSizeBytes );
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Fill the output buffer with L/R samples
  379. //-----------------------------------------------------------------------------
  380. int CAudioXAudio::TransferStereo( const portable_samplepair_t *pFrontBuffer, int paintedTime, int endTime, char *pOutputBuffer )
  381. {
  382. int linearCount;
  383. int i;
  384. int val;
  385. int volumeFactor = S_GetMasterVolume() * 256;
  386. int *pFront = (int *)pFrontBuffer;
  387. short *pOutput = (short *)pOutputBuffer;
  388. // get size of output buffer in full samples (LR pairs)
  389. // number of sequential sample pairs that can be wrriten
  390. linearCount = m_bufferSizeBytes/( DeviceSampleBytes() * ChannelCount() );
  391. // clamp output count to requested number of samples
  392. if ( linearCount > endTime - paintedTime )
  393. {
  394. linearCount = endTime - paintedTime;
  395. }
  396. // linearCount is now number of mono 16 bit samples (L and R) to xfer.
  397. linearCount <<= 1;
  398. // transfer mono 16bit samples multiplying each sample by volume.
  399. for ( i=0; i<linearCount; i+=2 )
  400. {
  401. // L Channel
  402. val = ( pFront[i] * volumeFactor ) >> 8;
  403. *pOutput++ = iclip( val );
  404. // R Channel
  405. val = ( pFront[i+1] * volumeFactor ) >> 8;
  406. *pOutput++ = iclip( val );
  407. }
  408. return linearCount * DeviceSampleBytes();
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Fill the output buffer with interleaved surround samples
  412. //-----------------------------------------------------------------------------
  413. int CAudioXAudio::TransferSurroundInterleaved( const portable_samplepair_t *pFrontBuffer, const portable_samplepair_t *pRearBuffer, const portable_samplepair_t *pCenterBuffer, int paintedTime, int endTime, char *pOutputBuffer )
  414. {
  415. int linearCount;
  416. int i, j;
  417. int val;
  418. int volumeFactor = S_GetMasterVolume() * 256;
  419. int *pFront = (int *)pFrontBuffer;
  420. int *pRear = (int *)pRearBuffer;
  421. int *pCenter = (int *)pCenterBuffer;
  422. short *pOutput = (short *)pOutputBuffer;
  423. // number of mono samples per channel
  424. // number of sequential samples that can be wrriten
  425. linearCount = m_bufferSizeBytes/( DeviceSampleBytes() * ChannelCount() );
  426. // clamp output count to requested number of samples
  427. if ( linearCount > endTime - paintedTime )
  428. {
  429. linearCount = endTime - paintedTime;
  430. }
  431. for ( i = 0, j = 0; i < linearCount; i++, j += 2 )
  432. {
  433. // FL
  434. val = ( pFront[j] * volumeFactor ) >> 8;
  435. *pOutput++ = iclip( val );
  436. // FR
  437. val = ( pFront[j+1] * volumeFactor ) >> 8;
  438. *pOutput++ = iclip( val );
  439. // Center
  440. val = ( pCenter[j] * volumeFactor) >> 8;
  441. *pOutput++ = iclip( val );
  442. // Let the hardware mix the sub from the main channels since
  443. // we don't have any sub-specific sounds, or direct sub-addressing
  444. *pOutput++ = 0;
  445. // RL
  446. val = ( pRear[j] * volumeFactor ) >> 8;
  447. *pOutput++ = iclip( val );
  448. // RR
  449. val = ( pRear[j+1] * volumeFactor ) >> 8;
  450. *pOutput++ = iclip( val );
  451. }
  452. return linearCount * DeviceSampleBytes() * ChannelCount();
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Transfer up to a full paintbuffer (PAINTBUFFER_SIZE) of samples out to the xaudio buffer(s).
  456. //-----------------------------------------------------------------------------
  457. void CAudioXAudio::TransferSamples( int64 endTime )
  458. {
  459. XAUDIO2_BUFFER *pBuffer;
  460. if ( m_BufferHead - m_BufferTail >= MAX_XAUDIO2_BUFFERS )
  461. {
  462. DevWarning( "XAudio: No Free Buffers!\n" );
  463. return;
  464. }
  465. int sampleCount = endTime - g_paintedtime;
  466. if ( sampleCount > XAUDIO2_BUFFER_SAMPLES )
  467. {
  468. DevWarning( "XAudio: Overflowed mix buffer!\n" );
  469. endTime = g_paintedtime + XAUDIO2_BUFFER_SAMPLES;
  470. }
  471. unsigned int nBuffer = m_BufferHead++;
  472. pBuffer = &m_Buffers[nBuffer % MAX_XAUDIO2_BUFFERS];
  473. if ( !m_bSurround )
  474. {
  475. pBuffer->AudioBytes = TransferStereo( PAINTBUFFER, g_paintedtime, endTime, (char *)pBuffer->pAudioData );
  476. }
  477. else
  478. {
  479. pBuffer->AudioBytes = TransferSurroundInterleaved( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, g_paintedtime, endTime, (char *)pBuffer->pAudioData );
  480. }
  481. // submit buffer
  482. m_pSourceVoice->SubmitSourceBuffer( pBuffer );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Get our device name
  486. //-----------------------------------------------------------------------------
  487. const char *CAudioXAudio::DeviceName( void )
  488. {
  489. if ( m_bSurround )
  490. {
  491. return "XAudio: 5.1 Channel Surround";
  492. }
  493. return "XAudio: Stereo";
  494. }
  495. CXboxVoice::CXboxVoice()
  496. {
  497. m_pXHVEngine = NULL;
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Initialize Voice
  501. //-----------------------------------------------------------------------------
  502. void CXboxVoice::VoiceInit( void )
  503. {
  504. if ( !m_pXHVEngine )
  505. {
  506. // Set the processing modes
  507. XHV_PROCESSING_MODE rgMode = XHV_VOICECHAT_MODE;
  508. // Set up parameters for the voice chat engine
  509. XHV_INIT_PARAMS xhvParams = {0};
  510. xhvParams.dwMaxRemoteTalkers = g_pMatchFramework->GetMatchTitle()->GetTotalNumPlayersSupported();
  511. xhvParams.dwMaxLocalTalkers = XUSER_MAX_COUNT;
  512. xhvParams.localTalkerEnabledModes = &rgMode;
  513. xhvParams.remoteTalkerEnabledModes = &rgMode;
  514. xhvParams.dwNumLocalTalkerEnabledModes = 1;
  515. xhvParams.dwNumRemoteTalkerEnabledModes = 1;
  516. xhvParams.pXAudio2 = CAudioXAudio::m_pSingleton->GetXAudio2();
  517. // Create the engine
  518. HRESULT hr = XHV2CreateEngine( &xhvParams, NULL, &m_pXHVEngine );
  519. if ( hr != S_OK )
  520. {
  521. Warning( "Couldn't load XHV engine!\n" );
  522. }
  523. }
  524. memset( m_bUserRegistered, 0 ,sizeof( m_bUserRegistered ) );
  525. // Reset voice data for all ctrlrs
  526. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  527. {
  528. VoiceResetLocalData( k );
  529. }
  530. }
  531. void CXboxVoice::VoiceShutdown( void )
  532. {
  533. if ( !m_pXHVEngine )
  534. return;
  535. m_pXHVEngine->Release();
  536. m_pXHVEngine = NULL;
  537. }
  538. void CXboxVoice::AddPlayerToVoiceList( XUID xPlayer, int iController, uint64 uiFlags )
  539. {
  540. #ifdef _X360
  541. XHV_PROCESSING_MODE local_proc_mode = XHV_VOICECHAT_MODE;
  542. if ( !xPlayer && iController >= 0 && iController < XUSER_MAX_COUNT )
  543. {
  544. // If was registered from previous time, then unregister
  545. if( m_bUserRegistered[ iController ] )
  546. {
  547. m_pXHVEngine->UnregisterLocalTalker( iController );
  548. m_bUserRegistered[ iController ] = false;
  549. }
  550. // Now register local talker
  551. if ( m_pXHVEngine->RegisterLocalTalker( iController ) == S_OK )
  552. {
  553. m_bUserRegistered[ iController ] = true;
  554. m_pXHVEngine->StartLocalProcessingModes( iController, &local_proc_mode, 1 );
  555. }
  556. }
  557. else if ( xPlayer )
  558. {
  559. HRESULT res = m_pXHVEngine->RegisterRemoteTalker( xPlayer, NULL, NULL, NULL );
  560. ConVarRef voice_verbose( "voice_verbose" );
  561. if ( voice_verbose.GetBool() )
  562. {
  563. Msg( "* CXboxVoice::AddPlayerToVoiceList: Registering %llx returned 0x%08x\n", xPlayer, res );
  564. }
  565. if ( res == S_OK )
  566. {
  567. m_pXHVEngine->StartRemoteProcessingModes( xPlayer, &local_proc_mode, 1 );
  568. }
  569. }
  570. else
  571. {
  572. Assert( 0 );
  573. }
  574. #endif
  575. }
  576. void CXboxVoice::RemovePlayerFromVoiceList( XUID xPlayer, int iController )
  577. {
  578. if ( !xPlayer && iController >= 0 && iController < XUSER_MAX_COUNT )
  579. {
  580. if( m_bUserRegistered[ iController ] )
  581. {
  582. m_pXHVEngine->UnregisterLocalTalker( iController );
  583. m_bUserRegistered[ iController ] = false;
  584. }
  585. }
  586. else if ( xPlayer )
  587. {
  588. m_pXHVEngine->UnregisterRemoteTalker( xPlayer );
  589. }
  590. else
  591. {
  592. Assert( 0 );
  593. }
  594. }
  595. #ifdef _X360
  596. ConVar voice_xplay_debug( "voice_xplay_debug", "0" );
  597. #endif
  598. void CXboxVoice::PlayIncomingVoiceData( XUID xuid, const byte *pbData, unsigned int dwDataSize, const bool *bAudiblePlayers )
  599. {
  600. ConVarRef voice_verbose( "voice_verbose" );
  601. #ifdef _X360
  602. static double s_flLastCheckedTime = 0.0;
  603. static const double s_flCheckFreq = 0.5;
  604. double flTime = Plat_FloatTime();
  605. if ( flTime - s_flLastCheckedTime > s_flCheckFreq )
  606. {
  607. s_flLastCheckedTime = flTime;
  608. // Register all idle signed in players
  609. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  610. {
  611. bool bSignedIn = !( XUserGetSigninState( k ) == eXUserSigninState_NotSignedIn );
  612. if ( m_bUserRegistered[k] == bSignedIn )
  613. continue;
  614. XHV_PROCESSING_MODE local_proc_mode = XHV_VOICECHAT_MODE;
  615. if ( bSignedIn )
  616. {
  617. if ( m_pXHVEngine->RegisterLocalTalker( k ) == S_OK )
  618. {
  619. m_bUserRegistered[ k ] = true;
  620. m_pXHVEngine->StartLocalProcessingModes( k, &local_proc_mode, 1 );
  621. }
  622. }
  623. else
  624. {
  625. m_pXHVEngine->UnregisterLocalTalker( k );
  626. m_bUserRegistered[ k ] = false;
  627. }
  628. // Notify matchmaking that local talkers have changed
  629. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnSysMuteListChanged" ) );
  630. }
  631. }
  632. #endif
  633. for ( DWORD dwSlot = 0; dwSlot < XBX_GetNumGameUsers(); ++ dwSlot )
  634. {
  635. int iCtrlr = XBX_GetUserId( dwSlot );
  636. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iCtrlr );
  637. if ( pPlayer && pPlayer->GetXUID() == xuid )
  638. {
  639. //Hack: Don't play stuff that comes from ourselves.
  640. if ( voice_verbose.GetBool() )
  641. {
  642. Msg( "* CXboxVoice::PlayIncomingVoiceData: dropping voice data from self with dwBytes %u\n", dwDataSize );
  643. }
  644. return;
  645. }
  646. }
  647. if ( g_pMatchFramework->GetMatchSystem()->GetMatchVoice()->CanPlaybackTalker( xuid ) )
  648. {
  649. // Set the playback priority for talkers that we can't hear due to game rules.
  650. for ( DWORD dwSlot = 0; dwSlot < XBX_GetNumGameUsers(); ++dwSlot )
  651. {
  652. bool bCanHearPlayer = !bAudiblePlayers || bAudiblePlayers[dwSlot];
  653. // Check if the client thinks the player is audible
  654. if ( !bAudiblePlayers )
  655. {
  656. for ( int iClient = 0; iClient < GetBaseLocalClient().m_nMaxClients; iClient++ )
  657. {
  658. int iIndex = iClient + 1;
  659. player_info_t infoClient;
  660. if ( engineClient->GetPlayerInfo( iIndex, &infoClient ) )
  661. {
  662. if ( xuid == infoClient.xuid )
  663. {
  664. bCanHearPlayer = g_pSoundServices->GetPlayerAudible( iIndex );
  665. break;
  666. }
  667. }
  668. }
  669. }
  670. if ( voice_xplay_debug.GetBool() )
  671. {
  672. DevMsg( "XVoiceDebug: %llx -> %d = %s\n", xuid, XBX_GetUserId( dwSlot ), bCanHearPlayer ? "yes" : "no" );
  673. }
  674. m_pXHVEngine->SetPlaybackPriority( xuid, XBX_GetUserId( dwSlot ), bCanHearPlayer ? XHV_PLAYBACK_PRIORITY_MAX : XHV_PLAYBACK_PRIORITY_NEVER );
  675. }
  676. // For idle users who are simply signed in on the console, but do not participate in the game
  677. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  678. {
  679. if ( m_bUserRegistered[k] && ( XBX_GetSlotByUserId( k ) < 0 ) )
  680. {
  681. if ( voice_xplay_debug.GetBool() )
  682. {
  683. DevMsg( "XVoiceDebug: %llx -> %d = idle\n", xuid, k );
  684. }
  685. m_pXHVEngine->SetPlaybackPriority( xuid, k, XHV_PLAYBACK_PRIORITY_NEVER );
  686. }
  687. }
  688. }
  689. else
  690. {
  691. // Cannot submit voice for the player that we are not allowed to playback!
  692. if ( voice_xplay_debug.GetBool() )
  693. {
  694. DevMsg( "XVoiceDebug: %llx muted\n", xuid );
  695. }
  696. return;
  697. }
  698. DWORD dwApiSize = dwDataSize;
  699. HRESULT hrSubmit = m_pXHVEngine->SubmitIncomingChatData( xuid, pbData, &dwApiSize );
  700. if ( voice_verbose.GetBool() )
  701. {
  702. Msg( "* CXboxVoice::PlayIncomingVoiceData: SubmitIncomingChatData with %u bytes returned 0x%08x and copied dwBytes %u\n", dwDataSize, hrSubmit, dwApiSize );
  703. }
  704. }
  705. void CXboxVoice::UpdateHUDVoiceStatus( void )
  706. {
  707. for ( int iClient = 0; iClient < GetBaseLocalClient().m_nMaxClients; iClient++ )
  708. {
  709. // Information about local client if it's a local client speaking
  710. bool bLocalClient = false;
  711. int iSsSlot = -1;
  712. int iCtrlr = -1;
  713. // Detection if it's a local client
  714. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  715. {
  716. CClientState &cs = GetLocalClient( k );
  717. if ( cs.m_nPlayerSlot == iClient )
  718. {
  719. bLocalClient = true;
  720. iSsSlot = k;
  721. iCtrlr = XBX_GetUserId( iSsSlot );
  722. }
  723. }
  724. // Convert into index and XUID
  725. int iIndex = iClient + 1;
  726. XUID xid = NULL;
  727. player_info_t infoClient;
  728. if ( engineClient->GetPlayerInfo( iIndex, &infoClient ) )
  729. {
  730. xid = infoClient.xuid;
  731. }
  732. // [jason] skip any bots - we don't want to override their voice status from the chatter
  733. if ( infoClient.fakeplayer )
  734. continue;
  735. if ( !xid )
  736. // No XUID means no VOIP
  737. {
  738. g_pSoundServices->OnChangeVoiceStatus( iIndex, -1, false );
  739. if ( bLocalClient )
  740. g_pSoundServices->OnChangeVoiceStatus( iIndex, iSsSlot, false );
  741. continue;
  742. }
  743. // Determine talking status
  744. bool bTalking = false;
  745. if ( bLocalClient )
  746. {
  747. //Make sure the player's own "remote" label is not on.
  748. g_pSoundServices->OnChangeVoiceStatus( iIndex, -1, false );
  749. iIndex = -1; // issue notification as ent=-1
  750. bTalking = IsLocalPlayerTalking( iCtrlr );
  751. }
  752. else
  753. {
  754. bTalking = IsPlayerTalking( xid );
  755. }
  756. g_pSoundServices->OnChangeVoiceStatus( iIndex, iSsSlot, bTalking );
  757. }
  758. }
  759. bool CXboxVoice::VoiceUpdateData( int iCtrlr )
  760. {
  761. DWORD dwNumPackets = 0;
  762. DWORD dwBytes = 0;
  763. WORD wVoiceBytes = 0;
  764. bool bShouldSend = false;
  765. DWORD dwVoiceFlags = m_pXHVEngine->GetDataReadyFlags();
  766. //Update UI stuff.
  767. UpdateHUDVoiceStatus();
  768. while ( 1 )
  769. {
  770. int i = iCtrlr;
  771. if ( IsHeadsetPresent( i ) == false )
  772. break;
  773. if ( !(dwVoiceFlags & ( 1 << i )) )
  774. break;
  775. dwBytes = m_ChatBufferSize - m_wLocalDataSize[i];
  776. if( dwBytes < XHV_VOICECHAT_MODE_PACKET_SIZE )
  777. {
  778. bShouldSend = true;
  779. }
  780. else
  781. {
  782. HRESULT hr = m_pXHVEngine->GetLocalChatData( i, m_ChatBuffer[i] + m_wLocalDataSize[i], &dwBytes, &dwNumPackets );
  783. ConVarRef voice_verbose( "voice_verbose" );
  784. if ( voice_verbose.GetBool() )
  785. {
  786. Msg( "* CXboxVoice::VoiceUpdateData: GetLocalChatData for user %d returned 0x%08x with dwBytes %u and dwNumPackets %u\n", i, hr, dwBytes, dwNumPackets );
  787. }
  788. m_wLocalDataSize[i] += ((WORD)dwBytes) & MAXWORD;
  789. if( m_wLocalDataSize[i] > ( ( m_ChatBufferSize * 7 ) / 10 ) )
  790. {
  791. bShouldSend = true;
  792. }
  793. }
  794. wVoiceBytes += m_wLocalDataSize[i] & MAXWORD;
  795. break;
  796. }
  797. return bShouldSend ||
  798. ( wVoiceBytes &&
  799. ( GetTickCount() - m_dwLastVoiceSend[ iCtrlr ] ) > MAX_VOICE_BUFFER_TIME );
  800. }
  801. void CXboxVoice::SetPlaybackPriority( XUID remoteTalker, int iController, int iAllowPlayback )
  802. {
  803. XHV_PLAYBACK_PRIORITY playbackPriority = iAllowPlayback ? XHV_PLAYBACK_PRIORITY_MAX : XHV_PLAYBACK_PRIORITY_NEVER;
  804. // DevMsg( "[XAUDIO] SetPlaybackPriority %I64x %d %08X\n", remoteTalker, dwUserIndex, playbackPriority );
  805. m_pXHVEngine->SetPlaybackPriority( remoteTalker, iController, playbackPriority );
  806. #ifdef _X360
  807. // When setting NEVER playback priority, make sure it is set for all controllers
  808. if ( playbackPriority == XHV_PLAYBACK_PRIORITY_NEVER )
  809. {
  810. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  811. {
  812. m_pXHVEngine->SetPlaybackPriority( remoteTalker, k, playbackPriority );
  813. }
  814. }
  815. #endif
  816. }
  817. void CXboxVoice::GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers )
  818. {
  819. m_pXHVEngine->GetRemoteTalkers( (DWORD*)pNumTalkers, pRemoteTalkers );
  820. }
  821. void CXboxVoice::GetVoiceData( int iCtrlr, CCLCMsg_VoiceData_t *pMessage )
  822. {
  823. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iCtrlr );
  824. pMessage->set_xuid( pPlayer ? pPlayer->GetXUID() : 0ull );
  825. if ( !pMessage->xuid() )
  826. return;
  827. if ( !m_wLocalDataSize[ iCtrlr ] )
  828. return;
  829. pMessage->set_data( m_ChatBuffer[ iCtrlr ], m_wLocalDataSize[ iCtrlr ] );
  830. }
  831. void CXboxVoice::GetVoiceData( int iController, const byte **ppvVoiceDataBuffer, unsigned int *pnumVoiceDataBytes )
  832. {
  833. *pnumVoiceDataBytes = m_wLocalDataSize[ iController ];
  834. *ppvVoiceDataBuffer = m_ChatBuffer[ iController ];
  835. }
  836. void CXboxVoice::VoiceSendData( int iCtrlr, INetChannel *pChannel )
  837. {
  838. CCLCMsg_VoiceData_t voiceMsg;
  839. GetVoiceData( iCtrlr, &voiceMsg );
  840. if ( pChannel )
  841. {
  842. pChannel->SendNetMsg( voiceMsg, false, true );
  843. VoiceResetLocalData( iCtrlr );
  844. }
  845. }
  846. void CXboxVoice::VoiceResetLocalData( int iCtrlr )
  847. {
  848. m_dwLastVoiceSend[ iCtrlr ] = GetTickCount();
  849. Q_memset( m_ChatBuffer[ iCtrlr ], 0, m_ChatBufferSize );
  850. m_wLocalDataSize[ iCtrlr ] = 0;
  851. }
  852. #pragma warning(push) // warning C4800 is meaningless or worse
  853. #pragma warning( disable: 4800 )
  854. bool CXboxVoice::IsLocalPlayerTalking( int controllerID )
  855. {
  856. return m_pXHVEngine->IsLocalTalking( controllerID ) != 0;
  857. }
  858. bool CXboxVoice::IsPlayerTalking( XUID uid )
  859. {
  860. #ifdef _X360
  861. if ( !g_pMatchFramework->GetMatchSystem()->GetMatchVoice()->CanPlaybackTalker( uid ) )
  862. return false;
  863. return m_pXHVEngine->IsRemoteTalking( uid ) != 0;
  864. #else
  865. return false;
  866. #endif
  867. }
  868. bool CXboxVoice::IsHeadsetPresent( int id )
  869. {
  870. return m_pXHVEngine->IsHeadsetPresent( id ) != 0;
  871. }
  872. #pragma warning(pop)
  873. void CXboxVoice::RemoveAllTalkers()
  874. {
  875. #ifdef _X360
  876. int numRemoteTalkers;
  877. CArrayAutoPtr< XUID > remoteTalkers( new XUID[ g_pMatchFramework->GetMatchTitle()->GetTotalNumPlayersSupported() ] );
  878. GetRemoteTalkers( &numRemoteTalkers, remoteTalkers.Get() );
  879. for ( int iRemote = 0; iRemote < numRemoteTalkers; iRemote++ )
  880. {
  881. m_pXHVEngine->UnregisterRemoteTalker( remoteTalkers[iRemote] );
  882. }
  883. for ( int i = 0; i < XUSER_MAX_COUNT; ++i )
  884. {
  885. if( !m_bUserRegistered[ i ] )
  886. continue;
  887. m_pXHVEngine->UnregisterLocalTalker( i );
  888. m_bUserRegistered[ i ] = false;
  889. }
  890. #endif
  891. }
  892. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CXboxVoice, IEngineVoice,
  893. IENGINEVOICE_INTERFACE_VERSION, *Audio_GetXVoice() );