sdl2.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2018 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <stdlib.h>
  22. #include <SDL2/SDL.h>
  23. #include "alMain.h"
  24. #include "alu.h"
  25. #include "threads.h"
  26. #include "compat.h"
  27. #include "backends/base.h"
  28. #ifdef _WIN32
  29. #define DEVNAME_PREFIX "OpenAL Soft on "
  30. #else
  31. #define DEVNAME_PREFIX ""
  32. #endif
  33. typedef struct ALCsdl2Backend {
  34. DERIVE_FROM_TYPE(ALCbackend);
  35. SDL_AudioDeviceID deviceID;
  36. ALsizei frameSize;
  37. ALuint Frequency;
  38. enum DevFmtChannels FmtChans;
  39. enum DevFmtType FmtType;
  40. ALuint UpdateSize;
  41. } ALCsdl2Backend;
  42. static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device);
  43. static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self);
  44. static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name);
  45. static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self);
  46. static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self);
  47. static void ALCsdl2Backend_stop(ALCsdl2Backend *self);
  48. static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
  49. static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples)
  50. static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency)
  51. static void ALCsdl2Backend_lock(ALCsdl2Backend *self);
  52. static void ALCsdl2Backend_unlock(ALCsdl2Backend *self);
  53. DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend)
  54. DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend);
  55. static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device";
  56. static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device)
  57. {
  58. ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
  59. SET_VTABLE2(ALCsdl2Backend, ALCbackend, self);
  60. self->deviceID = 0;
  61. self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
  62. self->Frequency = device->Frequency;
  63. self->FmtChans = device->FmtChans;
  64. self->FmtType = device->FmtType;
  65. self->UpdateSize = device->UpdateSize;
  66. }
  67. static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self)
  68. {
  69. if(self->deviceID)
  70. SDL_CloseAudioDevice(self->deviceID);
  71. self->deviceID = 0;
  72. ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
  73. }
  74. static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len)
  75. {
  76. ALCsdl2Backend *self = (ALCsdl2Backend*)ptr;
  77. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  78. assert((len % self->frameSize) == 0);
  79. aluMixData(device, stream, len / self->frameSize);
  80. }
  81. static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name)
  82. {
  83. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  84. SDL_AudioSpec want, have;
  85. SDL_zero(want);
  86. SDL_zero(have);
  87. want.freq = device->Frequency;
  88. switch(device->FmtType)
  89. {
  90. case DevFmtUByte: want.format = AUDIO_U8; break;
  91. case DevFmtByte: want.format = AUDIO_S8; break;
  92. case DevFmtUShort: want.format = AUDIO_U16SYS; break;
  93. case DevFmtShort: want.format = AUDIO_S16SYS; break;
  94. case DevFmtUInt: /* fall-through */
  95. case DevFmtInt: want.format = AUDIO_S32SYS; break;
  96. case DevFmtFloat: want.format = AUDIO_F32; break;
  97. }
  98. want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2;
  99. want.samples = device->UpdateSize;
  100. want.callback = ALCsdl2Backend_audioCallback;
  101. want.userdata = self;
  102. /* Passing NULL to SDL_OpenAudioDevice opens a default, which isn't
  103. * necessarily the first in the list.
  104. */
  105. if(!name || strcmp(name, defaultDeviceName) == 0)
  106. self->deviceID = SDL_OpenAudioDevice(NULL, SDL_FALSE, &want, &have,
  107. SDL_AUDIO_ALLOW_ANY_CHANGE);
  108. else
  109. {
  110. const size_t prefix_len = strlen(DEVNAME_PREFIX);
  111. if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0)
  112. self->deviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have,
  113. SDL_AUDIO_ALLOW_ANY_CHANGE);
  114. else
  115. self->deviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have,
  116. SDL_AUDIO_ALLOW_ANY_CHANGE);
  117. }
  118. if(self->deviceID == 0)
  119. return ALC_INVALID_VALUE;
  120. device->Frequency = have.freq;
  121. if(have.channels == 1)
  122. device->FmtChans = DevFmtMono;
  123. else if(have.channels == 2)
  124. device->FmtChans = DevFmtStereo;
  125. else
  126. {
  127. ERR("Got unhandled SDL channel count: %d\n", (int)have.channels);
  128. return ALC_INVALID_VALUE;
  129. }
  130. switch(have.format)
  131. {
  132. case AUDIO_U8: device->FmtType = DevFmtUByte; break;
  133. case AUDIO_S8: device->FmtType = DevFmtByte; break;
  134. case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break;
  135. case AUDIO_S16SYS: device->FmtType = DevFmtShort; break;
  136. case AUDIO_S32SYS: device->FmtType = DevFmtInt; break;
  137. case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break;
  138. default:
  139. ERR("Got unsupported SDL format: 0x%04x\n", have.format);
  140. return ALC_INVALID_VALUE;
  141. }
  142. device->UpdateSize = have.samples;
  143. device->NumUpdates = 2; /* SDL always (tries to) use two periods. */
  144. self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
  145. self->Frequency = device->Frequency;
  146. self->FmtChans = device->FmtChans;
  147. self->FmtType = device->FmtType;
  148. self->UpdateSize = device->UpdateSize;
  149. alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName);
  150. return ALC_NO_ERROR;
  151. }
  152. static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self)
  153. {
  154. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  155. device->Frequency = self->Frequency;
  156. device->FmtChans = self->FmtChans;
  157. device->FmtType = self->FmtType;
  158. device->UpdateSize = self->UpdateSize;
  159. device->NumUpdates = 2;
  160. SetDefaultWFXChannelOrder(device);
  161. return ALC_TRUE;
  162. }
  163. static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self)
  164. {
  165. SDL_PauseAudioDevice(self->deviceID, 0);
  166. return ALC_TRUE;
  167. }
  168. static void ALCsdl2Backend_stop(ALCsdl2Backend *self)
  169. {
  170. SDL_PauseAudioDevice(self->deviceID, 1);
  171. }
  172. static void ALCsdl2Backend_lock(ALCsdl2Backend *self)
  173. {
  174. SDL_LockAudioDevice(self->deviceID);
  175. }
  176. static void ALCsdl2Backend_unlock(ALCsdl2Backend *self)
  177. {
  178. SDL_UnlockAudioDevice(self->deviceID);
  179. }
  180. typedef struct ALCsdl2BackendFactory {
  181. DERIVE_FROM_TYPE(ALCbackendFactory);
  182. } ALCsdl2BackendFactory;
  183. #define ALCsdl2BACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory) } }
  184. ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void);
  185. static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self);
  186. static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self);
  187. static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type);
  188. static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type);
  189. static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type);
  190. DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory);
  191. ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void)
  192. {
  193. static ALCsdl2BackendFactory factory = ALCsdl2BACKENDFACTORY_INITIALIZER;
  194. return STATIC_CAST(ALCbackendFactory, &factory);
  195. }
  196. static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self))
  197. {
  198. if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0)
  199. return AL_TRUE;
  200. return ALC_FALSE;
  201. }
  202. static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self))
  203. {
  204. SDL_QuitSubSystem(SDL_INIT_AUDIO);
  205. }
  206. static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type)
  207. {
  208. if(type == ALCbackend_Playback)
  209. return ALC_TRUE;
  210. return ALC_FALSE;
  211. }
  212. static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type)
  213. {
  214. int num_devices, i;
  215. al_string name;
  216. if(type != ALL_DEVICE_PROBE)
  217. return;
  218. AL_STRING_INIT(name);
  219. num_devices = SDL_GetNumAudioDevices(SDL_FALSE);
  220. AppendAllDevicesList(defaultDeviceName);
  221. for(i = 0;i < num_devices;++i)
  222. {
  223. alstr_copy_cstr(&name, DEVNAME_PREFIX);
  224. alstr_append_cstr(&name, SDL_GetAudioDeviceName(i, SDL_FALSE));
  225. AppendAllDevicesList(alstr_get_cstr(name));
  226. }
  227. alstr_reset(&name);
  228. }
  229. static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
  230. {
  231. if(type == ALCbackend_Playback)
  232. {
  233. ALCsdl2Backend *backend;
  234. NEW_OBJ(backend, ALCsdl2Backend)(device);
  235. if(!backend) return NULL;
  236. return STATIC_CAST(ALCbackend, backend);
  237. }
  238. return NULL;
  239. }