Add a skeleton backend for JACK
[openal-soft.git] / Alc / backends / jack.c
blobbb7054fef9546fc63954161b548f9603cdcc59c7
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "threads.h"
30 #include "compat.h"
32 #include "backends/base.h"
34 #include <jack/jack.h>
35 #include <jack/ringbuffer.h>
38 static const ALCchar jackDevice[] = "JACK Default";
41 #ifdef HAVE_DYNLOAD
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);
48 static void *jack_handle;
49 #define MAKE_FUNC(f) static __typeof(f) * p##f
50 JACK_FUNCS(MAKE_FUNC);
51 #undef MAKE_FUNC
53 #define jack_client_open pjack_client_open
54 #define jack_client_close pjack_client_close
55 #define jack_client_name_size pjack_client_name_size
56 #define jack_get_client_name pjack_get_client_name
57 #endif
60 static ALCboolean jack_load(void)
62 ALCboolean error = ALC_FALSE;
64 #ifdef HAVE_DYNLOAD
65 if(!jack_handle)
67 jack_handle = LoadLib("libjack.so.0");
68 if(!jack_handle)
69 return ALC_FALSE;
71 error = ALC_FALSE;
72 #define LOAD_FUNC(f) do { \
73 p##f = GetSymbol(jack_handle, #f); \
74 if(p##f == NULL) { \
75 error = ALC_TRUE; \
76 } \
77 } while(0)
78 JACK_FUNCS(LOAD_FUNC);
79 #undef LOAD_FUNC
81 if(error)
83 CloseLib(jack_handle);
84 jack_handle = NULL;
85 return ALC_FALSE;
88 #endif
90 return !error;
94 typedef struct ALCjackPlayback {
95 DERIVE_FROM_TYPE(ALCbackend);
97 jack_client_t *Client;
99 volatile int killNow;
100 althrd_t thread;
101 } ALCjackPlayback;
103 static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device);
104 static void ALCjackPlayback_Destruct(ALCjackPlayback *self);
105 static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name);
106 static void ALCjackPlayback_close(ALCjackPlayback *self);
107 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self);
108 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self);
109 static void ALCjackPlayback_stop(ALCjackPlayback *self);
110 static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
111 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples)
112 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALint64, getLatency)
113 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock)
114 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock)
115 DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback)
117 DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback);
120 static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device)
122 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
123 SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
125 self->Client = NULL;
126 self->killNow = 1;
129 static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
131 if(self->Client)
132 jack_client_close(self->Client);
133 self->Client = NULL;
135 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
139 static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name)
141 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
143 if(!name)
144 name = jackDevice;
145 else if(strcmp(name, jackDevice) != 0)
146 return ALC_INVALID_VALUE;
149 al_string_copy_cstr(&device->DeviceName, name);
151 return ALC_INVALID_VALUE;
154 static void ALCjackPlayback_close(ALCjackPlayback *UNUSED(self))
158 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *UNUSED(self))
160 //jack_set_process_callback (client, process, &data);
161 return ALC_FALSE;
164 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *UNUSED(self))
166 return ALC_FALSE;
169 static void ALCjackPlayback_stop(ALCjackPlayback *self)
171 int res;
173 if(self->killNow)
174 return;
176 self->killNow = 1;
177 althrd_join(self->thread, &res);
181 typedef struct ALCjackBackendFactory {
182 DERIVE_FROM_TYPE(ALCbackendFactory);
183 } ALCjackBackendFactory;
184 #define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } }
186 static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self))
188 jack_client_t *client;
189 jack_status_t status;
191 if(!jack_load())
192 return ALC_FALSE;
194 client = jack_client_open("alsoft", 0, &status, NULL);
195 if(client == NULL)
197 WARN("jack_client_open() failed, 0x%02x\n", status);
198 if((status&JackServerFailed))
199 ERR("Unable to connect to JACK server\n");
200 return ALC_FALSE;
203 jack_client_close(client);
204 return ALC_TRUE;
207 static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self))
209 #ifdef HAVE_DYNLOAD
210 if(jack_handle)
211 CloseLib(jack_handle);
212 jack_handle = NULL;
213 #endif
216 static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type)
218 if(type == ALCbackend_Playback)
219 return ALC_TRUE;
220 return ALC_FALSE;
223 static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type)
225 switch(type)
227 case ALL_DEVICE_PROBE:
228 AppendAllDevicesList(jackDevice);
229 break;
231 case CAPTURE_DEVICE_PROBE:
232 break;
236 static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
238 if(type == ALCbackend_Playback)
240 ALCjackPlayback *backend;
242 backend = ALCjackPlayback_New(sizeof(*backend));
243 if(!backend) return NULL;
244 memset(backend, 0, sizeof(*backend));
246 ALCjackPlayback_Construct(backend, device);
248 return STATIC_CAST(ALCbackend, backend);
251 return NULL;
254 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory);
257 ALCbackendFactory *ALCjackBackendFactory_getFactory(void)
259 static ALCjackBackendFactory factory = ALCJACKBACKENDFACTORY_INITIALIZER;
260 return STATIC_CAST(ALCbackendFactory, &factory);