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.

319 lines
7.1 KiB

  1. #include "basetypes.h"
  2. #include "commonmacros.h"
  3. #include "soundsystem/lowlevel.h"
  4. #include "soundsystem/audio_mix.h"
  5. CInterlockedInt g_nDetectedAudioError(0);
  6. CInterlockedInt g_nDetectedBufferStarvation( 0 );
  7. uint g_nDeviceStamp = 0x100;
  8. class CAudioDeviceNull2 : public IAudioDevice2
  9. {
  10. public:
  11. CAudioDeviceNull2()
  12. {
  13. m_pName = "Sound Disabled";
  14. m_nChannels = 2;
  15. m_nSampleBits = 16;
  16. m_nSampleRate = int(MIX_DEFAULT_SAMPLING_RATE);
  17. m_bIsActive = false;
  18. m_bIsHeadphone = false;
  19. m_bSupportsBufferStarvationDetection = false;
  20. m_bIsCaptureDevice = false;
  21. }
  22. virtual ~CAudioDeviceNull2() {}
  23. virtual void OutputBuffer( int nChannels, CAudioMixBuffer *pChannelArray ) {}
  24. virtual void Shutdown() {}
  25. virtual int QueuedBufferCount() { return 0; }
  26. virtual int EmptyBufferCount() { return 0; }
  27. virtual void CancelOutput() {}
  28. virtual void WaitForComplete() {}
  29. virtual void UpdateFocus( bool bWindowHasFocus ) {}
  30. virtual void ClearBuffer() {}
  31. virtual const wchar_t *GetDeviceID() const
  32. {
  33. static wchar_t deviceID[4] = {0};
  34. return deviceID;
  35. }
  36. virtual void OutputDebugInfo() const
  37. {
  38. Msg( "Sound Disabled.\n" );
  39. }
  40. virtual bool SetShouldPlayWhenNotInFocus( bool bPlayEvenWhenNotInFocus ) OVERRIDE
  41. {
  42. return true;
  43. }
  44. };
  45. IAudioDevice2 *Audio_CreateNullDevice()
  46. {
  47. return new CAudioDeviceNull2;
  48. }
  49. int Audio_EnumerateDevices( eSubSystems_t nSubsystem, audio_device_description_t *pDeviceListOut, int nListCount )
  50. {
  51. int nDeviceCount = 0;
  52. switch( nSubsystem )
  53. {
  54. #ifdef IS_WINDOWS_PC
  55. case AUDIO_SUBSYSTEM_XAUDIO:
  56. nDeviceCount = Audio_EnumerateXAudio2Devices( pDeviceListOut, nListCount );
  57. break;
  58. case AUDIO_SUBSYSTEM_DSOUND:
  59. nDeviceCount = Audio_EnumerateDSoundDevices( pDeviceListOut, nListCount );
  60. break;
  61. #endif
  62. #ifdef POSIX
  63. case AUDIO_SUBSYSTEM_SDL:
  64. nDeviceCount = Audio_EnumerateSDLDevices( pDeviceListOut, nListCount );
  65. break;
  66. #endif
  67. case AUDIO_SUBSYSTEM_NULL:
  68. nDeviceCount = 1;
  69. if ( nListCount > 0 )
  70. {
  71. pDeviceListOut[0].InitAsNullDevice();
  72. V_strcpy_safe( pDeviceListOut[0].m_friendlyName, "Sound Disabled" );
  73. }
  74. break;
  75. }
  76. return nDeviceCount;
  77. }
  78. int CAudioDeviceList::FindDeviceById( const wchar_t *pId, finddevice_t nFind )
  79. {
  80. for ( int i = 0; i < m_list.Count(); i++ )
  81. {
  82. if ( nFind == FIND_AVAILABLE_DEVICE_ONLY && !m_list[i].m_bIsAvailable )
  83. continue;
  84. if ( !V_wcscmp( pId, m_list[i].m_deviceName ) )
  85. return i;
  86. }
  87. return -1;
  88. }
  89. audio_device_description_t *CAudioDeviceList::FindDeviceById( const char *pId )
  90. {
  91. wchar_t tempName[256];
  92. V_strtowcs( pId, -1, tempName, Q_ARRAYSIZE(tempName) );
  93. int nDevice = FindDeviceById( tempName, FIND_AVAILABLE_DEVICE_ONLY );
  94. if ( nDevice >= 0 && nDevice < m_list.Count() )
  95. return &m_list[nDevice];
  96. return NULL;
  97. }
  98. void CAudioDeviceList::BuildDeviceList( eSubSystems_t nPreferredSubsystem )
  99. {
  100. m_nDeviceStamp = g_nDeviceStamp;
  101. audio_device_description_t initList[32];
  102. int nCount = Audio_EnumerateDevices( nPreferredSubsystem, initList, Q_ARRAYSIZE(initList) );
  103. // No XAudio2? Fall back to direct sound.
  104. if ( nCount == 0 && nPreferredSubsystem == AUDIO_SUBSYSTEM_XAUDIO )
  105. {
  106. nPreferredSubsystem = AUDIO_SUBSYSTEM_DSOUND;
  107. nCount = Audio_EnumerateDevices( nPreferredSubsystem, initList, Q_ARRAYSIZE(initList) );
  108. }
  109. m_nSubsystem = nPreferredSubsystem;
  110. // No sound devices? Add a NULL device.
  111. if ( nCount == 0 )
  112. {
  113. nCount = Audio_EnumerateDevices( AUDIO_SUBSYSTEM_NULL, initList, Q_ARRAYSIZE(initList) );
  114. }
  115. if ( !m_list.Count() )
  116. {
  117. m_list.CopyArray( initList, nCount );
  118. for ( int i = 0; i < m_list.Count(); i++ )
  119. {
  120. m_list[i].m_bIsAvailable = true;
  121. }
  122. }
  123. else
  124. {
  125. for ( int i = 0; i < m_list.Count(); i++ )
  126. {
  127. m_list[i].m_bIsAvailable = false;
  128. m_list[i].m_bIsDefault = false;
  129. }
  130. for ( int i = 0; i < nCount; i++ )
  131. {
  132. int nIndex = FindDeviceById( initList[i].m_deviceName, FIND_ANY_DEVICE );
  133. if ( nIndex >= 0 )
  134. {
  135. m_list[nIndex] = initList[i];
  136. }
  137. else
  138. {
  139. m_list.AddToTail( initList[i] );
  140. }
  141. }
  142. }
  143. UpdateDefaultDevice();
  144. }
  145. bool CAudioDeviceList::UpdateDeviceList()
  146. {
  147. if ( m_nDeviceStamp == g_nDeviceStamp )
  148. return false;
  149. BuildDeviceList( m_nSubsystem );
  150. return true;
  151. }
  152. void CAudioDeviceList::UpdateDefaultDevice()
  153. {
  154. #if IS_WINDOWS_PC
  155. // BUG: DirectSound devices use a different string format for GUIDs. Fix so this works?
  156. wchar_t deviceName[256];
  157. if ( GetWindowsDefaultAudioDevice( deviceName, sizeof(deviceName ) ) )
  158. {
  159. int nIndex = FindDeviceById( deviceName, FIND_AVAILABLE_DEVICE_ONLY );
  160. if ( nIndex >= 0 )
  161. {
  162. m_nDefaultDevice = nIndex;
  163. return;
  164. }
  165. }
  166. #endif
  167. m_nDefaultDevice = -1;
  168. int nFirst = -1;
  169. for ( int i = 0; i < m_list.Count(); i++ )
  170. {
  171. if ( m_list[i].m_bIsAvailable )
  172. {
  173. if ( nFirst < 0 )
  174. {
  175. nFirst = i;
  176. }
  177. if ( m_list[i].m_bIsDefault )
  178. {
  179. m_nDefaultDevice = i;
  180. break;
  181. }
  182. }
  183. }
  184. if ( m_nDefaultDevice < 0 )
  185. {
  186. m_nDefaultDevice = nFirst;
  187. }
  188. }
  189. IAudioDevice2 *CAudioDeviceList::CreateDevice( audio_device_init_params_t &params )
  190. {
  191. Assert( IsValid() );
  192. int nSubsystem = m_nSubsystem;
  193. #if !defined( _GAMECONSOLE )
  194. if ( params.m_bOverrideDevice )
  195. {
  196. nSubsystem = params.m_nOverrideSubsystem;
  197. }
  198. #endif
  199. #if IS_WINDOWS_PC
  200. // try xaudio2
  201. if ( nSubsystem == AUDIO_SUBSYSTEM_XAUDIO )
  202. {
  203. IAudioDevice2 *pDevice = Audio_CreateXAudio2Device( params );
  204. if ( pDevice )
  205. return pDevice;
  206. Warning("Failed to initialize XAudio2 device!\n");
  207. nSubsystem = AUDIO_SUBSYSTEM_DSOUND;
  208. }
  209. if ( nSubsystem == AUDIO_SUBSYSTEM_DSOUND )
  210. {
  211. // either we were asked for dsound or we failed to create xaudio2, try dsound
  212. IAudioDevice2 *pDevice = Audio_CreateDSoundDevice( params );
  213. if ( pDevice )
  214. return pDevice;
  215. Warning("Failed to initialize DirectSound device!\n");
  216. nSubsystem = AUDIO_SUBSYSTEM_NULL;
  217. }
  218. #endif
  219. #ifdef POSIX
  220. nSubsystem = AUDIO_SUBSYSTEM_SDL;
  221. if ( nSubsystem == AUDIO_SUBSYSTEM_SDL )
  222. {
  223. IAudioDevice2 *pDevice = Audio_CreateSDLDevice( params );
  224. if ( pDevice )
  225. return pDevice;
  226. Warning("Failed to initialize SDL device!\n");
  227. nSubsystem = AUDIO_SUBSYSTEM_NULL;
  228. }
  229. #endif
  230. // failed
  231. return Audio_CreateNullDevice();
  232. }
  233. const wchar_t *CAudioDeviceList::GetDeviceToCreate( audio_device_init_params_t &params )
  234. {
  235. if ( params.m_bOverrideDevice )
  236. {
  237. int nIndex = FindDeviceById( params.m_overrideDeviceName, FIND_AVAILABLE_DEVICE_ONLY );
  238. if ( nIndex >= 0 )
  239. {
  240. return m_list[nIndex].m_deviceName;
  241. }
  242. }
  243. Assert( m_nDefaultDevice >= 0 && m_nDefaultDevice < m_list.Count() );
  244. return m_list[m_nDefaultDevice].m_deviceName;
  245. }
  246. int SpeakerConfigValueToChannelCount( int nSpeakerConfig )
  247. {
  248. // headphone or stereo
  249. switch( nSpeakerConfig )
  250. {
  251. case -1:
  252. return 0;
  253. case 0: // headphone
  254. case 2: // stereo
  255. return 2;
  256. case 4: // quad surround
  257. return 4;
  258. case 5: // 5.1 surround
  259. return 6;
  260. case 7: // 7.1 surround
  261. return 8;
  262. }
  263. // doesn't map to anything, return stereo
  264. AssertMsg( 0, "Bad speaker config requested\n");
  265. return 2;
  266. }
  267. int ChannelCountToSpeakerConfigValue( int nChannelCount, bool bIsHeadphone )
  268. {
  269. switch( nChannelCount )
  270. {
  271. case 2:
  272. return bIsHeadphone ? 0 : 2;
  273. case 4:
  274. return 4;
  275. case 6:
  276. return 5;
  277. case 8:
  278. return 7;
  279. }
  280. AssertMsg(0, "Bad channel count\n");
  281. return 2;
  282. }
  283. bool Audio_PollErrorEvents()
  284. {
  285. int nError = g_nDetectedAudioError.InterlockedExchange(0);
  286. return nError != 0;
  287. }