diff options
author | Chris Robinson <[email protected]> | 2014-12-21 15:51:16 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2014-12-21 15:51:16 -0800 |
commit | 23197ddbc35db09301b22636ea83e770a7900458 (patch) | |
tree | 05658f2c46fbd72e0222bb0bc32c433d109f7b31 | |
parent | f2d59671b2410b575224b8ebddb89b62d61bf3e2 (diff) |
Add a skeleton backend for JACK
-rw-r--r-- | Alc/ALc.c | 3 | ||||
-rw-r--r-- | Alc/backends/base.h | 1 | ||||
-rw-r--r-- | Alc/backends/jack.c | 261 | ||||
-rw-r--r-- | CMakeLists.txt | 22 | ||||
-rw-r--r-- | config.h.in | 3 |
5 files changed, 290 insertions, 0 deletions
@@ -82,6 +82,9 @@ static struct BackendInfo BackendList[] = { #ifdef HAVE_QSA { "qsa", NULL, alc_qsa_init, alc_qsa_deinit, alc_qsa_probe, EmptyFuncs }, #endif +#ifdef HAVE_JACK + { "jack", ALCjackBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, +#endif #ifdef HAVE_MMDEVAPI { "mmdevapi", ALCmmdevBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 4ed3bfc9..1423268a 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -123,6 +123,7 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ ALCbackendFactory *ALCpulseBackendFactory_getFactory(void); ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); +ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c new file mode 100644 index 00000000..bb7054fe --- /dev/null +++ b/Alc/backends/jack.c @@ -0,0 +1,261 @@ +/** + * 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 "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); + +static void *jack_handle; +#define MAKE_FUNC(f) static __typeof(f) * p##f +JACK_FUNCS(MAKE_FUNC); +#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 +#endif + + +static ALCboolean jack_load(void) +{ + ALCboolean error = ALC_FALSE; + +#ifdef HAVE_DYNLOAD + if(!jack_handle) + { + jack_handle = LoadLib("libjack.so.0"); + if(!jack_handle) + return ALC_FALSE; + + error = ALC_FALSE; +#define LOAD_FUNC(f) do { \ + p##f = GetSymbol(jack_handle, #f); \ + if(p##f == NULL) { \ + error = ALC_TRUE; \ + } \ +} while(0) + JACK_FUNCS(LOAD_FUNC); +#undef LOAD_FUNC + + if(error) + { + CloseLib(jack_handle); + jack_handle = NULL; + return ALC_FALSE; + } + } +#endif + + return !error; +} + + +typedef struct ALCjackPlayback { + DERIVE_FROM_TYPE(ALCbackend); + + jack_client_t *Client; + + volatile int killNow; + althrd_t thread; +} ALCjackPlayback; + +static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); +static void ALCjackPlayback_Destruct(ALCjackPlayback *self); +static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); +static void ALCjackPlayback_close(ALCjackPlayback *self); +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 DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALint64, getLatency) +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) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCjackPlayback, ALCbackend, self); + + self->Client = NULL; + self->killNow = 1; +} + +static void ALCjackPlayback_Destruct(ALCjackPlayback *self) +{ + if(self->Client) + jack_client_close(self->Client); + self->Client = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + if(!name) + name = jackDevice; + else if(strcmp(name, jackDevice) != 0) + return ALC_INVALID_VALUE; + + + al_string_copy_cstr(&device->DeviceName, name); + + return ALC_INVALID_VALUE; +} + +static void ALCjackPlayback_close(ALCjackPlayback *UNUSED(self)) +{ +} + +static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *UNUSED(self)) +{ + //jack_set_process_callback (client, process, &data); + return ALC_FALSE; +} + +static ALCboolean ALCjackPlayback_start(ALCjackPlayback *UNUSED(self)) +{ + return ALC_FALSE; +} + +static void ALCjackPlayback_stop(ALCjackPlayback *self) +{ + int res; + + if(self->killNow) + return; + + self->killNow = 1; + althrd_join(self->thread, &res); +} + + +typedef struct ALCjackBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCjackBackendFactory; +#define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)) +{ + jack_client_t *client; + jack_status_t status; + + if(!jack_load()) + return ALC_FALSE; + + client = jack_client_open("alsoft", 0, &status, NULL); + if(client == NULL) + { + WARN("jack_client_open() failed, 0x%02x\n", status); + if((status&JackServerFailed)) + 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) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(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; + + backend = ALCjackPlayback_New(sizeof(*backend)); + if(!backend) return NULL; + memset(backend, 0, sizeof(*backend)); + + ALCjackPlayback_Construct(backend, device); + + 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); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index c4d4286c..80bcadb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -913,6 +913,25 @@ IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO) MESSAGE(FATAL_ERROR "Failed to enabled required PulseAudio backend") ENDIF() +# Check JACK backend +OPTION(ALSOFT_REQUIRE_JACK "Require JACK backend" OFF) +FIND_PACKAGE(JACK) +IF(JACK_FOUND) + OPTION(ALSOFT_BACKEND_JACK "Enable JACK backend" ON) + IF(ALSOFT_BACKEND_JACK) + SET(HAVE_JACK 1) + SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c) + ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) + IF(CMAKE_VERSION VERSION_LESS "2.8.8") + INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS}) + ENDIF() + ENDIF() +ENDIF() +IF(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK) + MESSAGE(FATAL_ERROR "Failed to enabled required JACK backend") +ENDIF() + # Check CoreAudio backend OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF) FIND_LIBRARY(COREAUDIO_FRAMEWORK @@ -1059,6 +1078,9 @@ ENDIF() IF(HAVE_PULSEAUDIO) SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() +IF(HAVE_JACK) + SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) +ENDIF() SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION}) IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") diff --git a/config.h.in b/config.h.in index af0d8bfd..f999eb49 100644 --- a/config.h.in +++ b/config.h.in @@ -64,6 +64,9 @@ /* Define if we have the PulseAudio backend */ #cmakedefine HAVE_PULSEAUDIO +/* Define if we have the JACK backend */ +#cmakedefine HAVE_JACK + /* Define if we have the CoreAudio backend */ #cmakedefine HAVE_COREAUDIO |