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
23 #include "backends/jack.h"
32 #include "ringbuffer.h"
36 #include <jack/jack.h>
37 #include <jack/ringbuffer.h>
40 static const ALCchar jackDevice
[] = "JACK Default";
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); \
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
;
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)
96 static jack_options_t ClientOptions
= JackNullOption
;
98 static ALCboolean
jack_load(void)
100 ALCboolean error
= ALC_FALSE
;
105 std::string missing_funcs
;
108 #define JACKLIB "libjack.dll"
110 #define JACKLIB "libjack.so.0"
112 jack_handle
= LoadLib(JACKLIB
);
115 WARN("Failed to load %s\n", JACKLIB
);
120 #define LOAD_FUNC(f) do { \
121 p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \
122 if(p##f == nullptr) { \
124 missing_funcs += "\n" #f; \
127 JACK_FUNCS(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
);
136 WARN("Missing expected functions:%s\n", missing_funcs
.c_str());
137 CloseLib(jack_handle
);
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};
154 std::atomic
<ALenum
> mKillNow
{AL_TRUE
};
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
)
192 for(ALsizei i
{0};i
< MAX_OUTPUT_CHANNELS
;i
++)
195 jack_port_unregister(self
->Client
, self
->Port
[i
]);
196 self
->Port
[i
] = NULL
;
198 jack_client_close(self
->Client
);
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
;
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
),
233 ERR("Failed to reallocate ringbuffer\n");
234 aluHandleDisconnect(device
, "Failed to reallocate %u-sample buffer", bufsize
);
236 ALCjackPlayback_unlock(self
);
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};
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
));
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
];
265 todo
= minu(numframes
-total
, data
.second
.len
);
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
];
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
++)
294 static int ALCjackPlayback_mixerProc(void *arg
)
296 ALCjackPlayback
*self
= static_cast<ALCjackPlayback
*>(arg
);
297 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
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
);
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
);
325 aluMixData(device
, data
.second
.buf
, len2
);
326 ll_ringbuffer_write_advance(self
->Ring
, todo
);
328 ALCjackPlayback_unlock(self
);
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
;
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
;
366 static ALCboolean
ALCjackPlayback_reset(ALCjackPlayback
*self
)
368 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
372 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;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
++)
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
;
410 device
->FmtChans
= DevFmtMono
;
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
),
429 ERR("Failed to allocate ringbuffer\n");
433 SetDefaultChannelOrder(device
);
438 static ALCboolean
ALCjackPlayback_start(ALCjackPlayback
*self
)
443 if(jack_activate(self
->Client
))
445 ERR("Failed to activate client\n");
449 ports
= jack_get_ports(self
->Client
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsInput
);
452 ERR("No physical playback ports found\n");
453 jack_deactivate(self
->Client
);
456 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& self
->Port
[i
];i
++)
460 ERR("No physical playback port for \"%s\"\n", jack_port_name(self
->Port
[i
]));
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
]);
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
);
478 static void ALCjackPlayback_stop(ALCjackPlayback
*self
)
482 if(self
->mKillNow
.exchange(AL_TRUE
, std::memory_order_acq_rel
))
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
;
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
);
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
;
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
);
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");
536 jack_client_close(client
);
540 void JackBackendFactory::deinit()
544 CloseLib(jack_handle
);
545 jack_handle
= nullptr;
549 bool JackBackendFactory::querySupport(ALCbackend_Type type
)
550 { return (type
== ALCbackend_Playback
); }
552 void JackBackendFactory::probe(enum DevProbe type
, std::string
*outnames
)
556 case ALL_DEVICE_PROBE
:
557 /* Includes null char. */
558 outnames
->append(jackDevice
, sizeof(jackDevice
));
561 case CAPTURE_DEVICE_PROBE
:
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
);
579 BackendFactory
&JackBackendFactory::getFactory()
581 static JackBackendFactory factory
{};