Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1566 lines
41 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "audio_pch.h"
  9. #include "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 "ivoicerecord.h"
  17. #include "ivoicecodec.h"
  18. #include "filesystem.h"
  19. #include "../../filesystem_engine.h"
  20. #include "tier1/utlbuffer.h"
  21. #if defined( _X360 )
  22. #include "xauddefs.h"
  23. #endif
  24. #include "steam/steam_api.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. static CSteamAPIContext g_SteamAPIContext;
  28. static CSteamAPIContext *steamapicontext = NULL;
  29. void Voice_EndChannel( int iChannel );
  30. void VoiceTweak_EndVoiceTweakMode();
  31. void EngineTool_OverrideSampleRate( int& rate );
  32. // A fallback codec that should be the most likely to work for local/offline use
  33. #define VOICE_FALLBACK_CODEC "vaudio_celt"
  34. // Special entity index used for tweak mode.
  35. #define TWEAKMODE_ENTITYINDEX -500
  36. // Special channel index passed to Voice_AddIncomingData when in tweak mode.
  37. #define TWEAKMODE_CHANNELINDEX -100
  38. // How long does the sign stay above someone's head when they talk?
  39. #define SPARK_TIME 0.2
  40. // How long a voice channel has to be inactive before we free it.
  41. #define DIE_COUNTDOWN 0.5
  42. #define VOICE_RECEIVE_BUFFER_SIZE (VOICE_OUTPUT_SAMPLE_RATE_MAX * BYTES_PER_SAMPLE)
  43. #define LOCALPLAYERTALKING_TIMEOUT 0.2f // How long it takes for the client to decide the server isn't sending acks
  44. // of voice data back.
  45. // If this is defined, then the data is converted to 8-bit and sent otherwise uncompressed.
  46. // #define VOICE_SEND_RAW_TEST
  47. // The format we sample voice in.
  48. WAVEFORMATEX g_VoiceSampleFormat =
  49. {
  50. WAVE_FORMAT_PCM, // wFormatTag
  51. 1, // nChannels
  52. // These two can be dynamically changed by voice_init
  53. VOICE_OUTPUT_SAMPLE_RATE_LOW, // nSamplesPerSec
  54. VOICE_OUTPUT_SAMPLE_RATE_LOW*2, // nAvgBytesPerSec
  55. 2, // nBlockAlign
  56. 16, // wBitsPerSample
  57. sizeof(WAVEFORMATEX) // cbSize
  58. };
  59. static bool Voice_SetSampleRate( DWORD rate )
  60. {
  61. if ( g_VoiceSampleFormat.nSamplesPerSec != rate ||
  62. g_VoiceSampleFormat.nAvgBytesPerSec != rate * 2 )
  63. {
  64. g_VoiceSampleFormat.nSamplesPerSec = rate;
  65. g_VoiceSampleFormat.nAvgBytesPerSec = rate * 2;
  66. return true;
  67. }
  68. return false;
  69. }
  70. int Voice_SamplesPerSec()
  71. {
  72. int rate = g_VoiceSampleFormat.nSamplesPerSec;
  73. EngineTool_OverrideSampleRate( rate );
  74. return rate;
  75. }
  76. int Voice_AvgBytesPerSec()
  77. {
  78. int rate = g_VoiceSampleFormat.nSamplesPerSec;
  79. EngineTool_OverrideSampleRate( rate );
  80. return ( rate * g_VoiceSampleFormat.wBitsPerSample ) >> 3;
  81. }
  82. ConVar voice_avggain( "voice_avggain", "0.5" );
  83. ConVar voice_maxgain( "voice_maxgain", "10" );
  84. ConVar voice_scale( "voice_scale", "1", FCVAR_ARCHIVE );
  85. ConVar voice_loopback( "voice_loopback", "0", FCVAR_USERINFO );
  86. ConVar voice_fadeouttime( "voice_fadeouttime", "0.1" ); // It fades to no sound at the tail end of your voice data when you release the key.
  87. // Debugging cvars.
  88. ConVar voice_profile( "voice_profile", "0" );
  89. ConVar voice_showchannels( "voice_showchannels", "0" ); // 1 = list channels
  90. // 2 = show timing info, etc
  91. ConVar voice_showincoming( "voice_showincoming", "0" ); // show incoming voice data
  92. ConVar voice_enable( "voice_enable", "1", FCVAR_ARCHIVE ); // Globally enable or disable voice.
  93. #ifdef VOICE_VOX_ENABLE
  94. ConVar voice_threshold( "voice_threshold", "2000", FCVAR_ARCHIVE );
  95. #endif // VOICE_VOX_ENABLE
  96. // Have it force your mixer control settings so waveIn comes from the microphone.
  97. // CD rippers change your waveIn to come from the CD drive
  98. ConVar voice_forcemicrecord( "voice_forcemicrecord", "1", FCVAR_ARCHIVE );
  99. // This should not be lower than the maximum difference between clients' frame durations (due to cmdrate/updaterate),
  100. // plus some jitter allowance.
  101. ConVar voice_buffer_ms( "voice_buffer_ms", "100", FCVAR_INTERNAL_USE,
  102. "How many milliseconds of voice to buffer to avoid dropouts due to jitter and frame time differences." );
  103. int g_nVoiceFadeSamples = 1; // Calculated each frame from the cvar.
  104. float g_VoiceFadeMul = 1; // 1 / (g_nVoiceFadeSamples - 1).
  105. // While in tweak mode, you can't hear anything anyone else is saying, and your own voice data
  106. // goes directly to the speakers.
  107. bool g_bInTweakMode = false;
  108. int g_VoiceTweakSpeakingVolume = 0;
  109. bool g_bVoiceAtLeastPartiallyInitted = false;
  110. // The codec and sample rate passed to Voice_Init. "" and -1 if voice is not initialized
  111. char g_szVoiceCodec[_MAX_PATH] = { 0 };
  112. int g_nVoiceRequestedSampleRate = -1;
  113. const char *Voice_ConfiguredCodec() { return g_szVoiceCodec; }
  114. int Voice_ConfiguredSampleRate() { return g_nVoiceRequestedSampleRate; }
  115. // Timing info for each frame.
  116. static double g_CompressTime = 0;
  117. static double g_DecompressTime = 0;
  118. static double g_GainTime = 0;
  119. static double g_UpsampleTime = 0;
  120. class CVoiceTimer
  121. {
  122. public:
  123. inline void Start()
  124. {
  125. if( voice_profile.GetInt() )
  126. {
  127. m_StartTime = Plat_FloatTime();
  128. }
  129. }
  130. inline void End(double *out)
  131. {
  132. if( voice_profile.GetInt() )
  133. {
  134. *out += Plat_FloatTime() - m_StartTime;
  135. }
  136. }
  137. double m_StartTime;
  138. };
  139. static bool g_bLocalPlayerTalkingAck = false;
  140. static float g_LocalPlayerTalkingTimeout = 0;
  141. CSysModule *g_hVoiceCodecDLL = 0;
  142. // Voice recorder. Can be waveIn, DSound, or whatever.
  143. static IVoiceRecord *g_pVoiceRecord = NULL;
  144. static IVoiceCodec *g_pEncodeCodec = NULL;
  145. static bool g_bVoiceRecording = false; // Are we recording at the moment?
  146. static bool g_bVoiceRecordStopping = false; // Are we waiting to stop?
  147. bool g_bUsingSteamVoice = false;
  148. #ifdef WIN32
  149. extern IVoiceRecord* CreateVoiceRecord_DSound(int nSamplesPerSec);
  150. #elif defined( OSX )
  151. extern IVoiceRecord* CreateVoiceRecord_AudioQueue(int sampleRate);
  152. #endif
  153. #ifdef POSIX
  154. extern IVoiceRecord* CreateVoiceRecord_OpenAL(int sampleRate);
  155. #endif
  156. static bool VoiceRecord_Start()
  157. {
  158. if ( g_bUsingSteamVoice )
  159. {
  160. if ( steamapicontext && steamapicontext->SteamUser() )
  161. {
  162. steamapicontext->SteamUser()->StartVoiceRecording();
  163. return true;
  164. }
  165. }
  166. else if ( g_pVoiceRecord )
  167. {
  168. return g_pVoiceRecord->RecordStart();
  169. }
  170. return false;
  171. }
  172. static void VoiceRecord_Stop()
  173. {
  174. if ( g_bUsingSteamVoice )
  175. {
  176. if ( steamapicontext && steamapicontext->SteamUser() )
  177. {
  178. steamapicontext->SteamUser()->StopVoiceRecording();
  179. }
  180. }
  181. else if ( g_pVoiceRecord )
  182. {
  183. return g_pVoiceRecord->RecordStop();
  184. }
  185. }
  186. //
  187. // Used for storing incoming voice data from an entity.
  188. //
  189. class CVoiceChannel
  190. {
  191. public:
  192. CVoiceChannel();
  193. // Called when someone speaks and a new voice channel is setup to hold the data.
  194. void Init(int nEntity);
  195. public:
  196. int m_iEntity; // Number of the entity speaking on this channel (index into cl_entities).
  197. // This is -1 when the channel is unused.
  198. CSizedCircularBuffer
  199. <VOICE_RECEIVE_BUFFER_SIZE> m_Buffer; // Circular buffer containing the voice data.
  200. // Used for upsampling..
  201. double m_LastFraction; // Fraction between m_LastSample and the next sample.
  202. short m_LastSample;
  203. bool m_bStarved; // Set to true when the channel runs out of data for the mixer.
  204. // The channel is killed at that point.
  205. float m_TimePad; // Set to TIME_PADDING when the first voice packet comes in from a sender.
  206. // We add time padding (for frametime differences)
  207. // by waiting a certain amount of time before starting to output the sound.
  208. IVoiceCodec *m_pVoiceCodec; // Each channel gets is own IVoiceCodec instance so the codec can maintain state.
  209. CAutoGain m_AutoGain; // Gain we're applying to this channel
  210. CVoiceChannel *m_pNext;
  211. bool m_bProximity;
  212. int m_nViewEntityIndex;
  213. int m_nSoundGuid;
  214. };
  215. CVoiceChannel::CVoiceChannel()
  216. {
  217. m_iEntity = -1;
  218. m_pVoiceCodec = NULL;
  219. m_nViewEntityIndex = -1;
  220. m_nSoundGuid = -1;
  221. }
  222. void CVoiceChannel::Init(int nEntity)
  223. {
  224. m_iEntity = nEntity;
  225. m_bStarved = false;
  226. m_Buffer.Flush();
  227. m_TimePad = Clamp( voice_buffer_ms.GetFloat(), 1.f, 5000.f ) / 1000.f;
  228. m_LastSample = 0;
  229. m_LastFraction = 0.999;
  230. m_AutoGain.Reset( 128, voice_maxgain.GetFloat(), voice_avggain.GetFloat(), voice_scale.GetFloat() );
  231. }
  232. // Incoming voice channels.
  233. CVoiceChannel g_VoiceChannels[VOICE_NUM_CHANNELS];
  234. // These are used for recording the wave data into files for debugging.
  235. #define MAX_WAVEFILEDATA_LEN 1024*1024
  236. char *g_pUncompressedFileData = NULL;
  237. int g_nUncompressedDataBytes = 0;
  238. const char *g_pUncompressedDataFilename = NULL;
  239. char *g_pDecompressedFileData = NULL;
  240. int g_nDecompressedDataBytes = 0;
  241. const char *g_pDecompressedDataFilename = NULL;
  242. char *g_pMicInputFileData = NULL;
  243. int g_nMicInputFileBytes = 0;
  244. int g_CurMicInputFileByte = 0;
  245. double g_MicStartTime;
  246. static ConVar voice_writevoices( "voice_writevoices", "0", 0, "Saves each speaker's voice data into separate .wav files\n" );
  247. class CVoiceWriterData
  248. {
  249. public:
  250. CVoiceWriterData() :
  251. m_pChannel( NULL ),
  252. m_nCount( 0 ),
  253. m_Buffer()
  254. {
  255. }
  256. // Copy ctor is needed to insert into CVoiceWriter's CUtlRBTree.
  257. CVoiceWriterData(const CVoiceWriterData& other) :
  258. m_pChannel( other.m_pChannel ),
  259. m_nCount( other.m_nCount ),
  260. m_Buffer( )
  261. {
  262. m_Buffer.CopyBuffer( other.m_Buffer );
  263. }
  264. static bool Less( const CVoiceWriterData &lhs, const CVoiceWriterData &rhs )
  265. {
  266. return lhs.m_pChannel < rhs.m_pChannel;
  267. }
  268. CVoiceChannel *m_pChannel;
  269. int m_nCount;
  270. CUtlBuffer m_Buffer;
  271. private:
  272. CVoiceWriterData& operator=(const CVoiceWriterData&);
  273. };
  274. class CVoiceWriter
  275. {
  276. public:
  277. CVoiceWriter() :
  278. m_VoiceWriter( 0, 0, CVoiceWriterData::Less )
  279. {
  280. }
  281. void Flush()
  282. {
  283. for ( int i = m_VoiceWriter.FirstInorder(); i != m_VoiceWriter.InvalidIndex(); i = m_VoiceWriter.NextInorder( i ) )
  284. {
  285. CVoiceWriterData *data = &m_VoiceWriter[ i ];
  286. if ( data->m_Buffer.TellPut() <= 0 )
  287. continue;
  288. data->m_Buffer.Purge();
  289. }
  290. }
  291. void Finish()
  292. {
  293. if ( !g_pSoundServices->IsConnected() )
  294. {
  295. Flush();
  296. return;
  297. }
  298. for ( int i = m_VoiceWriter.FirstInorder(); i != m_VoiceWriter.InvalidIndex(); i = m_VoiceWriter.NextInorder( i ) )
  299. {
  300. CVoiceWriterData *data = &m_VoiceWriter[ i ];
  301. if ( data->m_Buffer.TellPut() <= 0 )
  302. continue;
  303. int index = data->m_pChannel - g_VoiceChannels;
  304. Assert( index >= 0 && index < (int)ARRAYSIZE( g_VoiceChannels ) );
  305. char path[ MAX_PATH ];
  306. Q_snprintf( path, sizeof( path ), "%s/voice", g_pSoundServices->GetGameDir() );
  307. g_pFileSystem->CreateDirHierarchy( path );
  308. char fn[ MAX_PATH ];
  309. Q_snprintf( fn, sizeof( fn ), "%s/pl%02d_slot%d-time%d.wav", path, index, data->m_nCount, (int)g_pSoundServices->GetClientTime() );
  310. WriteWaveFile( fn, (const char *)data->m_Buffer.Base(), data->m_Buffer.TellPut(), g_VoiceSampleFormat.wBitsPerSample, g_VoiceSampleFormat.nChannels, Voice_SamplesPerSec() );
  311. Msg( "Writing file %s\n", fn );
  312. ++data->m_nCount;
  313. data->m_Buffer.Purge();
  314. }
  315. }
  316. void AddDecompressedData( CVoiceChannel *ch, const byte *data, size_t datalen )
  317. {
  318. if ( !voice_writevoices.GetBool() )
  319. return;
  320. CVoiceWriterData search;
  321. search.m_pChannel = ch;
  322. int idx = m_VoiceWriter.Find( search );
  323. if ( idx == m_VoiceWriter.InvalidIndex() )
  324. {
  325. idx = m_VoiceWriter.Insert( search );
  326. }
  327. CVoiceWriterData *slot = &m_VoiceWriter[ idx ];
  328. slot->m_Buffer.Put( data, datalen );
  329. }
  330. private:
  331. CUtlRBTree< CVoiceWriterData > m_VoiceWriter;
  332. };
  333. static CVoiceWriter g_VoiceWriter;
  334. inline void ApplyFadeToSamples(short *pSamples, int nSamples, int fadeOffset, float fadeMul)
  335. {
  336. for(int i=0; i < nSamples; i++)
  337. {
  338. float percent = (i+fadeOffset) * fadeMul;
  339. pSamples[i] = (short)(pSamples[i] * (1 - percent));
  340. }
  341. }
  342. bool Voice_Enabled( void )
  343. {
  344. return voice_enable.GetBool();
  345. }
  346. int Voice_GetOutputData(
  347. const int iChannel, //! The voice channel it wants samples from.
  348. char *copyBufBytes, //! The buffer to copy the samples into.
  349. const int copyBufSize, //! Maximum size of copyBuf.
  350. const int samplePosition, //! Which sample to start at.
  351. const int sampleCount //! How many samples to get.
  352. )
  353. {
  354. CVoiceChannel *pChannel = &g_VoiceChannels[iChannel];
  355. short *pCopyBuf = (short*)copyBufBytes;
  356. int maxOutSamples = copyBufSize / BYTES_PER_SAMPLE;
  357. // Find out how much we want and get it from the received data channel.
  358. CCircularBuffer *pBuffer = &pChannel->m_Buffer;
  359. int nBytesToRead = pBuffer->GetReadAvailable();
  360. nBytesToRead = min(min(nBytesToRead, (int)maxOutSamples), sampleCount * BYTES_PER_SAMPLE);
  361. int nSamplesGotten = pBuffer->Read(pCopyBuf, nBytesToRead) / BYTES_PER_SAMPLE;
  362. // Are we at the end of the buffer's data? If so, fade data to silence so it doesn't clip.
  363. int readSamplesAvail = pBuffer->GetReadAvailable() / BYTES_PER_SAMPLE;
  364. if(readSamplesAvail < g_nVoiceFadeSamples)
  365. {
  366. int bufferFadeOffset = max((readSamplesAvail + nSamplesGotten) - g_nVoiceFadeSamples, 0);
  367. int globalFadeOffset = max(g_nVoiceFadeSamples - (readSamplesAvail + nSamplesGotten), 0);
  368. ApplyFadeToSamples(
  369. &pCopyBuf[bufferFadeOffset],
  370. nSamplesGotten - bufferFadeOffset,
  371. globalFadeOffset,
  372. g_VoiceFadeMul);
  373. }
  374. // If there weren't enough samples in the received data channel,
  375. // pad it with a copy of the most recent data, and if there
  376. // isn't any, then use zeros.
  377. if ( nSamplesGotten < sampleCount )
  378. {
  379. int wantedSampleCount = min( sampleCount, maxOutSamples );
  380. int nAdditionalNeeded = (wantedSampleCount - nSamplesGotten);
  381. if ( nSamplesGotten > 0 )
  382. {
  383. short *dest = (short *)&pCopyBuf[ nSamplesGotten ];
  384. int nSamplesToDuplicate = min( nSamplesGotten, nAdditionalNeeded );
  385. const short *src = (short *)&pCopyBuf[ nSamplesGotten - nSamplesToDuplicate ];
  386. Q_memcpy( dest, src, nSamplesToDuplicate * BYTES_PER_SAMPLE );
  387. //Msg( "duplicating %d samples\n", nSamplesToDuplicate );
  388. nAdditionalNeeded -= nSamplesToDuplicate;
  389. if ( nAdditionalNeeded > 0 )
  390. {
  391. dest = (short *)&pCopyBuf[ nSamplesGotten + nSamplesToDuplicate ];
  392. Q_memset(dest, 0, nAdditionalNeeded * BYTES_PER_SAMPLE);
  393. // Msg( "zeroing %d samples\n", nAdditionalNeeded );
  394. Assert( ( nAdditionalNeeded + nSamplesGotten + nSamplesToDuplicate ) == wantedSampleCount );
  395. }
  396. }
  397. else
  398. {
  399. Q_memset( &pCopyBuf[ nSamplesGotten ], 0, nAdditionalNeeded * BYTES_PER_SAMPLE );
  400. }
  401. nSamplesGotten = wantedSampleCount;
  402. }
  403. // If the buffer is out of data, mark this channel to go away.
  404. if(pBuffer->GetReadAvailable() == 0)
  405. {
  406. pChannel->m_bStarved = true;
  407. }
  408. if(voice_showchannels.GetInt() >= 2)
  409. {
  410. Msg("Voice - mixed %d samples from channel %d\n", nSamplesGotten, iChannel);
  411. }
  412. VoiceSE_MoveMouth(pChannel->m_iEntity, (short*)copyBufBytes, nSamplesGotten);
  413. return nSamplesGotten;
  414. }
  415. void Voice_OnAudioSourceShutdown( int iChannel )
  416. {
  417. Voice_EndChannel( iChannel );
  418. }
  419. // ------------------------------------------------------------------------ //
  420. // Internal stuff.
  421. // ------------------------------------------------------------------------ //
  422. CVoiceChannel* GetVoiceChannel(int iChannel, bool bAssert=true)
  423. {
  424. if(iChannel < 0 || iChannel >= VOICE_NUM_CHANNELS)
  425. {
  426. if(bAssert)
  427. {
  428. Assert(false);
  429. }
  430. return NULL;
  431. }
  432. else
  433. {
  434. return &g_VoiceChannels[iChannel];
  435. }
  436. }
  437. // Helper for doing a default-init with some codec if we weren't passed specific parameters
  438. bool Voice_InitWithDefault( const char *pCodecName )
  439. {
  440. if ( !pCodecName || !*pCodecName )
  441. {
  442. return false;
  443. }
  444. int nRate = Voice_GetDefaultSampleRate( pCodecName );
  445. if ( nRate < 0 )
  446. {
  447. Msg( "Voice_InitWithDefault: Unable to determine defaults for codec \"%s\"\n", pCodecName );
  448. return false;
  449. }
  450. return Voice_Init( pCodecName, Voice_GetDefaultSampleRate( pCodecName ) );
  451. }
  452. bool Voice_Init( const char *pCodecName, int nSampleRate )
  453. {
  454. if ( voice_enable.GetInt() == 0 )
  455. {
  456. return false;
  457. }
  458. if ( !pCodecName || !pCodecName[0] )
  459. {
  460. return false;
  461. }
  462. bool bSpeex = Q_stricmp( pCodecName, "vaudio_speex" ) == 0;
  463. bool bCelt = Q_stricmp( pCodecName, "vaudio_celt" ) == 0;
  464. bool bSteam = Q_stricmp( pCodecName, "steam" ) == 0;
  465. // Miles has not been in use for voice in a long long time. Not worth the surface to support ancient demos that may
  466. // use it (and probably do not work for other reasons)
  467. // "vaudio_miles"
  468. if ( !( bSpeex || bCelt || bSteam ) )
  469. {
  470. Msg( "Voice_Init Failed: invalid voice codec %s.\n", pCodecName );
  471. return false;
  472. }
  473. Voice_Deinit();
  474. g_bVoiceAtLeastPartiallyInitted = true;
  475. V_strncpy( g_szVoiceCodec, pCodecName, sizeof(g_szVoiceCodec) );
  476. g_nVoiceRequestedSampleRate = nSampleRate;
  477. g_bUsingSteamVoice = bSteam;
  478. if ( !steamapicontext )
  479. {
  480. steamapicontext = &g_SteamAPIContext;
  481. steamapicontext->Init();
  482. }
  483. if ( g_bUsingSteamVoice )
  484. {
  485. if ( !steamapicontext->SteamFriends() || !steamapicontext->SteamUser() )
  486. {
  487. Msg( "Voice_Init: Requested Steam voice, but cannot access API. Voice will not function\n" );
  488. return false;
  489. }
  490. }
  491. // For steam, nSampleRate 0 means "use optimal steam sample rate".
  492. if ( bSteam && nSampleRate == 0 )
  493. {
  494. Msg( "Voice_Init: Using Steam voice optimal sample rate %d\n",
  495. steamapicontext->SteamUser()->GetVoiceOptimalSampleRate() );
  496. // Steam's sample rate may change and not be supported by our rather unflexible sound engine. However, steam
  497. // will resample as necessary in DecompressVoice, so we can pretend we're outputting at native rates.
  498. //
  499. // Behind the scenes, we'll request steam give us the encoded stream at its "optimal" rate, then we'll try to
  500. // decompress the output at this rate, making it transparent to us that the encoded stream is not at our output
  501. // rate.
  502. Voice_SetSampleRate( SOUND_DMA_SPEED );
  503. }
  504. else
  505. {
  506. Voice_SetSampleRate( nSampleRate );
  507. }
  508. if(!VoiceSE_Init())
  509. return false;
  510. // Get the voice input device.
  511. #ifdef OSX
  512. g_pVoiceRecord = CreateVoiceRecord_AudioQueue( Voice_SamplesPerSec() );
  513. if ( !g_pVoiceRecord )
  514. {
  515. // Fall back to OpenAL
  516. g_pVoiceRecord = CreateVoiceRecord_OpenAL( Voice_SamplesPerSec() );
  517. }
  518. #elif defined( WIN32 )
  519. g_pVoiceRecord = CreateVoiceRecord_DSound( Voice_SamplesPerSec() );
  520. #else
  521. g_pVoiceRecord = CreateVoiceRecord_OpenAL( Voice_SamplesPerSec() );
  522. #endif
  523. if( !g_pVoiceRecord )
  524. {
  525. Msg( "Unable to initialize sound capture. You won't be able to speak to other players." );
  526. }
  527. // Init codec DLL for non-steam
  528. if ( !bSteam )
  529. {
  530. // CELT's qualities are 0-3, we historically just passed 4 to the other two even though they don't really map to the
  531. // same thing.
  532. //
  533. // Changing the quality level we use here will require either extending SVC_VoiceInit to pass down which quality is
  534. // in use or using a different codec name (vaudio_celtHD!) for backwards compatibility
  535. int quality = bCelt ? 3 : 4;
  536. // Get the codec.
  537. CreateInterfaceFn createCodecFn = NULL;
  538. g_hVoiceCodecDLL = FileSystem_LoadModule(pCodecName);
  539. if ( !g_hVoiceCodecDLL || (createCodecFn = Sys_GetFactory(g_hVoiceCodecDLL)) == NULL ||
  540. (g_pEncodeCodec = (IVoiceCodec*)createCodecFn(pCodecName, NULL)) == NULL || !g_pEncodeCodec->Init( quality ) )
  541. {
  542. Msg("Unable to load voice codec '%s'. Voice disabled. (module %i, iface %i, codec %i)\n",
  543. pCodecName, !!g_hVoiceCodecDLL, !!createCodecFn, !!g_pEncodeCodec);
  544. Voice_Deinit();
  545. return false;
  546. }
  547. for (int i=0; i < VOICE_NUM_CHANNELS; i++)
  548. {
  549. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  550. if ((pChannel->m_pVoiceCodec = (IVoiceCodec*)createCodecFn(pCodecName, NULL)) == NULL || !pChannel->m_pVoiceCodec->Init( quality ))
  551. {
  552. Voice_Deinit();
  553. return false;
  554. }
  555. }
  556. }
  557. // XXX(JohnS): These don't do much in Steam codec mode, but code below uses their presence to mean 'voice fully
  558. // initialized' and other things assume they will succeed.
  559. InitMixerControls();
  560. // Steam mode uses steam for raw input so this isn't meaningful and could have side-effects
  561. if( voice_forcemicrecord.GetInt() && !bSteam )
  562. {
  563. if( g_pMixerControls )
  564. g_pMixerControls->SelectMicrophoneForWaveInput();
  565. }
  566. return true;
  567. }
  568. void Voice_EndChannel(int iChannel)
  569. {
  570. Assert(iChannel >= 0 && iChannel < VOICE_NUM_CHANNELS);
  571. CVoiceChannel *pChannel = &g_VoiceChannels[iChannel];
  572. if ( pChannel->m_iEntity != -1 )
  573. {
  574. int iEnt = pChannel->m_iEntity;
  575. pChannel->m_iEntity = -1;
  576. if ( pChannel->m_bProximity == true )
  577. {
  578. VoiceSE_EndChannel( iChannel, iEnt );
  579. }
  580. else
  581. {
  582. VoiceSE_EndChannel( iChannel, pChannel->m_nViewEntityIndex );
  583. }
  584. g_pSoundServices->OnChangeVoiceStatus( iEnt, false );
  585. VoiceSE_CloseMouth( iEnt );
  586. pChannel->m_nViewEntityIndex = -1;
  587. pChannel->m_nSoundGuid = -1;
  588. // If the tweak mode channel is ending
  589. if ( iChannel == 0 &&
  590. g_bInTweakMode )
  591. {
  592. VoiceTweak_EndVoiceTweakMode();
  593. }
  594. }
  595. }
  596. void Voice_EndAllChannels()
  597. {
  598. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  599. {
  600. Voice_EndChannel(i);
  601. }
  602. }
  603. bool EngineTool_SuppressDeInit();
  604. void Voice_Deinit()
  605. {
  606. // This call tends to be expensive and when voice is not enabled it will continually
  607. // call in here, so avoid the work if possible.
  608. if( !g_bVoiceAtLeastPartiallyInitted )
  609. return;
  610. if ( EngineTool_SuppressDeInit() )
  611. return;
  612. Voice_EndAllChannels();
  613. Voice_RecordStop();
  614. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  615. {
  616. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  617. if ( pChannel->m_pVoiceCodec )
  618. {
  619. pChannel->m_pVoiceCodec->Release();
  620. pChannel->m_pVoiceCodec = NULL;
  621. }
  622. }
  623. if( g_pEncodeCodec )
  624. {
  625. g_pEncodeCodec->Release();
  626. g_pEncodeCodec = NULL;
  627. }
  628. if(g_hVoiceCodecDLL)
  629. {
  630. FileSystem_UnloadModule(g_hVoiceCodecDLL);
  631. g_hVoiceCodecDLL = NULL;
  632. }
  633. if(g_pVoiceRecord)
  634. {
  635. g_pVoiceRecord->Release();
  636. g_pVoiceRecord = NULL;
  637. }
  638. VoiceSE_Term();
  639. g_bVoiceAtLeastPartiallyInitted = false;
  640. g_szVoiceCodec[0] = '\0';
  641. g_nVoiceRequestedSampleRate = -1;
  642. g_bUsingSteamVoice = false;
  643. }
  644. bool Voice_GetLoopback()
  645. {
  646. return !!voice_loopback.GetInt();
  647. }
  648. void Voice_LocalPlayerTalkingAck()
  649. {
  650. if(!g_bLocalPlayerTalkingAck)
  651. {
  652. // Tell the client DLL when this changes.
  653. g_pSoundServices->OnChangeVoiceStatus(-2, TRUE);
  654. }
  655. g_bLocalPlayerTalkingAck = true;
  656. g_LocalPlayerTalkingTimeout = 0;
  657. }
  658. void Voice_UpdateVoiceTweakMode()
  659. {
  660. if(!g_bInTweakMode || !g_pVoiceRecord)
  661. return;
  662. CVoiceChannel *pTweakChannel = GetVoiceChannel( 0 );
  663. if ( pTweakChannel->m_nSoundGuid != -1 &&
  664. !S_IsSoundStillPlaying( pTweakChannel->m_nSoundGuid ) )
  665. {
  666. VoiceTweak_EndVoiceTweakMode();
  667. return;
  668. }
  669. char uchVoiceData[4096];
  670. bool bFinal = false;
  671. int nDataLength = Voice_GetCompressedData(uchVoiceData, sizeof(uchVoiceData), bFinal);
  672. Voice_AddIncomingData(TWEAKMODE_CHANNELINDEX, uchVoiceData, nDataLength, 0);
  673. }
  674. void Voice_Idle(float frametime)
  675. {
  676. if( voice_enable.GetInt() == 0 )
  677. {
  678. Voice_Deinit();
  679. return;
  680. }
  681. if( g_bLocalPlayerTalkingAck )
  682. {
  683. g_LocalPlayerTalkingTimeout += frametime;
  684. if(g_LocalPlayerTalkingTimeout > LOCALPLAYERTALKING_TIMEOUT)
  685. {
  686. g_bLocalPlayerTalkingAck = false;
  687. // Tell the client DLL.
  688. g_pSoundServices->OnChangeVoiceStatus(-2, FALSE);
  689. }
  690. }
  691. // Precalculate these to speedup the voice fadeout.
  692. g_nVoiceFadeSamples = max((int)(voice_fadeouttime.GetFloat() * g_VoiceSampleFormat.nSamplesPerSec ), 2);
  693. g_VoiceFadeMul = 1.0f / (g_nVoiceFadeSamples - 1);
  694. if(g_pVoiceRecord)
  695. g_pVoiceRecord->Idle();
  696. // If we're in voice tweak mode, feed our own data back to us.
  697. Voice_UpdateVoiceTweakMode();
  698. // Age the channels.
  699. int nActive = 0;
  700. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  701. {
  702. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  703. if(pChannel->m_iEntity != -1)
  704. {
  705. if(pChannel->m_bStarved)
  706. {
  707. // Kill the channel. It's done playing.
  708. Voice_EndChannel(i);
  709. pChannel->m_nSoundGuid = -1;
  710. }
  711. else
  712. {
  713. float oldpad = pChannel->m_TimePad;
  714. pChannel->m_TimePad -= frametime;
  715. if(oldpad > 0 && pChannel->m_TimePad <= 0)
  716. {
  717. // Start its audio.
  718. pChannel->m_nViewEntityIndex = g_pSoundServices->GetViewEntity();
  719. pChannel->m_nSoundGuid = VoiceSE_StartChannel( i, pChannel->m_iEntity, pChannel->m_bProximity, pChannel->m_nViewEntityIndex );
  720. g_pSoundServices->OnChangeVoiceStatus(pChannel->m_iEntity, TRUE);
  721. VoiceSE_InitMouth(pChannel->m_iEntity);
  722. }
  723. ++nActive;
  724. }
  725. }
  726. }
  727. if(nActive == 0)
  728. VoiceSE_EndOverdrive();
  729. VoiceSE_Idle(frametime);
  730. // voice_showchannels.
  731. if( voice_showchannels.GetInt() >= 1 )
  732. {
  733. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  734. {
  735. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  736. if(pChannel->m_iEntity == -1)
  737. continue;
  738. Msg("Voice - chan %d, ent %d, bufsize: %d\n", i, pChannel->m_iEntity, pChannel->m_Buffer.GetReadAvailable());
  739. }
  740. }
  741. // Show profiling data?
  742. if( voice_profile.GetInt() )
  743. {
  744. Msg("Voice - compress: %7.2fu, decompress: %7.2fu, gain: %7.2fu, upsample: %7.2fu, total: %7.2fu\n",
  745. g_CompressTime*1000000.0,
  746. g_DecompressTime*1000000.0,
  747. g_GainTime*1000000.0,
  748. g_UpsampleTime*1000000.0,
  749. (g_CompressTime+g_DecompressTime+g_GainTime+g_UpsampleTime)*1000000.0
  750. );
  751. g_CompressTime = g_DecompressTime = g_GainTime = g_UpsampleTime = 0;
  752. }
  753. }
  754. bool Voice_IsRecording()
  755. {
  756. return g_bVoiceRecording && !g_bInTweakMode;
  757. }
  758. bool Voice_RecordStart(
  759. const char *pUncompressedFile,
  760. const char *pDecompressedFile,
  761. const char *pMicInputFile)
  762. {
  763. if( !g_pEncodeCodec && !g_bUsingSteamVoice )
  764. return false;
  765. g_VoiceWriter.Flush();
  766. Voice_RecordStop();
  767. if ( !g_bUsingSteamVoice )
  768. {
  769. g_pEncodeCodec->ResetState();
  770. }
  771. if(pMicInputFile)
  772. {
  773. int a, b, c;
  774. ReadWaveFile(pMicInputFile, g_pMicInputFileData, g_nMicInputFileBytes, a, b, c);
  775. g_CurMicInputFileByte = 0;
  776. g_MicStartTime = Plat_FloatTime();
  777. }
  778. if(pUncompressedFile)
  779. {
  780. g_pUncompressedFileData = new char[MAX_WAVEFILEDATA_LEN];
  781. g_nUncompressedDataBytes = 0;
  782. g_pUncompressedDataFilename = pUncompressedFile;
  783. }
  784. if(pDecompressedFile)
  785. {
  786. g_pDecompressedFileData = new char[MAX_WAVEFILEDATA_LEN];
  787. g_nDecompressedDataBytes = 0;
  788. g_pDecompressedDataFilename = pDecompressedFile;
  789. }
  790. g_bVoiceRecording = false;
  791. if ( g_pVoiceRecord )
  792. {
  793. g_bVoiceRecording = VoiceRecord_Start();
  794. if ( g_bVoiceRecording )
  795. {
  796. if ( steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUser() )
  797. {
  798. // Tell Friends' Voice chat that the local user has started speaking
  799. steamapicontext->SteamFriends()->SetInGameVoiceSpeaking( steamapicontext->SteamUser()->GetSteamID(), true );
  800. }
  801. g_pSoundServices->OnChangeVoiceStatus( -1, true ); // Tell the client DLL.
  802. }
  803. }
  804. return g_bVoiceRecording;
  805. }
  806. void Voice_UserDesiresStop()
  807. {
  808. if ( g_bVoiceRecordStopping )
  809. return;
  810. g_bVoiceRecordStopping = true;
  811. g_pSoundServices->OnChangeVoiceStatus( -1, false ); // Tell the client DLL.
  812. // If we're using Steam voice, we'll keep recording until Steam tells us we
  813. // received all the data.
  814. if ( g_bUsingSteamVoice )
  815. {
  816. steamapicontext->SteamUser()->StopVoiceRecording();
  817. }
  818. else
  819. {
  820. VoiceRecord_Stop();
  821. }
  822. }
  823. bool Voice_RecordStop()
  824. {
  825. // Write the files out for debugging.
  826. if(g_pMicInputFileData)
  827. {
  828. delete [] g_pMicInputFileData;
  829. g_pMicInputFileData = NULL;
  830. }
  831. if(g_pUncompressedFileData)
  832. {
  833. WriteWaveFile(g_pUncompressedDataFilename, g_pUncompressedFileData, g_nUncompressedDataBytes, g_VoiceSampleFormat.wBitsPerSample, g_VoiceSampleFormat.nChannels, Voice_SamplesPerSec() );
  834. delete [] g_pUncompressedFileData;
  835. g_pUncompressedFileData = NULL;
  836. }
  837. if(g_pDecompressedFileData)
  838. {
  839. WriteWaveFile(g_pDecompressedDataFilename, g_pDecompressedFileData, g_nDecompressedDataBytes, g_VoiceSampleFormat.wBitsPerSample, g_VoiceSampleFormat.nChannels, Voice_SamplesPerSec() );
  840. delete [] g_pDecompressedFileData;
  841. g_pDecompressedFileData = NULL;
  842. }
  843. g_VoiceWriter.Finish();
  844. VoiceRecord_Stop();
  845. if ( g_bVoiceRecording )
  846. {
  847. if ( steamapicontext->SteamFriends() && steamapicontext->SteamUser() )
  848. {
  849. // Tell Friends' Voice chat that the local user has stopped speaking
  850. steamapicontext->SteamFriends()->SetInGameVoiceSpeaking( steamapicontext->SteamUser()->GetSteamID(), false );
  851. }
  852. }
  853. g_bVoiceRecording = false;
  854. g_bVoiceRecordStopping = false;
  855. return(true);
  856. }
  857. int Voice_GetCompressedData(char *pchDest, int nCount, bool bFinal)
  858. {
  859. // Check g_bVoiceRecordStopping in case g_bUsingSteamVoice changes on us
  860. // while waiting for the end of voice data.
  861. if ( g_bUsingSteamVoice || g_bVoiceRecordStopping )
  862. {
  863. uint32 cbCompressedWritten = 0;
  864. uint32 cbUncompressedWritten = 0;
  865. uint32 cbCompressed = 0;
  866. uint32 cbUncompressed = 0;
  867. // We're going to always request steam give us the encoded stream at the optimal rate, unless our final output
  868. // rate is lower than it. We'll pass our output rate when we actually extract the data, which Steam will
  869. // happily upsample from its optimal rate for us.
  870. int nEncodeRate = min( (int)steamapicontext->SteamUser()->GetVoiceOptimalSampleRate(), Voice_SamplesPerSec() );
  871. EVoiceResult result = steamapicontext->SteamUser()->GetAvailableVoice( &cbCompressed, &cbUncompressed, nEncodeRate );
  872. if ( result == k_EVoiceResultOK )
  873. {
  874. result = steamapicontext->SteamUser()->GetVoice( true, pchDest, nCount, &cbCompressedWritten,
  875. g_pUncompressedFileData != NULL, g_pUncompressedFileData,
  876. MAX_WAVEFILEDATA_LEN - g_nUncompressedDataBytes,
  877. &cbUncompressedWritten, nEncodeRate );
  878. if ( g_pUncompressedFileData )
  879. {
  880. g_nUncompressedDataBytes += cbUncompressedWritten;
  881. }
  882. g_pSoundServices->OnChangeVoiceStatus( -3, true );
  883. }
  884. else
  885. {
  886. if ( result == k_EVoiceResultNotRecording && g_bVoiceRecording )
  887. {
  888. Voice_RecordStop();
  889. }
  890. g_pSoundServices->OnChangeVoiceStatus( -3, false );
  891. }
  892. return cbCompressedWritten;
  893. }
  894. IVoiceCodec *pCodec = g_pEncodeCodec;
  895. if( g_pVoiceRecord && pCodec )
  896. {
  897. #ifdef VOICE_VOX_ENABLE
  898. static ConVarRef voice_vox( "voice_vox" );
  899. #endif // VOICE_VOX_ENABLE
  900. short tempData[8192];
  901. int samplesWanted = min(nCount/BYTES_PER_SAMPLE, (int)sizeof(tempData)/BYTES_PER_SAMPLE);
  902. int gotten = g_pVoiceRecord->GetRecordedData(tempData, samplesWanted);
  903. // If they want to get the data from a file instead of the mic, use that.
  904. if(g_pMicInputFileData)
  905. {
  906. double curtime = Plat_FloatTime();
  907. int nShouldGet = (curtime - g_MicStartTime) * Voice_SamplesPerSec();
  908. gotten = min(sizeof(tempData)/BYTES_PER_SAMPLE,
  909. (size_t)min(nShouldGet, (g_nMicInputFileBytes - g_CurMicInputFileByte) / BYTES_PER_SAMPLE));
  910. memcpy(tempData, &g_pMicInputFileData[g_CurMicInputFileByte], gotten*BYTES_PER_SAMPLE);
  911. g_CurMicInputFileByte += gotten * BYTES_PER_SAMPLE;
  912. g_MicStartTime = curtime;
  913. }
  914. #ifdef VOICE_VOX_ENABLE
  915. else if ( gotten && voice_vox.GetBool() == true )
  916. {
  917. // If the voice data is essentially silent, don't transmit
  918. short *pData = tempData;
  919. int averageData = 0;
  920. int minData = 16384;
  921. int maxData = -16384;
  922. for ( int i=0; i<gotten; ++i )
  923. {
  924. short val = *pData;
  925. averageData += val;
  926. minData = min( val, minData );
  927. maxData = max( val, maxData );
  928. ++pData;
  929. }
  930. averageData /= gotten;
  931. int deltaData = maxData - minData;
  932. if ( deltaData < voice_threshold.GetFloat() && maxData < voice_threshold.GetFloat() )
  933. {
  934. // -3 signals that we're silent
  935. g_pSoundServices->OnChangeVoiceStatus( -3, false );
  936. return 0;
  937. }
  938. }
  939. #endif // VOICE_VOX_ENABLE
  940. #ifdef VOICE_SEND_RAW_TEST
  941. int nCompressedBytes = min( gotten, nCount );
  942. for ( int i=0; i < nCompressedBytes; i++ )
  943. {
  944. pchDest[i] = (char)(tempData[i] >> 8);
  945. }
  946. #else
  947. int nCompressedBytes = pCodec->Compress((char*)tempData, gotten, pchDest, nCount, !!bFinal);
  948. #endif
  949. // Write to our file buffers..
  950. if(g_pUncompressedFileData)
  951. {
  952. int nToWrite = min(gotten*BYTES_PER_SAMPLE, MAX_WAVEFILEDATA_LEN - g_nUncompressedDataBytes);
  953. memcpy(&g_pUncompressedFileData[g_nUncompressedDataBytes], tempData, nToWrite);
  954. g_nUncompressedDataBytes += nToWrite;
  955. }
  956. #ifdef VOICE_VOX_ENABLE
  957. // -3 signals that we're talking
  958. g_pSoundServices->OnChangeVoiceStatus( -3, (nCompressedBytes > 0) );
  959. #endif // VOICE_VOX_ENABLE
  960. return nCompressedBytes;
  961. }
  962. else
  963. {
  964. #ifdef VOICE_VOX_ENABLE
  965. // -3 signals that we're silent
  966. g_pSoundServices->OnChangeVoiceStatus( -3, false );
  967. #endif // VOICE_VOX_ENABLE
  968. return 0;
  969. }
  970. }
  971. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  972. // Purpose: Assigns a channel to an entity by searching for either a channel
  973. // already assigned to that entity or picking the least recently used
  974. // channel. If the LRU channel is picked, it is flushed and all other
  975. // channels are aged.
  976. // Input : nEntity - entity number to assign to a channel.
  977. // Output : A channel index to which the entity has been assigned.
  978. //------------------------------------------------------------------------------
  979. int Voice_AssignChannel(int nEntity, bool bProximity)
  980. {
  981. if(g_bInTweakMode)
  982. return VOICE_CHANNEL_IN_TWEAK_MODE;
  983. // See if a channel already exists for this entity and if so, just return it.
  984. int iFree = -1;
  985. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  986. {
  987. CVoiceChannel *pChannel = &g_VoiceChannels[i];
  988. if(pChannel->m_iEntity == nEntity)
  989. {
  990. return i;
  991. }
  992. else if(pChannel->m_iEntity == -1 && ( pChannel->m_pVoiceCodec || g_bUsingSteamVoice ) )
  993. {
  994. // Won't exist in steam voice mode
  995. if ( pChannel->m_pVoiceCodec )
  996. {
  997. pChannel->m_pVoiceCodec->ResetState();
  998. }
  999. iFree = i;
  1000. break;
  1001. }
  1002. }
  1003. // If they're all used, then don't allow them to make a new channel.
  1004. if(iFree == -1)
  1005. {
  1006. return VOICE_CHANNEL_ERROR;
  1007. }
  1008. CVoiceChannel *pChannel = &g_VoiceChannels[iFree];
  1009. pChannel->Init(nEntity);
  1010. pChannel->m_bProximity = bProximity;
  1011. VoiceSE_StartOverdrive();
  1012. return iFree;
  1013. }
  1014. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1015. // Purpose: Determines which channel has been assigened to a given entity.
  1016. // Input : nEntity - entity number.
  1017. // Output : The index of the channel assigned to the entity, VOICE_CHANNEL_ERROR
  1018. // if no channel is currently assigned to the given entity.
  1019. //------------------------------------------------------------------------------
  1020. int Voice_GetChannel(int nEntity)
  1021. {
  1022. for(int i=0; i < VOICE_NUM_CHANNELS; i++)
  1023. if(g_VoiceChannels[i].m_iEntity == nEntity)
  1024. return i;
  1025. return VOICE_CHANNEL_ERROR;
  1026. }
  1027. double UpsampleIntoBuffer(
  1028. const short *pSrc,
  1029. int nSrcSamples,
  1030. CCircularBuffer *pBuffer,
  1031. double startFraction,
  1032. double rate)
  1033. {
  1034. double maxFraction = nSrcSamples - 1;
  1035. while(1)
  1036. {
  1037. if(startFraction >= maxFraction)
  1038. break;
  1039. int iSample = (int)startFraction;
  1040. double frac = startFraction - floor(startFraction);
  1041. double val1 = pSrc[iSample];
  1042. double val2 = pSrc[iSample+1];
  1043. short newSample = (short)(val1 + (val2 - val1) * frac);
  1044. pBuffer->Write(&newSample, sizeof(newSample));
  1045. startFraction += rate;
  1046. }
  1047. return startFraction - floor(startFraction);
  1048. }
  1049. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1050. // Purpose: Adds received voice data to
  1051. // Input :
  1052. // Output :
  1053. //------------------------------------------------------------------------------
  1054. int Voice_AddIncomingData(int nChannel, const char *pchData, int nCount, int iSequenceNumber)
  1055. {
  1056. CVoiceChannel *pChannel;
  1057. // If in tweak mode, we call this during Idle with -1 as the channel, so any channel data from the network
  1058. // gets rejected.
  1059. if(g_bInTweakMode)
  1060. {
  1061. if(nChannel == TWEAKMODE_CHANNELINDEX)
  1062. nChannel = 0;
  1063. else
  1064. return 0;
  1065. }
  1066. if ( ( pChannel = GetVoiceChannel(nChannel)) == NULL || ( !g_bUsingSteamVoice && !pChannel->m_pVoiceCodec ) )
  1067. {
  1068. return(0);
  1069. }
  1070. pChannel->m_bStarved = false; // This only really matters if you call Voice_AddIncomingData between the time the mixer
  1071. // asks for data and Voice_Idle is called.
  1072. // Decompress.
  1073. // @note Tom Bui: suggested destination buffer for Steam voice is 22kb
  1074. char decompressed[22528];
  1075. #ifdef VOICE_SEND_RAW_TEST
  1076. int nDecompressed = nCount;
  1077. for ( int i=0; i < nDecompressed; i++ )
  1078. ((short*)decompressed)[i] = pchData[i] << 8;
  1079. #else
  1080. int nDecompressed = 0;
  1081. if ( g_bUsingSteamVoice )
  1082. {
  1083. uint32 nBytesWritten = 0;
  1084. EVoiceResult result = steamapicontext->SteamUser()->DecompressVoice( pchData, nCount,
  1085. decompressed, sizeof( decompressed ),
  1086. &nBytesWritten, Voice_SamplesPerSec() );
  1087. if ( result == k_EVoiceResultOK )
  1088. {
  1089. nDecompressed = nBytesWritten / BYTES_PER_SAMPLE;
  1090. }
  1091. }
  1092. else
  1093. {
  1094. nDecompressed = pChannel->m_pVoiceCodec->Decompress(pchData, nCount, decompressed, sizeof(decompressed));
  1095. }
  1096. #endif
  1097. if ( g_bInTweakMode )
  1098. {
  1099. short *data = (short *)decompressed;
  1100. g_VoiceTweakSpeakingVolume = 0;
  1101. // Find the highest value
  1102. for ( int i=0; i<nDecompressed; ++i )
  1103. {
  1104. g_VoiceTweakSpeakingVolume = max((int)abs(data[i]), g_VoiceTweakSpeakingVolume);
  1105. }
  1106. // Smooth it out
  1107. g_VoiceTweakSpeakingVolume &= 0xFE00;
  1108. }
  1109. pChannel->m_AutoGain.ProcessSamples((short*)decompressed, nDecompressed);
  1110. // Upsample into the dest buffer. We could do this in a mixer but it complicates the mixer.
  1111. pChannel->m_LastFraction = UpsampleIntoBuffer( (short*)decompressed,
  1112. nDecompressed,
  1113. &pChannel->m_Buffer,
  1114. pChannel->m_LastFraction,
  1115. (double)Voice_SamplesPerSec()/g_VoiceSampleFormat.nSamplesPerSec );
  1116. pChannel->m_LastSample = decompressed[nDecompressed];
  1117. // Write to our file buffer..
  1118. if(g_pDecompressedFileData)
  1119. {
  1120. int nToWrite = min(nDecompressed*2, MAX_WAVEFILEDATA_LEN - g_nDecompressedDataBytes);
  1121. memcpy(&g_pDecompressedFileData[g_nDecompressedDataBytes], decompressed, nToWrite);
  1122. g_nDecompressedDataBytes += nToWrite;
  1123. }
  1124. g_VoiceWriter.AddDecompressedData( pChannel, (const byte *)decompressed, nDecompressed * 2 );
  1125. if( voice_showincoming.GetInt() != 0 )
  1126. {
  1127. Msg("Voice - %d incoming samples added to channel %d\n", nDecompressed, nChannel);
  1128. }
  1129. return(nChannel);
  1130. }
  1131. #if DEAD
  1132. //------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
  1133. // Purpose: Flushes a given receive channel.
  1134. // Input : nChannel - index of channel to flush.
  1135. //------------------------------------------------------------------------------
  1136. void Voice_FlushChannel(int nChannel)
  1137. {
  1138. if ((nChannel < 0) || (nChannel >= VOICE_NUM_CHANNELS))
  1139. {
  1140. Assert(false);
  1141. return;
  1142. }
  1143. g_VoiceChannels[nChannel].m_Buffer.Flush();
  1144. }
  1145. #endif
  1146. //------------------------------------------------------------------------------
  1147. // IVoiceTweak implementation.
  1148. //------------------------------------------------------------------------------
  1149. int VoiceTweak_StartVoiceTweakMode()
  1150. {
  1151. // If we're already in voice tweak mode, return an error.
  1152. if(g_bInTweakMode)
  1153. {
  1154. Assert(!"VoiceTweak_StartVoiceTweakMode called while already in tweak mode.");
  1155. return 0;
  1156. }
  1157. if ( !g_pMixerControls && voice_enable.GetBool() )
  1158. {
  1159. Voice_ForceInit();
  1160. }
  1161. if( !g_pMixerControls )
  1162. return 0;
  1163. Voice_EndAllChannels();
  1164. Voice_RecordStart(NULL, NULL, NULL);
  1165. Voice_AssignChannel(TWEAKMODE_ENTITYINDEX, false );
  1166. g_bInTweakMode = true;
  1167. InitMixerControls();
  1168. return 1;
  1169. }
  1170. void VoiceTweak_EndVoiceTweakMode()
  1171. {
  1172. if(!g_bInTweakMode)
  1173. {
  1174. Assert(!"VoiceTweak_EndVoiceTweakMode called when not in tweak mode.");
  1175. return;
  1176. }
  1177. g_bInTweakMode = false;
  1178. Voice_RecordStop();
  1179. }
  1180. void VoiceTweak_SetControlFloat(VoiceTweakControl iControl, float flValue)
  1181. {
  1182. if(!g_pMixerControls)
  1183. return;
  1184. if(iControl == MicrophoneVolume)
  1185. {
  1186. g_pMixerControls->SetValue_Float(IMixerControls::MicVolume, flValue);
  1187. }
  1188. else if ( iControl == MicBoost )
  1189. {
  1190. g_pMixerControls->SetValue_Float( IMixerControls::MicBoost, flValue );
  1191. }
  1192. else if(iControl == OtherSpeakerScale)
  1193. {
  1194. voice_scale.SetValue( flValue );
  1195. }
  1196. }
  1197. void Voice_ForceInit()
  1198. {
  1199. if ( g_pMixerControls || !voice_enable.GetBool() )
  1200. {
  1201. // Nothing to do
  1202. return;
  1203. }
  1204. // Lacking a better default, just peak at what the server's sv_voicecodec is set to
  1205. static ConVarRef sv_voicecodec( "sv_voicecodec" );
  1206. if ( !Voice_InitWithDefault( sv_voicecodec.GetString() ) )
  1207. {
  1208. // Try ultimate fallback
  1209. Voice_InitWithDefault( VOICE_FALLBACK_CODEC );
  1210. }
  1211. }
  1212. float VoiceTweak_GetControlFloat(VoiceTweakControl iControl)
  1213. {
  1214. Voice_ForceInit();
  1215. if(!g_pMixerControls)
  1216. return 0;
  1217. if(iControl == MicrophoneVolume)
  1218. {
  1219. float value = 1;
  1220. g_pMixerControls->GetValue_Float(IMixerControls::MicVolume, value);
  1221. return value;
  1222. }
  1223. else if(iControl == OtherSpeakerScale)
  1224. {
  1225. return voice_scale.GetFloat();
  1226. }
  1227. else if(iControl == SpeakingVolume)
  1228. {
  1229. return g_VoiceTweakSpeakingVolume * 1.0f / 32768;
  1230. }
  1231. else if ( iControl == MicBoost )
  1232. {
  1233. float flValue = 1;
  1234. g_pMixerControls->GetValue_Float( IMixerControls::MicBoost, flValue );
  1235. return flValue;
  1236. }
  1237. else
  1238. {
  1239. return 1;
  1240. }
  1241. }
  1242. bool VoiceTweak_IsStillTweaking()
  1243. {
  1244. return g_bInTweakMode;
  1245. }
  1246. void Voice_Spatialize( channel_t *channel )
  1247. {
  1248. if ( !g_bInTweakMode )
  1249. return;
  1250. Assert( channel->sfx );
  1251. Assert( channel->sfx->pSource );
  1252. Assert( channel->sfx->pSource->GetType() == CAudioSource::AUDIO_SOURCE_VOICE );
  1253. // Place the tweak mode sound back at the view entity
  1254. CVoiceChannel *pVoiceChannel = GetVoiceChannel( 0 );
  1255. Assert( pVoiceChannel );
  1256. if ( !pVoiceChannel )
  1257. return;
  1258. if ( pVoiceChannel->m_nSoundGuid != channel->guid )
  1259. return;
  1260. // No change
  1261. if ( g_pSoundServices->GetViewEntity() == pVoiceChannel->m_nViewEntityIndex )
  1262. return;
  1263. DevMsg( 1, "Voice_Spatialize changing voice tweak entity from %d to %d\n", pVoiceChannel->m_nViewEntityIndex, g_pSoundServices->GetViewEntity() );
  1264. pVoiceChannel->m_nViewEntityIndex = g_pSoundServices->GetViewEntity();
  1265. channel->soundsource = pVoiceChannel->m_nViewEntityIndex;
  1266. }
  1267. IVoiceTweak g_VoiceTweakAPI =
  1268. {
  1269. VoiceTweak_StartVoiceTweakMode,
  1270. VoiceTweak_EndVoiceTweakMode,
  1271. VoiceTweak_SetControlFloat,
  1272. VoiceTweak_GetControlFloat,
  1273. VoiceTweak_IsStillTweaking,
  1274. };