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_ringbuffer_create); \
58 MAGIC(jack_ringbuffer_free); \
59 MAGIC(jack_ringbuffer_get_read_vector); \
60 MAGIC(jack_ringbuffer_get_write_vector); \
61 MAGIC(jack_ringbuffer_read_advance); \
62 MAGIC(jack_ringbuffer_write_advance); \
63 MAGIC(jack_ringbuffer_write_space); \
64 MAGIC(jack_set_process_callback); \
65 MAGIC(jack_set_buffer_size_callback); \
66 MAGIC(jack_set_buffer_size); \
67 MAGIC(jack_get_buffer_size);
69 static void *jack_handle
;
70 #define MAKE_FUNC(f) static __typeof(f) * p##f
71 JACK_FUNCS(MAKE_FUNC
);
74 #define jack_client_open pjack_client_open
75 #define jack_client_close pjack_client_close
76 #define jack_client_name_size pjack_client_name_size
77 #define jack_get_client_name pjack_get_client_name
78 #define jack_connect pjack_connect
79 #define jack_activate pjack_activate
80 #define jack_deactivate pjack_deactivate
81 #define jack_port_register pjack_port_register
82 #define jack_port_unregister pjack_port_unregister
83 #define jack_port_get_buffer pjack_port_get_buffer
84 #define jack_port_name pjack_port_name
85 #define jack_get_ports pjack_get_ports
86 #define jack_free pjack_free
87 #define jack_get_sample_rate pjack_get_sample_rate
88 #define jack_ringbuffer_create pjack_ringbuffer_create
89 #define jack_ringbuffer_free pjack_ringbuffer_free
90 #define jack_ringbuffer_get_read_vector pjack_ringbuffer_get_read_vector
91 #define jack_ringbuffer_get_write_vector pjack_ringbuffer_get_write_vector
92 #define jack_ringbuffer_read_advance pjack_ringbuffer_read_advance
93 #define jack_ringbuffer_write_advance pjack_ringbuffer_write_advance
94 #define jack_ringbuffer_write_space pjack_ringbuffer_write_space
95 #define jack_set_process_callback pjack_set_process_callback
96 #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
97 #define jack_set_buffer_size pjack_set_buffer_size
98 #define jack_get_buffer_size pjack_get_buffer_size
102 static jack_options_t ClientOptions
= JackNullOption
;
104 static ALCboolean
jack_load(void)
106 ALCboolean error
= ALC_FALSE
;
111 jack_handle
= LoadLib("libjack.so.0");
116 #define LOAD_FUNC(f) do { \
117 p##f = GetSymbol(jack_handle, #f); \
122 JACK_FUNCS(LOAD_FUNC
);
127 CloseLib(jack_handle
);
138 typedef struct ALCjackPlayback
{
139 DERIVE_FROM_TYPE(ALCbackend
);
141 jack_client_t
*Client
;
142 jack_port_t
*Port
[MAX_OUTPUT_CHANNELS
];
144 jack_ringbuffer_t
*Ring
;
147 volatile int killNow
;
151 static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes
, void *arg
);
153 static int ALCjackPlayback_process(jack_nframes_t numframes
, void *arg
);
154 static int ALCjackPlayback_mixerProc(void *arg
);
156 static void ALCjackPlayback_Construct(ALCjackPlayback
*self
, ALCdevice
*device
);
157 static void ALCjackPlayback_Destruct(ALCjackPlayback
*self
);
158 static ALCenum
ALCjackPlayback_open(ALCjackPlayback
*self
, const ALCchar
*name
);
159 static void ALCjackPlayback_close(ALCjackPlayback
*self
);
160 static ALCboolean
ALCjackPlayback_reset(ALCjackPlayback
*self
);
161 static ALCboolean
ALCjackPlayback_start(ALCjackPlayback
*self
);
162 static void ALCjackPlayback_stop(ALCjackPlayback
*self
);
163 static DECLARE_FORWARD2(ALCjackPlayback
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
164 static DECLARE_FORWARD(ALCjackPlayback
, ALCbackend
, ALCuint
, availableSamples
)
165 static DECLARE_FORWARD(ALCjackPlayback
, ALCbackend
, ALint64
, getLatency
)
166 static void ALCjackPlayback_lock(ALCjackPlayback
*self
);
167 static void ALCjackPlayback_unlock(ALCjackPlayback
*self
);
168 DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback
)
170 DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback
);
173 static void ALCjackPlayback_Construct(ALCjackPlayback
*self
, ALCdevice
*device
)
177 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
178 SET_VTABLE2(ALCjackPlayback
, ALCbackend
, self
);
180 alcnd_init(&self
->Cond
);
183 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
184 self
->Port
[i
] = NULL
;
190 static void ALCjackPlayback_Destruct(ALCjackPlayback
*self
)
196 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
199 jack_port_unregister(self
->Client
, self
->Port
[i
]);
200 self
->Port
[i
] = NULL
;
202 jack_client_close(self
->Client
);
206 alcnd_destroy(&self
->Cond
);
208 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
212 static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes
, void *arg
)
214 ALCjackPlayback
*self
= arg
;
215 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
218 ALCjackPlayback_lock(self
);
219 if(ConfigValueUInt("jack", "buffer-size", &bufsize
))
220 device
->UpdateSize
= maxu(numframes
, NextPowerOf2(bufsize
));
222 device
->UpdateSize
= numframes
;
223 TRACE("%u update size x%u\n", device
->UpdateSize
, device
->NumUpdates
);
225 jack_ringbuffer_free(self
->Ring
);
226 self
->Ring
= jack_ringbuffer_create(device
->UpdateSize
* device
->NumUpdates
*
227 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
));
230 ERR("Failed to reallocate ringbuffer\n");
231 aluHandleDisconnect(device
);
233 ALCjackPlayback_unlock(self
);
238 static int ALCjackPlayback_process(jack_nframes_t numframes
, void *arg
)
240 ALCjackPlayback
*self
= arg
;
241 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
242 ALuint frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
243 jack_default_audio_sample_t
*out
[MAX_OUTPUT_CHANNELS
];
244 jack_ringbuffer_data_t data
[2];
245 jack_nframes_t total
= 0;
247 ALuint i
, c
, numchans
;
249 jack_ringbuffer_get_read_vector(self
->Ring
, data
);
251 for(c
= 0;c
< MAX_OUTPUT_CHANNELS
&& self
->Port
[c
];c
++)
252 out
[c
] = jack_port_get_buffer(self
->Port
[c
], numframes
);
254 for(;c
< MAX_OUTPUT_CHANNELS
;c
++)
257 todo
= minu(numframes
, data
[0].len
/frame_size
);
258 for(c
= 0;c
< numchans
;c
++)
260 for(i
= 0;i
< todo
;i
++)
261 out
[c
][i
] = ((ALfloat
*)data
[0].buf
)[i
*numchans
+ c
];
266 todo
= minu(numframes
-total
, data
[1].len
/frame_size
);
267 for(c
= 0;c
< numchans
;c
++)
269 for(i
= 0;i
< todo
;i
++)
270 out
[c
][i
] = ((ALfloat
*)data
[1].buf
)[i
*numchans
+ c
];
275 jack_ringbuffer_read_advance(self
->Ring
, total
*frame_size
);
276 alcnd_signal(&self
->Cond
);
278 if(numframes
> total
)
280 todo
= numframes
-total
;
281 for(c
= 0;c
< numchans
;c
++)
283 for(i
= 0;i
< todo
;i
++)
291 static int ALCjackPlayback_mixerProc(void *arg
)
293 ALCjackPlayback
*self
= arg
;
294 ALCdevice
*device
= STATIC_CAST(ALCbackend
,self
)->mDevice
;
295 ALuint frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
296 jack_ringbuffer_data_t data
[2];
299 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
301 ALCjackPlayback_lock(self
);
302 while(!self
->killNow
&& device
->Connected
)
304 ALuint todo
, len1
, len2
;
306 if(jack_ringbuffer_write_space(self
->Ring
)/frame_size
< device
->UpdateSize
)
308 alcnd_wait(&self
->Cond
, &STATIC_CAST(ALCbackend
,self
)->mMutex
);
312 jack_ringbuffer_get_write_vector(self
->Ring
, data
);
313 todo
= (data
[0].len
+data
[1].len
)/frame_size
;
314 todo
-= todo
%device
->UpdateSize
;
316 len1
= minu(data
[0].len
/frame_size
, todo
);
317 len2
= minu(data
[1].len
/frame_size
, todo
-len1
);
319 aluMixData(device
, data
[0].buf
, len1
);
321 aluMixData(device
, data
[1].buf
, len2
);
322 jack_ringbuffer_write_advance(self
->Ring
, todo
*frame_size
);
324 ALCjackPlayback_unlock(self
);
330 static ALCenum
ALCjackPlayback_open(ALCjackPlayback
*self
, const ALCchar
*name
)
332 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
333 const char *client_name
= "alsoft";
334 jack_status_t status
;
338 else if(strcmp(name
, jackDevice
) != 0)
339 return ALC_INVALID_VALUE
;
341 self
->Client
= jack_client_open(client_name
, ClientOptions
, &status
, NULL
);
342 if(self
->Client
== NULL
)
344 ERR("jack_client_open() failed, status = 0x%02x\n", status
);
345 return ALC_INVALID_VALUE
;
347 if((status
&JackServerStarted
))
348 TRACE("JACK server started\n");
349 if((status
&JackNameNotUnique
))
351 client_name
= jack_get_client_name(self
->Client
);
352 TRACE("Client name not unique, got `%s' instead\n", client_name
);
355 jack_set_process_callback(self
->Client
, ALCjackPlayback_process
, self
);
356 jack_set_buffer_size_callback(self
->Client
, ALCjackPlayback_bufferSizeNotify
, self
);
358 al_string_copy_cstr(&device
->DeviceName
, name
);
363 static void ALCjackPlayback_close(ALCjackPlayback
*self
)
367 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
370 jack_port_unregister(self
->Client
, self
->Port
[i
]);
371 self
->Port
[i
] = NULL
;
373 jack_client_close(self
->Client
);
377 static ALCboolean
ALCjackPlayback_reset(ALCjackPlayback
*self
)
379 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
383 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
386 jack_port_unregister(self
->Client
, self
->Port
[i
]);
387 self
->Port
[i
] = NULL
;
390 /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
391 * ready for when requested. Note that even though the ringbuffer will have
392 * 2 periods worth of space, only half of it will be filled at a given time
393 * because there's one byte less of it that's writeable, and we only write
394 * in update-sized chunks. */
395 device
->Frequency
= jack_get_sample_rate(self
->Client
);
396 if(ConfigValueUInt("jack", "buffer-size", &bufsize
))
397 device
->UpdateSize
= maxu(jack_get_buffer_size(self
->Client
), NextPowerOf2(bufsize
));
399 device
->UpdateSize
= jack_get_buffer_size(self
->Client
);
400 device
->NumUpdates
= 2;
402 /* FIXME: Force stereo, 32-bit float output. */
403 device
->FmtChans
= DevFmtStereo
;
404 device
->FmtType
= DevFmtFloat
;
406 numchans
= ChannelsFromDevFmt(device
->FmtChans
);
407 for(i
= 0;i
< numchans
;i
++)
410 snprintf(name
, sizeof(name
), "channel_%d", i
+1);
411 self
->Port
[i
] = jack_port_register(self
->Client
, name
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
412 if(self
->Port
[i
] == NULL
)
414 ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device
->FmtChans
));
420 jack_ringbuffer_free(self
->Ring
);
421 self
->Ring
= jack_ringbuffer_create(device
->UpdateSize
* device
->NumUpdates
*
422 FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
));
425 ERR("Failed to allocate ringbuffer\n");
429 SetDefaultChannelOrder(device
);
434 static ALCboolean
ALCjackPlayback_start(ALCjackPlayback
*self
)
439 if(jack_activate(self
->Client
))
441 ERR("Failed to activate client\n");
445 ports
= jack_get_ports(self
->Client
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsInput
);
448 ERR("No physical playback ports found\n");
449 jack_deactivate(self
->Client
);
452 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& self
->Port
[i
];i
++)
456 ERR("No physical playback port for \"%s\"\n", jack_port_name(self
->Port
[i
]));
459 if(jack_connect(self
->Client
, jack_port_name(self
->Port
[i
]), ports
[i
]))
460 ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self
->Port
[i
]), ports
[i
]);
465 if(althrd_create(&self
->thread
, ALCjackPlayback_mixerProc
, self
) != althrd_success
)
467 jack_deactivate(self
->Client
);
474 static void ALCjackPlayback_stop(ALCjackPlayback
*self
)
482 ALCjackPlayback_lock(self
);
483 alcnd_signal(&self
->Cond
);
484 ALCjackPlayback_unlock(self
);
485 althrd_join(self
->thread
, &res
);
487 jack_deactivate(self
->Client
);
491 static void ALCjackPlayback_lock(ALCjackPlayback
*self
)
493 almtx_lock(&STATIC_CAST(ALCbackend
,self
)->mMutex
);
496 static void ALCjackPlayback_unlock(ALCjackPlayback
*self
)
498 almtx_unlock(&STATIC_CAST(ALCbackend
,self
)->mMutex
);
502 typedef struct ALCjackBackendFactory
{
503 DERIVE_FROM_TYPE(ALCbackendFactory
);
504 } ALCjackBackendFactory
;
505 #define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } }
507 static ALCboolean
ALCjackBackendFactory_init(ALCjackBackendFactory
* UNUSED(self
))
509 jack_client_t
*client
;
510 jack_status_t status
;
515 if(!GetConfigValueBool("jack", "spawn-server", 1))
516 ClientOptions
|= JackNoStartServer
;
517 client
= jack_client_open("alsoft", ClientOptions
, &status
, NULL
);
520 WARN("jack_client_open() failed, 0x%02x\n", status
);
521 if((status
&JackServerFailed
))
522 ERR("Unable to connect to JACK server\n");
526 jack_client_close(client
);
530 static void ALCjackBackendFactory_deinit(ALCjackBackendFactory
* UNUSED(self
))
534 CloseLib(jack_handle
);
539 static ALCboolean
ALCjackBackendFactory_querySupport(ALCjackBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
541 if(type
== ALCbackend_Playback
)
546 static void ALCjackBackendFactory_probe(ALCjackBackendFactory
* UNUSED(self
), enum DevProbe type
)
550 case ALL_DEVICE_PROBE
:
551 AppendAllDevicesList(jackDevice
);
554 case CAPTURE_DEVICE_PROBE
:
559 static ALCbackend
* ALCjackBackendFactory_createBackend(ALCjackBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
561 if(type
== ALCbackend_Playback
)
563 ALCjackPlayback
*backend
;
565 backend
= ALCjackPlayback_New(sizeof(*backend
));
566 if(!backend
) return NULL
;
567 memset(backend
, 0, sizeof(*backend
));
569 ALCjackPlayback_Construct(backend
, device
);
571 return STATIC_CAST(ALCbackend
, backend
);
577 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory
);
580 ALCbackendFactory
*ALCjackBackendFactory_getFactory(void)
582 static ALCjackBackendFactory factory
= ALCJACKBACKENDFACTORY_INITIALIZER
;
583 return STATIC_CAST(ALCbackendFactory
, &factory
);