SDL_jackaudio.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 Sam Lantinga <[email protected]>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. #ifdef SDL_AUDIO_DRIVER_JACK
  20. #include "../SDL_sysaudio.h"
  21. #include "SDL_jackaudio.h"
  22. #include "../../thread/SDL_systhread.h"
  23. static jack_client_t *(*JACK_jack_client_open)(const char *, jack_options_t, jack_status_t *, ...);
  24. static int (*JACK_jack_client_close)(jack_client_t *);
  25. static void (*JACK_jack_on_shutdown)(jack_client_t *, JackShutdownCallback, void *);
  26. static int (*JACK_jack_activate)(jack_client_t *);
  27. static int (*JACK_jack_deactivate)(jack_client_t *);
  28. static void *(*JACK_jack_port_get_buffer)(jack_port_t *, jack_nframes_t);
  29. static int (*JACK_jack_port_unregister)(jack_client_t *, jack_port_t *);
  30. static void (*JACK_jack_free)(void *);
  31. static const char **(*JACK_jack_get_ports)(jack_client_t *, const char *, const char *, unsigned long);
  32. static jack_nframes_t (*JACK_jack_get_sample_rate)(jack_client_t *);
  33. static jack_nframes_t (*JACK_jack_get_buffer_size)(jack_client_t *);
  34. static jack_port_t *(*JACK_jack_port_register)(jack_client_t *, const char *, const char *, unsigned long, unsigned long);
  35. static jack_port_t *(*JACK_jack_port_by_name)(jack_client_t *, const char *);
  36. static const char *(*JACK_jack_port_name)(const jack_port_t *);
  37. static const char *(*JACK_jack_port_type)(const jack_port_t *);
  38. static int (*JACK_jack_connect)(jack_client_t *, const char *, const char *);
  39. static int (*JACK_jack_set_process_callback)(jack_client_t *, JackProcessCallback, void *);
  40. static int (*JACK_jack_set_sample_rate_callback)(jack_client_t *, JackSampleRateCallback, void *);
  41. static int (*JACK_jack_set_buffer_size_callback)(jack_client_t *, JackBufferSizeCallback, void *);
  42. static bool load_jack_syms(void);
  43. #ifdef SDL_AUDIO_DRIVER_JACK_DYNAMIC
  44. static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
  45. static void *jack_handle = NULL;
  46. // !!! FIXME: this is copy/pasted in several places now
  47. static bool load_jack_sym(const char *fn, void **addr)
  48. {
  49. *addr = SDL_LoadFunction(jack_handle, fn);
  50. if (!*addr) {
  51. // Don't call SDL_SetError(): SDL_LoadFunction already did.
  52. return false;
  53. }
  54. return true;
  55. }
  56. // cast funcs to char* first, to please GCC's strict aliasing rules.
  57. #define SDL_JACK_SYM(x) \
  58. if (!load_jack_sym(#x, (void **)(char *)&JACK_##x)) \
  59. return false
  60. static void UnloadJackLibrary(void)
  61. {
  62. if (jack_handle) {
  63. SDL_UnloadObject(jack_handle);
  64. jack_handle = NULL;
  65. }
  66. }
  67. static bool LoadJackLibrary(void)
  68. {
  69. bool result = true;
  70. if (!jack_handle) {
  71. jack_handle = SDL_LoadObject(jack_library);
  72. if (!jack_handle) {
  73. result = false;
  74. // Don't call SDL_SetError(): SDL_LoadObject already did.
  75. } else {
  76. result = load_jack_syms();
  77. if (!result) {
  78. UnloadJackLibrary();
  79. }
  80. }
  81. }
  82. return result;
  83. }
  84. #else
  85. #define SDL_JACK_SYM(x) JACK_##x = x
  86. static void UnloadJackLibrary(void)
  87. {
  88. }
  89. static bool LoadJackLibrary(void)
  90. {
  91. load_jack_syms();
  92. return true;
  93. }
  94. #endif // SDL_AUDIO_DRIVER_JACK_DYNAMIC
  95. static bool load_jack_syms(void)
  96. {
  97. SDL_JACK_SYM(jack_client_open);
  98. SDL_JACK_SYM(jack_client_close);
  99. SDL_JACK_SYM(jack_on_shutdown);
  100. SDL_JACK_SYM(jack_activate);
  101. SDL_JACK_SYM(jack_deactivate);
  102. SDL_JACK_SYM(jack_port_get_buffer);
  103. SDL_JACK_SYM(jack_port_unregister);
  104. SDL_JACK_SYM(jack_free);
  105. SDL_JACK_SYM(jack_get_ports);
  106. SDL_JACK_SYM(jack_get_sample_rate);
  107. SDL_JACK_SYM(jack_get_buffer_size);
  108. SDL_JACK_SYM(jack_port_register);
  109. SDL_JACK_SYM(jack_port_by_name);
  110. SDL_JACK_SYM(jack_port_name);
  111. SDL_JACK_SYM(jack_port_type);
  112. SDL_JACK_SYM(jack_connect);
  113. SDL_JACK_SYM(jack_set_process_callback);
  114. SDL_JACK_SYM(jack_set_sample_rate_callback);
  115. SDL_JACK_SYM(jack_set_buffer_size_callback);
  116. return true;
  117. }
  118. static void jackShutdownCallback(void *arg) // JACK went away; device is lost.
  119. {
  120. SDL_AudioDeviceDisconnected((SDL_AudioDevice *)arg);
  121. }
  122. static int jackSampleRateCallback(jack_nframes_t nframes, void *arg)
  123. {
  124. //SDL_Log("JACK Sample Rate Callback! %d", (int) nframes);
  125. SDL_AudioDevice *device = (SDL_AudioDevice *) arg;
  126. SDL_AudioSpec newspec;
  127. SDL_copyp(&newspec, &device->spec);
  128. newspec.freq = (int) nframes;
  129. if (!SDL_AudioDeviceFormatChanged(device, &newspec, device->sample_frames)) {
  130. SDL_AudioDeviceDisconnected(device);
  131. }
  132. return 0;
  133. }
  134. static int jackBufferSizeCallback(jack_nframes_t nframes, void *arg)
  135. {
  136. //SDL_Log("JACK Buffer Size Callback! %d", (int) nframes);
  137. SDL_AudioDevice *device = (SDL_AudioDevice *) arg;
  138. SDL_AudioSpec newspec;
  139. SDL_copyp(&newspec, &device->spec);
  140. if (!SDL_AudioDeviceFormatChanged(device, &newspec, (int) nframes)) {
  141. SDL_AudioDeviceDisconnected(device);
  142. }
  143. return 0;
  144. }
  145. static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
  146. {
  147. SDL_assert(nframes == ((SDL_AudioDevice *)arg)->sample_frames);
  148. SDL_PlaybackAudioThreadIterate((SDL_AudioDevice *)arg);
  149. return 0;
  150. }
  151. static bool JACK_PlayDevice(SDL_AudioDevice *device, const Uint8 *ui8buffer, int buflen)
  152. {
  153. const float *buffer = (float *) ui8buffer;
  154. jack_port_t **ports = device->hidden->sdlports;
  155. const int total_channels = device->spec.channels;
  156. const int total_frames = device->sample_frames;
  157. const jack_nframes_t nframes = (jack_nframes_t) device->sample_frames;
  158. for (int channelsi = 0; channelsi < total_channels; channelsi++) {
  159. float *dst = (float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
  160. if (dst) {
  161. const float *src = buffer + channelsi;
  162. for (int framesi = 0; framesi < total_frames; framesi++) {
  163. *(dst++) = *src;
  164. src += total_channels;
  165. }
  166. }
  167. }
  168. return true;
  169. }
  170. static Uint8 *JACK_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
  171. {
  172. return (Uint8 *)device->hidden->iobuffer;
  173. }
  174. static int jackProcessRecordingCallback(jack_nframes_t nframes, void *arg)
  175. {
  176. SDL_assert(nframes == ((SDL_AudioDevice *)arg)->sample_frames);
  177. SDL_RecordingAudioThreadIterate((SDL_AudioDevice *)arg);
  178. return 0;
  179. }
  180. static int JACK_RecordDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
  181. {
  182. float *buffer = (float *) vbuffer;
  183. jack_port_t **ports = device->hidden->sdlports;
  184. const int total_channels = device->spec.channels;
  185. const int total_frames = device->sample_frames;
  186. const jack_nframes_t nframes = (jack_nframes_t) device->sample_frames;
  187. for (int channelsi = 0; channelsi < total_channels; channelsi++) {
  188. const float *src = (const float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
  189. if (src) {
  190. float *dst = buffer + channelsi;
  191. for (int framesi = 0; framesi < total_frames; framesi++) {
  192. *dst = *(src++);
  193. dst += total_channels;
  194. }
  195. }
  196. }
  197. return buflen;
  198. }
  199. static void JACK_FlushRecording(SDL_AudioDevice *device)
  200. {
  201. // do nothing, the data will just be replaced next callback.
  202. }
  203. static void JACK_CloseDevice(SDL_AudioDevice *device)
  204. {
  205. if (device->hidden) {
  206. if (device->hidden->client) {
  207. JACK_jack_deactivate(device->hidden->client);
  208. if (device->hidden->sdlports) {
  209. const int channels = device->spec.channels;
  210. int i;
  211. for (i = 0; i < channels; i++) {
  212. JACK_jack_port_unregister(device->hidden->client, device->hidden->sdlports[i]);
  213. }
  214. SDL_free(device->hidden->sdlports);
  215. }
  216. JACK_jack_client_close(device->hidden->client);
  217. }
  218. SDL_free(device->hidden->iobuffer);
  219. SDL_free(device->hidden);
  220. device->hidden = NULL;
  221. SDL_AudioThreadFinalize(device);
  222. }
  223. }
  224. // !!! FIXME: unify this (PulseAudio has a getAppName, Pipewire has a thing, etc)
  225. static const char *GetJackAppName(void)
  226. {
  227. return SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING);
  228. }
  229. static bool JACK_OpenDevice(SDL_AudioDevice *device)
  230. {
  231. /* Note that JACK uses "output" for recording devices (they output audio
  232. data to us) and "input" for playback (we input audio data to them).
  233. Likewise, SDL's playback port will be "output" (we write data out)
  234. and recording will be "input" (we read data in). */
  235. const bool recording = device->recording;
  236. const unsigned long sysportflags = recording ? JackPortIsOutput : JackPortIsInput;
  237. const unsigned long sdlportflags = recording ? JackPortIsInput : JackPortIsOutput;
  238. const JackProcessCallback callback = recording ? jackProcessRecordingCallback : jackProcessPlaybackCallback;
  239. const char *sdlportstr = recording ? "input" : "output";
  240. const char **devports = NULL;
  241. int *audio_ports;
  242. jack_client_t *client = NULL;
  243. jack_status_t status;
  244. int channels = 0;
  245. int ports = 0;
  246. int i;
  247. // Initialize all variables that we clean on shutdown
  248. device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
  249. if (!device->hidden) {
  250. return false;
  251. }
  252. client = JACK_jack_client_open(GetJackAppName(), JackNoStartServer, &status, NULL);
  253. device->hidden->client = client;
  254. if (!client) {
  255. return SDL_SetError("Can't open JACK client");
  256. }
  257. devports = JACK_jack_get_ports(client, NULL, NULL, JackPortIsPhysical | sysportflags);
  258. if (!devports || !devports[0]) {
  259. return SDL_SetError("No physical JACK ports available");
  260. }
  261. while (devports[++ports]) {
  262. // spin to count devports
  263. }
  264. // Filter out non-audio ports
  265. audio_ports = SDL_calloc(ports, sizeof(*audio_ports));
  266. for (i = 0; i < ports; i++) {
  267. const jack_port_t *dport = JACK_jack_port_by_name(client, devports[i]);
  268. const char *type = JACK_jack_port_type(dport);
  269. const int len = SDL_strlen(type);
  270. // See if type ends with "audio"
  271. if (len >= 5 && !SDL_memcmp(type + len - 5, "audio", 5)) {
  272. audio_ports[channels++] = i;
  273. }
  274. }
  275. if (channels == 0) {
  276. SDL_free(audio_ports);
  277. return SDL_SetError("No physical JACK ports available");
  278. }
  279. // Jack pretty much demands what it wants.
  280. device->spec.format = SDL_AUDIO_F32;
  281. device->spec.freq = JACK_jack_get_sample_rate(client);
  282. device->spec.channels = channels;
  283. device->sample_frames = JACK_jack_get_buffer_size(client);
  284. SDL_UpdatedAudioDeviceFormat(device);
  285. if (!recording) {
  286. device->hidden->iobuffer = (float *)SDL_calloc(1, device->buffer_size);
  287. if (!device->hidden->iobuffer) {
  288. SDL_free(audio_ports);
  289. return false;
  290. }
  291. }
  292. // Build SDL's ports, which we will connect to the device ports.
  293. device->hidden->sdlports = (jack_port_t **)SDL_calloc(channels, sizeof(jack_port_t *));
  294. if (!device->hidden->sdlports) {
  295. SDL_free(audio_ports);
  296. return false;
  297. }
  298. for (i = 0; i < channels; i++) {
  299. char portname[32];
  300. (void)SDL_snprintf(portname, sizeof(portname), "sdl_jack_%s_%d", sdlportstr, i);
  301. device->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
  302. if (device->hidden->sdlports[i] == NULL) {
  303. SDL_free(audio_ports);
  304. return SDL_SetError("jack_port_register failed");
  305. }
  306. }
  307. if (JACK_jack_set_buffer_size_callback(client, jackBufferSizeCallback, device) != 0) {
  308. SDL_free(audio_ports);
  309. return SDL_SetError("JACK: Couldn't set buffer size callback");
  310. } else if (JACK_jack_set_sample_rate_callback(client, jackSampleRateCallback, device) != 0) {
  311. SDL_free(audio_ports);
  312. return SDL_SetError("JACK: Couldn't set sample rate callback");
  313. } else if (JACK_jack_set_process_callback(client, callback, device) != 0) {
  314. SDL_free(audio_ports);
  315. return SDL_SetError("JACK: Couldn't set process callback");
  316. }
  317. JACK_jack_on_shutdown(client, jackShutdownCallback, device);
  318. if (JACK_jack_activate(client) != 0) {
  319. SDL_free(audio_ports);
  320. return SDL_SetError("Failed to activate JACK client");
  321. }
  322. // once activated, we can connect all the ports.
  323. for (i = 0; i < channels; i++) {
  324. const char *sdlport = JACK_jack_port_name(device->hidden->sdlports[i]);
  325. const char *srcport = recording ? devports[audio_ports[i]] : sdlport;
  326. const char *dstport = recording ? sdlport : devports[audio_ports[i]];
  327. if (JACK_jack_connect(client, srcport, dstport) != 0) {
  328. SDL_free(audio_ports);
  329. return SDL_SetError("Couldn't connect JACK ports: %s => %s", srcport, dstport);
  330. }
  331. }
  332. // don't need these anymore.
  333. JACK_jack_free(devports);
  334. SDL_free(audio_ports);
  335. // We're ready to rock and roll. :-)
  336. return true;
  337. }
  338. static void JACK_Deinitialize(void)
  339. {
  340. UnloadJackLibrary();
  341. }
  342. static bool JACK_Init(SDL_AudioDriverImpl *impl)
  343. {
  344. if (!LoadJackLibrary()) {
  345. return false;
  346. } else {
  347. // Make sure a JACK server is running and available.
  348. jack_status_t status;
  349. jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
  350. if (!client) {
  351. UnloadJackLibrary();
  352. return SDL_SetError("Can't open JACK client");
  353. }
  354. JACK_jack_client_close(client);
  355. }
  356. impl->OpenDevice = JACK_OpenDevice;
  357. impl->GetDeviceBuf = JACK_GetDeviceBuf;
  358. impl->PlayDevice = JACK_PlayDevice;
  359. impl->CloseDevice = JACK_CloseDevice;
  360. impl->Deinitialize = JACK_Deinitialize;
  361. impl->RecordDevice = JACK_RecordDevice;
  362. impl->FlushRecording = JACK_FlushRecording;
  363. impl->OnlyHasDefaultPlaybackDevice = true;
  364. impl->OnlyHasDefaultRecordingDevice = true;
  365. impl->HasRecordingSupport = true;
  366. impl->ProvidesOwnCallbackThread = true;
  367. return true;
  368. }
  369. AudioBootStrap JACK_bootstrap = {
  370. "jack", "JACK Audio Connection Kit", JACK_Init, false
  371. };
  372. #endif // SDL_AUDIO_DRIVER_JACK