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.

953 lines
27 KiB

  1. #include "audio_pch.h"
  2. #include "matchmaking/imatchframework.h"
  3. #include "tier2/tier2.h"
  4. #include "fmtstr.h"
  5. #include "audio/public/voice.h"
  6. #if !defined( DEDICATED ) && ( defined( OSX ) || defined( _WIN32 ) || defined( LINUX ) ) && !defined( NO_STEAM )
  7. #include "cl_steamauth.h"
  8. #include "client.h"
  9. #if defined( PS3SDK_INSTALLED )
  10. #define PS3_CROSS_PLAY
  11. #endif
  12. #if !defined( CSTRIKE15 )
  13. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  14. #include "ps3sceCelp8.h"
  15. #define SOUND_PC_CELP_ENABLED
  16. #endif
  17. #endif // CSTRIKE15
  18. extern IVEngineClient *engineClient;
  19. #endif
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. CEngineVoiceStub *Audio_GetEngineVoiceStub()
  23. {
  24. static CEngineVoiceStub s_EngineVoiceStub;
  25. return &s_EngineVoiceStub;
  26. }
  27. #if !defined( DEDICATED ) && ( defined( OSX ) || defined( _WIN32 ) || defined( LINUX ) ) && !defined( NO_STEAM )
  28. ConVar snd_voice_echo( "snd_voice_echo", "0", FCVAR_DEVELOPMENTONLY );
  29. // #define SND_VOICE_LOG_DEBUG
  30. #ifdef SND_VOICE_LOG_DEBUG
  31. ConVar snd_voice_log( "snd_voice_log", "0", FCVAR_DEVELOPMENTONLY ); // 1 = record, 2 = playback
  32. enum SndVoiceLog_t
  33. {
  34. SND_VOICE_LOG_RECORD_REMOTE = 1,
  35. SND_VOICE_LOG_TEST_PLAYBACK_LOG = 2,
  36. SND_VOICE_LOG_RECORD_REMOTE_11025 = 4,
  37. SND_VOICE_LOG_RECORD_LOCAL = 8,
  38. SND_VOICE_LOG_RECORD_LOCAL_11025 = 16,
  39. };
  40. CUtlBuffer g_bufSndVoiceLog;
  41. CUtlBuffer g_bufSndVoiceLog11025;
  42. CON_COMMAND( snd_voice_log_commit, "Commit voice log to file" )
  43. {
  44. if ( ( args.ArgC() <= 1 ) || ( g_bufSndVoiceLog.TellMaxPut() <= 0 ) )
  45. {
  46. Msg( "Voice log size: %u/%u\n", g_bufSndVoiceLog.TellMaxPut(), g_bufSndVoiceLog11025.TellMaxPut() );
  47. return;
  48. }
  49. if ( !strcmp( "0", args.Arg( 1 ) ) )
  50. {
  51. Msg( "Voice log discarded\n" );
  52. g_bufSndVoiceLog.Purge();
  53. g_bufSndVoiceLog11025.Purge();
  54. return;
  55. }
  56. if ( g_pFullFileSystem->WriteFile( args.Arg( 1 ), NULL, g_bufSndVoiceLog ) )
  57. {
  58. Msg( "Voice log committed to file '%s', %u bytes\n", args.Arg(1), g_bufSndVoiceLog.TellMaxPut() );
  59. g_bufSndVoiceLog.Purge();
  60. }
  61. else
  62. {
  63. Warning( "Failed to commit voice log to file '%s', keeping %u bytes\n", args.Arg(1), g_bufSndVoiceLog.TellMaxPut() );
  64. }
  65. if ( g_pFullFileSystem->WriteFile( CFmtStr( "%s.11025", args.Arg( 1 ) ), NULL, g_bufSndVoiceLog11025 ) )
  66. {
  67. Msg( "Voice log committed to file '%s.11025', %u bytes\n", args.Arg(1), g_bufSndVoiceLog11025.TellMaxPut() );
  68. g_bufSndVoiceLog11025.Purge();
  69. }
  70. else
  71. {
  72. Warning( "Failed to commit voice log to file '%s.11025', keeping %u bytes\n", args.Arg(1), g_bufSndVoiceLog11025.TellMaxPut() );
  73. }
  74. }
  75. CON_COMMAND( snd_voice_log_load, "Load voice log file" )
  76. {
  77. g_bufSndVoiceLog.Purge();
  78. if ( !g_pFullFileSystem->ReadFile( args.Arg( 1 ), NULL, g_bufSndVoiceLog ) )
  79. {
  80. Warning( "Failed to read voice log from file '%s'\n", args.Arg( 1 ) );
  81. }
  82. else
  83. {
  84. Msg( "Loaded voice log from file '%s'\n", args.Arg( 1 ) );
  85. }
  86. }
  87. CON_COMMAND( snd_voice_log_setsin, "Set voice log sin-wave" )
  88. {
  89. g_bufSndVoiceLog.Purge();
  90. const int kNumSamples = 500000;
  91. g_bufSndVoiceLog.EnsureCapacity( kNumSamples * sizeof( int16 ) );
  92. g_bufSndVoiceLog.SeekPut( CUtlBuffer::SEEK_HEAD, kNumSamples * sizeof( int16 ) );
  93. float flSinFreq = 2.0/128.0;
  94. if ( args.ArgC() > 1 )
  95. {
  96. flSinFreq = atof( args.Arg( 1 ) );
  97. if ( flSinFreq <= 0.00001 )
  98. flSinFreq = 0.00001;
  99. }
  100. // PURELY FOR EXAMPLE: a basic sine wave test
  101. if ( 1 ) {
  102. for ( int q = 0 ; q < kNumSamples; ++ q )
  103. {
  104. float f = sin( flSinFreq * M_PI * q ) * 20000;
  105. ( ( int16 * ) g_bufSndVoiceLog.Base() )[q] = f;
  106. }
  107. }
  108. }
  109. #endif // SND_VOICE_LOG_DEBUG
  110. #define SOUND_PC_CELP_FREQ 8000
  111. template < int nSOURCE, int nTARGET >
  112. struct ResampleGeneric_t
  113. {
  114. public:
  115. ResampleGeneric_t() : m_sampLeftover( 0 ), m_flFractionalSamples( 0.0f ) { }
  116. uint32 Resample( const int16 *piSamples, uint32 numInSamples, int16 *poSamples )
  117. {
  118. if ( !poSamples )
  119. return ( 1 + ( numInSamples / nSOURCE ) ) * nTARGET;
  120. if ( !numInSamples )
  121. return 0;
  122. int numOutSamples = 0;
  123. const int16 *piSamplesEnd = piSamples + numInSamples;
  124. for ( int16 nextSamp = *( piSamples ++ ); ; m_flFractionalSamples += ((float) nSOURCE)/((float) nTARGET) )
  125. {
  126. // if we've passed a sample boundary, go onto the next sample
  127. while ( m_flFractionalSamples >= 1.0f )
  128. {
  129. m_flFractionalSamples -= 1.0f;
  130. m_sampLeftover = nextSamp;
  131. if ( piSamples < piSamplesEnd )
  132. {
  133. nextSamp = *( piSamples ++ );
  134. }
  135. else
  136. {
  137. return numOutSamples;
  138. }
  139. }
  140. *( poSamples ++ ) = Lerp( m_flFractionalSamples, m_sampLeftover, nextSamp ); // left
  141. ++ numOutSamples;
  142. }
  143. }
  144. private:
  145. float m_flFractionalSamples;
  146. int16 m_sampLeftover;
  147. };
  148. typedef ResampleGeneric_t< SOUND_PC_CELP_FREQ, VOICE_OUTPUT_SAMPLE_RATE > Resample_CELP_to_PC_t; // 320 CELP samples = 441 PC samples
  149. typedef ResampleGeneric_t< VOICE_OUTPUT_SAMPLE_RATE, SOUND_PC_CELP_FREQ > Resample_PC_to_CELP_t; // 441 PC samples = 320 PC samples
  150. #ifdef SND_VOICE_LOG_DEBUG
  151. CON_COMMAND( snd_voice_log_resample, "Resample voice log file" )
  152. {
  153. g_bufSndVoiceLog.Purge();
  154. CUtlBuffer bufRaw;
  155. if ( !g_pFullFileSystem->ReadFile( args.Arg( 1 ), NULL, bufRaw ) )
  156. {
  157. Warning( "Failed to read voice log from file '%s'\n", args.Arg( 1 ) );
  158. return;
  159. }
  160. else
  161. {
  162. Msg( "Loaded voice log from file '%s'\n", args.Arg( 1 ) );
  163. }
  164. Resample_CELP_to_PC_t rcpt;
  165. g_bufSndVoiceLog.EnsureCapacity( bufRaw.TellPut() * 2 );
  166. uint32 numResamples = rcpt.Resample( (int16*)bufRaw.Base(), bufRaw.TellPut()/2, (int16*) g_bufSndVoiceLog.Base() );
  167. g_bufSndVoiceLog.SeekPut( CUtlBuffer::SEEK_HEAD, numResamples*2 );
  168. Msg( "Resampled voice log from %d to %d samples\n", bufRaw.TellPut()/2, numResamples );
  169. }
  170. CON_COMMAND( snd_voice_log_resample44, "Resample voice log file all the way up to 44100" )
  171. {
  172. g_bufSndVoiceLog.Purge();
  173. CUtlBuffer bufRaw;
  174. if ( !g_pFullFileSystem->ReadFile( args.Arg( 1 ), NULL, bufRaw ) )
  175. {
  176. Warning( "Failed to read voice log from file '%s'\n", args.Arg( 1 ) );
  177. return;
  178. }
  179. else
  180. {
  181. Msg( "Loaded voice log from file '%s'\n", args.Arg( 1 ) );
  182. }
  183. Resample_CELP_to_PC_t rcpt;
  184. CUtlBuffer buf11025;
  185. buf11025.EnsureCapacity( bufRaw.TellPut() * 2 );
  186. uint32 numResamples = rcpt.Resample( (int16*)bufRaw.Base(), bufRaw.TellPut()/2, (int16*) buf11025.Base() );
  187. buf11025.SeekPut( CUtlBuffer::SEEK_HEAD, numResamples*2 );
  188. Msg( "Resampled voice log from %d to %d @11025 samples\n", bufRaw.TellPut()/2, numResamples );
  189. g_bufSndVoiceLog.EnsureCapacity( buf11025.TellPut() * 4 );
  190. int16 *pIn = (int16*) buf11025.Base();
  191. int16 *pInEnd = pIn + numResamples;
  192. int16 *pOut = (int16*) g_bufSndVoiceLog.Base();
  193. while ( pIn < pInEnd )
  194. {
  195. int16 a = *( pIn++ );
  196. int16 b = ( pIn < pInEnd ) ? *pIn : a;
  197. for ( int jj = 0; jj < 4; ++ jj )
  198. {
  199. *( pOut ++ ) = ( double( b ) * ( jj ) + double( a ) * ( 4 - jj ) ) / 4.0;
  200. }
  201. }
  202. g_bufSndVoiceLog.SeekPut( CUtlBuffer::SEEK_HEAD, numResamples*8 );
  203. }
  204. #endif // SND_VOICE_LOG_DEBUG
  205. class CEngineVoiceSteam : public IEngineVoice
  206. {
  207. public:
  208. CEngineVoiceSteam();
  209. ~CEngineVoiceSteam();
  210. public:
  211. virtual bool IsHeadsetPresent( int iController );
  212. virtual bool IsLocalPlayerTalking( int iController );
  213. virtual void AddPlayerToVoiceList( XUID xPlayer, int iController, uint64 uiFlags );
  214. virtual void RemovePlayerFromVoiceList( XUID xPlayer, int iController );
  215. virtual void GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers );
  216. virtual bool VoiceUpdateData( int iController );
  217. virtual void GetVoiceData( int iController, const byte **ppvVoiceDataBuffer, unsigned int *pnumVoiceDataBytes );
  218. virtual void VoiceResetLocalData( int iController );
  219. virtual void SetPlaybackPriority( XUID remoteTalker, int iController, int iAllowPlayback );
  220. virtual void PlayIncomingVoiceData( XUID xuid, const byte *pbData, unsigned int dwDataSize, const bool *bAudiblePlayers = NULL );
  221. virtual void RemoveAllTalkers();
  222. protected:
  223. void AudioInitializationUpdate();
  224. void UpdateHUDVoiceStatus();
  225. bool IsPlayerTalking( XUID xuid );
  226. public:
  227. bool m_bLocalVoice[ XUSER_MAX_COUNT ];
  228. struct RemoteTalker_t
  229. {
  230. XUID m_xuid;
  231. uint64 m_uiFlags;
  232. float m_flLastTalkTimestamp;
  233. };
  234. CUtlVector< RemoteTalker_t > m_arrRemoteVoice;
  235. bool m_bVoiceForPs3;
  236. int FindRemoteTalker( XUID xuid )
  237. {
  238. for ( int k = 0; k < m_arrRemoteVoice.Count(); ++ k )
  239. if ( m_arrRemoteVoice[k].m_xuid == xuid )
  240. return k;
  241. return m_arrRemoteVoice.InvalidIndex();
  242. }
  243. bool m_bInitializedAudio;
  244. byte m_pbVoiceData[ 18*1024 * XUSER_MAX_COUNT ];
  245. float m_flLastTalkingTimestamp;
  246. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  247. #ifdef SOUND_PC_CELP_ENABLED
  248. sceCelp8encHandle m_sceCelp8encHandle;
  249. sceCelp8decHandle m_sceCelp8decHandle;
  250. CUtlVectorFixed< byte, SCE_CELP8ENC_INPUT_SIZE > m_bufEncLeftover;
  251. CUtlVectorFixed< byte, SCE_CELP8DEC_INPUT_SIZE > m_bufDecLeftover;
  252. #endif // SOUND_PC_CELP_ENABLED
  253. Resample_CELP_to_PC_t m_resampleCelp2Pc;
  254. Resample_PC_to_CELP_t m_resamplePc2Celp;
  255. #endif
  256. };
  257. CEngineVoiceSteam::CEngineVoiceSteam()
  258. {
  259. memset( m_bLocalVoice, 0, sizeof( m_bLocalVoice ) );
  260. memset( m_pbVoiceData, 0, sizeof( m_pbVoiceData ) );
  261. m_bInitializedAudio = false;
  262. m_bVoiceForPs3 = false;
  263. m_flLastTalkingTimestamp = 0.0f;
  264. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  265. #ifdef SOUND_PC_CELP_ENABLED
  266. m_sceCelp8encHandle = NULL;
  267. sceCelp8encAttr encQueryAttr;
  268. if ( sceCelp8encQueryAttr( &encQueryAttr ) < 0 )
  269. {
  270. Warning( "ERROR: Failed to configure PS3 voice encoder!\n" );
  271. }
  272. else
  273. {
  274. DevMsg( "PS3 voice encoder version %d.%d.%d.%d [%u]\n",
  275. (encQueryAttr.verNumber&0xff000000)>>24,
  276. (encQueryAttr.verNumber&0xff0000)>>16,
  277. (encQueryAttr.verNumber&0xff00)>>8,
  278. (encQueryAttr.verNumber&0xff),
  279. encQueryAttr.memSize );
  280. m_sceCelp8encHandle = malloc( encQueryAttr.memSize );
  281. if ( m_sceCelp8encHandle )
  282. sceCelp8encInitInstance( m_sceCelp8encHandle );
  283. }
  284. #endif
  285. #ifdef SOUND_PC_CELP_ENABLED
  286. m_sceCelp8decHandle = NULL;
  287. sceCelp8decAttr decQueryAttr;
  288. if ( sceCelp8decQueryAttr( &decQueryAttr ) < 0 )
  289. {
  290. Warning( "ERROR: Failed to configure PS3 voice decoder!\n" );
  291. }
  292. else
  293. {
  294. DevMsg( "PS3 voice decoder version %d.%d.%d.%d [%u]\n",
  295. (decQueryAttr.verNumber&0xff000000)>>24,
  296. (decQueryAttr.verNumber&0xff0000)>>16,
  297. (decQueryAttr.verNumber&0xff00)>>8,
  298. (decQueryAttr.verNumber&0xff),
  299. decQueryAttr.memSize );
  300. m_sceCelp8decHandle = malloc( decQueryAttr.memSize );
  301. if ( m_sceCelp8decHandle )
  302. sceCelp8decInitInstance( m_sceCelp8decHandle );
  303. }
  304. #endif
  305. #endif
  306. }
  307. CEngineVoiceSteam::~CEngineVoiceSteam()
  308. {
  309. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  310. #ifdef SOUND_PC_CELP_ENABLED
  311. if ( m_sceCelp8encHandle )
  312. free( m_sceCelp8encHandle );
  313. m_sceCelp8encHandle = NULL;
  314. if ( m_sceCelp8decHandle )
  315. free( m_sceCelp8decHandle );
  316. m_sceCelp8decHandle = NULL;
  317. #endif // SOUND_PC_CELP_ENABLED
  318. #endif
  319. }
  320. bool CEngineVoiceSteam::IsHeadsetPresent( int iController )
  321. {
  322. return false;
  323. }
  324. bool CEngineVoiceSteam::IsLocalPlayerTalking( int iController )
  325. {
  326. #ifdef _PS3
  327. EVoiceResult res = Steam3Client().SteamUser()->GetAvailableVoice( NULL, NULL );
  328. #else
  329. EVoiceResult res = Steam3Client().SteamUser()->GetAvailableVoice( NULL, NULL, 0 );
  330. #endif
  331. switch ( res )
  332. {
  333. case k_EVoiceResultOK:
  334. case k_EVoiceResultNoData:
  335. return true;
  336. default:
  337. return ( ( Plat_FloatTime() - m_flLastTalkingTimestamp ) <= 0.2f );
  338. }
  339. }
  340. bool CEngineVoiceSteam::IsPlayerTalking( XUID uid )
  341. {
  342. if ( !g_pMatchFramework->GetMatchSystem()->GetMatchVoice()->CanPlaybackTalker( uid ) )
  343. return false;
  344. for ( int k = 0; k < m_arrRemoteVoice.Count(); ++ k )
  345. {
  346. if ( m_arrRemoteVoice[k].m_xuid == uid )
  347. {
  348. return ( ( Plat_FloatTime() - m_arrRemoteVoice[k].m_flLastTalkTimestamp ) < 0.2 );
  349. }
  350. }
  351. return false;
  352. }
  353. void CEngineVoiceSteam::AddPlayerToVoiceList( XUID xPlayer, int iController, uint64 uiFlags )
  354. {
  355. if ( !xPlayer && iController >= 0 && iController < XUSER_MAX_COUNT )
  356. {
  357. // Add local player
  358. m_bLocalVoice[ iController ] = true;
  359. AudioInitializationUpdate();
  360. if ( snd_voice_echo.GetBool() )
  361. {
  362. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  363. m_bVoiceForPs3 = (snd_voice_echo.GetInt() == 2);
  364. #endif
  365. Steam3Client().SteamUser()->StartVoiceRecording();
  366. }
  367. }
  368. if ( xPlayer )
  369. {
  370. if ( FindRemoteTalker( xPlayer ) == m_arrRemoteVoice.InvalidIndex() )
  371. {
  372. RemoteTalker_t rt = { xPlayer, uiFlags, 0 };
  373. m_arrRemoteVoice.AddToTail( rt );
  374. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  375. m_bVoiceForPs3 = !!(uiFlags & ENGINE_VOICE_FLAG_PS3);
  376. #endif
  377. AudioInitializationUpdate();
  378. // Steam3Client().SteamUser()->StartVoiceRecording();
  379. }
  380. }
  381. }
  382. void CEngineVoiceSteam::RemovePlayerFromVoiceList( XUID xPlayer, int iController )
  383. {
  384. if ( !xPlayer && iController >= 0 && iController < XUSER_MAX_COUNT )
  385. {
  386. // Remove local player
  387. m_bLocalVoice[ iController ] = false;
  388. AudioInitializationUpdate();
  389. Steam3Client().SteamUser()->StopVoiceRecording();
  390. }
  391. if ( xPlayer )
  392. {
  393. int idx = FindRemoteTalker( xPlayer );
  394. if ( idx != m_arrRemoteVoice.InvalidIndex() )
  395. {
  396. m_arrRemoteVoice.FastRemove( idx );
  397. AudioInitializationUpdate();
  398. }
  399. }
  400. }
  401. void CEngineVoiceSteam::GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers )
  402. {
  403. if ( pNumTalkers )
  404. *pNumTalkers = m_arrRemoteVoice.Count();
  405. if ( pRemoteTalkers )
  406. {
  407. for ( int k = 0; k < m_arrRemoteVoice.Count(); ++ k )
  408. pRemoteTalkers[k] = m_arrRemoteVoice[k].m_xuid;
  409. }
  410. }
  411. bool CEngineVoiceSteam::VoiceUpdateData( int iController )
  412. {
  413. #ifdef SND_VOICE_LOG_DEBUG
  414. if ( snd_voice_log.GetInt() == SND_VOICE_LOG_TEST_PLAYBACK_LOG )
  415. {
  416. PlayIncomingVoiceData( 2, NULL, 0, NULL );
  417. return false;
  418. }
  419. #endif // SND_VOICE_LOG_DEBUG
  420. #ifdef _PS3
  421. EVoiceResult res = Steam3Client().SteamUser()->GetAvailableVoice( NULL, NULL );
  422. #else
  423. EVoiceResult res = Steam3Client().SteamUser()->GetAvailableVoice( NULL, NULL, 0 );
  424. #endif
  425. bool bResult = ( res == k_EVoiceResultOK );
  426. if ( bResult )
  427. m_flLastTalkingTimestamp = Plat_FloatTime();
  428. UpdateHUDVoiceStatus();
  429. return bResult;
  430. }
  431. void CEngineVoiceSteam::UpdateHUDVoiceStatus( void )
  432. {
  433. for ( int iClient = 0; iClient < GetBaseLocalClient().m_nMaxClients; iClient++ )
  434. {
  435. // Information about local client if it's a local client speaking
  436. bool bLocalClient = false;
  437. int iSsSlot = -1;
  438. int iCtrlr = -1;
  439. // Detection if it's a local client
  440. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  441. {
  442. CClientState &cs = GetLocalClient( k );
  443. if ( cs.m_nPlayerSlot == iClient )
  444. {
  445. bLocalClient = true;
  446. iSsSlot = k;
  447. iCtrlr = XBX_GetUserId( iSsSlot );
  448. }
  449. }
  450. // Convert into index and XUID
  451. int iIndex = iClient + 1;
  452. XUID xid = NULL;
  453. player_info_t infoClient;
  454. if ( engineClient->GetPlayerInfo( iIndex, &infoClient ) )
  455. {
  456. xid = infoClient.xuid;
  457. }
  458. if ( !xid )
  459. // No XUID means no VOIP
  460. {
  461. g_pSoundServices->OnChangeVoiceStatus( iIndex, -1, false );
  462. if ( bLocalClient )
  463. g_pSoundServices->OnChangeVoiceStatus( iIndex, iSsSlot, false );
  464. continue;
  465. }
  466. // Determine talking status
  467. bool bTalking = false;
  468. if ( bLocalClient )
  469. {
  470. //Make sure the player's own "remote" label is not on.
  471. g_pSoundServices->OnChangeVoiceStatus( iIndex, -1, false );
  472. iIndex = -1; // issue notification as ent=-1
  473. bTalking = IsLocalPlayerTalking( iCtrlr );
  474. }
  475. else
  476. {
  477. bTalking = IsPlayerTalking( xid );
  478. }
  479. g_pSoundServices->OnChangeVoiceStatus( iIndex, iSsSlot, bTalking );
  480. }
  481. }
  482. void CEngineVoiceSteam::GetVoiceData( int iController, const byte **ppvVoiceDataBuffer, unsigned int *pnumVoiceDataBytes )
  483. {
  484. const int size = ARRAYSIZE( m_pbVoiceData ) / XUSER_MAX_COUNT;
  485. byte *pbVoiceData = m_pbVoiceData + iController * ARRAYSIZE( m_pbVoiceData ) / XUSER_MAX_COUNT;
  486. *ppvVoiceDataBuffer = pbVoiceData;
  487. EVoiceResult res = k_EVoiceResultOK;
  488. if ( !m_bVoiceForPs3 )
  489. {
  490. #ifdef _PS3
  491. res = Steam3Client().SteamUser()->GetVoice( true, pbVoiceData, size, pnumVoiceDataBytes, false, NULL, 0, NULL );
  492. #else
  493. res = Steam3Client().SteamUser()->GetVoice( true, pbVoiceData, size, pnumVoiceDataBytes, false, NULL, 0, NULL, 0 );
  494. #endif
  495. }
  496. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  497. else
  498. {
  499. #ifdef _PS3
  500. res = Steam3Client().SteamUser()->GetVoice( true, pbVoiceData, size, pnumVoiceDataBytes, false, NULL, 0, NULL );
  501. #else
  502. res = Steam3Client().SteamUser()->GetVoice( true, pbVoiceData, size, pnumVoiceDataBytes, false, NULL, 0, NULL, 0 );
  503. #endif
  504. #if defined( SOUND_PC_CELP_ENABLED )
  505. if ( !m_sceCelp8encHandle )
  506. res = k_EVoiceResultNotRecording;
  507. #endif
  508. int16 *pbUncompressedVoiceData = ( int16* ) stackalloc( 11025*2 );
  509. unsigned int numUncompressedVoiceBytes = 11025*2;
  510. if ( res == k_EVoiceResultOK )
  511. {
  512. #ifdef _PS3
  513. res = Steam3Client().SteamUser()->DecompressVoice( pbVoiceData, *pnumVoiceDataBytes, pbUncompressedVoiceData, numUncompressedVoiceBytes, &numUncompressedVoiceBytes );
  514. #else
  515. res = Steam3Client().SteamUser()->DecompressVoice( pbVoiceData, *pnumVoiceDataBytes, pbUncompressedVoiceData, numUncompressedVoiceBytes, &numUncompressedVoiceBytes, 11025 );
  516. #endif
  517. }
  518. if ( res == k_EVoiceResultOK )
  519. {
  520. uint32 numOutSamples = m_resamplePc2Celp.Resample( pbUncompressedVoiceData, numUncompressedVoiceBytes/2, ( int16* ) pbVoiceData );
  521. *pnumVoiceDataBytes = numOutSamples * 2;
  522. #ifdef SND_VOICE_LOG_DEBUG
  523. if ( snd_voice_log.GetInt() & SND_VOICE_LOG_RECORD_LOCAL_11025 )
  524. {
  525. g_bufSndVoiceLog11025.Put( pbUncompressedVoiceData, numUncompressedVoiceBytes );
  526. }
  527. if ( snd_voice_log.GetInt() & SND_VOICE_LOG_RECORD_LOCAL )
  528. {
  529. g_bufSndVoiceLog.Put( pbVoiceData, numOutSamples * 2 );
  530. }
  531. #endif // SND_VOICE_LOG_DEBUG
  532. #if defined( SOUND_PC_CELP_ENABLED )
  533. byte *pbSrc = pbVoiceData;
  534. byte *pbDst = pbVoiceData;
  535. byte *pbSrcEnd = pbSrc + *pnumVoiceDataBytes;
  536. while ( pbSrc < pbSrcEnd )
  537. {
  538. // Copy src data into encoding buffer, advance src
  539. int numBytesRoomForEncode = SCE_CELP8ENC_INPUT_SIZE - m_bufEncLeftover.Count();
  540. numBytesRoomForEncode = MIN( numBytesRoomForEncode, pbSrcEnd - pbSrc );
  541. m_bufEncLeftover.AddMultipleToTail( numBytesRoomForEncode, pbSrc );
  542. pbSrc += numBytesRoomForEncode;
  543. // If we have sufficient number of bytes for encoding, then encode, advance dst
  544. if ( m_bufEncLeftover.Count() == SCE_CELP8ENC_INPUT_SIZE )
  545. {
  546. byte encBuffer[ SCE_CELP8ENC_OUTPUT_SIZE ] = {0};
  547. int numBytesGenerated = 0;
  548. int encResult = sceCelp8encEncode( m_sceCelp8encHandle, m_bufEncLeftover.Base(), encBuffer, &numBytesGenerated );
  549. if ( encResult < 0 )
  550. numBytesGenerated = 0;
  551. if ( numBytesGenerated > 0 )
  552. {
  553. V_memcpy( pbDst, encBuffer, numBytesGenerated );
  554. pbDst += numBytesGenerated;
  555. }
  556. m_bufEncLeftover.RemoveAll();
  557. }
  558. else
  559. break;
  560. }
  561. // Set the number of bytes after encoding process
  562. *pnumVoiceDataBytes = pbDst - pbVoiceData;
  563. #endif
  564. }
  565. if ( res != k_EVoiceResultOK )
  566. {
  567. *pnumVoiceDataBytes = 0;
  568. *ppvVoiceDataBuffer = NULL;
  569. return;
  570. }
  571. }
  572. #endif
  573. // On PC respect user push-to-talk setting and don't transmit voice
  574. // if push-to-talk key is not held
  575. static ConVarRef voice_system_enable( "voice_system_enable" ); // voice system is initialized
  576. static ConVarRef voice_enable( "voice_enable" ); // mute all player voice data, and don't send voice data for this player
  577. static ConVarRef voice_vox( "voice_vox" ); // open mic
  578. static ConVarRef voice_ptt( "voice_ptt" ); // mic ptt release time
  579. if ( !voice_system_enable.GetBool() || !voice_enable.GetBool() )
  580. goto prevent_voice_comm;
  581. if ( !voice_vox.GetInt() )
  582. {
  583. float flPttReleaseTime = voice_ptt.GetFloat();
  584. if ( flPttReleaseTime && ( ( Plat_FloatTime() - flPttReleaseTime ) > 1.0f ) )
  585. {
  586. // User is in push-to-talk mode and released the talk key over a second ago
  587. // don't transmit any voice in this case
  588. goto prevent_voice_comm;
  589. }
  590. }
  591. switch ( res )
  592. {
  593. case k_EVoiceResultNoData:
  594. case k_EVoiceResultOK:
  595. return;
  596. default:
  597. prevent_voice_comm:
  598. *pnumVoiceDataBytes = 0;
  599. *ppvVoiceDataBuffer = NULL;
  600. return;
  601. }
  602. }
  603. void CEngineVoiceSteam::VoiceResetLocalData( int iController )
  604. {
  605. const int size = ARRAYSIZE( m_pbVoiceData ) / XUSER_MAX_COUNT;
  606. byte *pbVoiceData = m_pbVoiceData + iController * ARRAYSIZE( m_pbVoiceData ) / XUSER_MAX_COUNT;
  607. memset( pbVoiceData, 0, size );
  608. }
  609. void CEngineVoiceSteam::SetPlaybackPriority( XUID remoteTalker, int iController, int iAllowPlayback )
  610. {
  611. ;
  612. }
  613. void CEngineVoiceSteam::PlayIncomingVoiceData( XUID xuid, const byte *pbData, unsigned int dwDataSize, const bool *bAudiblePlayers /* = NULL */ )
  614. {
  615. int idxRemoteTalker = 0;
  616. for ( DWORD dwSlot = 0; dwSlot < XBX_GetNumGameUsers(); ++ dwSlot )
  617. {
  618. #ifdef _GAMECONSOLE
  619. int iCtrlr = XBX_GetUserId( dwSlot );
  620. #else
  621. int iCtrlr = dwSlot;
  622. #endif
  623. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iCtrlr );
  624. if ( pPlayer && pPlayer->GetXUID() == xuid )
  625. {
  626. //Hack: Don't play stuff that comes from ourselves.
  627. if ( snd_voice_echo.GetBool() )
  628. {
  629. if ( !m_arrRemoteVoice.Count() )
  630. {
  631. RemoteTalker_t rt = { 0, m_bVoiceForPs3 ? ENGINE_VOICE_FLAG_PS3 : 0, 0 };
  632. m_arrRemoteVoice.AddToTail( rt );
  633. }
  634. goto playvoice;
  635. }
  636. return;
  637. }
  638. }
  639. #ifdef SND_VOICE_LOG_DEBUG
  640. if ( snd_voice_log.GetInt() == SND_VOICE_LOG_TEST_PLAYBACK_LOG )
  641. {
  642. if ( !m_arrRemoteVoice.Count() )
  643. {
  644. RemoteTalker_t rt = { 0, m_bVoiceForPs3 ? ENGINE_VOICE_FLAG_PS3 : 0, 0 };
  645. m_arrRemoteVoice.AddToTail( rt );
  646. }
  647. }
  648. else
  649. #endif
  650. {
  651. // Make sure voice playback is allowed for the specified user
  652. if ( !g_pMatchFramework->GetMatchSystem()->GetMatchVoice()->CanPlaybackTalker( xuid ) )
  653. return;
  654. // Find registered remote talker
  655. idxRemoteTalker = FindRemoteTalker( xuid );
  656. if ( idxRemoteTalker == m_arrRemoteVoice.InvalidIndex() )
  657. return;
  658. }
  659. playvoice:
  660. // Uncompress the voice data
  661. char pbUncompressedVoice[ 11025 * 2 ];
  662. uint32 numUncompressedBytes = 0;
  663. #ifdef SND_VOICE_LOG_DEBUG
  664. if ( snd_voice_log.GetInt() == SND_VOICE_LOG_TEST_PLAYBACK_LOG )
  665. {
  666. const int nVoiceLogFreq = 11025;
  667. const int nVoiceLogSamples = 441;
  668. static float s_flLastTime = 0;
  669. static int s_nBufferPosition = 0;
  670. if ( g_bufSndVoiceLog.TellPut() <= nVoiceLogSamples )
  671. return;
  672. if ( !s_flLastTime )
  673. {
  674. s_flLastTime = Plat_FloatTime();
  675. return;
  676. }
  677. // See how many bytes we can send, assuming 16,000 bytes/sec (8000Hz), rounding to nearest 320 bytes
  678. float flCurTime = Plat_FloatTime();
  679. if ( flCurTime - s_flLastTime > 1.0f )
  680. {
  681. // drop frames
  682. s_flLastTime = Plat_FloatTime();
  683. return;
  684. }
  685. int numSoundFrames = nVoiceLogFreq * ( flCurTime - s_flLastTime ) / nVoiceLogSamples;
  686. if ( numSoundFrames <= 0 )
  687. return;
  688. // Advance time pointer
  689. s_flLastTime += numSoundFrames * nVoiceLogSamples / float( nVoiceLogFreq );
  690. int16 *piWritePos = ( int16 * ) pbUncompressedVoice;
  691. while ( numSoundFrames --> 0 )
  692. {
  693. // See if we need to reset buffer position
  694. if ( s_nBufferPosition + nVoiceLogSamples > g_bufSndVoiceLog.TellPut() )
  695. s_nBufferPosition = 0;
  696. // uint32 numOutSamples = m_resampleCelp2Pc.Resample( ( ( const int16 * ) g_bufSndVoiceLog.Base() ) + ( s_nBufferPosition / 2 ), 160, piWritePos );
  697. uint32 numOutSamples = nVoiceLogSamples;
  698. V_memcpy( piWritePos, ( ( const int16 * ) g_bufSndVoiceLog.Base() ) + ( s_nBufferPosition / sizeof( int16 ) ), nVoiceLogSamples* sizeof( int16 ) );
  699. piWritePos += numOutSamples;
  700. numUncompressedBytes += numOutSamples * 2;
  701. s_nBufferPosition += nVoiceLogSamples * sizeof( int16 );
  702. }
  703. if ( !numUncompressedBytes )
  704. return;
  705. }
  706. else
  707. #endif // SND_VOICE_LOG_DEBUG
  708. if ( !(m_arrRemoteVoice[idxRemoteTalker].m_uiFlags & ENGINE_VOICE_FLAG_PS3) )
  709. {
  710. #ifdef _PS3
  711. EVoiceResult res = Steam3Client().SteamUser()->DecompressVoice( const_cast< byte * >( pbData ), dwDataSize,
  712. pbUncompressedVoice, sizeof( pbUncompressedVoice ), &numUncompressedBytes );
  713. #else
  714. EVoiceResult res = Steam3Client().SteamUser()->DecompressVoice( const_cast< byte * >( pbData ), dwDataSize,
  715. pbUncompressedVoice, sizeof( pbUncompressedVoice ), &numUncompressedBytes, 11025 );
  716. #endif
  717. if ( res != k_EVoiceResultOK )
  718. return;
  719. }
  720. #if defined( PS3_CROSS_PLAY ) || defined ( _PS3 )
  721. #ifdef SOUND_PC_CELP_ENABLED
  722. else if ( m_sceCelp8decHandle )
  723. {
  724. int numCelpCompressedDecodedBufferMaxBytes = SOUND_PC_CELP_FREQ * 2;
  725. byte *pbCelpCompressedDecodedBuffer = ( byte * ) stackalloc( numCelpCompressedDecodedBufferMaxBytes );
  726. byte *pbSrc = const_cast< byte * >( pbData ), *pbDst = pbCelpCompressedDecodedBuffer;
  727. byte *pbSrcEnd = pbSrc + dwDataSize, *pbDstEnd = pbDst + numCelpCompressedDecodedBufferMaxBytes;
  728. while ( pbSrc < pbSrcEnd )
  729. {
  730. // Copy src data into decoding buffer, advance src
  731. int numBytesRoomForDecode = SCE_CELP8DEC_INPUT_SIZE - m_bufDecLeftover.Count();
  732. numBytesRoomForDecode = MIN( numBytesRoomForDecode, pbSrcEnd - pbSrc );
  733. m_bufDecLeftover.AddMultipleToTail( numBytesRoomForDecode, pbSrc );
  734. pbSrc += numBytesRoomForDecode;
  735. // If we have sufficient number of bytes for encoding, then encode, advance dst
  736. if ( m_bufDecLeftover.Count() == SCE_CELP8DEC_INPUT_SIZE )
  737. {
  738. byte decBuffer[ SCE_CELP8DEC_OUTPUT_SIZE ] = {0};
  739. int numBytesGenerated = SCE_CELP8DEC_OUTPUT_SIZE;
  740. #ifdef SOUND_PC_CELP_ENABLED
  741. int decResult = sceCelp8decDecode( m_sceCelp8decHandle, m_bufDecLeftover.Base(), decBuffer, 0 );
  742. #else
  743. int decResult = -1;
  744. #endif
  745. #ifdef SND_VOICE_LOG_DEBUG
  746. if ( snd_voice_log.GetInt() & SND_VOICE_LOG_RECORD_REMOTE )
  747. {
  748. g_bufSndVoiceLog.Put( decBuffer, numBytesGenerated );
  749. }
  750. #endif
  751. if ( decResult < 0 )
  752. numBytesGenerated = 0;
  753. if ( ( numBytesGenerated > 0 ) && ( pbDst + numBytesGenerated <= pbDstEnd ) )
  754. {
  755. // even if we have no room to store decoded data, keep decoding
  756. // to keep decoder state consistent
  757. V_memcpy( pbDst, decBuffer, numBytesGenerated );
  758. pbDst += numBytesGenerated;
  759. }
  760. m_bufDecLeftover.RemoveAll();
  761. }
  762. else
  763. break;
  764. }
  765. // Set the number of bytes after encoding process
  766. numUncompressedBytes = pbDst - pbCelpCompressedDecodedBuffer;
  767. uint32 numOutSamples = m_resampleCelp2Pc.Resample( ( const int16 * ) pbCelpCompressedDecodedBuffer, numUncompressedBytes/2, ( int16 * ) pbUncompressedVoice );
  768. numUncompressedBytes = numOutSamples * 2;
  769. if ( !numOutSamples )
  770. return;
  771. #ifdef SND_VOICE_LOG_DEBUG
  772. if ( snd_voice_log.GetInt() & SND_VOICE_LOG_RECORD_REMOTE_11025 )
  773. {
  774. g_bufSndVoiceLog11025.Put( pbUncompressedVoice, numUncompressedBytes );
  775. }
  776. #endif // SND_VOICE_LOG_DEBUG
  777. }
  778. #endif // SOUND_PC_CELP_ENABLED
  779. #endif // PS3_CROSS_PLAY || _PS3
  780. // Voice channel index
  781. int idxVoiceChan = idxRemoteTalker;
  782. int nChannel = Voice_GetChannel( idxVoiceChan );
  783. if ( nChannel == VOICE_CHANNEL_ERROR )
  784. {
  785. // Create a channel in the voice engine and a channel in the sound engine for this guy.
  786. nChannel = Voice_AssignChannel( idxVoiceChan, false, 0.0f );
  787. }
  788. // Give the voice engine the data (it in turn gives it to the mixer for the sound engine).
  789. if ( nChannel != VOICE_CHANNEL_ERROR )
  790. {
  791. Voice_AddIncomingData( nChannel, reinterpret_cast<const char*>(pbData), dwDataSize, 0, 0, 0, VoiceFormat_Steam );
  792. m_arrRemoteVoice[idxRemoteTalker].m_flLastTalkTimestamp = Plat_FloatTime();
  793. }
  794. }
  795. void CEngineVoiceSteam::RemoveAllTalkers()
  796. {
  797. memset( m_bLocalVoice, 0, sizeof( m_bLocalVoice ) );
  798. m_arrRemoteVoice.RemoveAll();
  799. AudioInitializationUpdate();
  800. }
  801. void CEngineVoiceSteam::AudioInitializationUpdate()
  802. {
  803. bool bHasTalkers = ( m_arrRemoteVoice.Count() > 0 );
  804. for ( int k = 0; k < ARRAYSIZE( m_bLocalVoice ); ++ k )
  805. {
  806. if ( m_bLocalVoice[k] )
  807. {
  808. bHasTalkers = true;
  809. break;
  810. }
  811. }
  812. // Initialized already
  813. if ( bHasTalkers == m_bInitializedAudio )
  814. return;
  815. // Clear out voice buffers
  816. memset( m_pbVoiceData, 0, sizeof( m_pbVoiceData ) );
  817. // Init or deinit voice system
  818. if ( bHasTalkers )
  819. {
  820. Voice_ForceInit();
  821. }
  822. else
  823. {
  824. Voice_Deinit();
  825. }
  826. m_bInitializedAudio = bHasTalkers;
  827. }
  828. IEngineVoice *Audio_GetEngineVoiceSteam()
  829. {
  830. static CEngineVoiceSteam s_EngineVoiceSteam;
  831. return &s_EngineVoiceSteam;
  832. }
  833. #else
  834. IEngineVoice *Audio_GetEngineVoiceSteam()
  835. {
  836. return Audio_GetEngineVoiceStub();
  837. }
  838. #endif