Rename some struct members
[openal-soft.git] / Alc / backends / jack.cpp
blobdaa15219eebc6f13b8c69c66f080259d30b294e7
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 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.
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.
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
21 #include "config.h"
23 #include "backends/jack.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <memory.h>
29 #include "alMain.h"
30 #include "alu.h"
31 #include "alconfig.h"
32 #include "ringbuffer.h"
33 #include "threads.h"
34 #include "compat.h"
36 #include <jack/jack.h>
37 #include <jack/ringbuffer.h>
40 static const ALCchar jackDevice[] = "JACK Default";
43 #ifdef HAVE_DYNLOAD
44 #define JACK_FUNCS(MAGIC) \
45 MAGIC(jack_client_open); \
46 MAGIC(jack_client_close); \
47 MAGIC(jack_client_name_size); \
48 MAGIC(jack_get_client_name); \
49 MAGIC(jack_connect); \
50 MAGIC(jack_activate); \
51 MAGIC(jack_deactivate); \
52 MAGIC(jack_port_register); \
53 MAGIC(jack_port_unregister); \
54 MAGIC(jack_port_get_buffer); \
55 MAGIC(jack_port_name); \
56 MAGIC(jack_get_ports); \
57 MAGIC(jack_free); \
58 MAGIC(jack_get_sample_rate); \
59 MAGIC(jack_set_error_function); \
60 MAGIC(jack_set_process_callback); \
61 MAGIC(jack_set_buffer_size_callback); \
62 MAGIC(jack_set_buffer_size); \
63 MAGIC(jack_get_buffer_size);
65 static void *jack_handle;
66 #define MAKE_FUNC(f) static decltype(f) * p##f
67 JACK_FUNCS(MAKE_FUNC);
68 static decltype(jack_error_callback) * pjack_error_callback;
69 #undef MAKE_FUNC
71 #ifndef IN_IDE_PARSER
72 #define jack_client_open pjack_client_open
73 #define jack_client_close pjack_client_close
74 #define jack_client_name_size pjack_client_name_size
75 #define jack_get_client_name pjack_get_client_name
76 #define jack_connect pjack_connect
77 #define jack_activate pjack_activate
78 #define jack_deactivate pjack_deactivate
79 #define jack_port_register pjack_port_register
80 #define jack_port_unregister pjack_port_unregister
81 #define jack_port_get_buffer pjack_port_get_buffer
82 #define jack_port_name pjack_port_name
83 #define jack_get_ports pjack_get_ports
84 #define jack_free pjack_free
85 #define jack_get_sample_rate pjack_get_sample_rate
86 #define jack_set_error_function pjack_set_error_function
87 #define jack_set_process_callback pjack_set_process_callback
88 #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
89 #define jack_set_buffer_size pjack_set_buffer_size
90 #define jack_get_buffer_size pjack_get_buffer_size
91 #define jack_error_callback (*pjack_error_callback)
92 #endif
93 #endif
96 static jack_options_t ClientOptions = JackNullOption;
98 static ALCboolean jack_load(void)
100 ALCboolean error = ALC_FALSE;
102 #ifdef HAVE_DYNLOAD
103 if(!jack_handle)
105 std::string missing_funcs;
107 #ifdef _WIN32
108 #define JACKLIB "libjack.dll"
109 #else
110 #define JACKLIB "libjack.so.0"
111 #endif
112 jack_handle = LoadLib(JACKLIB);
113 if(!jack_handle)
115 WARN("Failed to load %s\n", JACKLIB);
116 return ALC_FALSE;
119 error = ALC_FALSE;
120 #define LOAD_FUNC(f) do { \
121 p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \
122 if(p##f == nullptr) { \
123 error = ALC_TRUE; \
124 missing_funcs += "\n" #f; \
126 } while(0)
127 JACK_FUNCS(LOAD_FUNC);
128 #undef LOAD_FUNC
129 /* Optional symbols. These don't exist in all versions of JACK. */
130 #define LOAD_SYM(f) p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f))
131 LOAD_SYM(jack_error_callback);
132 #undef LOAD_SYM
134 if(error)
136 WARN("Missing expected functions:%s\n", missing_funcs.c_str());
137 CloseLib(jack_handle);
138 jack_handle = NULL;
141 #endif
143 return !error;
147 struct ALCjackPlayback final : public ALCbackend {
148 jack_client_t *Client{nullptr};
149 jack_port_t *Port[MAX_OUTPUT_CHANNELS]{};
151 ll_ringbuffer_t *Ring{nullptr};
152 alsem_t Sem;
154 std::atomic<ALenum> mKillNow{AL_TRUE};
155 althrd_t thread;
158 static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg);
160 static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg);
161 static int ALCjackPlayback_mixerProc(void *arg);
163 static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device);
164 static void ALCjackPlayback_Destruct(ALCjackPlayback *self);
165 static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name);
166 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self);
167 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self);
168 static void ALCjackPlayback_stop(ALCjackPlayback *self);
169 static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
170 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples)
171 static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self);
172 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock)
173 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock)
174 DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback)
176 DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback);
179 static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device)
181 new (self) ALCjackPlayback{};
182 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
183 SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
185 alsem_init(&self->Sem, 0);
188 static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
190 if(self->Client)
192 for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++)
194 if(self->Port[i])
195 jack_port_unregister(self->Client, self->Port[i]);
196 self->Port[i] = NULL;
198 jack_client_close(self->Client);
199 self->Client = NULL;
202 alsem_destroy(&self->Sem);
204 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
205 self->~ALCjackPlayback();
209 static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg)
211 ALCjackPlayback *self = static_cast<ALCjackPlayback*>(arg);
212 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
213 ALuint bufsize;
215 ALCjackPlayback_lock(self);
216 device->UpdateSize = numframes;
217 device->NumUpdates = 2;
219 bufsize = device->UpdateSize;
220 if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize))
221 bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
222 device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize;
224 TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates);
226 ll_ringbuffer_free(self->Ring);
227 self->Ring = ll_ringbuffer_create(bufsize,
228 FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder),
229 true
231 if(!self->Ring)
233 ERR("Failed to reallocate ringbuffer\n");
234 aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize);
236 ALCjackPlayback_unlock(self);
237 return 0;
241 static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
243 ALCjackPlayback *self = static_cast<ALCjackPlayback*>(arg);
244 jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS];
245 jack_nframes_t total{0};
246 jack_nframes_t todo;
247 ALsizei i, c, numchans;
249 auto data = ll_ringbuffer_get_read_vector(self->Ring);
251 for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++)
252 out[c] = static_cast<float*>(jack_port_get_buffer(self->Port[c], numframes));
253 numchans = c;
255 todo = minu(numframes, data.first.len);
256 for(c = 0;c < numchans;c++)
258 const ALfloat *RESTRICT in = ((ALfloat*)data.first.buf) + c;
259 for(i = 0;(jack_nframes_t)i < todo;i++)
260 out[c][i] = in[i*numchans];
261 out[c] += todo;
263 total += todo;
265 todo = minu(numframes-total, data.second.len);
266 if(todo > 0)
268 for(c = 0;c < numchans;c++)
270 const ALfloat *RESTRICT in = ((ALfloat*)data.second.buf) + c;
271 for(i = 0;(jack_nframes_t)i < todo;i++)
272 out[c][i] = in[i*numchans];
273 out[c] += todo;
275 total += todo;
278 ll_ringbuffer_read_advance(self->Ring, total);
279 alsem_post(&self->Sem);
281 if(numframes > total)
283 todo = numframes-total;
284 for(c = 0;c < numchans;c++)
286 for(i = 0;(jack_nframes_t)i < todo;i++)
287 out[c][i] = 0.0f;
291 return 0;
294 static int ALCjackPlayback_mixerProc(void *arg)
296 ALCjackPlayback *self = static_cast<ALCjackPlayback*>(arg);
297 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
299 SetRTPriority();
300 althrd_setname(MIXER_THREAD_NAME);
302 ALCjackPlayback_lock(self);
303 while(!self->mKillNow.load(std::memory_order_acquire) &&
304 ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
306 ALuint todo, len1, len2;
308 if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize)
310 ALCjackPlayback_unlock(self);
311 alsem_wait(&self->Sem);
312 ALCjackPlayback_lock(self);
313 continue;
316 auto data = ll_ringbuffer_get_write_vector(self->Ring);
317 todo = data.first.len + data.second.len;
318 todo -= todo%device->UpdateSize;
320 len1 = minu(data.first.len, todo);
321 len2 = minu(data.second.len, todo-len1);
323 aluMixData(device, data.first.buf, len1);
324 if(len2 > 0)
325 aluMixData(device, data.second.buf, len2);
326 ll_ringbuffer_write_advance(self->Ring, todo);
328 ALCjackPlayback_unlock(self);
330 return 0;
334 static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name)
336 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
337 const char *client_name = "alsoft";
338 jack_status_t status;
340 if(!name)
341 name = jackDevice;
342 else if(strcmp(name, jackDevice) != 0)
343 return ALC_INVALID_VALUE;
345 self->Client = jack_client_open(client_name, ClientOptions, &status, NULL);
346 if(self->Client == NULL)
348 ERR("jack_client_open() failed, status = 0x%02x\n", status);
349 return ALC_INVALID_VALUE;
351 if((status&JackServerStarted))
352 TRACE("JACK server started\n");
353 if((status&JackNameNotUnique))
355 client_name = jack_get_client_name(self->Client);
356 TRACE("Client name not unique, got `%s' instead\n", client_name);
359 jack_set_process_callback(self->Client, ALCjackPlayback_process, self);
360 jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self);
362 device->DeviceName = name;
363 return ALC_NO_ERROR;
366 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
368 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
369 ALsizei numchans, i;
370 ALuint bufsize;
372 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
374 if(self->Port[i])
375 jack_port_unregister(self->Client, self->Port[i]);
376 self->Port[i] = NULL;
379 /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
380 * ready for when requested.
382 device->Frequency = jack_get_sample_rate(self->Client);
383 device->UpdateSize = jack_get_buffer_size(self->Client);
384 device->NumUpdates = 2;
386 bufsize = device->UpdateSize;
387 if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize))
388 bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
389 device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize;
391 /* Force 32-bit float output. */
392 device->FmtType = DevFmtFloat;
394 numchans = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder);
395 for(i = 0;i < numchans;i++)
397 char name[64];
398 snprintf(name, sizeof(name), "channel_%d", i+1);
399 self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
400 if(self->Port[i] == NULL)
402 ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans));
403 if(i == 0) return ALC_FALSE;
404 break;
407 if(i < numchans)
409 if(i == 1)
410 device->FmtChans = DevFmtMono;
411 else
413 for(--i;i >= 2;i--)
415 jack_port_unregister(self->Client, self->Port[i]);
416 self->Port[i] = NULL;
418 device->FmtChans = DevFmtStereo;
422 ll_ringbuffer_free(self->Ring);
423 self->Ring = ll_ringbuffer_create(bufsize,
424 FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder),
425 true
427 if(!self->Ring)
429 ERR("Failed to allocate ringbuffer\n");
430 return ALC_FALSE;
433 SetDefaultChannelOrder(device);
435 return ALC_TRUE;
438 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
440 const char **ports;
441 ALsizei i;
443 if(jack_activate(self->Client))
445 ERR("Failed to activate client\n");
446 return ALC_FALSE;
449 ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
450 if(ports == NULL)
452 ERR("No physical playback ports found\n");
453 jack_deactivate(self->Client);
454 return ALC_FALSE;
456 for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++)
458 if(!ports[i])
460 ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i]));
461 break;
463 if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i]))
464 ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]);
466 jack_free(ports);
468 self->mKillNow.store(AL_FALSE, std::memory_order_release);
469 if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success)
471 jack_deactivate(self->Client);
472 return ALC_FALSE;
475 return ALC_TRUE;
478 static void ALCjackPlayback_stop(ALCjackPlayback *self)
480 int res;
482 if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel))
483 return;
485 alsem_post(&self->Sem);
486 althrd_join(self->thread, &res);
488 jack_deactivate(self->Client);
492 static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self)
494 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
495 ClockLatency ret;
497 ALCjackPlayback_lock(self);
498 ret.ClockTime = GetDeviceClockTime(device);
499 ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->Ring)};
500 ret.Latency /= device->Frequency;
501 ALCjackPlayback_unlock(self);
503 return ret;
507 static void jack_msg_handler(const char *message)
509 WARN("%s\n", message);
512 bool JackBackendFactory::init()
514 void (*old_error_cb)(const char*);
515 jack_client_t *client;
516 jack_status_t status;
518 if(!jack_load())
519 return false;
521 if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0))
522 ClientOptions = static_cast<jack_options_t>(ClientOptions | JackNoStartServer);
524 old_error_cb = (&jack_error_callback ? jack_error_callback : NULL);
525 jack_set_error_function(jack_msg_handler);
526 client = jack_client_open("alsoft", ClientOptions, &status, NULL);
527 jack_set_error_function(old_error_cb);
528 if(!client)
530 WARN("jack_client_open() failed, 0x%02x\n", status);
531 if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer))
532 ERR("Unable to connect to JACK server\n");
533 return false;
536 jack_client_close(client);
537 return true;
540 void JackBackendFactory::deinit()
542 #ifdef HAVE_DYNLOAD
543 if(jack_handle)
544 CloseLib(jack_handle);
545 jack_handle = nullptr;
546 #endif
549 bool JackBackendFactory::querySupport(ALCbackend_Type type)
550 { return (type == ALCbackend_Playback); }
552 void JackBackendFactory::probe(enum DevProbe type, std::string *outnames)
554 switch(type)
556 case ALL_DEVICE_PROBE:
557 /* Includes null char. */
558 outnames->append(jackDevice, sizeof(jackDevice));
559 break;
561 case CAPTURE_DEVICE_PROBE:
562 break;
566 ALCbackend *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type)
568 if(type == ALCbackend_Playback)
570 ALCjackPlayback *backend;
571 NEW_OBJ(backend, ALCjackPlayback)(device);
572 if(!backend) return nullptr;
573 return STATIC_CAST(ALCbackend, backend);
576 return nullptr;
579 BackendFactory &JackBackendFactory::getFactory()
581 static JackBackendFactory factory{};
582 return factory;