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.

2090 lines
64 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "audio_pch.h"
  9. #include "tier1/circularbuffer.h"
  10. #include "voice.h"
  11. #include "voice_wavefile.h"
  12. #include "r_efx.h"
  13. #include "cdll_int.h"
  14. #include "voice_gain.h"
  15. #include "voice_mixer_controls.h"
  16. #include "snd_dma.h"
  17. #include "ivoicerecord.h"
  18. #include "ivoicecodec.h"
  19. #include "filesystem.h"
  20. #include "../../filesystem_engine.h"
  21. #include "tier1/utlbuffer.h"
  22. #include "../../cl_splitscreen.h"
  23. #include "vgui_baseui_interface.h"
  24. #include "demo.h"
  25. extern IVEngineClient *engineClient;
  26. #if defined( _X360 )
  27. #include "xauddefs.h"
  28. #endif
  29. #include "steam/steam_api.h"
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. static CSteamAPIContext g_SteamAPIContext;
  33. static CSteamAPIContext *steamapicontext = NULL;
  34. void Voice_EndChannel( int iChannel );
  35. void VoiceTweak_EndVoiceTweakMode();
  36. void EngineTool_OverrideSampleRate( int& rate );
  37. // Special entity index used for tweak mode.
  38. #define TWEAKMODE_ENTITYINDEX -500
  39. // Special channel index passed to Voice_AddIncomingData when in tweak mode.
  40. #define TWEAKMODE_CHANNELINDEX -100
  41. // How long does the sign stay above someone's head when they talk?
  42. #define SPARK_TIME 0.2
  43. // How long a voice channel has to be inactive before we free it.
  44. #define DIE_COUNTDOWN 0.5
  45. // Size of the circular buffer. This should be BIGGER than the pad time,
  46. // or else a little burst of data right as we fil the buffer will cause
  47. // us to have nowhere to put the data and overflow the buffer!
  48. #define VOICE_RECEIVE_BUFFER_SECONDS 2.0
  49. // If you can figure out how to get OSX to just compute this value (and use it as a template argument)
  50. // in the circular buffer below. Then go for it.
  51. #define VOICE_RECEIVE_BUFFER_SIZE 88200
  52. COMPILE_TIME_ASSERT( VOICE_RECEIVE_BUFFER_SIZE == VOICE_OUTPUT_SAMPLE_RATE * BYTES_PER_SAMPLE * VOICE_RECEIVE_BUFFER_SECONDS );
  53. #define LOCALPLAYERTALKING_TIMEOUT 0.2f // How long it takes for the client to decide the server isn't sending acks
  54. // of voice data back.
  55. // true when using the speex codec
  56. static bool g_bIsSpeex = false;
  57. // If this is defined, then the data is converted to 8-bit and sent otherwise uncompressed.
  58. // #define VOICE_SEND_RAW_TEST
  59. // The format we sample voice in.
  60. WAVEFORMATEX g_VoiceSampleFormat =
  61. {
  62. WAVE_FORMAT_PCM, // wFormatTag
  63. 1, // nChannels
  64. VOICE_OUTPUT_SAMPLE_RATE, // nSamplesPerSec
  65. VOICE_OUTPUT_SAMPLE_RATE*2, // nAvgBytesPerSec
  66. 2, // nBlockAlign
  67. 16, // wBitsPerSample
  68. sizeof(WAVEFORMATEX) // cbSize
  69. };
  70. ConVar voice_loopback( "voice_loopback", "0", FCVAR_USERINFO );
  71. ConVar voice_fadeouttime( "voice_fadeouttime", "0.0" ); // It fades to no sound at the tail end of your voice data when you release the key.
  72. ConVar voice_threshold_delay( "voice_thresold_delay", "0.5" );
  73. ConVar voice_record_steam( "voice_record_steam", "0", 0, "If true use Steam to record voice (not the engine codec)" );
  74. ConVar voice_scale("voice_scale", "1.0", FCVAR_ARCHIVE | FCVAR_RELEASE, "Overall volume of voice over IP" );
  75. ConVar voice_caster_scale( "voice_caster_scale", "1", FCVAR_ARCHIVE );
  76. // Debugging cvars.
  77. ConVar voice_profile( "voice_profile", "0" );
  78. ConVar voice_showchannels( "voice_showchannels", "0" ); // 1 = list channels
  79. // 2 = show timing info, etc
  80. ConVar voice_showincoming( "voice_showincoming", "0" ); // show incoming voice data
  81. int Voice_SamplesPerSec()
  82. {
  83. if ( voice_record_steam.GetBool() && steamapicontext && steamapicontext->SteamUser() )
  84. return steamapicontext->SteamUser()->GetVoiceOptimalSampleRate();
  85. int rate = ( g_bIsSpeex ? VOICE_OUTPUT_SAMPLE_RATE_SPEEX : VOICE_OUTPUT_SAMPLE_RATE ); //g_VoiceSampleFormat.nSamplesPerSec;
  86. EngineTool_OverrideSampleRate( rate );
  87. return rate;
  88. }
  89. int Voice_AvgBytesPerSec()
  90. {
  91. int rate = Voice_SamplesPerSec();
  92. return ( rate * g_VoiceSampleFormat.wBitsPerSample ) >> 3;
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Convar callback
  96. //-----------------------------------------------------------------------------
  97. void VoiceEnableCallback( IConVar *var, const char *pOldValue, float flOldValue )
  98. {
  99. if ( ((ConVar *)var)->GetBool() )
  100. {
  101. Voice_ForceInit();
  102. }
  103. }
  104. ConVar voice_system_enable( "voice_system_enable", "1", FCVAR_ARCHIVE, "Toggle voice system.", VoiceEnableCallback ); // Globally enable or disable voice system.
  105. ConVar voice_enable( "voice_enable", "1", FCVAR_ARCHIVE, "Toggle voice transmit and receive." );
  106. ConVar voice_caster_enable( "voice_caster_enable", "0", FCVAR_ARCHIVE, "Toggle voice transmit and receive for casters. 0 = no caster, account number of caster to enable." );
  107. ConVar voice_threshold( "voice_threshold", "4000", FCVAR_ARCHIVE | FCVAR_CLIENTDLL );
  108. extern ConVar sv_voicecodec;
  109. // Have it force your mixer control settings so waveIn comes from the microphone.
  110. // CD rippers change your waveIn to come from the CD drive
  111. ConVar voice_forcemicrecord( "voice_forcemicrecord", "1", FCVAR_ARCHIVE );
  112. int g_nVoiceFadeSamples = 1; // Calculated each frame from the cvar.
  113. float g_VoiceFadeMul = 1; // 1 / (g_nVoiceFadeSamples - 1).
  114. // While in tweak mode, you can't hear anything anyone else is saying, and your own voice data
  115. // goes directly to the speakers.
  116. bool g_bInTweakMode = false;
  117. int g_VoiceTweakSpeakingVolume = 0;
  118. bool g_bVoiceAtLeastPartiallyInitted = false;
  119. // Timing info for each frame.
  120. static double g_CompressTime = 0;
  121. static double g_DecompressTime = 0;
  122. static double g_GainTime = 0;
  123. static double g_UpsampleTime = 0;
  124. class CVoiceTimer
  125. {
  126. public:
  127. inline void Start()
  128. {
  129. if( voice_profile.GetInt() )
  130. {
  131. m_StartTime = Plat_FloatTime();
  132. }
  133. }
  134. inline void End(double *out)
  135. {
  136. if( voice_profile.GetInt() )
  137. {
  138. *out += Plat_FloatTime() - m_StartTime;
  139. }
  140. }
  141. double m_StartTime;
  142. };
  143. static float g_fLocalPlayerTalkingLastUpdateRealTime = 0.0f;
  144. static bool g_bLocalPlayerTalkingAck[ MAX_SPLITSCREEN_CLIENTS ];
  145. static float g_LocalPlayerTalkingTimeout[ MAX_SPLITSCREEN_CLIENTS ];
  146. CSysModule *g_hVoiceCodecDLL = 0;
  147. // Voice recorder. Can be waveIn, DSound, or whatever.
  148. static IVoiceRecord *g_pVoiceRecord = NULL;
  149. static IVoiceCodec *g_pEncodeCodec = NULL;
  150. static bool g_bVoiceRecording = false; // Are we recording at the moment?
  151. // A high precision client-local timestamp that is assumed to progress in approximate realtime
  152. // (in lockstep with any transmitted audio). This is sent with voice packets, so that recipients
  153. // can properly account for silence.
  154. static uint32 s_nRecordingTimestamp_UncompressedSampleOffset;
  155. /// Realtime time value corresponding to the above audio recoridng timestamp. This realtime value
  156. /// is used so that we can advance the audio timestamp approximately if we don't get called for a while.
  157. /// if there's a gigantic gap, it probably really doesn't matter. But for small gaps we'd like to
  158. /// get the timing about right.
  159. static double s_flRecordingTimestamp_PlatTime;
  160. /// Make sure timestamnp system is ready to go.
  161. static void VoiceRecord_CheckInitTimestamp()
  162. {
  163. if ( s_flRecordingTimestamp_PlatTime == 0.0 && s_nRecordingTimestamp_UncompressedSampleOffset == 0 )
  164. {
  165. s_nRecordingTimestamp_UncompressedSampleOffset = 1;
  166. s_flRecordingTimestamp_PlatTime = Plat_FloatTime();
  167. }
  168. }
  169. /// Advance audio timestamp using the platform timer
  170. static void VoiceRecord_ForceAdvanceSampleOffsetUsingPlatTime()
  171. {
  172. VoiceRecord_CheckInitTimestamp();
  173. // Advance the timestamp forward
  174. double flNow = Plat_FloatTime();
  175. int nSamplesElapsed = ( flNow - s_flRecordingTimestamp_PlatTime ) * ( g_bIsSpeex ? VOICE_OUTPUT_SAMPLE_RATE_SPEEX : VOICE_OUTPUT_SAMPLE_RATE );
  176. if ( nSamplesElapsed > 0 )
  177. s_nRecordingTimestamp_UncompressedSampleOffset += (uint32)nSamplesElapsed;
  178. s_flRecordingTimestamp_PlatTime = flNow;
  179. }
  180. // Which "section" are we in? A section is basically a segment of non-silence data that we might want to transmit.
  181. static uint8 s_nRecordingSection;
  182. /// Byte offset of compressed data, within the current section. As per TCP-style sequence numbering conventions,
  183. /// this matches the most recent sequence number we sent.
  184. static uint32 s_nRecordingSectionCompressedByteOffset;
  185. // Called when we know that we are currently in silence, or at the beginning or end
  186. // of a non-silence section
  187. static void VoiceRecord_MarkSectionBoundary()
  188. {
  189. // We allow this function to be called redundantly.
  190. // Don't advance the section number unless we really need to
  191. if ( s_nRecordingSectionCompressedByteOffset > 0 || s_nRecordingSection == 0 )
  192. {
  193. ++s_nRecordingSection;
  194. if ( s_nRecordingSection == 0 ) // never use section 0
  195. s_nRecordingSection = 1;
  196. }
  197. // Always reset byte offset
  198. s_nRecordingSectionCompressedByteOffset = 0;
  199. // Reset encoder state for the next real section with data, whenever that may be
  200. if ( g_pEncodeCodec )
  201. g_pEncodeCodec->ResetState();
  202. }
  203. static bool VoiceRecord_Start()
  204. {
  205. // Update timestamp, so we can properly account for silence
  206. VoiceRecord_ForceAdvanceSampleOffsetUsingPlatTime();
  207. VoiceRecord_MarkSectionBoundary();
  208. if ( voice_record_steam.GetBool() && steamapicontext && steamapicontext->SteamUser() )
  209. {
  210. steamapicontext->SteamUser()->StartVoiceRecording();
  211. return true;
  212. }
  213. else if ( g_pVoiceRecord )
  214. {
  215. return g_pVoiceRecord->RecordStart();
  216. }
  217. return false;
  218. }
  219. static void VoiceRecord_Stop()
  220. {
  221. // Update timestamp, so we can properly account for silence
  222. VoiceRecord_ForceAdvanceSampleOffsetUsingPlatTime();
  223. VoiceRecord_MarkSectionBoundary();
  224. if ( voice_record_steam.GetBool() && steamapicontext && steamapicontext->SteamUser() )
  225. {
  226. steamapicontext->SteamUser()->StopVoiceRecording();
  227. }
  228. else if ( g_pVoiceRecord )
  229. {
  230. return g_pVoiceRecord->RecordStop();
  231. }
  232. }
  233. // Hacked functions to create the inputs and codecs..
  234. #ifdef _PS3
  235. static IVoiceRecord* CreateVoiceRecord_DSound(int nSamplesPerSec) { return NULL; }
  236. #else
  237. extern IVoiceRecord* CreateVoiceRecord_DSound(int nSamplesPerSec);
  238. #endif
  239. ConVar voice_gain_rate( "voice_gain_rate", "1.0", FCVAR_NONE );
  240. ConVar voice_gain_downward_multiplier( "voice_gain_downward_multiplier", "100.0", FCVAR_NONE ); // how quickly it will lower gain when it detects that the current gain value will cause clipping
  241. ConVar voice_gain_target( "voice_gain_target", "32000", FCVAR_NONE );
  242. ConVar voice_gain_max( "voice_gain_max", "35", FCVAR_NONE );
  243. class CGainManager
  244. {
  245. public:
  246. CGainManager( void );
  247. void Apply( short *pBuffer, int buffer_size, bool bCaster );
  248. private:
  249. double m_fTargetGain;
  250. double m_fCurrentGain;
  251. };
  252. CGainManager::CGainManager( void )
  253. {
  254. m_fTargetGain = 1.0f;
  255. m_fCurrentGain = 1.0f;
  256. }
  257. void CGainManager::Apply( short *pSamples, int nSamples, bool bCaster )
  258. {
  259. if ( nSamples == 0 )
  260. return;
  261. // Scan for peak
  262. int iPeak = 0;
  263. for ( int i = 0; i < nSamples; i++ )
  264. {
  265. int iSample = abs( pSamples[i] );
  266. iPeak = Max( iPeak, iSample );
  267. }
  268. if ( bCaster )
  269. {
  270. m_fTargetGain = ( voice_gain_target.GetFloat() * Clamp( voice_caster_scale.GetFloat(), 0.0f, 2.0f ) ) / (float)iPeak;
  271. }
  272. else
  273. {
  274. m_fTargetGain = ( voice_gain_target.GetFloat() * Clamp( voice_scale.GetFloat(), 0.0f, 2.0f ) ) / (float)iPeak;
  275. }
  276. double fMovementRate = voice_gain_rate.GetFloat();
  277. double fMaxGain = voice_gain_max.GetFloat();
  278. for ( int i = 0; i < nSamples; i++ )
  279. {
  280. int nSample = int( float( pSamples[i] ) * m_fCurrentGain );
  281. pSamples[i] = (short)Clamp( nSample, -32768, 32767 );
  282. // Adjust downward very very quickly to prevent clipping
  283. m_fCurrentGain += ( m_fTargetGain - m_fCurrentGain ) * fMovementRate * 0.0001 * ( ( m_fTargetGain < m_fCurrentGain ) ? voice_gain_downward_multiplier.GetFloat() : 1.0f );
  284. m_fCurrentGain = Clamp( m_fCurrentGain, 0.0, fMaxGain );
  285. }
  286. //Msg( "Peak: %d, Current Gain: %2.2f, TargetGain: %2.2f\n", iPeak, (float)m_fCurrentGain, (float)m_fTargetGain );
  287. }
  288. //
  289. // Used for storing incoming voice data from an entity.
  290. //
  291. class CVoiceChannel
  292. {
  293. public:
  294. CVoiceChannel();
  295. // Called when someone speaks and a new voice channel is setup to hold the data.
  296. void Init( int nEntity, float timePadding, bool bCaster = false );
  297. public:
  298. int m_iEntity; // Number of the entity speaking on this channel (index into cl_entities).
  299. // This is -1 when the channel is unused.
  300. CSizedCircularBuffer
  301. <VOICE_RECEIVE_BUFFER_SIZE> m_Buffer; // Circular buffer containing the voice data.
  302. bool m_bStarved; // Set to true when the channel runs out of data for the mixer.
  303. // The channel is killed at that point.
  304. bool m_bFirstPacket; // Have we received any packets yet?
  305. float m_TimePad; // Set to TIME_PADDING when the first voice packet comes in from a sender.
  306. // We add time padding (for frametime differences)
  307. // by waiting a certain amount of time before starting to output the sound.
  308. double m_flTimeFirstPacket;
  309. double m_flTimeExpectedStart;
  310. int m_nMinDesiredLeadSamples; // Healthy amount of buffering. This is simply the time padding value passed to init, times the expected sample rate
  311. int m_nMaxDesiredLeadSamples; // Excessive amount of buffering. Too much more and we risk overflowing the buffer.
  312. IVoiceCodec *m_pVoiceCodec; // Each channel gets is own IVoiceCodec instance so the codec can maintain state.
  313. CGainManager m_GainManager;
  314. CVoiceChannel *m_pNext;
  315. bool m_bProximity;
  316. int m_nViewEntityIndex;
  317. int m_nSoundGuid;
  318. uint8 m_nCurrentSection;
  319. uint32 m_nExpectedCompressedByteOffset;
  320. uint32 m_nExpectedUncompressedSampleOffset;
  321. short m_nLastSample;
  322. bool m_bCaster;
  323. };
  324. CVoiceChannel::CVoiceChannel()
  325. {
  326. m_iEntity = -1;
  327. m_pVoiceCodec = NULL;
  328. m_nViewEntityIndex = -1;
  329. m_nSoundGuid = -1;
  330. m_bCaster = false;
  331. }
  332. void CVoiceChannel::Init( int nEntity, float timePadding, bool bCaster )
  333. {
  334. m_iEntity = nEntity;
  335. m_bStarved = false;
  336. m_bFirstPacket = true;
  337. m_nLastSample = 0;
  338. m_Buffer.Flush();
  339. m_bCaster = bCaster;
  340. m_TimePad = timePadding;
  341. if ( m_TimePad <= 0.0f )
  342. {
  343. m_TimePad = FLT_EPSILON; // Must have at least one update
  344. }
  345. // Don't aim to fill the buffer up too full, or we will overflow.
  346. // this buffer class does not grow, so we really don't ever want
  347. // it to get full.
  348. const float kflMaxTimePad = VOICE_RECEIVE_BUFFER_SECONDS * 0.8f;
  349. if ( m_TimePad > kflMaxTimePad )
  350. {
  351. Assert( m_TimePad < kflMaxTimePad );
  352. m_TimePad = kflMaxTimePad;
  353. }
  354. if ( g_bIsSpeex )
  355. {
  356. m_nMaxDesiredLeadSamples = int( kflMaxTimePad * VOICE_OUTPUT_SAMPLE_RATE_SPEEX );
  357. m_nMinDesiredLeadSamples = Max( 256, int( m_TimePad * VOICE_OUTPUT_SAMPLE_RATE_SPEEX ) );
  358. }
  359. else
  360. {
  361. m_nMaxDesiredLeadSamples = int( kflMaxTimePad * VOICE_OUTPUT_SAMPLE_RATE );
  362. m_nMinDesiredLeadSamples = Max( 256, int( m_TimePad * VOICE_OUTPUT_SAMPLE_RATE ) );
  363. }
  364. m_flTimeFirstPacket = Plat_FloatTime();
  365. m_flTimeExpectedStart = m_flTimeFirstPacket + m_TimePad;
  366. m_nCurrentSection = 0;
  367. m_nExpectedCompressedByteOffset = 0;
  368. m_nExpectedUncompressedSampleOffset = 0;
  369. if ( m_pVoiceCodec )
  370. m_pVoiceCodec->ResetState();
  371. }
  372. // Incoming voice channels.
  373. CVoiceChannel g_VoiceChannels[VOICE_NUM_CHANNELS];
  374. // These are used for recording the wave data into files for debugging.
  375. #define MAX_WAVEFILEDATA_LEN 1024*1024
  376. char *g_pUncompressedFileData = NULL;
  377. int g_nUncompressedDataBytes = 0;
  378. const char *g_pUncompressedDataFilename = NULL;
  379. char *g_pDecompressedFileData = NULL;
  380. int g_nDecompressedDataBytes = 0;
  381. const char *g_pDecompressedDataFilename = NULL;
  382. char *g_pMicInputFileData = NULL;
  383. int g_nMicInputFileBytes = 0;
  384. int g_CurMicInputFileByte = 0;
  385. double g_MicStartTime;
  386. static ConVar voice_writevoices( "voice_writevoices", "0", 0, "Saves each speaker's voice data into separate .wav files\n" );
  387. class CVoiceWriterData
  388. {
  389. public:
  390. CVoiceWriterData() :
  391. m_pChannel( NULL ),
  392. m_nCount( 0 ),
  393. m_Buffer()
  394. {
  395. }
  396. CVoiceWriterData( const CVoiceWriterData &src )
  397. {
  398. m_pChannel = src.m_pChannel;
  399. m_nCount = src.m_nCount;
  400. m_Buffer.Clear();
  401. m_Buffer.Put( src.m_Buffer.Base(), src.m_Buffer.TellPut() );
  402. }
  403. static bool Less( const CVoiceWriterData &lhs, const CVoiceWriterData &rhs )
  404. {
  405. return lhs.m_pChannel < rhs.m_pChannel;
  406. }
  407. CVoiceChannel *m_pChannel;
  408. int m_nCount;
  409. CUtlBuffer m_Buffer;
  410. };
  411. class CVoiceWriter
  412. {
  413. public:
  414. CVoiceWriter() :
  415. m_VoiceWriter( 0, 0, CVoiceWriterData::Less )
  416. {
  417. }
  418. void Flush()
  419. {
  420. for ( int i = m_VoiceWriter.FirstInorder(); i != m_VoiceWriter.InvalidIndex(); i = m_VoiceWriter.NextInorder( i ) )
  421. {
  422. CVoiceWriterData *data = &m_VoiceWriter[ i ];
  423. if ( data->m_Buffer.TellPut() <= 0 )
  424. continue;
  425. data->m_Buffer.Purge();
  426. }
  427. }
  428. void Finish()
  429. {
  430. if ( !g_pSoundServices->IsConnected() )
  431. {
  432. Flush();
  433. return;
  434. }
  435. for ( int i = m_VoiceWriter.FirstInorder(); i != m_VoiceWriter.InvalidIndex(); i = m_VoiceWriter.NextInorder( i ) )
  436. {
  437. CVoiceWriterData *data = &m_VoiceWriter[ i ];
  438. if ( data->m_Buffer.TellPut() <= 0 )
  439. continue;
  440. int index = data->m_pChannel - g_VoiceChannels;
  441. Assert( index >= 0 && index < ARRAYSIZE( g_VoiceChannels ) );
  442. char path[ MAX_PATH ];
  443. Q_snprintf( path, sizeof( path ), "%s/voice", g_pSoundServices->GetGameDir() );
  444. g_pFileSystem->CreateDirHierarchy( path );
  445. char fn[ MAX_PATH ];
  446. Q_snprintf( fn, sizeof( fn ), "%s/pl%02d_slot%d-time%d.wav", path, index, data->m_nCount, (int)g_pSoundServices->GetClientTime() );
  447. WriteWaveFile( fn, (const char *)data->m_Buffer.Base(), data->m_Buffer.TellPut(), g_VoiceSampleFormat.wBitsPerSample, g_VoiceSampleFormat.nChannels, Voice_SamplesPerSec() );
  448. Msg( "Writing file %s\n", fn );
  449. ++data->m_nCount;
  450. data->m_Buffer.Purge();
  451. }
  452. }
  453. void AddDecompressedData( CVoiceChannel *ch, const byte *data, size_t datalen )
  454. {
  455. if ( !voice_writevoices.GetBool() )
  456. return;
  457. CVoiceWriterData search;
  458. search.m_pChannel = ch;
  459. int idx = m_VoiceWriter.Find( search );
  460. if ( idx == m_VoiceWriter.InvalidIndex() )
  461. {
  462. idx = m_VoiceWriter.Insert( search );
  463. }
  464. CVoiceWriterData *slot = &m_VoiceWriter[ idx ];
  465. slot->m_Buffer.Put( data, datalen );
  466. }
  467. private:
  468. CUtlRBTree< CVoiceWriterData > m_VoiceWriter;
  469. };
  470. static CVoiceWriter g_VoiceWriter;
  471. inline void ApplyFadeToSamples(short *pSamples, int nSamples, int fadeOffset, float fadeMul)
  472. {
  473. for(int i=0; i < nSamples; i++)
  474. {
  475. float percent = (i+fadeOffset) * fadeMul;
  476. pSamples[i] = (short)(pSamples[i] * (1 - percent));
  477. }
  478. }
  479. bool Voice_Enabled( void )
  480. {
  481. return voice_enable.GetBool();
  482. }
  483. bool Voice_CasterEnabled( uint32 uCasterAccountID )
  484. {
  485. return ( uCasterAccountID == ( uint32 )( voice_caster_enable.GetInt() ) );
  486. }
  487. void Voice_SetCaster( uint32 uCasterAccountID )
  488. {
  489. voice_caster_enable.SetValue( ( int )( uCasterAccountID ) );
  490. }
  491. bool Voice_SystemEnabled( void )
  492. {
  493. return voice_system_enable.GetBool();
  494. }
  495. ConVar voice_buffer_debug( "voice_buffer_debug", "0" );
  496. int Voice_GetOutputData(
  497. const int iChannel, //! The voice channel it wants samples from.
  498. char *copyBufBytes, //! The buffer to copy the samples into.
  499. const int copyBufSize, //! Maximum size of copyBuf.
  500. const int samplePosition, //! Which sample to start at.
  501. const int sampleCount //! How many samples to get.
  502. )
  503. {
  504. CVoiceChannel *pChannel = &g_VoiceChannels[iChannel];
  505. short *pCopyBuf = (short*)copyBufBytes;
  506. int maxOutSamples = copyBufSize / BYTES_PER_SAMPLE;
  507. // Find out how much we want and get it from the received data channel.
  508. CCircularBuffer *pBuffer = &pChannel->m_Buffer;
  509. int nReadAvail = pBuffer->GetReadAvailable();
  510. int nBytesToRead = MIN(MIN(nReadAvail, (int)maxOutSamples), sampleCount * BYTES_PER_SAMPLE);
  511. int nSamplesGotten = pBuffer->Read(pCopyBuf, nBytesToRead) / BYTES_PER_SAMPLE;
  512. if ( voice_buffer_debug.GetBool() )
  513. {
  514. Msg( "%.2f: Voice_GetOutputData channel %d avail %d bytes, tried %d bytes, got %d samples\n", Plat_FloatTime(), iChannel, nReadAvail, nBytesToRead, nSamplesGotten );
  515. }
  516. // Are we at the end of the buffer's data? If so, fade data to silence so it doesn't clip.
  517. int readSamplesAvail = pBuffer->GetReadAvailable() / BYTES_PER_SAMPLE;
  518. if(readSamplesAvail < g_nVoiceFadeSamples)
  519. {
  520. if ( voice_buffer_debug.GetBool() )
  521. {
  522. Msg( "%.2f: Voice_GetOutputData channel %d applying fade\n", Plat_FloatTime(), iChannel );
  523. }
  524. int bufferFadeOffset = MAX((readSamplesAvail + nSamplesGotten) - g_nVoiceFadeSamples, 0);
  525. int globalFadeOffset = MAX(g_nVoiceFadeSamples - (readSamplesAvail + nSamplesGotten), 0);
  526. ApplyFadeToSamples(
  527. &pCopyBuf[bufferFadeOffset],
  528. nSamplesGotten - bufferFadeOffset,
  529. globalFadeOffset,
  530. g_VoiceFadeMul);
  531. }
  532. // If there weren't enough samples in the received data channel,
  533. // pad it with a copy of the most recent data, and if there
  534. // isn't any, then use zeros.
  535. if ( nSamplesGotten < sampleCount )
  536. {
  537. if ( voice_buffer_debug.GetBool() )
  538. {
  539. Msg( "%.2f: Voice_GetOutputData channel %d padding!\n", Plat_FloatTime(), iChannel );
  540. }
  541. int wantedSampleCount = MIN( sampleCount, maxOutSamples );
  542. int nAdditionalNeeded = (wantedSampleCount - nSamplesGotten);
  543. if ( nSamplesGotten > 0 )
  544. {
  545. short *dest = (short *)&pCopyBuf[ nSamplesGotten ];
  546. int nSamplesToDuplicate = MIN( nSamplesGotten, nAdditionalNeeded );
  547. const short *src = (short *)&pCopyBuf[ nSamplesGotten - nSamplesToDuplicate ];
  548. Q_memcpy( dest, src, nSamplesToDuplicate * BYTES_PER_SAMPLE );
  549. if ( voice_buffer_debug.GetBool() )
  550. {
  551. Msg( "duplicating %d samples\n", nSamplesToDuplicate );
  552. }
  553. nAdditionalNeeded -= nSamplesToDuplicate;
  554. if ( nAdditionalNeeded > 0 )
  555. {
  556. dest = (short *)&pCopyBuf[ nSamplesGotten + nSamplesToDuplicate ];
  557. Q_memset(dest, 0, nAdditionalNeeded * BYTES_PER_SAMPLE);
  558. if ( voice_buffer_debug.GetBool() )
  559. {
  560. Msg( "zeroing %d samples\n", nAdditionalNeeded );
  561. }
  562. Assert( ( nAdditionalNeeded + nSamplesGotten + nSamplesToDuplicate ) == wantedSampleCount );
  563. }
  564. }
  565. else
  566. {
  567. Q_memset( &pCopyBuf[ nSamplesGotten ], 0, nAdditionalNeeded * BYTES_PER_SAMPLE );
  568. if ( voice_buffer_debug.GetBool() )
  569. {
  570. Msg( "no buffer data, zeroing all %d samples\n", nAdditionalNeeded );
  571. }
  572. }
  573. nSamplesGotten = wantedSampleCount;
  574. }
  575. // If the buffer is out of data, mark this channel to go away.
  576. if(pBuffer->GetReadAvailable() == 0)
  577. {
  578. if ( voice_buffer_debug.GetBool() )
  579. {
  580. Msg( "%.2f: Voice_GetOutputData channel %d starved!\n", Plat_FloatTime(), iChannel );
  581. }
  582. pChannel->m_bStarved = true;
  583. }
  584. if(voice_showchannels.GetInt() >= 2)
  585. {
  586. Msg("Voice - mixed %d samples from channel %d\n", nSamplesGotten, iChannel);
  587. }
  588. VoiceSE_MoveMouth(pChannel->m_iEntity, (short*)copyBufBytes, nSamplesGotten);
  589. return nSamplesGotten;
  590. }
  591. void Voice_OnAudioSourceShutdown( int iChannel )
  592. {
  593. Voice_EndChannel( iChannel );
  594. }
  595. // ------------------------------------------------------------------------ //
  596. // Internal stuff.
  597. // ------------------------------------------------------------------------ //
  598. CVoiceChannel* GetVoiceChannel(int iChannel, bool bAssert=true)
  599. {
  600. if(iChannel < 0 || iChannel >= VOICE_NUM_CHANNELS)
  601. {
  602. if(bAssert)
  603. {
  604. Assert(false);
  605. }
  606. return NULL;
  607. }
  608. else
  609. {
  610. return &g_VoiceChannels[iChannel];
  611. }
  612. }
  613. //char g_pszCurrentVoiceCodec[256];
  614. //int g_iCurrentVoiceVersion = -1;
  615. bool Voice_Init(const char *pCodecName, int iVersion )
  616. {
  617. if ( voice_system_enable.GetInt() == 0 )
  618. {
  619. return false;
  620. }
  621. // if ( V_strncmp( g_pszCurrentVoiceCodec, pCodecName, sizeof( g_pszCurrentVoiceCodec ) ) == 0 && g_iCurrentVoiceVersion == iVersion )
  622. // return true;
  623. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  624. Voice_Deinit();
  625. g_bVoiceAtLeastPartiallyInitted = true;
  626. if(!VoiceSE_Init())
  627. return false;
  628. if ( V_strcmp( pCodecName, "vaudio_speex" ) == 0 )
  629. {
  630. g_bIsSpeex = true;
  631. g_VoiceSampleFormat.nSamplesPerSec = VOICE_OUTPUT_SAMPLE_RATE_SPEEX;
  632. g_VoiceSampleFormat.nAvgBytesPerSec = VOICE_OUTPUT_SAMPLE_RATE_SPEEX * 2;
  633. }
  634. else
  635. {
  636. g_bIsSpeex = false;
  637. g_VoiceSampleFormat.nSamplesPerSec = VOICE_OUTPUT_SAMPLE_RATE;
  638. g_VoiceSampleFormat.nAvgBytesPerSec = VOICE_OUTPUT_SAMPLE_RATE * 2;
  639. }
  640. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  641. #ifdef OSX
  642. IVoiceRecord* CreateVoiceRecord_AudioQueue(int sampleRate);
  643. g_pVoiceRecord = CreateVoiceRecord_AudioQueue( Voice_SamplesPerSec() );
  644. //g_pVoiceRecord = NULL;
  645. if ( !g_pVoiceRecord )
  646. #endif
  647. // Get the voice input device.
  648. g_pVoiceRecord = CreateVoiceRecord_DSound( Voice_SamplesPerSec() );
  649. if( !g_pVoiceRecord )
  650. {
  651. Msg( "Unable to initialize DirectSoundCapture. You won't be able to speak to other players." );
  652. }
  653. if ( steamapicontext == NULL )
  654. {
  655. steamapicontext = &g_SteamAPIContext;
  656. steamapicontext->Init();
  657. }
  658. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  659. // Get the codec.
  660. CreateInterfaceFn createCodecFn;
  661. //
  662. // We must explicitly check codec DLL strings against valid codecs
  663. // to avoid remote code execution by loading a module supplied in server string
  664. // See security issue disclosed 12-Jan-2016
  665. //
  666. if ( !V_strcmp( pCodecName, "vaudio_celt" )
  667. || !V_strcmp( pCodecName, "vaudio_speex" )
  668. || !V_strcmp( pCodecName, "vaudio_miles" ) )
  669. {
  670. g_hVoiceCodecDLL = FileSystem_LoadModule( pCodecName );
  671. }
  672. else
  673. {
  674. g_hVoiceCodecDLL = NULL;
  675. }
  676. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  677. if ( !g_hVoiceCodecDLL || (createCodecFn = Sys_GetFactory(g_hVoiceCodecDLL)) == NULL ||
  678. (g_pEncodeCodec = (IVoiceCodec*)createCodecFn(pCodecName, NULL)) == NULL || !g_pEncodeCodec->Init( iVersion ) )
  679. {
  680. Msg("Unable to load voice codec '%s'. Voice disabled.\n", pCodecName);
  681. Voice_Deinit();
  682. return false;
  683. }
  684. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  685. {
  686. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  687. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  688. if((pChannel->m_pVoiceCodec = (IVoiceCodec*)createCodecFn(pCodecName, NULL)) == NULL || !pChannel->m_pVoiceCodec->Init( iVersion ))
  689. {
  690. Voice_Deinit();
  691. return false;
  692. }
  693. }
  694. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  695. InitMixerControls();
  696. if( voice_forcemicrecord.GetInt() )
  697. {
  698. if( g_pMixerControls )
  699. g_pMixerControls->SelectMicrophoneForWaveInput();
  700. }
  701. // V_strncpy( g_pszCurrentVoiceCodec, pCodecName, sizeof( g_pszCurrentVoiceCodec ) );
  702. // g_iCurrentVoiceVersion = iVersion;
  703. return true;
  704. }
  705. void Voice_EndChannel(int iChannel)
  706. {
  707. Assert(iChannel >= 0 && iChannel < VOICE_NUM_CHANNELS);
  708. CVoiceChannel *pChannel = &g_VoiceChannels[iChannel];
  709. if ( pChannel->m_iEntity != -1 )
  710. {
  711. int iEnt = pChannel->m_iEntity;
  712. pChannel->m_iEntity = -1;
  713. if ( pChannel->m_bProximity == true )
  714. {
  715. VoiceSE_EndChannel( iChannel, iEnt );
  716. }
  717. else
  718. {
  719. VoiceSE_EndChannel( iChannel, pChannel->m_nViewEntityIndex );
  720. }
  721. g_pSoundServices->OnChangeVoiceStatus( iEnt, -1, false );
  722. VoiceSE_CloseMouth( iEnt );
  723. pChannel->m_nViewEntityIndex = -1;
  724. pChannel->m_nSoundGuid = -1;
  725. // If the tweak mode channel is ending
  726. }
  727. }
  728. void Voice_EndAllChannels()
  729. {
  730. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  731. {
  732. Voice_EndChannel(i);
  733. }
  734. }
  735. bool EngineTool_SuppressDeInit();
  736. void Voice_Deinit()
  737. {
  738. // This call tends to be expensive and when voice is not enabled it will continually
  739. // call in here, so avoid the work if possible.
  740. if( !g_bVoiceAtLeastPartiallyInitted )
  741. return;
  742. if ( EngineTool_SuppressDeInit() )
  743. return;
  744. // g_pszCurrentVoiceCodec[0] = 0;
  745. // g_iCurrentVoiceVersion = -1;
  746. Voice_EndAllChannels();
  747. Voice_RecordStop();
  748. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  749. {
  750. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  751. if(pChannel->m_pVoiceCodec)
  752. {
  753. pChannel->m_pVoiceCodec->Release();
  754. pChannel->m_pVoiceCodec = NULL;
  755. }
  756. }
  757. if(g_pEncodeCodec)
  758. {
  759. g_pEncodeCodec->Release();
  760. g_pEncodeCodec = NULL;
  761. }
  762. if(g_hVoiceCodecDLL)
  763. {
  764. FileSystem_UnloadModule(g_hVoiceCodecDLL);
  765. g_hVoiceCodecDLL = NULL;
  766. }
  767. if(g_pVoiceRecord)
  768. {
  769. g_pVoiceRecord->Release();
  770. g_pVoiceRecord = NULL;
  771. }
  772. VoiceSE_Term();
  773. g_bVoiceAtLeastPartiallyInitted = false;
  774. }
  775. bool Voice_GetLoopback()
  776. {
  777. return !!voice_loopback.GetInt();
  778. }
  779. void Voice_LocalPlayerTalkingAck( int iSsSlot )
  780. {
  781. iSsSlot = clamp( iSsSlot, 0, MAX_SPLITSCREEN_CLIENTS - 1 );
  782. if( !g_bLocalPlayerTalkingAck[ iSsSlot ] )
  783. {
  784. // Tell the client DLL when this changes.
  785. g_pSoundServices->OnChangeVoiceStatus( -2, iSsSlot, TRUE );
  786. }
  787. g_bLocalPlayerTalkingAck[ iSsSlot ] = true;
  788. g_LocalPlayerTalkingTimeout[ iSsSlot ] = 0;
  789. }
  790. void Voice_UpdateVoiceTweakMode()
  791. {
  792. // Tweak mode just pulls data from the voice stream, and does nothing with it
  793. if(!g_bInTweakMode || !g_pVoiceRecord)
  794. return;
  795. char uchVoiceData[16384];
  796. bool bFinal = false;
  797. VoiceFormat_t format;
  798. Voice_GetCompressedData(uchVoiceData, sizeof(uchVoiceData), bFinal, &format );
  799. }
  800. bool Voice_Idle(float frametime)
  801. {
  802. if( voice_system_enable.GetInt() == 0 )
  803. {
  804. Voice_Deinit();
  805. return false;
  806. }
  807. float fTimeDiff = Plat_FloatTime() - g_fLocalPlayerTalkingLastUpdateRealTime;
  808. if ( fTimeDiff < frametime )
  809. {
  810. // Not enough time has passed... don't update
  811. return false;
  812. }
  813. // Set how much time has passed since the last update
  814. frametime = MIN( fTimeDiff, frametime * 2.0f ); // Cap how much time can pass at 2 tick sizes
  815. // Remember when we last updated
  816. g_fLocalPlayerTalkingLastUpdateRealTime = Plat_FloatTime();
  817. for ( int k = 0; k < MAX_SPLITSCREEN_CLIENTS; ++ k )
  818. {
  819. if(g_bLocalPlayerTalkingAck[k])
  820. {
  821. g_LocalPlayerTalkingTimeout[k] += frametime;
  822. if(g_LocalPlayerTalkingTimeout[k] > LOCALPLAYERTALKING_TIMEOUT)
  823. {
  824. g_bLocalPlayerTalkingAck[k] = false;
  825. // Tell the client DLL.
  826. g_pSoundServices->OnChangeVoiceStatus(-2, k, FALSE);
  827. }
  828. }
  829. }
  830. // Precalculate these to speedup the voice fadeout.
  831. g_nVoiceFadeSamples = MAX((int)(voice_fadeouttime.GetFloat() * ( g_bIsSpeex ? VOICE_OUTPUT_SAMPLE_RATE_SPEEX : VOICE_OUTPUT_SAMPLE_RATE ) ), 2);
  832. g_VoiceFadeMul = 1.0f / (g_nVoiceFadeSamples - 1);
  833. if(g_pVoiceRecord)
  834. g_pVoiceRecord->Idle();
  835. // If we're in voice tweak mode, feed our own data back to us.
  836. Voice_UpdateVoiceTweakMode();
  837. // Age the channels.
  838. int nActive = 0;
  839. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  840. {
  841. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  842. if(pChannel->m_iEntity != -1)
  843. {
  844. if(pChannel->m_bStarved)
  845. {
  846. // Kill the channel. It's done playing.
  847. Voice_EndChannel(i);
  848. pChannel->m_nSoundGuid = -1;
  849. }
  850. else if ( pChannel->m_nSoundGuid < 0 )
  851. {
  852. // Sound is not currently playing. Should it be?
  853. // Start it if enough time has elapsed, or if we have
  854. // enough buffered.
  855. pChannel->m_TimePad -= frametime;
  856. int nDesiredLeadBytes = pChannel->m_nMinDesiredLeadSamples*BYTES_PER_SAMPLE;
  857. if( pChannel->m_TimePad <= 0 || pChannel->m_Buffer.GetReadAvailable() >= nDesiredLeadBytes )
  858. {
  859. double flNow = Plat_FloatTime();
  860. float flEpasedSinceFirstPacket = flNow - pChannel->m_flTimeFirstPacket;
  861. if ( voice_showincoming.GetBool() )
  862. {
  863. Msg( "%.2f: Starting channel %d. %d bytes buffered, %.0fms elapsed. (%d samples more than desired, %.0fms later than expected)\n",
  864. flNow, i,
  865. pChannel->m_Buffer.GetReadAvailable(), flEpasedSinceFirstPacket * 1000.0f,
  866. pChannel->m_Buffer.GetReadAvailable() - nDesiredLeadBytes, ( flNow - pChannel->m_flTimeExpectedStart ) * 1000.0f );
  867. }
  868. // Start its audio.
  869. FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD;
  870. pChannel->m_nViewEntityIndex = g_pSoundServices->GetViewEntity( 0 );
  871. pChannel->m_nSoundGuid = VoiceSE_StartChannel( i, pChannel->m_iEntity, pChannel->m_bProximity, pChannel->m_nViewEntityIndex );
  872. if ( pChannel->m_nSoundGuid <= 0 )
  873. {
  874. // couldn't allocate a sound channel for this voice data
  875. Voice_EndChannel(i);
  876. pChannel->m_nSoundGuid = -1;
  877. }
  878. else
  879. {
  880. g_pSoundServices->OnChangeVoiceStatus( pChannel->m_iEntity, -1, true );
  881. VoiceSE_InitMouth(pChannel->m_iEntity);
  882. }
  883. }
  884. ++nActive;
  885. }
  886. }
  887. }
  888. if(nActive == 0)
  889. VoiceSE_EndOverdrive();
  890. VoiceSE_Idle(frametime);
  891. // voice_showchannels.
  892. if( voice_showchannels.GetInt() >= 1 )
  893. {
  894. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  895. {
  896. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  897. if(pChannel->m_iEntity == -1)
  898. continue;
  899. Msg("Voice - chan %d, ent %d, bufsize: %d\n", i, pChannel->m_iEntity, pChannel->m_Buffer.GetReadAvailable());
  900. }
  901. }
  902. // Show profiling data?
  903. if( voice_profile.GetInt() )
  904. {
  905. Msg("Voice - compress: %7.2fu, decompress: %7.2fu, gain: %7.2fu, upsample: %7.2fu, total: %7.2fu\n",
  906. g_CompressTime*1000000.0,
  907. g_DecompressTime*1000000.0,
  908. g_GainTime*1000000.0,
  909. g_UpsampleTime*1000000.0,
  910. (g_CompressTime+g_DecompressTime+g_GainTime+g_UpsampleTime)*1000000.0
  911. );
  912. g_CompressTime = g_DecompressTime = g_GainTime = g_UpsampleTime = 0;
  913. }
  914. return true;
  915. }
  916. bool Voice_IsRecording()
  917. {
  918. return g_bVoiceRecording;
  919. }
  920. bool Voice_RecordStart(
  921. const char *pUncompressedFile,
  922. const char *pDecompressedFile,
  923. const char *pMicInputFile)
  924. {
  925. if(!g_pEncodeCodec)
  926. return false;
  927. g_VoiceWriter.Flush();
  928. Voice_RecordStop();
  929. if(pMicInputFile)
  930. {
  931. int a, b, c;
  932. ReadWaveFile(pMicInputFile, g_pMicInputFileData, g_nMicInputFileBytes, a, b, c);
  933. g_CurMicInputFileByte = 0;
  934. g_MicStartTime = Plat_FloatTime();
  935. }
  936. if(pUncompressedFile)
  937. {
  938. g_pUncompressedFileData = new char[MAX_WAVEFILEDATA_LEN];
  939. g_nUncompressedDataBytes = 0;
  940. g_pUncompressedDataFilename = pUncompressedFile;
  941. }
  942. if(pDecompressedFile)
  943. {
  944. g_pDecompressedFileData = new char[MAX_WAVEFILEDATA_LEN];
  945. g_nDecompressedDataBytes = 0;
  946. g_pDecompressedDataFilename = pDecompressedFile;
  947. }
  948. g_bVoiceRecording = false;
  949. if(g_pVoiceRecord)
  950. {
  951. g_bVoiceRecording = VoiceRecord_Start();
  952. if(g_bVoiceRecording)
  953. {
  954. g_pSoundServices->OnChangeVoiceStatus(-1, GET_ACTIVE_SPLITSCREEN_SLOT(), TRUE); // Tell the client DLL.
  955. }
  956. }
  957. return g_bVoiceRecording;
  958. }
  959. bool Voice_RecordStop()
  960. {
  961. // Write the files out for debugging.
  962. if(g_pMicInputFileData)
  963. {
  964. delete [] g_pMicInputFileData;
  965. g_pMicInputFileData = NULL;
  966. }
  967. if(g_pUncompressedFileData)
  968. {
  969. WriteWaveFile(g_pUncompressedDataFilename, g_pUncompressedFileData, g_nUncompressedDataBytes, g_VoiceSampleFormat.wBitsPerSample, g_VoiceSampleFormat.nChannels, Voice_SamplesPerSec() );
  970. delete [] g_pUncompressedFileData;
  971. g_pUncompressedFileData = NULL;
  972. }
  973. if(g_pDecompressedFileData)
  974. {
  975. WriteWaveFile(g_pDecompressedDataFilename, g_pDecompressedFileData, g_nDecompressedDataBytes, g_VoiceSampleFormat.wBitsPerSample, g_VoiceSampleFormat.nChannels, Voice_SamplesPerSec() );
  976. delete [] g_pDecompressedFileData;
  977. g_pDecompressedFileData = NULL;
  978. }
  979. g_VoiceWriter.Finish();
  980. VoiceRecord_Stop();
  981. if(g_bVoiceRecording)
  982. {
  983. g_pSoundServices->OnChangeVoiceStatus(-1, GET_ACTIVE_SPLITSCREEN_SLOT(), FALSE); // Tell the client DLL.
  984. }
  985. g_bVoiceRecording = false;
  986. return(true);
  987. }
  988. static float s_flThresholdDecayTime = 0.0f;
  989. int Voice_GetCompressedData(char *pchDest, int nCount, bool bFinal, VoiceFormat_t *pOutFormat, uint8 *pnOutSectionNumber, uint32 *pnOutSectionSequenceNumber, uint32 *pnOutUncompressedSampleOffset )
  990. {
  991. double flNow = Plat_FloatTime();
  992. // Make sure timestamp is initialized
  993. VoiceRecord_CheckInitTimestamp();
  994. // Here we protect again a weird client usage pattern where they don't call this function for a while.
  995. // If that happens, advance the timestamp.
  996. float flSecondsElapsed = flNow - s_flRecordingTimestamp_PlatTime;
  997. if ( flSecondsElapsed > 2.0 )
  998. {
  999. Warning( "Voice_GetCompressedData not called for %.1fms; manually advancing uncompressed sample offset and starting a new section\n", flSecondsElapsed * 1000.0f );
  1000. VoiceRecord_ForceAdvanceSampleOffsetUsingPlatTime();
  1001. VoiceRecord_MarkSectionBoundary();
  1002. }
  1003. s_flRecordingTimestamp_PlatTime = flNow;
  1004. // Assume failure
  1005. if ( pnOutSectionNumber )
  1006. *pnOutSectionNumber = 0;
  1007. if ( pnOutSectionSequenceNumber )
  1008. *pnOutSectionSequenceNumber = 0;
  1009. if ( pnOutUncompressedSampleOffset )
  1010. *pnOutUncompressedSampleOffset = 0;
  1011. if ( voice_record_steam.GetBool() && steamapicontext && steamapicontext->SteamUser() )
  1012. {
  1013. uint32 cbCompressedWritten = 0;
  1014. uint32 cbCompressed = 0;
  1015. // uint32 cbUncompressed = 0;
  1016. EVoiceResult result = steamapicontext->SteamUser()->GetAvailableVoice( &cbCompressed, NULL, 0 );
  1017. if ( result == k_EVoiceResultOK )
  1018. {
  1019. result = steamapicontext->SteamUser()->GetVoice( true, pchDest, nCount, &cbCompressedWritten, false, NULL, 0, NULL, 0 );
  1020. g_pSoundServices->OnChangeVoiceStatus( -3, GET_ACTIVE_SPLITSCREEN_SLOT(), true );
  1021. }
  1022. else
  1023. {
  1024. g_pSoundServices->OnChangeVoiceStatus( -3, GET_ACTIVE_SPLITSCREEN_SLOT(), false );
  1025. }
  1026. if ( pOutFormat )
  1027. {
  1028. *pOutFormat = VoiceFormat_Steam;
  1029. }
  1030. if ( cbCompressedWritten > 0 )
  1031. {
  1032. s_nRecordingSectionCompressedByteOffset += cbCompressedWritten;
  1033. if ( pnOutSectionNumber )
  1034. *pnOutSectionNumber = s_nRecordingSection;
  1035. if ( pnOutSectionSequenceNumber )
  1036. *pnOutSectionSequenceNumber = s_nRecordingSectionCompressedByteOffset;
  1037. // !FIXME! Uncompressed sample offset doesn't work right now with the Steam codec.
  1038. // We'd have to get the uncompressed audio in order to advance it properly.
  1039. //if ( pnOutUncompressedSampleOffset )
  1040. // *pnOutUncompressedSampleOffset = s_nRecordingTimestamp_UncompressedSampleOffset;
  1041. // s_nRecordingTimestamp_UncompressedSampleOffset += xxxxx
  1042. }
  1043. return cbCompressedWritten;
  1044. }
  1045. IVoiceCodec *pCodec = g_pEncodeCodec;
  1046. if( g_pVoiceRecord && pCodec )
  1047. {
  1048. static ConVarRef voice_vox( "voice_vox" );
  1049. static ConVarRef voice_chat_bubble_show_volume( "voice_chat_bubble_show_volume" );
  1050. static ConVarRef voice_vox_current_peak( "voice_vox_current_peak" );
  1051. // Get uncompressed data from the recording device
  1052. short tempData[8192];
  1053. int samplesWanted = MIN(nCount/BYTES_PER_SAMPLE, (int)sizeof(tempData)/BYTES_PER_SAMPLE);
  1054. int gotten = g_pVoiceRecord->GetRecordedData(tempData, samplesWanted);
  1055. // If they want to get the data from a file instead of the mic, use that.
  1056. if(g_pMicInputFileData)
  1057. {
  1058. int nShouldGet = (flNow - g_MicStartTime) * Voice_SamplesPerSec();
  1059. gotten = MIN(sizeof(tempData)/BYTES_PER_SAMPLE, MIN(nShouldGet, (g_nMicInputFileBytes - g_CurMicInputFileByte) / BYTES_PER_SAMPLE));
  1060. memcpy(tempData, &g_pMicInputFileData[g_CurMicInputFileByte], gotten*BYTES_PER_SAMPLE);
  1061. g_CurMicInputFileByte += gotten * BYTES_PER_SAMPLE;
  1062. g_MicStartTime = flNow;
  1063. }
  1064. // Check for detecting levels
  1065. if ( !g_pMicInputFileData && gotten && ( voice_vox.GetBool() || g_VoiceTweakAPI.IsStillTweaking() || voice_chat_bubble_show_volume.GetBool() ) )
  1066. {
  1067. // TERROR: If the voice data is essentially silent, don't transmit
  1068. short *pData = tempData;
  1069. int averageData = 0;
  1070. int minData = 16384;
  1071. int maxData = -16384;
  1072. for ( int i=0; i<gotten; ++i )
  1073. {
  1074. short val = *pData;
  1075. averageData += val;
  1076. minData = MIN( val, minData );
  1077. maxData = MAX( val, maxData );
  1078. ++pData;
  1079. }
  1080. averageData /= gotten;
  1081. int deltaData = maxData - minData;
  1082. voice_vox_current_peak.SetValue( deltaData );
  1083. if ( voice_vox.GetBool() || g_VoiceTweakAPI.IsStillTweaking() )
  1084. {
  1085. if ( deltaData < voice_threshold.GetFloat() )
  1086. {
  1087. if ( s_flThresholdDecayTime < flNow )
  1088. {
  1089. g_pSoundServices->OnChangeVoiceStatus( -1, GET_ACTIVE_SPLITSCREEN_SLOT(), false );
  1090. // End the current section, if any
  1091. VoiceRecord_MarkSectionBoundary();
  1092. s_nRecordingTimestamp_UncompressedSampleOffset += gotten;
  1093. return 0;
  1094. }
  1095. }
  1096. else
  1097. {
  1098. g_pSoundServices->OnChangeVoiceStatus( -1, GET_ACTIVE_SPLITSCREEN_SLOT(), true );
  1099. // Pad out our threshold clipping so words aren't clipped together
  1100. s_flThresholdDecayTime = flNow + voice_threshold_delay.GetFloat();
  1101. }
  1102. }
  1103. }
  1104. #ifdef VOICE_SEND_RAW_TEST
  1105. int nCompressedBytes = MIN( gotten, nCount );
  1106. for ( int i=0; i < nCompressedBytes; i++ )
  1107. {
  1108. pchDest[i] = (char)(tempData[i] >> 8);
  1109. }
  1110. #else
  1111. int nCompressedBytes = pCodec->Compress((char*)tempData, gotten, pchDest, nCount, !!bFinal);
  1112. #endif
  1113. // Write to our file buffers..
  1114. if(g_pUncompressedFileData)
  1115. {
  1116. int nToWrite = MIN(gotten*BYTES_PER_SAMPLE, MAX_WAVEFILEDATA_LEN - g_nUncompressedDataBytes);
  1117. memcpy(&g_pUncompressedFileData[g_nUncompressedDataBytes], tempData, nToWrite);
  1118. g_nUncompressedDataBytes += nToWrite;
  1119. }
  1120. // TERROR: -3 signals that we're talking
  1121. // !FIXME! @FD: I think this is wrong. it's possible for us to get some data, but just
  1122. // not have enough for the compressor to spit out a packet. But I'm afraid to make this
  1123. // change so close to TI, so I'm just making a note in case we revisit this. I'm
  1124. // not sure that it matters.
  1125. g_pSoundServices->OnChangeVoiceStatus( -3, GET_ACTIVE_SPLITSCREEN_SLOT(), (nCompressedBytes > 0) );
  1126. if ( pOutFormat )
  1127. {
  1128. *pOutFormat = VoiceFormat_Engine;
  1129. }
  1130. if ( nCompressedBytes > 0 )
  1131. {
  1132. s_nRecordingSectionCompressedByteOffset += nCompressedBytes;
  1133. if ( pnOutSectionNumber )
  1134. *pnOutSectionNumber = s_nRecordingSection;
  1135. if ( pnOutSectionSequenceNumber )
  1136. *pnOutSectionSequenceNumber = s_nRecordingSectionCompressedByteOffset;
  1137. if ( pnOutUncompressedSampleOffset )
  1138. *pnOutUncompressedSampleOffset = s_nRecordingTimestamp_UncompressedSampleOffset;
  1139. }
  1140. // Advance uncompressed sample number. Note that if we feed a small number of samples into the compressor,
  1141. // it might not actually return compressed data, until we hit a complete packet.
  1142. // !KLUDGE! Here we are assuming a specific compression properties!
  1143. if ( g_bIsSpeex )
  1144. {
  1145. // speex compresses 160 samples into 20 bytes with our settings (quality 4, which is quality 6 internally)
  1146. int nPackets = nCompressedBytes / 20;
  1147. Assert( nCompressedBytes == nPackets * 20 );
  1148. s_nRecordingTimestamp_UncompressedSampleOffset += nPackets*160;
  1149. }
  1150. else
  1151. {
  1152. // celt compresses 512 samples into 64 bytes with our settings
  1153. int nPackets = nCompressedBytes / 64;
  1154. Assert( nCompressedBytes == nPackets * 64 );
  1155. s_nRecordingTimestamp_UncompressedSampleOffset += nPackets*512;
  1156. }
  1157. // If they are telling us this is the last packet (and they are about to stop recording),
  1158. // then believe them
  1159. if ( bFinal )
  1160. VoiceRecord_MarkSectionBoundary();
  1161. return nCompressedBytes;
  1162. }
  1163. else
  1164. {
  1165. // TERROR: -3 signals that we're silent
  1166. g_pSoundServices->OnChangeVoiceStatus( -3, GET_ACTIVE_SPLITSCREEN_SLOT(), false );
  1167. VoiceRecord_MarkSectionBoundary();
  1168. return 0;
  1169. }
  1170. }
  1171. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1172. // Purpose: Assigns a channel to an entity by searching for either a channel
  1173. // already assigned to that entity or picking the least recently used
  1174. // channel. If the LRU channel is picked, it is flushed and all other
  1175. // channels are aged.
  1176. // Input : nEntity - entity number to assign to a channel.
  1177. // Output : A channel index to which the entity has been assigned.
  1178. //------------------------------------------------------------------------------
  1179. int Voice_AssignChannel(int nEntity, bool bProximity, bool bCaster, float timePadding )
  1180. {
  1181. // See if a channel already exists for this entity and if so, just return it.
  1182. int iFree = -1;
  1183. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  1184. {
  1185. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  1186. if(pChannel->m_iEntity == nEntity)
  1187. {
  1188. return i;
  1189. }
  1190. else if(pChannel->m_iEntity == -1 && pChannel->m_pVoiceCodec)
  1191. {
  1192. pChannel->m_pVoiceCodec->ResetState();
  1193. iFree = i;
  1194. break;
  1195. }
  1196. }
  1197. // If they're all used, then don't allow them to make a new channel.
  1198. if(iFree == -1)
  1199. {
  1200. return VOICE_CHANNEL_ERROR;
  1201. }
  1202. CVoiceChannel *pChannel = &g_VoiceChannels[iFree];
  1203. pChannel->Init( nEntity, timePadding, bCaster );
  1204. pChannel->m_bProximity = bProximity;
  1205. VoiceSE_StartOverdrive();
  1206. return iFree;
  1207. }
  1208. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1209. // Purpose: Determines which channel has been assigened to a given entity.
  1210. // Input : nEntity - entity number.
  1211. // Output : The index of the channel assigned to the entity, VOICE_CHANNEL_ERROR
  1212. // if no channel is currently assigned to the given entity.
  1213. //------------------------------------------------------------------------------
  1214. int Voice_GetChannel(int nEntity)
  1215. {
  1216. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  1217. if(g_VoiceChannels[i].m_iEntity == nEntity)
  1218. return i;
  1219. return VOICE_CHANNEL_ERROR;
  1220. }
  1221. static void UpsampleIntoBuffer(
  1222. const short *pSrc,
  1223. int nSrcSamples,
  1224. CCircularBuffer *pBuffer,
  1225. int nDestSamples)
  1226. {
  1227. if ( nDestSamples == nSrcSamples )
  1228. {
  1229. // !FIXME! This function should accept a const pointer!
  1230. pBuffer->Write( const_cast<short*>( pSrc ), nDestSamples*sizeof(short) );
  1231. }
  1232. else
  1233. {
  1234. for ( int i = 0 ; i < nDestSamples ; ++i )
  1235. {
  1236. double flSrc = (double)nSrcSamples * i / nDestSamples;
  1237. int iSample = (int)flSrc;
  1238. double frac = flSrc - floor(flSrc);
  1239. int iSampleNext = Min( iSample + 1, nSrcSamples - 1 );
  1240. double val1 = pSrc[iSample];
  1241. double val2 = pSrc[iSampleNext];
  1242. short newSample = (short)(val1 + (val2 - val1) * frac);
  1243. pBuffer->Write(&newSample, sizeof(newSample));
  1244. }
  1245. }
  1246. }
  1247. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1248. // Purpose: Adds received voice data to
  1249. // Input :
  1250. // Output :
  1251. //------------------------------------------------------------------------------
  1252. void Voice_AddIncomingData(
  1253. int nChannel,
  1254. const char *pchData,
  1255. int nCount,
  1256. uint8 nSectionNumber,
  1257. uint32 nSectionSequenceNumber,
  1258. uint32 nUncompressedSampleOffset,
  1259. VoiceFormat_t format
  1260. ) {
  1261. CVoiceChannel *pChannel;
  1262. if((pChannel = GetVoiceChannel(nChannel)) == NULL || !pChannel->m_pVoiceCodec)
  1263. {
  1264. return;
  1265. }
  1266. if ( voice_showincoming.GetBool() )
  1267. {
  1268. Msg( "%.2f: Received voice channel=%2d: section=%4d seq=%8d time=%8d bytes=%4d, buffered=%5d\n",
  1269. Plat_FloatTime(), nChannel, nSectionNumber, nSectionSequenceNumber, nUncompressedSampleOffset, nCount, pChannel->m_Buffer.GetReadAvailable() );
  1270. }
  1271. // Get byte offset at the *start* of the packet.
  1272. uint32 nPacketByteOffsetWithinSection = nSectionSequenceNumber - (uint32)nCount;
  1273. // If we have previously been starved, but now are adding more data,
  1274. // then we need to reset the buffer back to a good state. Don't try
  1275. // to fill it up now. What should ordinarily happen when the buffer
  1276. // gets starved is that we should kill the channel, and any new data that
  1277. // comes in gets assigned a new channel. But if this channel is marked
  1278. // as having gotten starved out, and we are adding new data to it, then
  1279. // we have not yet killed it. So just insert some silence.
  1280. bool bFillWithSilenceToCatchUp = false;
  1281. if ( pChannel->m_bStarved )
  1282. {
  1283. if ( voice_showincoming.GetBool() )
  1284. {
  1285. Warning( "%.2f: Received voice channel=%2d: section=%4d seq=%8d time=%8d bytes=%4d reusing buffer after starvation. Padding with silence to reset buffering.\n",
  1286. Plat_FloatTime(), nChannel, nSectionNumber, nSectionSequenceNumber, nUncompressedSampleOffset, nCount );
  1287. }
  1288. bFillWithSilenceToCatchUp = true;
  1289. }
  1290. // Check section and sequence numbers, see if there was a dropped packet or maybe a gap of silence that was not transmitted
  1291. int nSampleOffsetGap = 0; // NOTE: measured in uncompressed rate (samplespersec below), NOT the data rate we send to the mixer, which is VOICE_OUTPUT_SAMPLE_RATE
  1292. int nLostBytes = 0;
  1293. if ( nSectionNumber != 0 ) // new format message? (This will be zero on matches before around 7/11/2014)
  1294. {
  1295. if ( nSectionNumber != pChannel->m_nCurrentSection )
  1296. {
  1297. pChannel->m_nExpectedCompressedByteOffset = 0;
  1298. pChannel->m_pVoiceCodec->ResetState();
  1299. }
  1300. // Check if the sample pointer is not the exact next thing we expected, then we might need to insert some silence.
  1301. // We'll handle the fact that the gap might have been due to a lost packet and not silence, and other degenerate
  1302. // cases, later
  1303. nSampleOffsetGap = nUncompressedSampleOffset - pChannel->m_nExpectedUncompressedSampleOffset;
  1304. }
  1305. else
  1306. {
  1307. Assert( nUncompressedSampleOffset == 0 ); // section number and uncompressed sample offset were added in the same protocol change. How could we have one without the other?
  1308. }
  1309. // If this is the first packet, or we were starved and getting rebooted, then
  1310. // force a reset. Otherwise, check if we lost a packet
  1311. if ( pChannel->m_bStarved || pChannel->m_bFirstPacket )
  1312. {
  1313. pChannel->m_pVoiceCodec->ResetState();
  1314. nLostBytes = 0;
  1315. nSampleOffsetGap = 0;
  1316. }
  1317. else if ( pChannel->m_nExpectedCompressedByteOffset != nPacketByteOffsetWithinSection )
  1318. {
  1319. if ( nSectionSequenceNumber != 0 ) // old voice packets don't have sequence numbers
  1320. nLostBytes = nPacketByteOffsetWithinSection - pChannel->m_nExpectedCompressedByteOffset;
  1321. // Check if the sequence number is significantly out of whack, then something went
  1322. // pretty badly wrong, or we have a bug. Don't try to handle this gracefully,
  1323. // just insert a little silence, and reset
  1324. if ( nLostBytes < 0 || nLostBytes > nCount*4 + 1024 )
  1325. {
  1326. Warning( "%.2f: Received voice channel=%2d: section=%4d seq=%8d time=%8d bytes=%4d LOST %d bytes? (Offset %d, expected %d)\n",
  1327. Plat_FloatTime(), nChannel, nSectionNumber, nSectionSequenceNumber, nUncompressedSampleOffset, nCount,
  1328. nLostBytes, pChannel->m_nExpectedCompressedByteOffset, nPacketByteOffsetWithinSection );
  1329. nLostBytes = 0;
  1330. pChannel->m_pVoiceCodec->ResetState();
  1331. bFillWithSilenceToCatchUp = true;
  1332. }
  1333. else
  1334. {
  1335. // Sequence number skipped by a reasonable amount, indicating a small amount of lost data,
  1336. // which is totally normal. Only spew if we're debugging this.
  1337. if ( voice_showincoming.GetBool() )
  1338. {
  1339. Warning( " LOST %d bytes. (Expected %u, got %u)\n", nLostBytes, pChannel->m_nExpectedCompressedByteOffset, nPacketByteOffsetWithinSection );
  1340. }
  1341. }
  1342. }
  1343. // Decompress.
  1344. short decompressedBuffer[11500];
  1345. COMPILE_TIME_ASSERT( BYTES_PER_SAMPLE == sizeof(decompressedBuffer[0]) );
  1346. int nDecompressedSamplesForDroppedPacket = 0;
  1347. int nDecompressedSamplesForThisPacket = 0;
  1348. #ifdef VOICE_SEND_RAW_TEST
  1349. for ( int i=0; i < nCount; i++ )
  1350. decompressedBuffer[i] = pchData[i] << 8;
  1351. nDecompressedSamplesForThisPacket = nCount
  1352. #else
  1353. const int nDesiredSampleRate = g_bIsSpeex ? VOICE_OUTPUT_SAMPLE_RATE_SPEEX : VOICE_OUTPUT_SAMPLE_RATE;
  1354. int samplesPerSec;
  1355. if ( format == VoiceFormat_Steam )
  1356. {
  1357. uint32 nBytesWritten = 0;
  1358. EVoiceResult result = steamapicontext->SteamUser()->DecompressVoice( pchData, nCount, decompressedBuffer, sizeof(decompressedBuffer), &nBytesWritten, nDesiredSampleRate );
  1359. if ( result == k_EVoiceResultOK )
  1360. {
  1361. nDecompressedSamplesForThisPacket = nBytesWritten / BYTES_PER_SAMPLE;
  1362. }
  1363. else
  1364. {
  1365. Warning( "%.2f: Voice_AddIncomingData channel %d Size %d failed to decompress steam data result %d\n", Plat_FloatTime(), nChannel, nCount, result );
  1366. }
  1367. samplesPerSec = nDesiredSampleRate;
  1368. }
  1369. else
  1370. {
  1371. char *decompressedDest = (char*)decompressedBuffer;
  1372. int nDecompressBytesRemaining = sizeof(decompressedBuffer);
  1373. // First, if we lost some data, let the codec know.
  1374. if ( nLostBytes > 0 )
  1375. {
  1376. nDecompressedSamplesForDroppedPacket = pChannel->m_pVoiceCodec->Decompress( NULL, nLostBytes, decompressedDest, nDecompressBytesRemaining );
  1377. int nDecompressedBytesForDroppedPacket = nDecompressedSamplesForDroppedPacket * BYTES_PER_SAMPLE;
  1378. decompressedDest += nDecompressedBytesForDroppedPacket;
  1379. nDecompressBytesRemaining -= nDecompressedBytesForDroppedPacket;
  1380. }
  1381. // Now decompress the actual data
  1382. nDecompressedSamplesForThisPacket = pChannel->m_pVoiceCodec->Decompress( pchData, nCount, decompressedDest, nDecompressBytesRemaining );
  1383. if ( nDecompressedSamplesForThisPacket <= 0 )
  1384. {
  1385. Warning( "%.2f: Voice_AddIncomingData channel %d Size %d engine failed to decompress\n", Plat_FloatTime(), nChannel, nCount );
  1386. nDecompressedSamplesForThisPacket = 0;
  1387. }
  1388. samplesPerSec = g_VoiceSampleFormat.nSamplesPerSec;
  1389. EngineTool_OverrideSampleRate( samplesPerSec );
  1390. }
  1391. #endif
  1392. int nDecompressedSamplesTotal = nDecompressedSamplesForDroppedPacket + nDecompressedSamplesForThisPacket;
  1393. int nDecompressedBytesTotal = nDecompressedSamplesTotal * BYTES_PER_SAMPLE;
  1394. pChannel->m_GainManager.Apply( decompressedBuffer, nDecompressedSamplesTotal, pChannel->m_bCaster );
  1395. // We might need to fill with some silence. Calculate the number of samples we need to fill.
  1396. // Note that here we need to be careful not to confuse the network transmission reference
  1397. // rate with the rate of data sent to the mixer. (At the time I write this, they are the same,
  1398. // but that might change in the future.)
  1399. int nSamplesOfSilenceToInsertToMixer = 0; // mixer rate
  1400. if ( nSampleOffsetGap != 0 )
  1401. {
  1402. //
  1403. // Check for some things going way off the rails
  1404. //
  1405. // If it's already negative, then something went haywire.
  1406. if ( nSampleOffsetGap < 0 )
  1407. {
  1408. // This is weird. The sample number moved backwards.
  1409. Warning( "%.2f: Received voice channel=%2d: section=%4d seq=%8d time=%8d bytes=%4d, timestamp moved backwards (%d). Expected %u, received %u.\n",
  1410. Plat_FloatTime(), nChannel, nSectionNumber, nSectionSequenceNumber, nUncompressedSampleOffset, nCount,
  1411. nSampleOffsetGap, pChannel->m_nExpectedCompressedByteOffset, nUncompressedSampleOffset );
  1412. }
  1413. else
  1414. {
  1415. // If we dropped a packet, this would totally explain the gap.
  1416. nSampleOffsetGap -= nDecompressedSamplesForDroppedPacket;
  1417. if ( nSampleOffsetGap < 0 )
  1418. {
  1419. Warning( "%.2f: Received voice channel=%2d: section=%4d seq=%8d time=%8d bytes=%4d, timestamp moved backwards (%d) after synthesizing dropped packet. Expected %u+%u = %u, received %u.\n",
  1420. Plat_FloatTime(), nChannel, nSectionNumber, nSectionSequenceNumber, nUncompressedSampleOffset, nCount,
  1421. nSampleOffsetGap,
  1422. pChannel->m_nExpectedCompressedByteOffset,
  1423. nDecompressedSamplesForDroppedPacket,
  1424. pChannel->m_nExpectedCompressedByteOffset + nDecompressedSamplesForDroppedPacket,
  1425. nUncompressedSampleOffset );
  1426. }
  1427. }
  1428. // Is the gap massively larger than we should reasonably expect?
  1429. // this probably indicates something is wrong or we have a bug.
  1430. if ( nSampleOffsetGap > VOICE_RECEIVE_BUFFER_SECONDS * samplesPerSec )
  1431. {
  1432. Warning( "%.2f: Received voice channel=%2d: section=%4d seq=%8d time=%8d bytes=%4d, timestamp moved backwards (%d) after synthesizing dropped packet. Expected %u+%u = %u, received %u.\n",
  1433. Plat_FloatTime(), nChannel, nSectionNumber, nSectionSequenceNumber, nUncompressedSampleOffset, nCount,
  1434. nSampleOffsetGap,
  1435. pChannel->m_nExpectedCompressedByteOffset,
  1436. nDecompressedSamplesForDroppedPacket,
  1437. pChannel->m_nExpectedCompressedByteOffset + nDecompressedSamplesForDroppedPacket,
  1438. nUncompressedSampleOffset );
  1439. }
  1440. else if ( nSampleOffsetGap > 0 )
  1441. {
  1442. // A relatively small positive gap, which means we actually want to insert silence.
  1443. // This is the normal situation.
  1444. // Convert from the network reference rate to the mixer rate
  1445. nSamplesOfSilenceToInsertToMixer = nSampleOffsetGap * samplesPerSec / nDesiredSampleRate;
  1446. // Only spew about this if we're logging
  1447. if ( voice_showincoming.GetBool() )
  1448. {
  1449. Msg( " Timestamp gap of %d (%u -> %u). Will insert %d samples of silence\n", nSampleOffsetGap, pChannel->m_nExpectedUncompressedSampleOffset, nUncompressedSampleOffset, nSamplesOfSilenceToInsertToMixer );
  1450. }
  1451. }
  1452. }
  1453. // Convert from voice decompression rate to the rate we send to the mixer.
  1454. int nDecompressedSamplesAtMixerRate = nDecompressedSamplesTotal * samplesPerSec / nDesiredSampleRate;
  1455. // Check current buffer state do some calculations on how much we could fit, and how
  1456. // much would get us to our ideal amount
  1457. int nBytesBuffered = pChannel->m_Buffer.GetReadAvailable();
  1458. int nSamplesBuffered = nBytesBuffered / BYTES_PER_SAMPLE;
  1459. int nMaxBytesToWrite = pChannel->m_Buffer.GetWriteAvailable();
  1460. int nMaxSamplesToWrite = nMaxBytesToWrite / BYTES_PER_SAMPLE;
  1461. int nSamplesNeededToReachMinDesiredLeadTime = Max( pChannel->m_nMinDesiredLeadSamples - nSamplesBuffered, 0 );
  1462. int nSamplesNeededToReachMaxDesiredLeadTime = Max( pChannel->m_nMaxDesiredLeadSamples - nSamplesBuffered, 0 );
  1463. int nSamplesOfSilenceMax = Max( 0, nMaxSamplesToWrite - nDecompressedSamplesAtMixerRate );
  1464. int nSamplesOfSilenceToReachMinDesiredLeadTime = Clamp( nSamplesNeededToReachMinDesiredLeadTime - nDecompressedSamplesAtMixerRate, 0, nSamplesOfSilenceMax );
  1465. int nSamplesOfSilenceToReachMaxDesiredLeadTime = Clamp( nSamplesNeededToReachMaxDesiredLeadTime - nDecompressedSamplesAtMixerRate, 0, nSamplesOfSilenceMax );
  1466. Assert( nSamplesOfSilenceToReachMinDesiredLeadTime <= nSamplesOfSilenceToReachMaxDesiredLeadTime );
  1467. Assert( nSamplesOfSilenceToReachMaxDesiredLeadTime <= nSamplesOfSilenceMax );
  1468. // Check if something went wrong with a previous batch of audio in this buffer,
  1469. // and we should just try to reset the buffering to a healthy position by
  1470. // filling with silence.
  1471. if ( bFillWithSilenceToCatchUp && nSamplesOfSilenceToReachMinDesiredLeadTime > nSamplesOfSilenceToInsertToMixer )
  1472. nSamplesOfSilenceToInsertToMixer = nSamplesOfSilenceToReachMinDesiredLeadTime;
  1473. // Limit silence samples
  1474. if ( nSamplesOfSilenceToInsertToMixer > nSamplesOfSilenceMax )
  1475. nSamplesOfSilenceToInsertToMixer = nSamplesOfSilenceMax;
  1476. // Insert silence, if necessary
  1477. if ( nSamplesOfSilenceToInsertToMixer > 0 )
  1478. {
  1479. // Check if out buffer lead time is not where we want it to be, then silence
  1480. // is a great opportunity to stretch things a bit and get us back where we'd like.
  1481. // This does change the timing slightly, but that is a far preferable change than
  1482. // later the buffer draining and us outputting distorted audio.
  1483. float kMaxStretch = 1.2f;
  1484. if ( nSamplesOfSilenceToInsertToMixer < nSamplesOfSilenceToReachMinDesiredLeadTime )
  1485. {
  1486. nSamplesOfSilenceToInsertToMixer = Min( int( nSamplesOfSilenceToInsertToMixer * kMaxStretch ), nSamplesOfSilenceToReachMinDesiredLeadTime );
  1487. }
  1488. else if ( nSamplesOfSilenceToInsertToMixer > nSamplesOfSilenceToReachMaxDesiredLeadTime )
  1489. {
  1490. float kMinStretch = 1.0 / kMaxStretch;
  1491. nSamplesOfSilenceToInsertToMixer = Max( int( nSamplesOfSilenceToInsertToMixer * kMinStretch ), nSamplesOfSilenceToReachMaxDesiredLeadTime );
  1492. }
  1493. if ( voice_showincoming.GetBool() )
  1494. {
  1495. Msg( " Actually inserting %d samples of silence\n", nSamplesOfSilenceToInsertToMixer );
  1496. }
  1497. // OK, we know how much silence we're going to insert. Before we insert silence,
  1498. // we're going to try to make a nice transition back down to zero, in case
  1499. // the last data didn't end near zero. (Highly likely if we dropped a packet.)
  1500. // This prevents a pop.
  1501. int nDesiredSamplesToRamp = nDesiredSampleRate / 500; // 2ms
  1502. int nSamplesToRamp = Min( nDesiredSamplesToRamp, nSamplesOfSilenceToInsertToMixer );
  1503. for ( int i = 1 ; i <= nSamplesToRamp ; ++i ) // No need to duplicate the previous sample. But make sure we end at zero
  1504. {
  1505. // Compute interpolation parameter
  1506. float t = float(i) / float(nSamplesToRamp);
  1507. // Smoothstep
  1508. t = 3.0f * t*t - 2.0 * t*t*t;
  1509. short val = short( pChannel->m_nLastSample * ( 1.0f - t ) );
  1510. pChannel->m_Buffer.Write( &val, sizeof(val) );
  1511. }
  1512. // Fill with silence
  1513. int nSilenceSamplesRemaining = nSamplesOfSilenceToInsertToMixer - nSamplesToRamp;
  1514. short zero = 0;
  1515. while ( nSilenceSamplesRemaining > 0 )
  1516. {
  1517. pChannel->m_Buffer.Write( &zero, sizeof(zero) );
  1518. --nSilenceSamplesRemaining;
  1519. }
  1520. pChannel->m_nLastSample = 0;
  1521. nSamplesNeededToReachMinDesiredLeadTime -= nSamplesOfSilenceToInsertToMixer;
  1522. nSamplesNeededToReachMaxDesiredLeadTime -= nSamplesOfSilenceToInsertToMixer;
  1523. }
  1524. if ( nDecompressedSamplesTotal > 0 )
  1525. {
  1526. // Upsample the actual voice data into the dest buffer. We could do this in a mixer but it complicates the mixer.
  1527. UpsampleIntoBuffer(
  1528. decompressedBuffer,
  1529. nDecompressedSamplesTotal,
  1530. &pChannel->m_Buffer,
  1531. nDecompressedSamplesAtMixerRate );
  1532. // Save off the value of the last sample, in case the next bit of data is missing and we need to transition out.
  1533. pChannel->m_nLastSample = decompressedBuffer[nDecompressedSamplesTotal-1];
  1534. // Write to our file buffer..
  1535. if(g_pDecompressedFileData)
  1536. {
  1537. int nToWrite = MIN(nDecompressedSamplesTotal*BYTES_PER_SAMPLE, MAX_WAVEFILEDATA_LEN - g_nDecompressedDataBytes);
  1538. memcpy(&g_pDecompressedFileData[g_nDecompressedDataBytes], decompressedBuffer, nToWrite);
  1539. g_nDecompressedDataBytes += nToWrite;
  1540. }
  1541. g_VoiceWriter.AddDecompressedData( pChannel, (const byte *)decompressedBuffer, nDecompressedBytesTotal );
  1542. }
  1543. // Check if our circular buffer is totally full, then that's bad.
  1544. // The circular buffer is a fixed size, and overflow is not
  1545. // graceful. This really should never happen, except when skipping a lot of frames in a demo.
  1546. if ( pChannel->m_Buffer.GetWriteAvailable() <= 0 )
  1547. {
  1548. if ( demoplayer && demoplayer->IsPlayingBack() )
  1549. {
  1550. // well, this is normal: demo is being played back and large chunks of it may be skipped at a time
  1551. }
  1552. else
  1553. {
  1554. Warning( "Voice channel %d circular buffer overflow!\n", nChannel );
  1555. }
  1556. }
  1557. // Save state for next time
  1558. pChannel->m_nCurrentSection = nSectionNumber;
  1559. pChannel->m_nExpectedCompressedByteOffset = nSectionSequenceNumber;
  1560. pChannel->m_nExpectedUncompressedSampleOffset = nUncompressedSampleOffset + nDecompressedSamplesForThisPacket;
  1561. pChannel->m_bFirstPacket = false;
  1562. pChannel->m_bStarved = false; // This only really matters if you call Voice_AddIncomingData between the time the mixer
  1563. // asks for data and Voice_Idle is called.
  1564. }
  1565. #if DEAD
  1566. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1567. // Purpose: Flushes a given receive channel.
  1568. // Input : nChannel - index of channel to flush.
  1569. //------------------------------------------------------------------------------
  1570. void Voice_FlushChannel(int nChannel)
  1571. {
  1572. if ((nChannel < 0) || (nChannel >= VOICE_NUM_CHANNELS))
  1573. {
  1574. Assert(false);
  1575. return;
  1576. }
  1577. g_VoiceChannels[nChannel].m_Buffer.Flush();
  1578. }
  1579. #endif
  1580. //------------------------------------------------------------------------------
  1581. // IVoiceTweak implementation.
  1582. //------------------------------------------------------------------------------
  1583. int VoiceTweak_StartVoiceTweakMode()
  1584. {
  1585. // If we're already in voice tweak mode, return an error.
  1586. if ( g_bInTweakMode )
  1587. {
  1588. Assert(!"VoiceTweak_StartVoiceTweakMode called while already in tweak mode.");
  1589. return 0;
  1590. }
  1591. if ( g_pEncodeCodec == NULL )
  1592. {
  1593. Voice_Init( sv_voicecodec.GetString(), VOICE_CURRENT_VERSION );
  1594. }
  1595. g_bInTweakMode = true;
  1596. Voice_RecordStart(NULL, NULL, NULL);
  1597. return 1;
  1598. }
  1599. void VoiceTweak_EndVoiceTweakMode()
  1600. {
  1601. if(!g_bInTweakMode)
  1602. {
  1603. Assert(!"VoiceTweak_EndVoiceTweakMode called when not in tweak mode.");
  1604. return;
  1605. }
  1606. static ConVarRef voice_vox( "voice_vox" );
  1607. if ( !voice_vox.GetBool() )
  1608. {
  1609. Voice_RecordStop();
  1610. }
  1611. g_bInTweakMode = false;
  1612. }
  1613. void VoiceTweak_SetControlFloat(VoiceTweakControl iControl, float flValue)
  1614. {
  1615. if(!g_pMixerControls)
  1616. return;
  1617. if(iControl == MicrophoneVolume)
  1618. {
  1619. g_pMixerControls->SetValue_Float(IMixerControls::MicVolume, flValue);
  1620. }
  1621. else if ( iControl == MicBoost )
  1622. {
  1623. g_pMixerControls->SetValue_Float( IMixerControls::MicBoost, flValue );
  1624. }
  1625. else if(iControl == OtherSpeakerScale)
  1626. {
  1627. voice_scale.SetValue( flValue );
  1628. // this forces all voice channels to use the new voice_scale value instead of waiting for the next network update
  1629. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  1630. {
  1631. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  1632. if ( pChannel && pChannel->m_iEntity > -1 )
  1633. {
  1634. pChannel->Init( pChannel->m_iEntity, pChannel->m_TimePad );
  1635. }
  1636. }
  1637. }
  1638. }
  1639. void Voice_ForceInit()
  1640. {
  1641. if ( voice_system_enable.GetBool())
  1642. {
  1643. Voice_Init( sv_voicecodec.GetString(), VOICE_CURRENT_VERSION );
  1644. }
  1645. }
  1646. float VoiceTweak_GetControlFloat(VoiceTweakControl iControl)
  1647. {
  1648. if (!g_pMixerControls && voice_system_enable.GetBool())
  1649. {
  1650. Voice_Init( sv_voicecodec.GetString(), VOICE_CURRENT_VERSION );
  1651. }
  1652. if(!g_pMixerControls)
  1653. return 0;
  1654. if(iControl == MicrophoneVolume)
  1655. {
  1656. float value = 1;
  1657. g_pMixerControls->GetValue_Float(IMixerControls::MicVolume, value);
  1658. return value;
  1659. }
  1660. else if(iControl == OtherSpeakerScale)
  1661. {
  1662. return voice_scale.GetFloat();
  1663. }
  1664. else if(iControl == SpeakingVolume)
  1665. {
  1666. return g_VoiceTweakSpeakingVolume * 1.0f / 32768;
  1667. }
  1668. else if ( iControl == MicBoost )
  1669. {
  1670. float flValue = 1;
  1671. g_pMixerControls->GetValue_Float( IMixerControls::MicBoost, flValue );
  1672. return flValue;
  1673. }
  1674. else
  1675. {
  1676. return 1;
  1677. }
  1678. }
  1679. bool VoiceTweak_IsStillTweaking()
  1680. {
  1681. return g_bInTweakMode;
  1682. }
  1683. bool VoiceTweak_IsControlFound(VoiceTweakControl iControl)
  1684. {
  1685. if (!g_pMixerControls && voice_system_enable.GetBool())
  1686. {
  1687. Voice_Init( sv_voicecodec.GetString(), VOICE_CURRENT_VERSION );
  1688. }
  1689. if(!g_pMixerControls)
  1690. return false;
  1691. if(iControl == MicrophoneVolume)
  1692. {
  1693. float fDummy;
  1694. return g_pMixerControls->GetValue_Float(IMixerControls::MicVolume,fDummy);
  1695. }
  1696. return true;
  1697. }
  1698. void Voice_Spatialize( channel_t *channel )
  1699. {
  1700. // do nothing now
  1701. }
  1702. IVoiceTweak g_VoiceTweakAPI =
  1703. {
  1704. VoiceTweak_StartVoiceTweakMode,
  1705. VoiceTweak_EndVoiceTweakMode,
  1706. VoiceTweak_SetControlFloat,
  1707. VoiceTweak_GetControlFloat,
  1708. VoiceTweak_IsStillTweaking,
  1709. VoiceTweak_IsControlFound,
  1710. };