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.

493 lines
12 KiB

  1. #include "basetypes.h"
  2. #include "commonmacros.h"
  3. #include "SDL.h"
  4. #include "mix.h"
  5. #include "soundsystem/lowlevel.h"
  6. #define DEFAULT_DEVICE_NAME "SDLDefaultDevice"
  7. #define DEFAULT_DEVICE_NAME_WIDE L"SDLDefaultDevice"
  8. class CAudioSDL : public IAudioDevice2
  9. {
  10. public:
  11. CAudioSDL()
  12. {
  13. m_nDeviceID = 0;
  14. m_nDeviceIndex = -1;
  15. m_nBufferSizeBytes = 0;
  16. m_nBufferCount = 0;
  17. m_bIsActive = true;
  18. m_bIsHeadphone = false;
  19. m_bSupportsBufferStarvationDetection = false;
  20. m_bIsCaptureDevice = false;
  21. m_nReadBuffer = m_nWriteBuffer = 0;
  22. m_nPartialRead = 0;
  23. m_bAudioStarted = false;
  24. m_bSilenced = false;
  25. m_fSilencedVol = 1.0f;
  26. V_memset( m_pBuffer, 0, sizeof( m_pBuffer ) );
  27. };
  28. ~CAudioSDL();
  29. bool Init( const audio_device_init_params_t &params );
  30. void OutputBuffer( int nChannels, CAudioMixBuffer *pChannelArray );
  31. void Shutdown();
  32. int QueuedBufferCount();
  33. int EmptyBufferCount();
  34. void CancelOutput();
  35. void WaitForComplete();
  36. void UpdateFocus( bool bWindowHasFocus );
  37. void ClearBuffer();
  38. const wchar_t *GetDeviceID() const;
  39. void OutputDebugInfo() const;
  40. virtual bool SetShouldPlayWhenNotInFocus( bool bPlayEvenWhenNotInFocus )
  41. {
  42. m_savedParams.m_bPlayEvenWhenNotInFocus = bPlayEvenWhenNotInFocus;
  43. return true;
  44. }
  45. // inline methods
  46. inline int BytesPerSample() { return BitsPerSample()>>3; }
  47. void FillAudioBuffer( Uint8 *buf, int len );
  48. private:
  49. // no copies of this class ever
  50. CAudioSDL( const CAudioSDL & );
  51. CAudioSDL & operator=( const CAudioSDL & );
  52. int SamplesPerBuffer() { return MIX_BUFFER_SIZE; }
  53. int BytesPerBuffer() { return m_nBufferSizeBytes; }
  54. SDL_AudioDeviceID m_nDeviceID;
  55. SDL_AudioSpec m_deviceSpec;
  56. audio_device_init_params_t m_savedParams;
  57. int m_nDeviceIndex;
  58. uint m_nBufferSizeBytes;
  59. uint m_nBufferCount;
  60. wchar_t m_deviceID[256];
  61. enum { kNumBuffers = 32 };
  62. short *m_pBuffer[ kNumBuffers ];
  63. int m_nReadBuffer, m_nWriteBuffer;
  64. int m_nPartialRead;
  65. bool m_bAudioStarted;
  66. CThreadMutex m_mutexBuffer;
  67. bool m_bSilenced;
  68. float m_fSilencedVol;
  69. };
  70. CAudioSDL::~CAudioSDL()
  71. {
  72. Shutdown();
  73. for ( int i = 0; i != kNumBuffers; ++i )
  74. {
  75. if ( m_pBuffer[ i ] )
  76. {
  77. MemAlloc_FreeAligned( m_pBuffer[ i ] );
  78. }
  79. }
  80. }
  81. static void AudioCallback( void *userdata, Uint8 *stream, int len )
  82. {
  83. CAudioSDL *dev = reinterpret_cast<CAudioSDL*>( userdata );
  84. dev->FillAudioBuffer( stream, len );
  85. }
  86. bool CAudioSDL::Init( const audio_device_init_params_t &params )
  87. {
  88. m_savedParams = params;
  89. int nDeviceCount = SDL_GetNumAudioDevices( 0 );
  90. if ( !nDeviceCount )
  91. return false;
  92. m_nDeviceIndex = -1;
  93. if ( params.m_bOverrideDevice )
  94. {
  95. if ( wcscmp( params.m_overrideDeviceName, DEFAULT_DEVICE_NAME_WIDE ) == 0 )
  96. {
  97. m_nDeviceIndex = -1;
  98. }
  99. else
  100. {
  101. for( int i = 0; i < nDeviceCount; ++i )
  102. {
  103. const char *devName = SDL_GetAudioDeviceName( i, 0 );
  104. if ( devName == NULL )
  105. {
  106. continue;
  107. }
  108. wchar_t devNameWide[AUDIO_DEVICE_NAME_MAX];
  109. Q_UTF8ToWString( devName, devNameWide, sizeof( devNameWide ) );
  110. if ( wcscmp( devNameWide, params.m_overrideDeviceName ) == 0 )
  111. {
  112. m_nDeviceIndex = i;
  113. break;
  114. }
  115. }
  116. }
  117. }
  118. #if 0
  119. // setup the format structure
  120. {
  121. int nChannels = details.InputChannels;
  122. if ( params.m_bOverrideSpeakerConfig )
  123. {
  124. nChannels = SpeakerConfigValueToChannelCount( params.m_nOverrideSpeakerConfig );
  125. if ( params.m_nOverrideSpeakerConfig == 0 )
  126. {
  127. m_bIsHeadphone = true;
  128. }
  129. }
  130. m_nChannels = nChannels;
  131. }
  132. #endif
  133. SDL_AudioSpec desired;
  134. desired.freq = int(MIX_DEFAULT_SAMPLING_RATE);
  135. desired.format = AUDIO_S16SYS;
  136. desired.channels = 2;
  137. desired.samples = 1024;
  138. desired.callback = AudioCallback;
  139. desired.userdata = this;
  140. m_nDeviceID = SDL_OpenAudioDevice( m_nDeviceIndex == -1 ? NULL : SDL_GetAudioDeviceName( m_nDeviceIndex, 0 ), 0, &desired, &m_deviceSpec, SDL_AUDIO_ALLOW_ANY_CHANGE );
  141. const char *pDeviceNameUTF8 = m_nDeviceIndex == -1 ? DEFAULT_DEVICE_NAME : SDL_GetAudioDeviceName( m_nDeviceIndex, 0 );
  142. Q_UTF8ToWString( pDeviceNameUTF8, m_deviceID, sizeof( m_deviceID ) );
  143. // UNDONE: Have the device report MIX_DEFAULT_SAMPLING_RATE to the outside world
  144. // and build an SDL_AudioCVT to convert from the engine's mix to the SDL device's audio output?
  145. // BUGBUG: Assert this for now
  146. Assert( m_deviceSpec.channels == 2 );
  147. Assert( m_deviceSpec.freq == int(MIX_DEFAULT_SAMPLING_RATE) );
  148. m_nChannels = m_deviceSpec.channels;
  149. m_nSampleBits = SDL_AUDIO_BITSIZE( m_deviceSpec.format );
  150. m_nSampleRate = m_deviceSpec.freq;
  151. m_bIsActive = true;
  152. m_bIsHeadphone = false;
  153. m_pName = "SDL Audio";
  154. //m_nBufferCount = params.m_nOutputBufferCount;
  155. m_nBufferCount = 1;
  156. int nBufferSize = MIX_BUFFER_SIZE * m_nChannels * BytesPerSample();
  157. m_nBufferSizeBytes = nBufferSize;
  158. for ( int i = 0; i != kNumBuffers; ++i )
  159. {
  160. m_pBuffer[ i ] = (short *)MemAlloc_AllocAligned( nBufferSize * m_nBufferCount, 16 );
  161. }
  162. m_nReadBuffer = m_nWriteBuffer = 0;
  163. m_nPartialRead = 0;
  164. m_bAudioStarted = false;
  165. // start audio playback
  166. SDL_PauseAudioDevice( m_nDeviceID, 0 );
  167. #if defined( LINUX ) && defined( INCLUDE_SCALEFORM )
  168. // Send the obtained audio device details to scaleform
  169. if ( g_pScaleformUI )
  170. {
  171. g_pScaleformUI->SDLSetAudioSpec( sizeof(m_deviceSpec), &m_deviceSpec );
  172. }
  173. #endif
  174. return true;
  175. }
  176. void CAudioSDL::OutputBuffer( int nChannels, CAudioMixBuffer *pChannelArray )
  177. {
  178. AUTO_LOCK( m_mutexBuffer );
  179. m_bAudioStarted = true;
  180. if ( ( (m_nWriteBuffer+1) % kNumBuffers ) == m_nReadBuffer )
  181. {
  182. // Filled up with data, can't take anymore.
  183. // This shouldn't really happen unless SDL stops consuming data for us or the
  184. // game pushes data at us at an unreasonable rate.
  185. return;
  186. }
  187. short *pWaveData = m_pBuffer[ m_nWriteBuffer ];
  188. m_nWriteBuffer = (m_nWriteBuffer+1) % kNumBuffers;
  189. if ( nChannels == 2 && nChannels == m_nChannels )
  190. {
  191. ConvertFloat32Int16_Clamp_Interleave2( pWaveData, pChannelArray[0].m_flData, pChannelArray[1].m_flData, MIX_BUFFER_SIZE );
  192. }
  193. else
  194. {
  195. ConvertFloat32Int16_Clamp_InterleaveStride( pWaveData, m_nChannels, MIX_BUFFER_SIZE, pChannelArray[0].m_flData, nChannels, MIX_BUFFER_SIZE );
  196. }
  197. #if defined( LINUX ) && defined( INCLUDE_SCALEFORM )
  198. if ( g_pScaleformUI )
  199. {
  200. g_pScaleformUI->SDLMixAudio( nChannels, pWaveData, m_nBufferSizeBytes );
  201. }
  202. #endif
  203. // Old way of sending data, by queueing it. Now we do it by providing it in the callback.
  204. // SDL_QueueAudio( m_nDeviceID, m_pBuffer, m_nBufferSizeBytes );
  205. }
  206. void CAudioSDL::Shutdown()
  207. {
  208. if ( m_nDeviceID > 0 )
  209. {
  210. SDL_CloseAudioDevice( m_nDeviceID );
  211. m_nDeviceID = 0;
  212. }
  213. }
  214. int CAudioSDL::QueuedBufferCount()
  215. {
  216. AUTO_LOCK( m_mutexBuffer );
  217. if ( m_nWriteBuffer >= m_nReadBuffer )
  218. {
  219. return m_nWriteBuffer - m_nReadBuffer;
  220. }
  221. else
  222. {
  223. return (kNumBuffers - m_nReadBuffer) + m_nWriteBuffer;
  224. }
  225. }
  226. int CAudioSDL::EmptyBufferCount()
  227. {
  228. return (kNumBuffers - QueuedBufferCount()) - 1;
  229. }
  230. void CAudioSDL::CancelOutput()
  231. {
  232. // SDL_ClearQueuedAudio( m_nDeviceID );
  233. }
  234. void CAudioSDL::WaitForComplete()
  235. {
  236. while( QueuedBufferCount() )
  237. {
  238. ThreadSleep(0);
  239. }
  240. }
  241. void CAudioSDL::UpdateFocus( bool bWindowHasFocus )
  242. {
  243. m_bSilenced = !bWindowHasFocus && !m_savedParams.m_bPlayEvenWhenNotInFocus;
  244. }
  245. void CAudioSDL::ClearBuffer()
  246. {
  247. }
  248. const wchar_t* CAudioSDL::GetDeviceID() const
  249. {
  250. return L"SDL Device";
  251. }
  252. void CAudioSDL::OutputDebugInfo() const
  253. {
  254. fprintf(stderr, "SDL Audio Device\n" );
  255. fprintf(stderr, "Channels:\t%d\n", ChannelCount() );
  256. fprintf(stderr, "Bits/Sample:\t%d\n", BitsPerSample() );
  257. fprintf(stderr, "Rate:\t\t%d\n", SampleRate() );
  258. }
  259. void CAudioSDL::FillAudioBuffer( Uint8 *buf, int len )
  260. {
  261. m_mutexBuffer.Lock();
  262. bool bFailedToGetMore = false;
  263. while ( m_bAudioStarted && len > 0 && !bFailedToGetMore )
  264. {
  265. if ( m_nReadBuffer == m_nWriteBuffer )
  266. {
  267. m_mutexBuffer.Unlock();
  268. /*
  269. if ( m_savedParams.m_pfnMixAudio != NULL )
  270. {
  271. //We are going to be starved, so ask the mixer to mix
  272. //some more audio for us right now. We expect this
  273. //call to fill our buffers up.
  274. m_savedParams.m_pfnMixAudio( 0.01 );
  275. }
  276. */
  277. m_mutexBuffer.Lock();
  278. if ( m_nReadBuffer == m_nWriteBuffer )
  279. {
  280. //The mixer couldn't get us more data for some reason.
  281. //We are starved.
  282. bFailedToGetMore = true;
  283. break;
  284. }
  285. }
  286. while ( len > 0 && m_nReadBuffer != m_nWriteBuffer )
  287. {
  288. int bufsize = m_nBufferSizeBytes - m_nPartialRead;
  289. int nbytes = len < bufsize ? len : bufsize;
  290. if(m_bSilenced && m_fSilencedVol <= 0.0f)
  291. {
  292. memset( buf, 0, nbytes );
  293. }
  294. else
  295. {
  296. memcpy( buf, ((unsigned char*)m_pBuffer[ m_nReadBuffer ]) + m_nPartialRead, nbytes );
  297. // If we are silencing or unsilencing, make the volume fade rather than
  298. // changing abruptly.
  299. static const float FadeTime = 0.5f;
  300. static const int FadeTick = 16;
  301. static const float FadeDelta = FadeTick / ( m_nChannels * m_nSampleRate * FadeTime );
  302. if ( m_bSilenced )
  303. {
  304. short* sbuf = reinterpret_cast<short*>(buf);
  305. int i = 0;
  306. while ( i < nbytes/2 )
  307. {
  308. sbuf[i] *= m_fSilencedVol;
  309. ++i;
  310. if ( i%FadeTick == 0 && m_fSilencedVol > 0.0f )
  311. {
  312. m_fSilencedVol -= FadeDelta;
  313. if ( m_fSilencedVol < 0.0f )
  314. {
  315. m_fSilencedVol = 0.0f;
  316. }
  317. }
  318. }
  319. }
  320. else if ( m_fSilencedVol < 1.0f )
  321. {
  322. short* sbuf = reinterpret_cast<short*>(buf);
  323. int i = 0;
  324. while ( i < nbytes/2 && m_fSilencedVol < 1.0f )
  325. {
  326. sbuf[i] *= m_fSilencedVol;
  327. ++i;
  328. if ( i%FadeTick == 0 && m_fSilencedVol < 1.0f )
  329. {
  330. m_fSilencedVol += FadeDelta;
  331. }
  332. }
  333. }
  334. }
  335. if ( nbytes == bufsize )
  336. {
  337. m_nReadBuffer = (m_nReadBuffer+1) % kNumBuffers;
  338. m_nPartialRead = 0;
  339. }
  340. else
  341. {
  342. m_nPartialRead += nbytes;
  343. }
  344. buf += nbytes;
  345. len -= nbytes;
  346. }
  347. }
  348. m_mutexBuffer.Unlock();
  349. if ( len > 0 )
  350. {
  351. // We have been starved of data and have to fill with silence.
  352. memset( buf, 0, len );
  353. }
  354. }
  355. static bool g_bInitSDLAudio = false;
  356. static bool InitSDLAudio()
  357. {
  358. if ( !g_bInitSDLAudio )
  359. {
  360. int nRet = SDL_InitSubSystem( SDL_INIT_AUDIO );
  361. if ( nRet < 0 )
  362. {
  363. return false;
  364. }
  365. g_bInitSDLAudio = true;
  366. }
  367. return true;
  368. }
  369. // enumerate the available devices so the app can select one
  370. // fills out app-supplied list & returns count of available devices. If the list is too small, the count
  371. // will signal the app to call again with a larger list
  372. int Audio_EnumerateSDLDevices( audio_device_description_t *pDeviceListOut, int nListCount )
  373. {
  374. if ( !InitSDLAudio() )
  375. return 0;
  376. if ( nListCount > 0 )
  377. {
  378. audio_device_description_t& description = pDeviceListOut[0];
  379. Q_UTF8ToWString( DEFAULT_DEVICE_NAME, description.m_deviceName, sizeof(description.m_deviceName) );
  380. V_strcpy_safe( description.m_friendlyName, "#OS_Default_Device" );
  381. description.m_nChannelCount = 6;
  382. description.m_bIsDefault = true;
  383. description.m_bIsAvailable = true;
  384. description.m_nSubsystemId = AUDIO_SUBSYSTEM_SDL;
  385. }
  386. int nOutputDeviceCount = SDL_GetNumAudioDevices( 0 );
  387. int nIterateCount = MIN(nListCount-1, nOutputDeviceCount);
  388. for ( int i = 0; i < nIterateCount; i++ )
  389. {
  390. const char *pNameUTF8 = SDL_GetAudioDeviceName( i, 0 );
  391. audio_device_description_t& description = pDeviceListOut[i+1];
  392. Q_UTF8ToWString( pNameUTF8, description.m_deviceName, sizeof(description.m_deviceName) );
  393. Q_WStringToUTF8( description.m_deviceName, description.m_friendlyName, sizeof(description.m_friendlyName) );
  394. description.m_nChannelCount = 6;
  395. description.m_bIsDefault = false;
  396. description.m_bIsAvailable = true;
  397. description.m_nSubsystemId = AUDIO_SUBSYSTEM_SDL;
  398. }
  399. return nIterateCount + 1;
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Class factory
  403. //-----------------------------------------------------------------------------
  404. IAudioDevice2 *Audio_CreateSDLDevice( const audio_device_init_params_t &params )
  405. {
  406. if ( !InitSDLAudio() )
  407. return NULL;
  408. CAudioSDL *pDevice = new CAudioSDL;
  409. if ( pDevice->Init( params ) )
  410. {
  411. return pDevice;
  412. }
  413. delete pDevice;
  414. return NULL;
  415. }