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
32 #include "backends/base.h"
34 #include <jack/jack.h>
35 #include <jack/ringbuffer.h>
38 static const ALCchar jackDevice
[] = "JACK Default";
42 #define JACK_FUNCS(MAGIC) \
43 MAGIC(jack_client_open); \
44 MAGIC(jack_client_close); \
45 MAGIC(jack_client_name_size); \
46 MAGIC(jack_get_client_name); \
47 MAGIC(jack_connect); \
48 MAGIC(jack_activate); \
49 MAGIC(jack_deactivate); \
50 MAGIC(jack_port_register); \
51 MAGIC(jack_port_unregister); \
52 MAGIC(jack_port_get_buffer); \
53 MAGIC(jack_port_name); \
54 MAGIC(jack_get_ports); \
56 MAGIC(jack_get_sample_rate); \
57 MAGIC(jack_set_error_function); \
58 MAGIC(jack_set_process_callback); \
59 MAGIC(jack_set_buffer_size_callback); \
60 MAGIC(jack_set_buffer_size); \
61 MAGIC(jack_get_buffer_size);
63 static void *jack_handle
;
64 #define MAKE_FUNC(f) static __typeof(f) * p##f
65 JACK_FUNCS(MAKE_FUNC
);
66 static __typeof(jack_error_callback
) * pjack_error_callback
;
69 #define jack_client_open pjack_client_open
70 #define jack_client_close pjack_client_close
71 #define jack_client_name_size pjack_client_name_size
72 #define jack_get_client_name pjack_get_client_name
73 #define jack_connect pjack_connect
74 #define jack_activate pjack_activate
75 #define jack_deactivate pjack_deactivate
76 #define jack_port_register pjack_port_register
77 #define jack_port_unregister pjack_port_unregister
78 #define jack_port_get_buffer pjack_port_get_buffer
79 #define jack_port_name pjack_port_name
80 #define jack_get_ports pjack_get_ports
81 #define jack_free pjack_free
82 #define jack_get_sample_rate pjack_get_sample_rate
83 #define jack_set_error_function pjack_set_error_function
84 #define jack_set_process_callback pjack_set_process_callback
85 #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
86 #define jack_set_buffer_size pjack_set_buffer_size
87 #define jack_get_buffer_size pjack_get_buffer_size
88 #define jack_error_callback (*pjack_error_callback)
92 static jack_options_t ClientOptions
= JackNullOption
;
94 static ALCboolean
jack_load(void)
96 ALCboolean error
= ALC_FALSE
;
101 al_string missing_funcs
= AL_STRING_INIT_STATIC();
104 #define JACKLIB "libjack.dll"
106 #define JACKLIB "libjack.so.0"
108 jack_handle
= LoadLib(JACKLIB
);
111 WARN("Failed to load %s\n", JACKLIB
);
116 #define LOAD_FUNC(f) do { \
117 p##f = GetSymbol(jack_handle, #f); \
120 alstr_append_cstr(&missing_funcs, "\n" #f); \
123 JACK_FUNCS(LOAD_FUNC
);
125 /* Optional symbols. These don't exist in all versions of JACK. */
126 #define LOAD_SYM(f) p##f = GetSymbol(jack_handle, #f)
127 LOAD_SYM(jack_error_callback
);
132 WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs
));
133 CloseLib(jack_handle
);
136 alstr_reset(&missing_funcs
);
144 typedef struct ALCjackPlayback
{
145 DERIVE_FROM_TYPE(ALCbackend
);
147 jack_client_t
*Client
;
148 jack_port_t
*Port
[MAX_OUTPUT_CHANNELS
];
150 ll_ringbuffer_t
*Ring
;
153 volatile int killNow
;
157 static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes
, void *arg
);
159 static int ALCjackPlayback_process(jack_nframes_t numframes
, void *arg
);
160 static int ALCjackPlayback_mixerProc(void *arg
);
162 static void ALCjackPlayback_Construct(ALCjackPlayback
*self
, ALCdevice
*device
);
163 static void ALCjackPlayback_Destruct(ALCjackPlayback
*self
);
164 static ALCenum
ALCjackPlayback_open(ALCjackPlayback
*self
, const ALCchar
*name
);
165 static void ALCjackPlayback_close(ALCjackPlayback
*self
);
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
)
183 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
184 SET_VTABLE2(ALCjackPlayback
, ALCbackend
, self
);
186 alcnd_init(&self
->Cond
);
189 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
190 self
->Port
[i
] = NULL
;
196 static void ALCjackPlayback_Destruct(ALCjackPlayback
*self
)
202 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
205 jack_port_unregister(self
->Client
, self
->Port
[i
]);
206 self
->Port
[i
] = NULL
;
208 jack_client_close(self
->Client
);
212 alcnd_destroy(&self
->Cond
);
214 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
218 static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes
, void *arg
)
220 ALCjackPlayback
*self
= arg
;
221 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
224 ALCjackPlayback_lock(self
);
225 device
->UpdateSize
= numframes
;
226 device
->NumUpdates
= 2;
228 bufsize
= device
->UpdateSize
;
229 if(ConfigValueUInt(alstr_get_cstr(device
->DeviceName
), "jack", "buffer-size", &bufsize
))
230 bufsize
= maxu(NextPowerOf2(bufsize
), device
->UpdateSize
);
231 bufsize
+= device
->UpdateSize
;
232 device
->NumUpdates
= bufsize
/ device
->UpdateSize
;
234 TRACE("%u update size x%u\n", device
->UpdateSize
, device
->NumUpdates
);
236 ll_ringbuffer_free(self
->Ring
);
237 self
->Ring
= ll_ringbuffer_create(bufsize
,
238 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
)
242 ERR("Failed to reallocate ringbuffer\n");
243 aluHandleDisconnect(device
);
245 ALCjackPlayback_unlock(self
);
250 static int ALCjackPlayback_process(jack_nframes_t numframes
, void *arg
)
252 ALCjackPlayback
*self
= arg
;
253 jack_default_audio_sample_t
*out
[MAX_OUTPUT_CHANNELS
];
254 ll_ringbuffer_data_t data
[2];
255 jack_nframes_t total
= 0;
257 ALsizei i
, c
, numchans
;
259 ll_ringbuffer_get_read_vector(self
->Ring
, data
);
261 for(c
= 0;c
< MAX_OUTPUT_CHANNELS
&& self
->Port
[c
];c
++)
262 out
[c
] = jack_port_get_buffer(self
->Port
[c
], numframes
);
265 todo
= minu(numframes
, data
[0].len
);
266 for(c
= 0;c
< numchans
;c
++)
268 const ALfloat
*restrict in
= ((ALfloat
*)data
[0].buf
) + c
;
269 for(i
= 0;(jack_nframes_t
)i
< todo
;i
++)
270 out
[c
][i
] = in
[i
*numchans
];
275 todo
= minu(numframes
-total
, data
[1].len
);
278 for(c
= 0;c
< numchans
;c
++)
280 const ALfloat
*restrict in
= ((ALfloat
*)data
[1].buf
) + c
;
281 for(i
= 0;(jack_nframes_t
)i
< todo
;i
++)
282 out
[c
][i
] = in
[i
*numchans
];
288 ll_ringbuffer_read_advance(self
->Ring
, total
);
289 alcnd_signal(&self
->Cond
);
291 if(numframes
> total
)
293 todo
= numframes
-total
;
294 for(c
= 0;c
< numchans
;c
++)
296 for(i
= 0;(jack_nframes_t
)i
< todo
;i
++)
304 static int ALCjackPlayback_mixerProc(void *arg
)
306 ALCjackPlayback
*self
= arg
;
307 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
308 ll_ringbuffer_data_t data
[2];
311 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
313 ALCjackPlayback_lock(self
);
314 while(!self
->killNow
&& device
->Connected
)
316 ALuint todo
, len1
, len2
;
318 /* NOTE: Unfortunately, there is an unavoidable race condition here.
319 * It's possible for the process() method to run, updating the read
320 * pointer and signaling the condition variable, in between the mixer
321 * loop checking the write size and waiting for the condition variable.
322 * This will cause the mixer loop to wait until the *next* process()
323 * invocation, most likely writing silence for it.
325 * However, this should only happen if the mixer is running behind
326 * anyway (as ideally we'll be asleep in alcnd_wait by the time the
327 * process() method is invoked), so this behavior is not unwarranted.
328 * It's unfortunate since it'll be wasting time sleeping that could be
329 * used to catch up, but there's no way around it without blocking in
330 * the process() method.
332 if(ll_ringbuffer_write_space(self
->Ring
) < device
->UpdateSize
)
334 alcnd_wait(&self
->Cond
, &STATIC_CAST(ALCbackend
,self
)->mMutex
);
338 ll_ringbuffer_get_write_vector(self
->Ring
, data
);
339 todo
= data
[0].len
+ data
[1].len
;
340 todo
-= todo
%device
->UpdateSize
;
342 len1
= minu(data
[0].len
, todo
);
343 len2
= minu(data
[1].len
, todo
-len1
);
345 aluMixData(device
, data
[0].buf
, len1
);
347 aluMixData(device
, data
[1].buf
, len2
);
348 ll_ringbuffer_write_advance(self
->Ring
, todo
);
350 ALCjackPlayback_unlock(self
);
356 static ALCenum
ALCjackPlayback_open(ALCjackPlayback
*self
, const ALCchar
*name
)
358 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
359 const char *client_name
= "alsoft";
360 jack_status_t status
;
364 else if(strcmp(name
, jackDevice
) != 0)
365 return ALC_INVALID_VALUE
;
367 self
->Client
= jack_client_open(client_name
, ClientOptions
, &status
, NULL
);
368 if(self
->Client
== NULL
)
370 ERR("jack_client_open() failed, status = 0x%02x\n", status
);
371 return ALC_INVALID_VALUE
;
373 if((status
&JackServerStarted
))
374 TRACE("JACK server started\n");
375 if((status
&JackNameNotUnique
))
377 client_name
= jack_get_client_name(self
->Client
);
378 TRACE("Client name not unique, got `%s' instead\n", client_name
);
381 jack_set_process_callback(self
->Client
, ALCjackPlayback_process
, self
);
382 jack_set_buffer_size_callback(self
->Client
, ALCjackPlayback_bufferSizeNotify
, self
);
384 alstr_copy_cstr(&device
->DeviceName
, name
);
389 static void ALCjackPlayback_close(ALCjackPlayback
*self
)
393 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
396 jack_port_unregister(self
->Client
, self
->Port
[i
]);
397 self
->Port
[i
] = NULL
;
399 jack_client_close(self
->Client
);
403 static ALCboolean
ALCjackPlayback_reset(ALCjackPlayback
*self
)
405 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
409 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
412 jack_port_unregister(self
->Client
, self
->Port
[i
]);
413 self
->Port
[i
] = NULL
;
416 /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
417 * ready for when requested. Note that one period's worth of audio in the
418 * ring buffer will always be left unfilled because one element of the ring
419 * buffer will not be writeable, and we only write in period-sized chunks.
421 device
->Frequency
= jack_get_sample_rate(self
->Client
);
422 device
->UpdateSize
= jack_get_buffer_size(self
->Client
);
423 device
->NumUpdates
= 2;
425 bufsize
= device
->UpdateSize
;
426 if(ConfigValueUInt(alstr_get_cstr(device
->DeviceName
), "jack", "buffer-size", &bufsize
))
427 bufsize
= maxu(NextPowerOf2(bufsize
), device
->UpdateSize
);
428 bufsize
+= device
->UpdateSize
;
429 device
->NumUpdates
= bufsize
/ device
->UpdateSize
;
431 /* Force 32-bit float output. */
432 device
->FmtType
= DevFmtFloat
;
434 numchans
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
435 for(i
= 0;i
< numchans
;i
++)
438 snprintf(name
, sizeof(name
), "channel_%d", i
+1);
439 self
->Port
[i
] = jack_port_register(self
->Client
, name
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
440 if(self
->Port
[i
] == NULL
)
442 ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device
->FmtChans
));
443 if(i
== 0) return ALC_FALSE
;
450 device
->FmtChans
= DevFmtMono
;
455 jack_port_unregister(self
->Client
, self
->Port
[i
]);
456 self
->Port
[i
] = NULL
;
458 device
->FmtChans
= DevFmtStereo
;
462 ll_ringbuffer_free(self
->Ring
);
463 self
->Ring
= ll_ringbuffer_create(bufsize
,
464 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
)
468 ERR("Failed to allocate ringbuffer\n");
472 SetDefaultChannelOrder(device
);
477 static ALCboolean
ALCjackPlayback_start(ALCjackPlayback
*self
)
482 if(jack_activate(self
->Client
))
484 ERR("Failed to activate client\n");
488 ports
= jack_get_ports(self
->Client
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsInput
);
491 ERR("No physical playback ports found\n");
492 jack_deactivate(self
->Client
);
495 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& self
->Port
[i
];i
++)
499 ERR("No physical playback port for \"%s\"\n", jack_port_name(self
->Port
[i
]));
502 if(jack_connect(self
->Client
, jack_port_name(self
->Port
[i
]), ports
[i
]))
503 ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self
->Port
[i
]), ports
[i
]);
508 if(althrd_create(&self
->thread
, ALCjackPlayback_mixerProc
, self
) != althrd_success
)
510 jack_deactivate(self
->Client
);
517 static void ALCjackPlayback_stop(ALCjackPlayback
*self
)
525 /* Lock the backend to ensure we don't flag the mixer to die and signal the
526 * mixer to wake up in between it checking the flag and going to sleep and
527 * wait for a wakeup (potentially leading to it never waking back up to see
529 ALCjackPlayback_lock(self
);
530 ALCjackPlayback_unlock(self
);
531 alcnd_signal(&self
->Cond
);
532 althrd_join(self
->thread
, &res
);
534 jack_deactivate(self
->Client
);
538 static ClockLatency
ALCjackPlayback_getClockLatency(ALCjackPlayback
*self
)
540 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
543 ALCjackPlayback_lock(self
);
544 ret
.ClockTime
= GetDeviceClockTime(device
);
545 ret
.Latency
= ll_ringbuffer_read_space(self
->Ring
) * DEVICE_CLOCK_RES
/
547 ALCjackPlayback_unlock(self
);
553 static void jack_msg_handler(const char *message
)
555 WARN("%s\n", message
);
558 typedef struct ALCjackBackendFactory
{
559 DERIVE_FROM_TYPE(ALCbackendFactory
);
560 } ALCjackBackendFactory
;
561 #define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } }
563 static ALCboolean
ALCjackBackendFactory_init(ALCjackBackendFactory
* UNUSED(self
))
565 void (*old_error_cb
)(const char*);
566 jack_client_t
*client
;
567 jack_status_t status
;
572 if(!GetConfigValueBool(NULL
, "jack", "spawn-server", 0))
573 ClientOptions
|= JackNoStartServer
;
575 old_error_cb
= (&jack_error_callback
? jack_error_callback
: NULL
);
576 jack_set_error_function(jack_msg_handler
);
577 client
= jack_client_open("alsoft", ClientOptions
, &status
, NULL
);
578 jack_set_error_function(old_error_cb
);
581 WARN("jack_client_open() failed, 0x%02x\n", status
);
582 if((status
&JackServerFailed
) && !(ClientOptions
&JackNoStartServer
))
583 ERR("Unable to connect to JACK server\n");
587 jack_client_close(client
);
591 static void ALCjackBackendFactory_deinit(ALCjackBackendFactory
* UNUSED(self
))
595 CloseLib(jack_handle
);
600 static ALCboolean
ALCjackBackendFactory_querySupport(ALCjackBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
602 if(type
== ALCbackend_Playback
)
607 static void ALCjackBackendFactory_probe(ALCjackBackendFactory
* UNUSED(self
), enum DevProbe type
)
611 case ALL_DEVICE_PROBE
:
612 AppendAllDevicesList(jackDevice
);
615 case CAPTURE_DEVICE_PROBE
:
620 static ALCbackend
* ALCjackBackendFactory_createBackend(ALCjackBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
622 if(type
== ALCbackend_Playback
)
624 ALCjackPlayback
*backend
;
625 NEW_OBJ(backend
, ALCjackPlayback
)(device
);
626 if(!backend
) return NULL
;
627 return STATIC_CAST(ALCbackend
, backend
);
633 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory
);
636 ALCbackendFactory
*ALCjackBackendFactory_getFactory(void)
638 static ALCjackBackendFactory factory
= ALCJACKBACKENDFACTORY_INITIALIZER
;
639 return STATIC_CAST(ALCbackendFactory
, &factory
);