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.

517 lines
17 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "engine/IEngineSound.h"
  8. #include "tier0/dbg.h"
  9. #include "quakedef.h"
  10. #include "vox.h"
  11. #include "server.h"
  12. #include "sv_main.h"
  13. #include "edict.h"
  14. #include "sound.h"
  15. #include "host.h"
  16. #include "vengineserver_impl.h"
  17. #include "enginesingleuserfilter.h"
  18. #include "snd_audio_source.h"
  19. #include "soundchars.h"
  20. #include "tier0/vprof.h"
  21. #ifndef DEDICATED
  22. #include "vgui_baseui_interface.h"
  23. #endif
  24. #include "SoundEmitterSystem/isoundemittersystembase.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. //-----------------------------------------------------------------------------
  28. //
  29. // Server-side implementation of the engine sound interface
  30. //
  31. //-----------------------------------------------------------------------------
  32. class CEngineSoundServer : public IEngineSound
  33. {
  34. public:
  35. // constructor, destructor
  36. CEngineSoundServer();
  37. virtual ~CEngineSoundServer();
  38. virtual bool PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound );
  39. virtual bool IsSoundPrecached( const char *pSample );
  40. virtual void PrefetchSound( const char *pSample );
  41. virtual bool IsLoopingSound( const char *pSample )
  42. {
  43. Warning( "Can't call IsLoopingSound from server\n" );
  44. return false;
  45. }
  46. virtual float GetSoundDuration( const char *pSample );
  47. virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
  48. float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
  49. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  50. virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
  51. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  52. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  53. virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
  54. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  55. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  56. virtual void StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash = SOUNDEMITTER_INVALID_HASH );
  57. virtual void StopAllSounds( bool bClearBuffers );
  58. // Set the room type for a player
  59. virtual void SetRoomType( IRecipientFilter& filter, int roomType );
  60. virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset );
  61. // emit an "ambient" sound that isn't spatialized - specify left/right volume
  62. // only available on the client, assert on server
  63. virtual int EmitAmbientSound( const char *pSample, float flVolume, int iPitch, int flags, float soundtime = 0.0f );
  64. virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist );
  65. // Client .dll only functions
  66. virtual int GetGuidForLastSoundEmitted()
  67. {
  68. Warning( "Can't call GetGuidForLastSoundEmitted from server\n" );
  69. return 0;
  70. }
  71. virtual bool IsSoundStillPlaying( int guid )
  72. {
  73. Warning( "Can't call IsSoundStillPlaying from server\n" );
  74. return false;
  75. }
  76. virtual void StopSoundByGuid( int guid, bool bForce )
  77. {
  78. Warning( "Can't call StopSoundByGuid from server\n" );
  79. return;
  80. }
  81. // Retrieves list of all active sounds
  82. virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist )
  83. {
  84. Warning( "Can't call GetActiveSounds from server\n" );
  85. return;
  86. }
  87. // Set's master volume (0.0->1.0)
  88. virtual void SetVolumeByGuid( int guid, float fvol )
  89. {
  90. Warning( "Can't call SetVolumeByGuid from server\n" );
  91. return;
  92. }
  93. // return's sound's current elapsed time
  94. virtual float GetElapsedTimeByGuid( int guid)
  95. {
  96. Warning( "Can't call GetElapsedTimeByGuid from server\n" );
  97. return 0.0;
  98. }
  99. virtual void PrecacheSentenceGroup( const char *pGroupName )
  100. {
  101. VOX_PrecacheSentenceGroup( this, pGroupName );
  102. }
  103. virtual void NotifyBeginMoviePlayback()
  104. {
  105. AssertMsg( 0, "Not supported" );
  106. }
  107. virtual void NotifyEndMoviePlayback()
  108. {
  109. AssertMsg( 0, "Not supported" );
  110. }
  111. virtual bool IsMoviePlaying()
  112. {
  113. AssertMsg( 0, "Not supported" );
  114. return false;
  115. }
  116. virtual bool GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight )
  117. {
  118. Warning( "Can't call GetSoundChannelVolume from server\n" );
  119. return false;
  120. }
  121. virtual bool GetPreventSound( )
  122. {
  123. AssertMsg( 0, "Not supported" );
  124. return false;
  125. }
  126. virtual void SetReplaySoundFade( float flReplayVolume ) { Assert( !"Client-only service" ); }
  127. virtual float GetReplaySoundFade()const { Assert( !"Client-only service" ); return 0.0f; }
  128. virtual void SetReplayMusicGain( float flReplayMusicGain ) { Assert( !"Client-only service" ); }
  129. virtual float GetReplayMusicGain()const { Assert( !"Client-only service" ); return 0.0f; }
  130. #if defined( _GAMECONSOLE )
  131. virtual void UnloadSound( const char *pSample )
  132. {
  133. AssertMsg( 0, "Not supported" );
  134. }
  135. #endif
  136. private:
  137. void EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
  138. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  139. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  140. };
  141. //-----------------------------------------------------------------------------
  142. // Client-server neutral sound interface accessor
  143. //-----------------------------------------------------------------------------
  144. static CEngineSoundServer s_EngineSoundServer;
  145. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineSoundServer, IEngineSound,
  146. IENGINESOUND_SERVER_INTERFACE_VERSION, s_EngineSoundServer );
  147. IEngineSound *EngineSoundServer()
  148. {
  149. return &s_EngineSoundServer;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // constructor, destructor
  153. //-----------------------------------------------------------------------------
  154. CEngineSoundServer::CEngineSoundServer()
  155. {
  156. }
  157. CEngineSoundServer::~CEngineSoundServer()
  158. {
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Precache a particular sample
  162. //-----------------------------------------------------------------------------
  163. bool CEngineSoundServer::PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound )
  164. {
  165. #ifndef DEDICATED
  166. EngineVGui()->UpdateProgressBar( PROGRESS_DEFAULT );
  167. #endif
  168. int i;
  169. if ( pSample && TestSoundChar( pSample, CHAR_SENTENCE ) )
  170. {
  171. return true;
  172. }
  173. if ( pSample[0] <= ' ' )
  174. {
  175. Host_Error( "CEngineSoundServer::PrecacheSound: Bad string: %s", pSample );
  176. }
  177. // add the sound to the precache list
  178. // Start at 1, since 0 is used to indicate an error in the sound precache
  179. i = SV_FindOrAddSound( pSample, bPreload );
  180. if ( i >= 0 )
  181. return true;
  182. Host_Error( "CEngineSoundServer::PrecacheSound: '%s' overflow", pSample );
  183. return false;
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose:
  187. // Input : *pSample -
  188. // Output : Returns true on success, false on failure.
  189. //-----------------------------------------------------------------------------
  190. bool CEngineSoundServer::IsSoundPrecached( const char *pSample )
  191. {
  192. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  193. {
  194. return true;
  195. }
  196. int idx = SV_SoundIndex( pSample );
  197. if ( idx == -1 )
  198. {
  199. return false;
  200. }
  201. return true;
  202. }
  203. void CEngineSoundServer::PrefetchSound( const char *pSample )
  204. {
  205. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  206. {
  207. return;
  208. }
  209. int idx = SV_SoundIndex( pSample );
  210. if ( idx == -1 )
  211. {
  212. return;
  213. }
  214. // Tell clients to prefetch the sound
  215. CSVCMsg_Prefetch_t msg;
  216. msg.set_sound_index( idx );
  217. sv.BroadcastMessage( msg, true, false );
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Stops a sound
  221. //-----------------------------------------------------------------------------
  222. void CEngineSoundServer::EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
  223. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  224. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*=-1*/ )
  225. {
  226. AssertMsg( pDirection == NULL, "Direction specification not currently supported on server sounds" );
  227. AssertMsg( bUpdatePositions, "Non-updated positions not currently supported on server sounds" );
  228. if (flVolume < 0 || flVolume > 1)
  229. {
  230. Warning ("EmitSound: %s volume out of bounds = %f\n", pSample, flVolume);
  231. return;
  232. }
  233. if (iSoundLevel < MIN_SNDLVL_VALUE || iSoundLevel > MAX_SNDLVL_VALUE)
  234. {
  235. Warning ("EmitSound: %s soundlevel out of bounds = %d\n", pSample, iSoundLevel);
  236. return;
  237. }
  238. if (iPitch < 0 || iPitch > 255)
  239. {
  240. Warning ("EmitSound: %s pitch out of bounds = %i\n", pSample, iPitch);
  241. return;
  242. }
  243. edict_t *pEdict = (iEntIndex >= 0) ? &sv.edicts[iEntIndex] : NULL;
  244. SV_StartSound( filter, pEdict, iChannel, pSoundEntry, iSoundEntryHash, pSample, flVolume, iSoundLevel,
  245. iFlags, iPitch, pOrigin, soundtime, speakerentity, pUtlVecOrigins, nSeed );
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Plays a sentence
  249. //-----------------------------------------------------------------------------
  250. void CEngineSoundServer::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel,
  251. int iSentenceIndex, float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  252. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  253. {
  254. if ( iSentenceIndex >= 0 )
  255. {
  256. char pName[8];
  257. Q_snprintf( pName, sizeof(pName), "!%d", iSentenceIndex );
  258. EmitSoundInternal( filter, iEntIndex, iChannel, NULL, SOUNDEMITTER_INVALID_HASH, pName, flVolume, iSoundLevel, nSeed,
  259. iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Emits a sound
  264. //-----------------------------------------------------------------------------
  265. int CEngineSoundServer::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
  266. float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
  267. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  268. {
  269. VPROF( "CEngineSoundServer::EmitSound" );
  270. EmitSound( filter, iEntIndex, iChannel, pSoundEntry, iSoundEntryHash, pSample, flVolume, ATTN_TO_SNDLVL( flAttenuation ), nSeed, iFlags,
  271. iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  272. return -1; // Negative for unsupported feature.
  273. }
  274. int CEngineSoundServer::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample,
  275. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  276. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  277. {
  278. VPROF( "CEngineSoundServer::EmitSound" );
  279. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  280. {
  281. int iSentenceIndex = -1;
  282. VOX_LookupString( PSkipSoundChars(pSample), &iSentenceIndex );
  283. if (iSentenceIndex >= 0)
  284. {
  285. EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume,
  286. iSoundLevel, nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  287. }
  288. else
  289. {
  290. DevWarning( 2, "Unable to find %s in sentences.txt\n", PSkipSoundChars(pSample) );
  291. }
  292. }
  293. else
  294. {
  295. EmitSoundInternal( filter, iEntIndex, iChannel, pSoundEntry, iSoundEntryHash, pSample, flVolume, iSoundLevel, nSeed,
  296. iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  297. }
  298. return -1; // Negative for unsupported feature.
  299. }
  300. void BuildRecipientList( CUtlVector< edict_t * >& list, const IRecipientFilter& filter )
  301. {
  302. int c = filter.GetRecipientCount();
  303. for ( int i = 0; i < c; i++ )
  304. {
  305. int playerindex = filter.GetRecipientIndex( i );
  306. if ( playerindex < 1 || playerindex > sv.GetClientCount() )
  307. continue;
  308. CGameClient *cl = sv.Client( playerindex - 1 );
  309. // Never output to bots
  310. if ( cl->IsFakeClient() )
  311. continue;
  312. if ( !cl->IsSpawned() )
  313. continue;
  314. list.AddToTail( cl->edict );
  315. }
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose:
  319. // Input : filter -
  320. // roomType -
  321. //-----------------------------------------------------------------------------
  322. void CEngineSoundServer::SetRoomType( IRecipientFilter& filter, int roomType )
  323. {
  324. CUtlVector< edict_t * > players;
  325. BuildRecipientList( players, filter );
  326. for ( int i = 0 ; i < players.Count(); i++ )
  327. {
  328. g_pVEngineServer->ClientCommand( players[ i ], "room_type %i\n", roomType );
  329. }
  330. }
  331. // Set the dsp preset for a player (client only)
  332. //-----------------------------------------------------------------------------
  333. // Purpose:
  334. // Input : filter -
  335. // dspType -
  336. //-----------------------------------------------------------------------------
  337. void CEngineSoundServer::SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset )
  338. {
  339. Assert( !fastReset );
  340. if ( fastReset )
  341. {
  342. Warning( "SetPlayerDSP: fastReset only valid from client\n" );
  343. }
  344. CUtlVector< edict_t * > players;
  345. BuildRecipientList( players, filter );
  346. for ( int i = 0 ; i < players.Count(); i++ )
  347. {
  348. g_pVEngineServer->ClientCommand( players[ i ], "dsp_player %i\n", dspType );
  349. KeyValues *kvClientCmd = new KeyValues( "dsp_player" );
  350. kvClientCmd->SetInt( NULL, dspType );
  351. g_pVEngineServer->ClientCommandKeyValues( players[ i ], kvClientCmd );
  352. }
  353. }
  354. void CEngineSoundServer::StopAllSounds(bool bClearBuffers)
  355. {
  356. AssertMsg( 0, "Not supported" );
  357. }
  358. // bool CEngineSoundServer::GetPreventSound( void )
  359. // {
  360. // AssertMsg( 0, "Not supported" );
  361. // }
  362. int CEngineSoundServer::EmitAmbientSound( const char *pSample, float flVolume, int iPitch, int flags, float soundtime /*= 0.0f*/ )
  363. {
  364. AssertMsg( 0, "Not supported" );
  365. return 0;
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Stops a sound
  369. //-----------------------------------------------------------------------------
  370. void CEngineSoundServer::StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash )
  371. {
  372. CEngineRecipientFilter filter;
  373. filter.AddAllPlayers();
  374. filter.MakeReliable();
  375. int nFlags = SND_STOP | ( nSoundEntryHash != SOUNDEMITTER_INVALID_HASH ? SND_IS_SCRIPTHANDLE : 0 );
  376. EmitSound( filter, iEntIndex, iChannel, pSample, nSoundEntryHash, pSample, 0, SNDLVL_NONE, 0, nFlags, PITCH_NORM,
  377. NULL, NULL, NULL, true );
  378. }
  379. float SV_GetSoundDuration( const char *pSample )
  380. {
  381. #ifdef DEDICATED
  382. return 0; // TODO: make this return a real value (i.e implement an OS independent version of the sound code)
  383. #else
  384. return AudioSource_GetSoundDuration( pSample );
  385. #endif
  386. }
  387. //-----------------------------------------------------------------------------
  388. // Purpose:
  389. // Input : *pSample -
  390. // Output : float
  391. //-----------------------------------------------------------------------------
  392. float CEngineSoundServer::GetSoundDuration( const char *pSample )
  393. {
  394. return Host_GetSoundDuration( pSample );
  395. }
  396. float CEngineSoundServer::GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist )
  397. {
  398. return S_GetGainFromSoundLevel( soundlevel, dist );
  399. }
  400. /*
  401. //-----------------------------------------------------------------------------
  402. // FIXME: Move into the CEngineSoundServer class?
  403. //-----------------------------------------------------------------------------
  404. void Host_RestartAmbientSounds()
  405. {
  406. if (!sv.active)
  407. {
  408. return;
  409. }
  410. #ifndef DEDICATED
  411. const int NUM_INFOS = 64;
  412. SoundInfo_t soundInfo[NUM_INFOS];
  413. int nSounds = S_GetCurrentStaticSounds( soundInfo, NUM_INFOS, CHAN_STATIC );
  414. for ( int i = 0; i < nSounds; i++)
  415. {
  416. if (soundInfo[i].looping &&
  417. soundInfo[i].entity != -1 )
  418. {
  419. Msg("Restarting sound %s...\n", soundInfo[i].name);
  420. S_StopSound(soundInfo[i].entity, soundInfo[i].channel);
  421. CEngineRecipientFilter filter;
  422. filter.AddAllPlayers();
  423. SV_StartSound( filter, EDICT_NUM(soundInfo[i].entity),
  424. CHAN_STATIC,
  425. soundInfo[i].name,
  426. soundInfo[i].volume,
  427. soundInfo[i].soundlevel,
  428. 0, // @Q (toml 05-09-02): Is this correct, or will I need to squirrel away the original flags?
  429. soundInfo[i].pitch );
  430. }
  431. }
  432. #endif
  433. } */