diff options
Diffstat (limited to 'Alc/backends/jack.c')
-rw-r--r-- | Alc/backends/jack.c | 607 |
1 files changed, 0 insertions, 607 deletions
diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c deleted file mode 100644 index fdbe93f2..00000000 --- a/Alc/backends/jack.c +++ /dev/null @@ -1,607 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <memory.h> - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include <jack/jack.h> -#include <jack/ringbuffer.h> - - -static const ALCchar jackDevice[] = "JACK Default"; - - -#ifdef HAVE_DYNLOAD -#define JACK_FUNCS(MAGIC) \ - MAGIC(jack_client_open); \ - MAGIC(jack_client_close); \ - MAGIC(jack_client_name_size); \ - MAGIC(jack_get_client_name); \ - MAGIC(jack_connect); \ - MAGIC(jack_activate); \ - MAGIC(jack_deactivate); \ - MAGIC(jack_port_register); \ - MAGIC(jack_port_unregister); \ - MAGIC(jack_port_get_buffer); \ - MAGIC(jack_port_name); \ - MAGIC(jack_get_ports); \ - MAGIC(jack_free); \ - MAGIC(jack_get_sample_rate); \ - MAGIC(jack_set_error_function); \ - MAGIC(jack_set_process_callback); \ - MAGIC(jack_set_buffer_size_callback); \ - MAGIC(jack_set_buffer_size); \ - MAGIC(jack_get_buffer_size); - -static void *jack_handle; -#define MAKE_FUNC(f) static __typeof(f) * p##f -JACK_FUNCS(MAKE_FUNC); -static __typeof(jack_error_callback) * pjack_error_callback; -#undef MAKE_FUNC - -#define jack_client_open pjack_client_open -#define jack_client_close pjack_client_close -#define jack_client_name_size pjack_client_name_size -#define jack_get_client_name pjack_get_client_name -#define jack_connect pjack_connect -#define jack_activate pjack_activate -#define jack_deactivate pjack_deactivate -#define jack_port_register pjack_port_register -#define jack_port_unregister pjack_port_unregister -#define jack_port_get_buffer pjack_port_get_buffer -#define jack_port_name pjack_port_name -#define jack_get_ports pjack_get_ports -#define jack_free pjack_free -#define jack_get_sample_rate pjack_get_sample_rate -#define jack_set_error_function pjack_set_error_function -#define jack_set_process_callback pjack_set_process_callback -#define jack_set_buffer_size_callback pjack_set_buffer_size_callback -#define jack_set_buffer_size pjack_set_buffer_size -#define jack_get_buffer_size pjack_get_buffer_size -#define jack_error_callback (*pjack_error_callback) -#endif - - -static jack_options_t ClientOptions = JackNullOption; - -static ALCboolean jack_load(void) -{ - ALCboolean error = ALC_FALSE; - -#ifdef HAVE_DYNLOAD - if(!jack_handle) - { - al_string missing_funcs = AL_STRING_INIT_STATIC(); - -#ifdef _WIN32 -#define JACKLIB "libjack.dll" -#else -#define JACKLIB "libjack.so.0" -#endif - jack_handle = LoadLib(JACKLIB); - if(!jack_handle) - { - WARN("Failed to load %s\n", JACKLIB); - return ALC_FALSE; - } - - error = ALC_FALSE; -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(jack_handle, #f); \ - if(p##f == NULL) { \ - error = ALC_TRUE; \ - alstr_append_cstr(&missing_funcs, "\n" #f); \ - } \ -} while(0) - JACK_FUNCS(LOAD_FUNC); -#undef LOAD_FUNC - /* Optional symbols. These don't exist in all versions of JACK. */ -#define LOAD_SYM(f) p##f = GetSymbol(jack_handle, #f) - LOAD_SYM(jack_error_callback); -#undef LOAD_SYM - - if(error) - { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); - CloseLib(jack_handle); - jack_handle = NULL; - } - alstr_reset(&missing_funcs); - } -#endif - - return !error; -} - - -typedef struct ALCjackPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - jack_client_t *Client; - jack_port_t *Port[MAX_OUTPUT_CHANNELS]; - - ll_ringbuffer_t *Ring; - alsem_t Sem; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCjackPlayback; - -static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); - -static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); -static int ALCjackPlayback_mixerProc(void *arg); - -static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); -static void ALCjackPlayback_Destruct(ALCjackPlayback *self); -static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); -static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); -static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); -static void ALCjackPlayback_stop(ALCjackPlayback *self); -static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); - - -static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) -{ - ALuint i; - - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCjackPlayback, ALCbackend, self); - - alsem_init(&self->Sem, 0); - - self->Client = NULL; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - self->Port[i] = NULL; - self->Ring = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCjackPlayback_Destruct(ALCjackPlayback *self) -{ - ALuint i; - - if(self->Client) - { - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - jack_client_close(self->Client); - self->Client = NULL; - } - - alsem_destroy(&self->Sem); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) -{ - ALCjackPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALuint bufsize; - - ALCjackPlayback_lock(self); - device->UpdateSize = numframes; - device->NumUpdates = 2; - - bufsize = device->UpdateSize; - if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; - - TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); - - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - true - ); - if(!self->Ring) - { - ERR("Failed to reallocate ringbuffer\n"); - aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize); - } - ALCjackPlayback_unlock(self); - return 0; -} - - -static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) -{ - ALCjackPlayback *self = arg; - jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; - ll_ringbuffer_data_t data[2]; - jack_nframes_t total = 0; - jack_nframes_t todo; - ALsizei i, c, numchans; - - ll_ringbuffer_get_read_vector(self->Ring, data); - - for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++) - out[c] = jack_port_get_buffer(self->Port[c], numframes); - numchans = c; - - todo = minu(numframes, data[0].len); - for(c = 0;c < numchans;c++) - { - const ALfloat *restrict in = ((ALfloat*)data[0].buf) + c; - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = in[i*numchans]; - out[c] += todo; - } - total += todo; - - todo = minu(numframes-total, data[1].len); - if(todo > 0) - { - for(c = 0;c < numchans;c++) - { - const ALfloat *restrict in = ((ALfloat*)data[1].buf) + c; - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = in[i*numchans]; - out[c] += todo; - } - total += todo; - } - - ll_ringbuffer_read_advance(self->Ring, total); - alsem_post(&self->Sem); - - if(numframes > total) - { - todo = numframes-total; - for(c = 0;c < numchans;c++) - { - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = 0.0f; - } - } - - return 0; -} - -static int ALCjackPlayback_mixerProc(void *arg) -{ - ALCjackPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ll_ringbuffer_data_t data[2]; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - ALCjackPlayback_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - ALuint todo, len1, len2; - - if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize) - { - ALCjackPlayback_unlock(self); - alsem_wait(&self->Sem); - ALCjackPlayback_lock(self); - continue; - } - - ll_ringbuffer_get_write_vector(self->Ring, data); - todo = data[0].len + data[1].len; - todo -= todo%device->UpdateSize; - - len1 = minu(data[0].len, todo); - len2 = minu(data[1].len, todo-len1); - - aluMixData(device, data[0].buf, len1); - if(len2 > 0) - aluMixData(device, data[1].buf, len2); - ll_ringbuffer_write_advance(self->Ring, todo); - } - ALCjackPlayback_unlock(self); - - return 0; -} - - -static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *client_name = "alsoft"; - jack_status_t status; - - if(!name) - name = jackDevice; - else if(strcmp(name, jackDevice) != 0) - return ALC_INVALID_VALUE; - - self->Client = jack_client_open(client_name, ClientOptions, &status, NULL); - if(self->Client == NULL) - { - ERR("jack_client_open() failed, status = 0x%02x\n", status); - return ALC_INVALID_VALUE; - } - if((status&JackServerStarted)) - TRACE("JACK server started\n"); - if((status&JackNameNotUnique)) - { - client_name = jack_get_client_name(self->Client); - TRACE("Client name not unique, got `%s' instead\n", client_name); - } - - jack_set_process_callback(self->Client, ALCjackPlayback_process, self); - jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei numchans, i; - ALuint bufsize; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - - /* Ignore the requested buffer metrics and just keep one JACK-sized buffer - * ready for when requested. - */ - device->Frequency = jack_get_sample_rate(self->Client); - device->UpdateSize = jack_get_buffer_size(self->Client); - device->NumUpdates = 2; - - bufsize = device->UpdateSize; - if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; - - /* Force 32-bit float output. */ - device->FmtType = DevFmtFloat; - - numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - for(i = 0;i < numchans;i++) - { - char name[64]; - snprintf(name, sizeof(name), "channel_%d", i+1); - self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - if(self->Port[i] == NULL) - { - ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); - if(i == 0) return ALC_FALSE; - break; - } - } - if(i < numchans) - { - if(i == 1) - device->FmtChans = DevFmtMono; - else - { - for(--i;i >= 2;i--) - { - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - device->FmtChans = DevFmtStereo; - } - } - - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - true - ); - if(!self->Ring) - { - ERR("Failed to allocate ringbuffer\n"); - return ALC_FALSE; - } - - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) -{ - const char **ports; - ALsizei i; - - if(jack_activate(self->Client)) - { - ERR("Failed to activate client\n"); - return ALC_FALSE; - } - - ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - if(ports == NULL) - { - ERR("No physical playback ports found\n"); - jack_deactivate(self->Client); - return ALC_FALSE; - } - for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++) - { - if(!ports[i]) - { - ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i])); - break; - } - if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i])) - ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]); - } - jack_free(ports); - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success) - { - jack_deactivate(self->Client); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCjackPlayback_stop(ALCjackPlayback *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - - alsem_post(&self->Sem); - althrd_join(self->thread, &res); - - jack_deactivate(self->Client); -} - - -static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ClockLatency ret; - - ALCjackPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->Ring) * DEVICE_CLOCK_RES / - device->Frequency; - ALCjackPlayback_unlock(self); - - return ret; -} - - -static void jack_msg_handler(const char *message) -{ - WARN("%s\n", message); -} - -typedef struct ALCjackBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCjackBackendFactory; -#define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)) -{ - void (*old_error_cb)(const char*); - jack_client_t *client; - jack_status_t status; - - if(!jack_load()) - return ALC_FALSE; - - if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0)) - ClientOptions |= JackNoStartServer; - - old_error_cb = (&jack_error_callback ? jack_error_callback : NULL); - jack_set_error_function(jack_msg_handler); - client = jack_client_open("alsoft", ClientOptions, &status, NULL); - jack_set_error_function(old_error_cb); - if(client == NULL) - { - WARN("jack_client_open() failed, 0x%02x\n", status); - if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer)) - ERR("Unable to connect to JACK server\n"); - return ALC_FALSE; - } - - jack_client_close(client); - return ALC_TRUE; -} - -static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self)) -{ -#ifdef HAVE_DYNLOAD - if(jack_handle) - CloseLib(jack_handle); - jack_handle = NULL; -#endif -} - -static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - alstr_append_range(outnames, jackDevice, jackDevice+sizeof(jackDevice)); - break; - - case CAPTURE_DEVICE_PROBE: - break; - } -} - -static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCjackPlayback *backend; - NEW_OBJ(backend, ALCjackPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory); - - -ALCbackendFactory *ALCjackBackendFactory_getFactory(void) -{ - static ALCjackBackendFactory factory = ALCJACKBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} |