summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/JackAPI.cpp1114
-rw-r--r--common/JackActivationCount.cpp43
-rw-r--r--common/JackActivationCount.h83
-rw-r--r--common/JackAtomic.h197
-rw-r--r--common/JackAtomicArrayState.h235
-rw-r--r--common/JackAtomicState.h240
-rw-r--r--common/JackAudioDriver.cpp229
-rw-r--r--common/JackAudioDriver.h88
-rw-r--r--common/JackChannel.h210
-rw-r--r--common/JackChannelTransaction.h48
-rw-r--r--common/JackClient.cpp767
-rw-r--r--common/JackClient.h162
-rw-r--r--common/JackClientControl.h76
-rw-r--r--common/JackClientInterface.h56
-rw-r--r--common/JackConnectionManager.cpp452
-rw-r--r--common/JackConnectionManager.h468
-rw-r--r--common/JackConstants.h64
-rw-r--r--common/JackDebugClient.cpp457
-rw-r--r--common/JackDebugClient.h127
-rw-r--r--common/JackDriver.cpp204
-rw-r--r--common/JackDriver.h215
-rw-r--r--common/JackDriverLoader.cpp498
-rw-r--r--common/JackDriverLoader.h66
-rw-r--r--common/JackDummyDriver.cpp224
-rw-r--r--common/JackDummyDriver.h68
-rw-r--r--common/JackEngine.cpp644
-rw-r--r--common/JackEngine.h119
-rw-r--r--common/JackEngineControl.h58
-rw-r--r--common/JackEngineTiming.cpp229
-rw-r--r--common/JackEngineTiming.h105
-rw-r--r--common/JackError.c48
-rw-r--r--common/JackError.h48
-rw-r--r--common/JackExports.h30
-rw-r--r--common/JackExternalClient.cpp83
-rw-r--r--common/JackExternalClient.h60
-rwxr-xr-xcommon/JackFifo.cpp209
-rwxr-xr-xcommon/JackFifo.h73
-rw-r--r--common/JackFrameTimer.cpp109
-rw-r--r--common/JackFrameTimer.h81
-rw-r--r--common/JackFreewheelDriver.cpp47
-rw-r--r--common/JackFreewheelDriver.h54
-rw-r--r--common/JackGlobals.cpp28
-rw-r--r--common/JackGlobals.h282
-rw-r--r--common/JackGlobalsClient.cpp460
-rw-r--r--common/JackGlobalsServer.cpp460
-rw-r--r--common/JackGraphManager.cpp777
-rw-r--r--common/JackGraphManager.h121
-rw-r--r--common/JackInternalClient.cpp105
-rw-r--r--common/JackInternalClient.h60
-rw-r--r--common/JackInternalClientChannel.h116
-rw-r--r--common/JackLibAPI.cpp133
-rw-r--r--common/JackLibClient.cpp162
-rw-r--r--common/JackLibClient.h60
-rw-r--r--common/JackLibGlobals.h97
-rw-r--r--common/JackLoopbackDriver.cpp209
-rw-r--r--common/JackLoopbackDriver.h63
-rw-r--r--common/JackPort.cpp229
-rw-r--r--common/JackPort.h98
-rw-r--r--common/JackPosixSemaphore.cpp205
-rw-r--r--common/JackPosixSemaphore.h71
-rw-r--r--common/JackPosixThread.cpp209
-rw-r--r--common/JackPosixThread.h73
-rw-r--r--common/JackProcessSync.h180
-rw-r--r--common/JackPthreadCond.cpp207
-rw-r--r--common/JackPthreadCond.h133
-rw-r--r--common/JackRequest.h612
-rw-r--r--common/JackServer.cpp339
-rw-r--r--common/JackServer.h96
-rw-r--r--common/JackServerAPI.cpp174
-rw-r--r--common/JackServerGlobals.cpp389
-rw-r--r--common/JackServerGlobals.h58
-rw-r--r--common/JackShmMem.cpp92
-rw-r--r--common/JackShmMem.h308
-rw-r--r--common/JackSocket.cpp312
-rw-r--r--common/JackSocket.h104
-rw-r--r--common/JackSocketClientChannel.cpp264
-rw-r--r--common/JackSocketClientChannel.h89
-rw-r--r--common/JackSocketNotifyChannel.cpp79
-rw-r--r--common/JackSocketNotifyChannel.h56
-rw-r--r--common/JackSocketServerChannel.cpp375
-rw-r--r--common/JackSocketServerChannel.h70
-rw-r--r--common/JackSocketServerNotifyChannel.cpp59
-rw-r--r--common/JackSocketServerNotifyChannel.h55
-rw-r--r--common/JackSyncInterface.h51
-rw-r--r--common/JackSynchro.h102
-rw-r--r--common/JackThread.h97
-rw-r--r--common/JackThreadedDriver.cpp89
-rw-r--r--common/JackThreadedDriver.h154
-rw-r--r--common/JackTime.c121
-rw-r--r--common/JackTime.h111
-rw-r--r--common/JackTransportEngine.cpp259
-rw-r--r--common/JackTransportEngine.h137
-rw-r--r--common/JackTypes.h36
-rw-r--r--common/Jackdmp.cpp569
-rw-r--r--common/cycles.h94
-rw-r--r--common/driver_interface.h97
-rw-r--r--common/driver_parse.h33
-rw-r--r--common/intclient.h132
-rw-r--r--common/jack.h805
-rw-r--r--common/jslist.h287
-rw-r--r--common/patest_sine.c151
-rw-r--r--common/ringbuffer.c359
-rw-r--r--common/ringbuffer.h235
-rw-r--r--common/shm.c1182
-rw-r--r--common/shm.h156
-rw-r--r--common/statistics.h59
-rw-r--r--common/thread.h92
-rw-r--r--common/transport.h430
-rw-r--r--common/transport_types.h223
-rw-r--r--common/types.h395
-rw-r--r--common/varargs.h71
111 files changed, 22984 insertions, 0 deletions
diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp
new file mode 100644
index 00000000..705a112b
--- /dev/null
+++ b/common/JackAPI.cpp
@@ -0,0 +1,1114 @@
+/*
+Copyright (C) 2001-2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackClient.h"
+#include "JackError.h"
+#include "JackGraphManager.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include "JackGlobals.h"
+#include "JackTime.h"
+#include "JackExports.h"
+#include <math.h>
+
+using namespace Jack;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ EXPORT int jack_client_name_size (void);
+ EXPORT char* jack_get_client_name (jack_client_t *client);
+ EXPORT int jack_internal_client_new (const char *client_name,
+ const char *load_name,
+ const char *load_init);
+ EXPORT jack_client_t* my_jack_internal_client_new(const char* client_name);
+ EXPORT void jack_internal_client_close (const char *client_name);
+ EXPORT void my_jack_internal_client_close (jack_client_t* client);
+ EXPORT int jack_is_realtime (jack_client_t *client);
+ EXPORT void jack_on_shutdown (jack_client_t *client,
+ void (*function)(void *arg), void *arg);
+ EXPORT int jack_set_process_callback (jack_client_t *client,
+ JackProcessCallback process_callback,
+ void *arg);
+ EXPORT int jack_set_thread_init_callback (jack_client_t *client,
+ JackThreadInitCallback thread_init_callback,
+ void *arg);
+ EXPORT int jack_set_freewheel_callback (jack_client_t *client,
+ JackFreewheelCallback freewheel_callback,
+ void *arg);
+ EXPORT int jack_set_freewheel(jack_client_t* client, int onoff);
+ EXPORT int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes);
+ EXPORT int jack_set_buffer_size_callback (jack_client_t *client,
+ JackBufferSizeCallback bufsize_callback,
+ void *arg);
+ EXPORT int jack_set_sample_rate_callback (jack_client_t *client,
+ JackSampleRateCallback srate_callback,
+ void *arg);
+ EXPORT int jack_set_port_registration_callback (jack_client_t *,
+ JackPortRegistrationCallback
+ registration_callback, void *arg);
+ EXPORT int jack_set_graph_order_callback (jack_client_t *,
+ JackGraphOrderCallback graph_callback,
+ void *);
+ EXPORT int jack_set_xrun_callback (jack_client_t *,
+ JackXRunCallback xrun_callback, void *arg);
+ EXPORT int jack_activate (jack_client_t *client);
+ EXPORT int jack_deactivate (jack_client_t *client);
+ EXPORT jack_port_t * jack_port_register (jack_client_t *client,
+ const char *port_name,
+ const char *port_type,
+ unsigned long flags,
+ unsigned long buffer_size);
+ EXPORT int jack_port_unregister (jack_client_t *, jack_port_t *);
+ EXPORT void * jack_port_get_buffer (jack_port_t *, jack_nframes_t);
+ EXPORT const char * jack_port_name (const jack_port_t *port);
+ EXPORT const char * jack_port_short_name (const jack_port_t *port);
+ EXPORT int jack_port_flags (const jack_port_t *port);
+ EXPORT const char * jack_port_type (const jack_port_t *port);
+ EXPORT int jack_port_is_mine (const jack_client_t *, const jack_port_t *port);
+ EXPORT int jack_port_connected (const jack_port_t *port);
+ EXPORT int jack_port_connected_to (const jack_port_t *port,
+ const char *port_name);
+ EXPORT const char ** jack_port_get_connections (const jack_port_t *port);
+ EXPORT const char ** jack_port_get_all_connections (const jack_client_t *client,
+ const jack_port_t *port);
+ EXPORT int jack_port_tie (jack_port_t *src, jack_port_t *dst);
+ EXPORT int jack_port_untie (jack_port_t *port);
+ EXPORT int jack_port_lock (jack_client_t *, jack_port_t *);
+ EXPORT int jack_port_unlock (jack_client_t *, jack_port_t *);
+ EXPORT jack_nframes_t jack_port_get_latency (jack_port_t *port);
+ EXPORT jack_nframes_t jack_port_get_total_latency (jack_client_t *,
+ jack_port_t *port);
+ EXPORT void jack_port_set_latency (jack_port_t *, jack_nframes_t);
+ EXPORT int jack_recompute_total_latencies (jack_client_t*);
+ EXPORT int jack_port_set_name (jack_port_t *port, const char *port_name);
+ EXPORT int jack_port_request_monitor (jack_port_t *port, int onoff);
+ EXPORT int jack_port_request_monitor_by_name (jack_client_t *client,
+ const char *port_name, int onoff);
+ EXPORT int jack_port_ensure_monitor (jack_port_t *port, int onoff);
+ EXPORT int jack_port_monitoring_input (jack_port_t *port);
+ EXPORT int jack_connect (jack_client_t *,
+ const char *source_port,
+ const char *destination_port);
+ EXPORT int jack_disconnect (jack_client_t *,
+ const char *source_port,
+ const char *destination_port);
+ EXPORT int jack_port_disconnect (jack_client_t *, jack_port_t *);
+ EXPORT int jack_port_name_size(void);
+ EXPORT int jack_port_type_size(void);
+ EXPORT jack_nframes_t jack_get_sample_rate (jack_client_t *);
+ EXPORT jack_nframes_t jack_get_buffer_size (jack_client_t *);
+ EXPORT const char ** jack_get_ports (jack_client_t *,
+ const char *port_name_pattern,
+ const char *type_name_pattern,
+ unsigned long flags);
+ EXPORT jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name);
+ EXPORT jack_port_t * jack_port_by_id (jack_client_t *client,
+ jack_port_id_t port_id);
+ EXPORT int jack_engine_takeover_timebase (jack_client_t *);
+ EXPORT jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *);
+ EXPORT jack_nframes_t jack_frame_time (const jack_client_t *);
+ EXPORT jack_nframes_t jack_last_frame_time (const jack_client_t *client);
+ EXPORT float jack_cpu_load (jack_client_t *client);
+ EXPORT pthread_t jack_client_thread_id (jack_client_t *);
+ EXPORT void jack_set_error_function (void (*func)(const char *));
+
+ EXPORT float jack_get_max_delayed_usecs (jack_client_t *client);
+ EXPORT float jack_get_xrun_delayed_usecs (jack_client_t *client);
+ EXPORT void jack_reset_max_delayed_usecs (jack_client_t *client);
+
+ EXPORT int jack_release_timebase (jack_client_t *client);
+ EXPORT int jack_set_sync_callback (jack_client_t *client,
+ JackSyncCallback sync_callback,
+ void *arg);
+ EXPORT int jack_set_sync_timeout (jack_client_t *client,
+ jack_time_t timeout);
+ EXPORT int jack_set_timebase_callback (jack_client_t *client,
+ int conditional,
+ JackTimebaseCallback timebase_callback,
+ void *arg);
+ EXPORT int jack_transport_locate (jack_client_t *client,
+ jack_nframes_t frame);
+ EXPORT jack_transport_state_t jack_transport_query (const jack_client_t *client,
+ jack_position_t *pos);
+ EXPORT jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client);
+ EXPORT int jack_transport_reposition (jack_client_t *client,
+ jack_position_t *pos);
+ EXPORT void jack_transport_start (jack_client_t *client);
+ EXPORT void jack_transport_stop (jack_client_t *client);
+ EXPORT void jack_get_transport_info (jack_client_t *client,
+ jack_transport_info_t *tinfo);
+ EXPORT void jack_set_transport_info (jack_client_t *client,
+ jack_transport_info_t *tinfo);
+
+ EXPORT int jack_acquire_real_time_scheduling (pthread_t thread, int priority);
+ EXPORT int jack_client_create_thread (jack_client_t* client,
+ pthread_t *thread,
+ int priority,
+ int realtime, // boolean
+ void *(*start_routine)(void*),
+ void *arg);
+ EXPORT int jack_drop_real_time_scheduling (pthread_t thread);
+
+ EXPORT char * jack_get_internal_client_name (jack_client_t *client,
+ jack_intclient_t intclient);
+ EXPORT jack_intclient_t jack_internal_client_handle (jack_client_t *client,
+ const char *client_name,
+ jack_status_t *status);
+ EXPORT jack_intclient_t jack_internal_client_load (jack_client_t *client,
+ const char *client_name,
+ jack_options_t options,
+ jack_status_t *status, ...);
+ EXPORT jack_status_t jack_internal_client_unload (jack_client_t *client,
+ jack_intclient_t intclient);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef WIN32
+/* missing on Windows : see http://bugs.mysql.com/bug.php?id=15936 */
+inline double rint(double nr)
+{
+ double f = floor(nr);
+ double c = ceil(nr);
+ return (((c -nr) >= (nr - f)) ? f : c);
+}
+#endif
+
+static inline bool CheckPort(jack_port_id_t port_index)
+{
+ return (port_index < PORT_NUM);
+}
+
+static inline void WaitGraphChange()
+{
+ if (GetGraphManager()->IsPendingChange()) {
+ JackLog("WaitGraphChange...\n");
+ JackSleep(GetEngineControl()->fPeriodUsecs * 2);
+ }
+}
+
+static void default_jack_error_callback (const char *desc)
+{
+ fprintf(stderr, "%s\n", desc);
+}
+
+void (*jack_error_callback)(const char *desc) = &default_jack_error_callback;
+
+EXPORT void jack_set_error_function (void (*func)(const char *))
+{
+ jack_error_callback = func;
+}
+
+EXPORT void* jack_port_get_buffer(jack_port_t* port, jack_nframes_t frames)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_get_buffer called with an incorrect port %ld", myport);
+ return NULL;
+ } else {
+ return GetGraphManager()->GetBuffer(myport, frames);
+ }
+}
+
+EXPORT const char* jack_port_name(const jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_name called with an incorrect port %ld", myport);
+ return NULL;
+ } else {
+ return GetGraphManager()->GetPort(myport)->GetName();
+ }
+}
+
+EXPORT const char* jack_port_short_name(const jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_short_name called with an incorrect port %ld", myport);
+ return NULL;
+ } else {
+ return GetGraphManager()->GetPort(myport)->GetShortName();
+ }
+}
+
+EXPORT int jack_port_flags(const jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_flags called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return GetGraphManager()->GetPort(myport)->Flags();
+ }
+}
+
+EXPORT const char* jack_port_type(const jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_flags called an incorrect port %ld", myport);
+ return NULL;
+ } else {
+ return GetGraphManager()->GetPort(myport)->Type();
+ }
+}
+
+EXPORT int jack_port_connected(const jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_connected called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ WaitGraphChange();
+ return GetGraphManager()->GetConnectionsNum(myport);
+ }
+}
+
+EXPORT int jack_port_connected_to(const jack_port_t* port, const char* portname)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_connected_to called with an incorrect port %ld", myport);
+ return -1;
+ } else if (portname == NULL) {
+ jack_error("jack_port_connected_to called with a NULL port name");
+ return -1;
+ } else {
+ WaitGraphChange();
+ return GetGraphManager()->ConnectedTo(myport, portname);
+ }
+}
+
+EXPORT int jack_port_tie(jack_port_t* src, jack_port_t* dst)
+{
+ jack_port_id_t mysrc = (jack_port_id_t)src;
+ if (!CheckPort(mysrc)) {
+ jack_error("jack_port_tie called with a NULL src port");
+ return -1;
+ }
+ jack_port_id_t mydst = (jack_port_id_t)dst;
+ if (!CheckPort(mydst)) {
+ jack_error("jack_port_tie called with a NULL dst port");
+ return -1;
+ }
+ if (GetGraphManager()->GetPort(mysrc)->GetRefNum() != GetGraphManager()->GetPort(mydst)->GetRefNum()) {
+ jack_error("jack_port_tie called with ports not belonging to the same client");
+ return -1;
+ }
+ return GetGraphManager()->GetPort(mydst)->Tie(mysrc);
+}
+
+EXPORT int jack_port_untie(jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_untie called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return GetGraphManager()->GetPort(myport)->UnTie();
+ }
+}
+
+EXPORT jack_nframes_t jack_port_get_latency(jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_get_latency called with an incorrect port %ld", myport);
+ return 0;
+ } else {
+ WaitGraphChange();
+ return GetGraphManager()->GetPort(myport)->GetLatency();
+ }
+}
+
+EXPORT void jack_port_set_latency(jack_port_t* port, jack_nframes_t frames)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_set_latency called with an incorrect port %ld", myport);
+ } else {
+ GetGraphManager()->GetPort(myport)->SetLatency(frames);
+ }
+}
+
+EXPORT int jack_recompute_total_latencies(jack_client_t* ext_client)
+{
+ // The latency computation is done each time jack_port_get_total_latency is called
+ return 0;
+}
+
+EXPORT int jack_port_set_name(jack_port_t* port, const char* name)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_set_name called with an incorrect port %ld", myport);
+ return -1;
+ } else if (name == NULL) {
+ jack_error("jack_port_set_name called with a NULL port name");
+ return -1;
+ } else {
+ return GetGraphManager()->GetPort(myport)->SetName(name);
+ }
+}
+
+EXPORT int jack_port_request_monitor(jack_port_t* port, int onoff)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_request_monitor called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return GetGraphManager()->RequestMonitor(myport, onoff);
+ }
+}
+
+EXPORT int jack_port_request_monitor_by_name(jack_client_t* ext_client, const char* port_name, int onoff)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_request_monitor_by_name called with a NULL client");
+ return -1;
+ } else {
+ jack_port_id_t myport = GetGraphManager()->GetPort(port_name);
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_request_monitor_by_name called with an incorrect port %s", port_name);
+ return -1;
+ } else {
+ return GetGraphManager()->RequestMonitor(myport, onoff);
+ }
+ }
+}
+
+EXPORT int jack_port_ensure_monitor(jack_port_t* port, int onoff)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_ensure_monitor called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return GetGraphManager()->GetPort(myport)->EnsureMonitor(onoff);
+ }
+}
+
+EXPORT int jack_port_monitoring_input(jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_monitoring_input called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return GetGraphManager()->GetPort(myport)->MonitoringInput();
+ }
+}
+
+EXPORT int jack_is_realtime(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_is_realtime called with a NULL client");
+ return -1;
+ } else {
+ return GetEngineControl()->fRealTime;
+ }
+}
+
+EXPORT void jack_on_shutdown(jack_client_t* ext_client, void (*function)(void* arg), void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_on_shutdown called with a NULL client");
+ } else {
+ client->OnShutdown(function, arg);
+ }
+}
+
+EXPORT int jack_set_process_callback(jack_client_t* ext_client, JackProcessCallback callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_process_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetProcessCallback(callback, arg);
+ }
+}
+
+EXPORT int jack_set_freewheel_callback(jack_client_t* ext_client, JackFreewheelCallback freewheel_callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_freewheel_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetFreewheelCallback(freewheel_callback, arg);
+ }
+}
+
+EXPORT int jack_set_freewheel(jack_client_t* ext_client, int onoff)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_freewheel called with a NULL client");
+ return -1;
+ } else {
+ return client->SetFreeWheel(onoff);
+ }
+}
+
+EXPORT int jack_set_buffer_size(jack_client_t* ext_client, jack_nframes_t nframes)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_buffer_size called with a NULL client");
+ return -1;
+ } else {
+ return client->SetBufferSize(nframes);
+ }
+}
+
+EXPORT int jack_set_buffer_size_callback(jack_client_t* ext_client, JackBufferSizeCallback bufsize_callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_buffer_size_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetBufferSizeCallback(bufsize_callback, arg);
+ }
+}
+
+EXPORT int jack_set_sample_rate_callback(jack_client_t* ext_client, JackSampleRateCallback srate_callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ JackLog("jack_set_sample_rate_callback ext_client %x client %x \n", ext_client, client);
+ if (client == NULL) {
+ jack_error("jack_set_sample_rate_callback called with a NULL client");
+ return -1;
+ } else {
+ JackLog("jack_set_sample_rate_callback: deprecated\n");
+ return -1;
+ }
+}
+
+EXPORT int jack_set_port_registration_callback(jack_client_t* ext_client, JackPortRegistrationCallback registration_callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_port_registration_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetPortRegistrationCallback(registration_callback, arg);
+ }
+}
+
+EXPORT int jack_set_graph_order_callback(jack_client_t* ext_client, JackGraphOrderCallback graph_callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ JackLog("jack_set_graph_order_callback ext_client %x client %x \n", ext_client, client);
+ if (client == NULL) {
+ jack_error("jack_set_graph_order_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetGraphOrderCallback(graph_callback, arg);
+ }
+}
+
+EXPORT int jack_set_xrun_callback(jack_client_t* ext_client, JackXRunCallback callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_xrun_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetXRunCallback(callback, arg);
+ }
+}
+
+EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback callback, void *arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ JackLog("jack_set_thread_init_callback ext_client %x client %x \n", ext_client, client);
+ if (client == NULL) {
+ jack_error("jack_set_thread_init_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetInitCallback(callback, arg);
+ }
+}
+
+EXPORT int jack_activate(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_activate called with a NULL client");
+ return -1;
+ } else {
+ return client->Activate();
+ }
+}
+
+EXPORT int jack_deactivate(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_deactivate called with a NULL client");
+ return -1;
+ } else {
+ return client->Deactivate();
+ }
+}
+
+EXPORT jack_port_t* jack_port_register(jack_client_t* ext_client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_register called with a NULL client");
+ return NULL;
+ } else if ((port_name == NULL) || (port_type == NULL)) {
+ jack_error("jack_port_register called with a NULL port name or a NULL port_type");
+ return NULL;
+ } else {
+ return (jack_port_t *)client->PortRegister(port_name, port_type, flags, buffer_size);
+ }
+}
+
+EXPORT int jack_port_unregister(jack_client_t* ext_client, jack_port_t* port)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_unregister called with a NULL client");
+ return -1;
+ }
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_unregister called with an incorrect port %ld", myport);
+ return -1;
+ }
+ return client->PortUnRegister(myport);
+}
+
+EXPORT int jack_port_is_mine(const jack_client_t* ext_client, const jack_port_t* port)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_is_mine called with a NULL client");
+ return -1;
+ }
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_is_mine called with an incorrect port %ld", myport);
+ return -1;
+ }
+ return client->PortIsMine(myport);
+}
+
+EXPORT const char** jack_port_get_connections(const jack_port_t* port)
+{
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_get_connections called with an incorrect port %ld", myport);
+ return NULL;
+ } else {
+ WaitGraphChange();
+ return GetGraphManager()->GetConnections(myport);
+ }
+}
+
+// Calling client does not need to "own" the port
+EXPORT const char** jack_port_get_all_connections(const jack_client_t* ext_client, const jack_port_t* port)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_get_all_connections called with a NULL client");
+ return NULL;
+ }
+
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_get_all_connections called with an incorrect port %ld", myport);
+ return NULL;
+ } else {
+ WaitGraphChange();
+ return GetGraphManager()->GetConnections(myport);
+ }
+}
+
+// Does not use the client parameter
+EXPORT int jack_port_lock(jack_client_t* ext_client, jack_port_t* port)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_lock called with a NULL client");
+ return -1;
+ }
+
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_lock called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return (myport && client->PortIsMine(myport)) ? GetGraphManager()->GetPort(myport)->Lock() : -1;
+ }
+}
+
+// Does not use the client parameter
+EXPORT int jack_port_unlock(jack_client_t* ext_client, jack_port_t* port)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_unlock called with a NULL client");
+ return -1;
+ }
+
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_unlock called with an incorrect port %ld", myport);
+ return -1;
+ } else {
+ return (myport && client->PortIsMine(myport)) ? GetGraphManager()->GetPort(myport)->Unlock() : -1;
+ }
+}
+
+EXPORT jack_nframes_t jack_port_get_total_latency(jack_client_t* ext_client, jack_port_t* port)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_get_total_latency called with a NULL client");
+ return 0;
+ }
+
+ jack_port_id_t myport = (jack_port_id_t)port;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_get_total_latency called with an incorrect port %ld", myport);
+ return 0;
+ } else {
+ // The latency computation is done each time
+ WaitGraphChange();
+ return GetGraphManager()->GetTotalLatency(myport);
+ }
+}
+
+EXPORT int jack_connect(jack_client_t* ext_client, const char* src, const char* dst)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_connect called with a NULL client");
+ return -1;
+ } else if ((src == NULL) || (dst == NULL)) {
+ jack_error("jack_connect called with a NULL port name");
+ return -1;
+ } else {
+ return client->PortConnect(src, dst);
+ }
+}
+
+EXPORT int jack_disconnect(jack_client_t* ext_client, const char* src, const char* dst)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_disconnect called with a NULL client");
+ return -1;
+ } else if ((src == NULL) || (dst == NULL)) {
+ jack_error("jack_connect called with a NULL port name");
+ return -1;
+ } else {
+ return client->PortDisconnect(src, dst);
+ }
+}
+
+EXPORT int jack_port_connect(jack_client_t* ext_client, jack_port_t* src, jack_port_t* dst)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_connect called with a NULL client");
+ return -1;
+ }
+ jack_port_id_t mysrc = (jack_port_id_t)src;
+ if (!CheckPort(mysrc)) {
+ jack_error("jack_port_connect called with a NULL src port");
+ return -1;
+ }
+ jack_port_id_t mydst = (jack_port_id_t)dst;
+ if (!CheckPort(mydst)) {
+ jack_error("jack_port_connect called with a NULL dst port");
+ return -1;
+ }
+ return client->PortConnect(mysrc, mydst);
+}
+
+EXPORT int jack_port_disconnect(jack_client_t* ext_client, jack_port_t* src)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_port_disconnect called with a NULL client");
+ return -1;
+ }
+ jack_port_id_t myport = (jack_port_id_t)src;
+ if (!CheckPort(myport)) {
+ jack_error("jack_port_disconnect called with an incorrect port %ld", myport);
+ return -1;
+ }
+ return client->PortDisconnect(myport);
+}
+
+EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_get_sample_rate called with a NULL client");
+ return 0;
+ } else {
+ return GetEngineControl()->fSampleRate;
+ }
+}
+
+EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_get_buffer_size called with a NULL client");
+ return 0;
+ } else {
+ return GetEngineControl()->fBufferSize;
+ }
+}
+
+EXPORT const char** jack_get_ports(jack_client_t* ext_client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_get_ports called with a NULL client");
+ return NULL;
+ }
+ return GetGraphManager()->GetPorts(port_name_pattern, type_name_pattern, flags);
+}
+
+EXPORT jack_port_t* jack_port_by_name(jack_client_t* ext_client, const char* portname)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_get_ports called with a NULL client");
+ return 0;
+ }
+
+ if (portname == NULL) {
+ jack_error("jack_port_by_name called with a NULL port name");
+ return NULL;
+ } else {
+ int res = GetGraphManager()->GetPort(portname); // returns a port index at least > 1
+ return (res == NO_PORT) ? NULL : (jack_port_t*)res;
+ }
+}
+
+EXPORT jack_port_t* jack_port_by_id(const jack_client_t* ext_client, jack_port_id_t id)
+{
+ /* jack_port_t* type is actually the port index */
+ return (jack_port_t*)id;
+}
+
+EXPORT int jack_engine_takeover_timebase(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_engine_takeover_timebase called with a NULL client");
+ return -1;
+ } else {
+ jack_error("jack_engine_takeover_timebase : not yet implemented\n");
+ return 0;
+ }
+}
+
+EXPORT jack_nframes_t jack_frames_since_cycle_start(const jack_client_t* ext_client)
+{
+ JackTimer timer;
+ GetEngineControl()->fFrameTimer.ReadFrameTime(&timer);
+ return (jack_nframes_t) floor((((float)GetEngineControl()->fSampleRate) / 1000000.0f) * (GetMicroSeconds() - timer.fCurrentCallback));
+}
+
+EXPORT jack_nframes_t jack_frame_time(const jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_frame_time called with a NULL client");
+ return 0;
+ } else {
+ JackTimer timer;
+ GetEngineControl()->fFrameTimer.ReadFrameTime(&timer);
+ if (timer.fInitialized) {
+ return timer.fFrames +
+ (long) rint(((double) ((jack_time_t)(GetMicroSeconds() - timer.fCurrentWakeup)) /
+ ((jack_time_t)(timer.fNextWakeUp - timer.fCurrentWakeup))) * GetEngineControl()->fBufferSize);
+ } else {
+ return 0;
+ }
+ }
+}
+
+EXPORT jack_nframes_t jack_last_frame_time(const jack_client_t* ext_client)
+{
+ JackTimer timer;
+ GetEngineControl()->fFrameTimer.ReadFrameTime(&timer);
+ return timer.fFrames;
+}
+
+EXPORT float jack_cpu_load(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_cpu_load called with a NULL client");
+ return 0.0f;
+ } else {
+ return GetEngineControl()->fCPULoad;
+ }
+}
+
+pthread_t EXPORT jack_client_thread_id(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_client_thread_id called with a NULL client");
+ return (pthread_t)NULL;
+ } else {
+ return client->GetThreadID();
+ }
+}
+
+EXPORT char* jack_get_client_name (jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_get_client_name called with a NULL client");
+ return NULL;
+ } else {
+ return client->GetClientControl()->fName;
+ }
+}
+
+EXPORT int jack_client_name_size(void)
+{
+ return JACK_CLIENT_NAME_SIZE;
+}
+
+EXPORT int jack_port_name_size(void)
+{
+ return JACK_PORT_NAME_SIZE;
+}
+
+// transport.h
+
+EXPORT int jack_release_timebase(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_release_timebase called with a NULL client");
+ return -1;
+ } else {
+ return client->ReleaseTimebase();
+ }
+}
+
+EXPORT int jack_set_sync_callback(jack_client_t* ext_client, JackSyncCallback sync_callback, void *arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_sync_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetSyncCallback(sync_callback, arg);
+ }
+}
+
+EXPORT int jack_set_sync_timeout(jack_client_t* ext_client, jack_time_t timeout)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_sync_timeout called with a NULL client");
+ return -1;
+ } else {
+ return client->SetSyncTimeout(timeout);
+ }
+}
+
+EXPORT int jack_set_timebase_callback(jack_client_t* ext_client, int conditional, JackTimebaseCallback timebase_callback, void* arg)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_set_timebase_callback called with a NULL client");
+ return -1;
+ } else {
+ return client->SetTimebaseCallback(conditional, timebase_callback, arg);
+ }
+}
+
+EXPORT int jack_transport_locate(jack_client_t* ext_client, jack_nframes_t frame)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_transport_locate called with a NULL client");
+ return -1;
+ } else {
+ return client->TransportLocate(frame);
+ }
+}
+
+EXPORT jack_transport_state_t jack_transport_query(const jack_client_t* ext_client, jack_position_t* pos)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_transport_query called with a NULL client");
+ return JackTransportStopped;
+ } else {
+ return client->TransportQuery(pos);
+ }
+}
+
+EXPORT jack_nframes_t jack_get_current_transport_frame(const jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_get_current_transport_frame called with a NULL client");
+ return 0;
+ } else {
+ return client->GetCurrentTransportFrame();
+ }
+}
+
+EXPORT int jack_transport_reposition(jack_client_t* ext_client, jack_position_t* pos)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_transport_reposition called with a NULL client");
+ return -1;
+ } else {
+ return client->TransportReposition(pos);
+ }
+}
+
+EXPORT void jack_transport_start(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_transport_start called with a NULL client");
+ } else {
+ client->TransportStart();
+ }
+}
+
+EXPORT void jack_transport_stop(jack_client_t* ext_client)
+{
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_transport_stop called with a NULL client");
+ } else {
+ client->TransportStop();
+ }
+}
+
+// deprecated
+
+EXPORT void jack_get_transport_info(jack_client_t* ext_client, jack_transport_info_t* tinfo)
+{
+ JackLog("jack_get_transport_info : deprecated");
+ if (tinfo)
+ memset(tinfo, 0, sizeof(jack_transport_info_t));
+}
+
+EXPORT void jack_set_transport_info(jack_client_t* ext_client, jack_transport_info_t* tinfo)
+{
+ JackLog("jack_set_transport_info : deprecated");
+ if (tinfo)
+ memset(tinfo, 0, sizeof(jack_transport_info_t));
+}
+
+// statistics.h
+
+EXPORT float jack_get_max_delayed_usecs(jack_client_t* client)
+{
+ JackLog("jack_get_max_delayed_usecs: not yet implemented\n");
+ return 0.f;
+}
+
+EXPORT float jack_get_xrun_delayed_usecs(jack_client_t* client)
+{
+ JackLog("jack_get_xrun_delayed_usecs: not yet implemented\n");
+ return 0.f;
+}
+
+EXPORT void jack_reset_max_delayed_usecs(jack_client_t* client)
+{
+ JackLog("jack_reset_max_delayed_usecs: not yet implemented\n");
+}
+
+// thread.h
+
+EXPORT int jack_acquire_real_time_scheduling(pthread_t thread, int priority)
+{
+ JackLog("jack_acquire_real_time_scheduling: not yet implemented\n");
+ return -1;
+}
+
+EXPORT int jack_client_create_thread(jack_client_t* client,
+ pthread_t *thread,
+ int priority,
+ int realtime, /* boolean */
+ void *(*start_routine)(void*),
+ void *arg)
+{
+ JackLog("jack_client_create_thread: not yet implemented\n");
+ return -1;
+}
+
+EXPORT int jack_drop_real_time_scheduling(pthread_t thread)
+{
+ JackLog("jack_drop_real_time_scheduling: not yet implemented\n");
+ return -1;
+}
+
+// intclient.h
+
+EXPORT char* jack_get_internal_client_name(jack_client_t* client, jack_intclient_t intclient)
+{
+ JackLog("jack_get_internal_client_name: not yet implemented\n");
+ return "";
+}
+
+EXPORT jack_intclient_t jack_internal_client_handle(jack_client_t* client, const char* client_name, jack_status_t* status)
+{
+ JackLog("jack_internal_client_handle: not yet implemented\n");
+ return 0;
+}
+
+EXPORT jack_intclient_t jack_internal_client_load(jack_client_t* client, const char* client_name, jack_options_t options, jack_status_t* status, ...)
+{
+ JackLog("jack_internal_client_load: not yet implemented\n");
+ return 0;
+}
+
+EXPORT jack_status_t jack_internal_client_unload(jack_client_t* client, jack_intclient_t intclient)
+{
+ JackLog("jack_internal_client_unload: not yet implemented\n");
+ return JackFailure;
+}
diff --git a/common/JackActivationCount.cpp b/common/JackActivationCount.cpp
new file mode 100644
index 00000000..6823fef5
--- /dev/null
+++ b/common/JackActivationCount.cpp
@@ -0,0 +1,43 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackAtomic.h"
+#include "JackActivationCount.h"
+#include "JackConstants.h"
+#include "JackClientControl.h"
+#include "JackError.h"
+
+namespace Jack
+{
+
+bool JackActivationCount::Signal(JackSynchro* synchro, JackClientControl* control)
+{
+ if (fValue == 0) {
+ // Transfer activation to next clients
+ jack_error("JackActivationCount::Signal value = 0 ref = %ld", control->fRefNum);
+ return synchro->Signal();
+ } else if (DEC_ATOMIC(&fValue) == 1) {
+ return synchro->Signal();
+ } else {
+ return true;
+ }
+}
+
+} // end of namespace
+
diff --git a/common/JackActivationCount.h b/common/JackActivationCount.h
new file mode 100644
index 00000000..6c72357c
--- /dev/null
+++ b/common/JackActivationCount.h
@@ -0,0 +1,83 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackActivationCount__
+#define __JackActivationCount__
+
+#include "JackSynchro.h"
+#include "JackTime.h"
+
+namespace Jack
+{
+
+struct JackClientControl;
+
+/*!
+\brief Client activation counter.
+*/
+
+class JackActivationCount
+{
+
+ private:
+
+ long fValue;
+ long fCount;
+
+ public:
+
+ JackActivationCount(): fValue(0), fCount(0)
+ {}
+ virtual ~JackActivationCount()
+ {}
+
+ bool Signal(JackSynchro* synchro, JackClientControl* control);
+
+ inline void Reset()
+ {
+ fValue = fCount;
+ }
+
+ inline void SetValue(int val)
+ {
+ fCount = val;
+ }
+
+ inline void IncValue()
+ {
+ fCount++;
+ }
+
+ inline void DecValue()
+ {
+ fCount--;
+ }
+
+ inline int GetValue() const
+ {
+ return fValue;
+ }
+
+};
+
+} // end of namespace
+
+
+#endif
+
diff --git a/common/JackAtomic.h b/common/JackAtomic.h
new file mode 100644
index 00000000..54ac8dc4
--- /dev/null
+++ b/common/JackAtomic.h
@@ -0,0 +1,197 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackAtomic__
+#define __JackAtomic__
+
+typedef unsigned short UInt16;
+typedef unsigned long UInt32;
+typedef long SInt32;
+#ifdef WIN32
+ #include <windows.h>
+
+typedef ULONGLONG UInt64;
+#else
+
+typedef unsigned long long UInt64;
+#endif
+
+#if defined(__APPLE__)
+
+#if defined(__ppc__)
+
+static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr)
+{
+ register int result;
+ asm volatile (
+ "# CAS \n"
+ " lwarx r0, 0, %1 \n" // creates a reservation on addr
+ " cmpw r0, %2 \n" // test value at addr
+ " bne- 1f \n"
+ " sync \n" // synchronize instructions
+ " stwcx. %3, 0, %1 \n" // if the reservation is not altered
+ // stores the new value at addr
+ " bne- 1f \n"
+ " li %0, 1 \n"
+ " b 2f \n"
+ "1: \n"
+ " li %0, 0 \n"
+ "2: \n"
+ : "=r" (result)
+ : "r" (addr), "r" (value), "r" (newvalue)
+ : "r0"
+ );
+ return result;
+}
+
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifdef __SMP__
+# define LOCK "lock ; "
+#else
+# define LOCK ""
+#endif
+
+static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
+{
+ register char ret;
+ __asm__ __volatile__ (
+ "# CAS \n\t"
+ LOCK "cmpxchg %2, (%1) \n\t"
+ "sete %0 \n\t"
+ : "=a" (ret)
+ : "c" (addr), "d" (newvalue), "a" (value)
+ );
+ return ret;
+}
+
+#endif
+
+#endif
+
+#ifdef __linux__
+
+#ifdef __PPC__
+
+static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr)
+{
+ register int result;
+ register UInt32 tmp;
+ asm volatile (
+ "# CAS \n"
+ " lwarx %4, 0, %1 \n" // creates a reservation on addr
+ " cmpw %4, %2 \n" // test value at addr
+ " bne- 1f \n"
+ " sync \n" // synchronize instructions
+ " stwcx. %3, 0, %1 \n" // if the reservation is not altered
+ // stores the new value at addr
+ " bne- 1f \n"
+ " li %0, 1 \n"
+ " b 2f \n"
+ "1: \n"
+ " li %0, 0 \n"
+ "2: \n"
+ : "=r" (result)
+ : "r" (addr), "r" (value), "r" (newvalue), "r" (tmp)
+ );
+ return result;
+}
+
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifdef __SMP__
+# define LOCK "lock ; "
+#else
+# define LOCK ""
+#endif
+
+static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
+{
+ register char ret;
+ __asm__ __volatile__ (
+ "# CAS \n\t"
+ LOCK "cmpxchg %2, (%1) \n\t"
+ "sete %0 \n\t"
+ : "=a" (ret)
+ : "c" (addr), "d" (newvalue), "a" (value)
+ );
+ return ret;
+}
+
+#endif
+
+#endif
+
+#ifdef WIN32
+
+#ifdef __SMP__
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+#define inline __inline
+
+//----------------------------------------------------------------
+// CAS functions
+//----------------------------------------------------------------
+inline char CAS (volatile UInt32 value, UInt32 newvalue, volatile void * addr)
+{
+ register char c;
+ __asm {
+ push ebx
+ push esi
+ mov esi, addr
+ mov eax, value
+ mov ebx, newvalue
+ LOCK cmpxchg dword ptr [esi], ebx
+ sete c
+ pop esi
+ pop ebx
+ }
+ return c;
+}
+
+#endif
+
+static inline long INC_ATOMIC(volatile SInt32* val)
+{
+ SInt32 actual;
+ do {
+ actual = *val;
+ } while (!CAS(actual, actual + 1, val));
+ return actual;
+}
+
+static inline long DEC_ATOMIC(volatile SInt32* val)
+{
+ SInt32 actual;
+ do {
+ actual = *val;
+ } while (!CAS(actual, actual - 1, val));
+ return actual;
+}
+
+#endif
+
+
diff --git a/common/JackAtomicArrayState.h b/common/JackAtomicArrayState.h
new file mode 100644
index 00000000..7ef69701
--- /dev/null
+++ b/common/JackAtomicArrayState.h
@@ -0,0 +1,235 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackAtomicArrayState__
+#define __JackAtomicArrayState__
+
+#include "JackAtomic.h"
+#include "JackError.h"
+#include <string.h> // for memcpy
+
+namespace Jack
+{
+
+/*!
+\brief Counter for CAS
+*/
+
+struct AtomicArrayCounter
+{
+ union {
+ struct {
+ unsigned char fByteVal[4];
+ }
+ scounter;
+ UInt32 fLongVal;
+ }info;
+
+ AtomicArrayCounter& operator=(volatile AtomicArrayCounter& obj)
+ {
+ info.fLongVal = obj.info.fLongVal;
+ return *this;
+ }
+};
+
+#define Counter1(e) (e).info.fLongVal
+#define GetIndex1(e, state) ((e).info.scounter.fByteVal[state])
+#define SetIndex1(e, state, val) ((e).info.scounter.fByteVal[state] = val)
+#define IncIndex1(e, state) ((e).info.scounter.fByteVal[state]++)
+#define SwapIndex1(e, state) (((e).info.scounter.fByteVal[0] == state) ? 0 : state)
+
+/*!
+\brief A class to handle serveral states in a lock-free manner
+
+Requirement:
+
+ - a "current" state
+ - several possible "pending" state
+ - an TrySwitchState(int state) operation to atomically switch a "pending" to the "current" state (the pending becomes the current).
+
+ The TrySwitchState operation returns a "current" state (either the same if switch fails or the new one; one can know if the switch has succeeded)
+
+ - a WriteStartState(int state) returns a "pending" state to be written into
+ - a WriteStartStop(int state) make the written "pending" state become "switchable"
+
+ Different pending states can be written independantly and concurently.
+
+ GetCurrentIndex() *must* return an increasing value to be able to check reading current state coherency
+
+ The fCounter is an array of indexes to access te current and 3 different "pending" states.
+
+ ¥ WriteNextStateStart(int index) must return a valid state to be written into, and must invalidate state "index" ==> cur state switch.
+ ¥ WriteNextStateStop(int index) makes the "index" state become "switchable" with the current state.
+ ¥ TrySwitchState(int index) must detect that pending state is a new state, and does the switch
+ ¥ ReadCurrentState() must return the state
+ ¥ GetCurrentIndex() must return an index increased each new switch.
+ ¥ WriteNextStateStart(int index1) and WriteNextStateStart(int index2) can be interleaved
+
+ [switch counter][index state][index state][cur index]
+
+*/
+
+// CHECK livelock
+
+template <class T>
+class JackAtomicArrayState
+{
+
+ protected:
+
+ // fState[0] ==> current
+ // fState[1] ==> pending
+ // fState[2] ==> request
+
+ T fState[3];
+ volatile AtomicArrayCounter fCounter;
+
+ UInt32 WriteNextStateStartAux(int state, bool* result)
+ {
+ AtomicArrayCounter old_val;
+ AtomicArrayCounter new_val;
+ UInt32 cur_index;
+ UInt32 next_index;
+ bool need_copy;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ *result = GetIndex1(new_val, state);
+ cur_index = GetIndex1(new_val, 0);
+ next_index = SwapIndex1(fCounter, state);
+ need_copy = (GetIndex1(new_val, state) == 0); // Written = false, switch just occured
+ SetIndex1(new_val, state, 0); // Written = false, invalidate state
+ } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
+ if (need_copy)
+ memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
+ return next_index;
+ }
+
+ void WriteNextStateStopAux(int state)
+ {
+ AtomicArrayCounter old_val;
+ AtomicArrayCounter new_val;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ SetIndex1(new_val, state, 1); // Written = true, state becomes "switchable"
+ } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
+ }
+
+ public:
+
+ JackAtomicArrayState()
+ {
+ JackLog("JackAtomicArrayState constructor\n");
+ Counter1(fCounter) = 0;
+ }
+
+ ~JackAtomicArrayState() // Not virtual ??
+ {}
+
+ /*!
+ \brief Returns the current state : only valid in the RT reader thread
+ */
+
+ T* ReadCurrentState()
+ {
+ return &fState[GetIndex1(fCounter, 0)];
+ }
+
+ /*!
+ \brief Returns the current switch counter
+ */
+
+ UInt16 GetCurrentIndex()
+ {
+ return GetIndex1(fCounter, 3);
+ }
+
+ /*!
+ \brief Tries to switch to the next state and returns the new current state (either the same as before if case of switch failure or the new one)
+ */
+
+ T* TrySwitchState(int state)
+ {
+ AtomicArrayCounter old_val;
+ AtomicArrayCounter new_val;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ if (GetIndex1(new_val, state)) { // If state has been written
+ SetIndex1(new_val, 0, SwapIndex1(new_val, state)); // Prepare switch
+ SetIndex1(new_val, state, 0); // Invalidate the state "state"
+ IncIndex1(new_val, 3); // Inc switch
+ }
+ } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
+ return &fState[GetIndex1(fCounter, 0)]; // Read the counter again
+ }
+
+ /*!
+ \brief Tries to switch to the next state and returns the new current state (either the same as before if case of switch failure or the new one)
+ */
+
+ T* TrySwitchState(int state, bool* result)
+ {
+ AtomicArrayCounter old_val;
+ AtomicArrayCounter new_val;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ if ((*result = GetIndex1(new_val, state))) { // If state has been written
+ SetIndex1(new_val, 0, SwapIndex1(new_val, state)); // Prepare switch
+ SetIndex1(new_val, state, 0); // Invalidate the state "state"
+ IncIndex1(new_val, 3); // Inc switch
+ }
+ } while (!CAS(Counter1(old_val), Counter1(new_val), (UInt32*)&fCounter));
+ return &fState[GetIndex1(fCounter, 0)]; // Read the counter again
+ }
+
+ /*!
+ \brief Start write operation : setup and returns the next state to update, check for recursive write calls.
+ */
+
+ T* WriteNextStateStart(int state)
+ {
+ bool tmp;
+ UInt32 index = WriteNextStateStartAux(state, &tmp);
+ return &fState[index];
+ }
+
+ T* WriteNextStateStart(int state, bool* result)
+ {
+ UInt32 index = WriteNextStateStartAux(state, result);
+ return &fState[index];
+ }
+
+ /*!
+ \brief Stop write operation : make the next state ready to be used by the RT thread
+ */
+ void WriteNextStateStop(int state)
+ {
+ WriteNextStateStopAux(state);
+ }
+
+};
+
+} // end of namespace
+
+
+#endif
+
diff --git a/common/JackAtomicState.h b/common/JackAtomicState.h
new file mode 100644
index 00000000..9e140d3e
--- /dev/null
+++ b/common/JackAtomicState.h
@@ -0,0 +1,240 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackAtomicState__
+#define __JackAtomicState__
+
+#include "JackAtomic.h"
+#include <string.h> // for memcpy
+
+namespace Jack
+{
+
+/*!
+\brief Counter for CAS
+*/
+
+struct AtomicCounter
+{
+ union {
+ struct {
+ UInt16 fShortVal1; // Cur
+ UInt16 fShortVal2; // Next
+ }
+ scounter;
+ UInt32 fLongVal;
+ }info;
+
+ AtomicCounter& operator=(volatile AtomicCounter& obj)
+ {
+ info.fLongVal = obj.info.fLongVal;
+ return *this;
+ }
+
+};
+
+
+#define Counter(e) (e).info.fLongVal
+#define CurIndex(e) (e).info.scounter.fShortVal1
+#define NextIndex(e) (e).info.scounter.fShortVal2
+
+#define CurArrayIndex(e) (CurIndex(e) & 0x0001)
+#define NextArrayIndex(e) ((CurIndex(e) + 1) & 0x0001)
+
+/*!
+\brief A class to handle two states (switching from one to the other) in a lock-free manner
+*/
+
+// CHECK livelock
+
+template <class T>
+class JackAtomicState
+{
+
+ protected:
+
+ T fState[2];
+ volatile AtomicCounter fCounter;
+ SInt32 fCallWriteCounter;
+
+ UInt32 WriteNextStateStartAux()
+ {
+ AtomicCounter old_val;
+ AtomicCounter new_val;
+ UInt32 cur_index;
+ UInt32 next_index;
+ bool need_copy;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ cur_index = CurArrayIndex(new_val);
+ next_index = NextArrayIndex(new_val);
+ need_copy = (CurIndex(new_val) == NextIndex(new_val));
+ NextIndex(new_val) = CurIndex(new_val); // Invalidate next index
+ } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
+ if (need_copy)
+ memcpy(&fState[next_index], &fState[cur_index], sizeof(T));
+ return next_index;
+ }
+
+ void WriteNextStateStopAux()
+ {
+ AtomicCounter old_val;
+ AtomicCounter new_val;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ NextIndex(new_val)++; // Set next index
+ } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
+ }
+
+ public:
+
+ JackAtomicState()
+ {
+ Counter(fCounter) = 0;
+ fCallWriteCounter = 0;
+ }
+
+ ~JackAtomicState() // Not virtual ??
+ {}
+
+ /*!
+ \brief Returns the current state : only valid in the RT reader thread
+ */
+ T* ReadCurrentState()
+ {
+ return &fState[CurArrayIndex(fCounter)];
+ }
+
+ /*!
+ \brief Returns the current state index
+ */
+ UInt16 GetCurrentIndex()
+ {
+ return CurIndex(fCounter);
+ }
+
+ /*!
+ \brief Tries to switch to the next state and returns the new current state (either the same as before if case of switch failure or the new one)
+ */
+ T* TrySwitchState()
+ {
+ AtomicCounter old_val;
+ AtomicCounter new_val;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ CurIndex(new_val) = NextIndex(new_val); // Prepare switch
+ } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
+ return &fState[CurArrayIndex(fCounter)]; // Read the counter again
+ }
+
+ /*!
+ \brief Tries to switch to the next state and returns the new current state (either the same as before if case of switch failure or the new one)
+ */
+ T* TrySwitchState(bool* result)
+ {
+ AtomicCounter old_val;
+ AtomicCounter new_val;
+ do {
+ old_val = fCounter;
+ new_val = old_val;
+ *result = (CurIndex(new_val) != NextIndex(new_val));
+ CurIndex(new_val) = NextIndex(new_val); // Prepare switch
+ } while (!CAS(Counter(old_val), Counter(new_val), (UInt32*)&fCounter));
+ return &fState[CurArrayIndex(fCounter)]; // Read the counter again
+ }
+
+ /*!
+ \brief Start write operation : setup and returns the next state to update, check for recursive write calls.
+ */
+ T* WriteNextStateStart()
+ {
+ UInt32 next_index = (fCallWriteCounter++ == 0)
+ ? WriteNextStateStartAux()
+ : NextArrayIndex(fCounter); // We are inside a wrapping WriteNextStateStart call, NextArrayIndex can be read safely
+ return &fState[next_index];
+ }
+
+ /*!
+ \brief Stop write operation : make the next state ready to be used by the RT thread
+ */
+ void WriteNextStateStop()
+ {
+ if (--fCallWriteCounter == 0)
+ WriteNextStateStopAux();
+ }
+
+ bool IsPendingChange()
+ {
+ return CurIndex(fCounter) != NextIndex(fCounter);
+ }
+
+ /*
+ // Single writer : write methods get the *next* state to be updated
+ void TestWriteMethod()
+ {
+ T* state = WriteNextStateStart();
+ ......
+ ......
+ WriteNextStateStop();
+ }
+
+ // First RT call possibly switch state
+ void TestReadRTMethod1()
+ {
+ T* state = TrySwitchState();
+ ......
+ ......
+ }
+
+ // Other RT methods can safely use the current state during the *same* RT cycle
+ void TestReadRTMethod2()
+ {
+ T* state = ReadCurrentState();
+ ......
+ ......
+ }
+
+ // Non RT read methods : must check state coherency
+ void TestReadMethod()
+ {
+ T* state;
+ UInt16 cur_index;
+ UInt16 next_index = GetCurrentIndex();
+ do {
+ cur_index = next_index;
+ state = ReadCurrentState();
+
+ ......
+ ......
+
+ next_index = GetCurrentIndex();
+ } while (cur_index != next_index);
+ }
+ */
+};
+
+
+} // end of namespace
+
+
+#endif
+
diff --git a/common/JackAudioDriver.cpp b/common/JackAudioDriver.cpp
new file mode 100644
index 00000000..1416a729
--- /dev/null
+++ b/common/JackAudioDriver.cpp
@@ -0,0 +1,229 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackAudioDriver.h"
+#include "JackTime.h"
+#include "JackError.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include "JackPort.h"
+#include "JackGraphManager.h"
+#include "JackEngine.h"
+#include <assert.h>
+
+namespace Jack
+{
+
+
+JackAudioDriver::JackAudioDriver(const char* name, JackEngine* engine, JackSynchro** table)
+ : JackDriver(name, engine, table),
+ fCaptureChannels(0),
+ fPlaybackChannels(0),
+ fWithMonitorPorts(false)
+{}
+
+JackAudioDriver::~JackAudioDriver()
+{}
+
+int JackAudioDriver::Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency)
+{
+ fCaptureChannels = inchannels;
+ fPlaybackChannels = outchannels;
+ fWithMonitorPorts = monitor;
+ return JackDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
+}
+
+int JackAudioDriver::Attach()
+{
+ JackPort* port;
+ jack_port_id_t port_index;
+ char buf[JACK_PORT_NAME_SIZE];
+ unsigned long port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
+ int i;
+
+ JackLog("JackAudioDriver::Attach fBufferSize %ld fSampleRate %ld\n", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
+
+ for (i = 0; i < fCaptureChannels; i++) {
+ snprintf(buf, sizeof(buf) - 1, "%s:%s:out%d", fClientControl->fName, fCaptureDriverName, i + 1);
+ if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, (JackPortFlags)port_flags)) == NO_PORT) {
+ jack_error("driver: cannot register port for %s", buf);
+ return -1;
+ }
+ port = fGraphManager->GetPort(port_index);
+ port->SetLatency(fEngineControl->fBufferSize + fCaptureLatency);
+ fCapturePortList[i] = port_index;
+ JackLog("JackAudioDriver::Attach fCapturePortList[i] %ld \n", port_index);
+ }
+
+ port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
+
+ for (i = 0; i < fPlaybackChannels; i++) {
+ snprintf(buf, sizeof(buf) - 1, "%s:%s:in%d", fClientControl->fName, fPlaybackDriverName, i + 1);
+ if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, (JackPortFlags)port_flags)) == NO_PORT) {
+ jack_error("driver: cannot register port for %s", buf);
+ return -1;
+ }
+ port = fGraphManager->GetPort(port_index);
+ port->SetLatency(fEngineControl->fBufferSize + fPlaybackLatency);
+ fPlaybackPortList[i] = port_index;
+ JackLog("JackAudioDriver::Attach fPlaybackPortList[i] %ld \n", port_index);
+
+ // Monitor ports
+ if (fWithMonitorPorts) {
+ JackLog("Create monitor port \n");
+ snprintf(buf, sizeof(buf) - 1, "%s:%s:monitor_%u", fClientControl->fName, fPlaybackDriverName, i + 1);
+ if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, JackPortIsOutput)) == NO_PORT) {
+ jack_error("Cannot register monitor port for %s", buf);
+ return -1;
+ } else {
+ port = fGraphManager->GetPort(port_index);
+ port->SetLatency(fEngineControl->fBufferSize);
+ fMonitorPortList[i] = port_index;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int JackAudioDriver::Detach()
+{
+ int i;
+ JackLog("JackAudioDriver::Detach\n");
+
+ for (i = 0; i < fCaptureChannels; i++) {
+ fGraphManager->RemovePort(fClientControl->fRefNum, fCapturePortList[i]);
+ }
+
+ for (i = 0; i < fPlaybackChannels; i++) {
+ fGraphManager->RemovePort(fClientControl->fRefNum, fPlaybackPortList[i]);
+ if (fWithMonitorPorts)
+ fGraphManager->RemovePort(fClientControl->fRefNum, fMonitorPortList[i]);
+ }
+
+ return 0;
+}
+
+int JackAudioDriver::Write()
+{
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
+ float* buffer = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[i], fEngineControl->fBufferSize);
+ int size = sizeof(float) * fEngineControl->fBufferSize;
+ // Monitor ports
+ if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0)
+ memcpy((jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[i], fEngineControl->fBufferSize), buffer, size);
+ }
+ }
+ return 0;
+}
+
+int JackAudioDriver::Process()
+{
+ return (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync();
+}
+
+/*
+The driver ASYNC mode: output buffers computed at the *previous cycle* are used, the server does not
+synchronize to the end of client graph execution.
+*/
+
+int JackAudioDriver::ProcessAsync()
+{
+ if (Read() < 0) { // Read input buffers for the current cycle
+ jack_error("ProcessAsync: read error");
+ return 0;
+ }
+
+ if (Write() < 0) { // Write output buffers from the previous cycle
+ jack_error("ProcessAsync: write error");
+ return 0;
+ }
+
+ if (fIsMaster) {
+ fEngine->Process(fLastWaitUst); // fLastWaitUst is set in the "low level" layer
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
+ ProcessSlaves();
+ } else {
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
+ }
+ return 0;
+}
+
+/*
+The driver SYNC mode: the server does synchronize to the end of client graph execution,
+output buffers computed at the *current cycle* are used.
+*/
+
+int JackAudioDriver::ProcessSync()
+{
+ if (Read() < 0) { // Read input buffers for the current cycle
+ jack_error("ProcessSync: read error");
+ return 0;
+ }
+
+ if (fIsMaster) {
+ fEngine->Process(fLastWaitUst); // fLastWaitUst is set in the "low level" layer
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
+ ProcessSlaves();
+ if (fGraphManager->SuspendRefNum(fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs) < 0)
+ jack_error("JackAudioDriver::ProcessSync SuspendRefNum error");
+ if (Write() < 0) // Write output buffers for the current cycle
+ jack_error("Process: write error");
+ } else {
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable);
+ }
+ return 0;
+}
+
+void JackAudioDriver::NotifyXRun(jack_time_t callback_usecs)
+{
+ fEngine->NotifyXRun(callback_usecs);
+}
+
+jack_default_audio_sample_t* JackAudioDriver::GetInputBuffer(int port_index)
+{
+ assert(fCapturePortList[port_index]);
+ return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[port_index], fEngineControl->fBufferSize);
+}
+
+jack_default_audio_sample_t* JackAudioDriver::GetOutputBuffer(int port_index)
+{
+ assert(fPlaybackPortList[port_index]);
+ return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[port_index], fEngineControl->fBufferSize);
+}
+
+jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index)
+{
+ assert(fPlaybackPortList[port_index]);
+ return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize);
+}
+
+} // end of namespace
diff --git a/common/JackAudioDriver.h b/common/JackAudioDriver.h
new file mode 100644
index 00000000..13de9096
--- /dev/null
+++ b/common/JackAudioDriver.h
@@ -0,0 +1,88 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackAudioDriver__
+#define __JackAudioDriver__
+
+#include "JackDriver.h"
+
+
+namespace Jack
+{
+
+/*!
+\brief The base class for audio drivers: drivers with audio ports.
+*/
+
+class EXPORT JackAudioDriver : public JackDriver
+{
+
+ protected:
+
+ int fCaptureChannels;
+ int fPlaybackChannels;
+
+ // static tables since the actual number of ports may be changed by the real driver
+ // thus dynamic allocation is more difficult to handle
+ jack_port_id_t fCapturePortList[PORT_NUM];
+ jack_port_id_t fPlaybackPortList[PORT_NUM];
+ jack_port_id_t fMonitorPortList[PORT_NUM];
+
+ bool fWithMonitorPorts;
+
+ jack_default_audio_sample_t* GetInputBuffer(int port_index);
+ jack_default_audio_sample_t* GetOutputBuffer(int port_index);
+ jack_default_audio_sample_t* GetMonitorBuffer(int port_index);
+
+ private:
+
+ int ProcessAsync();
+ int ProcessSync();
+
+ public:
+
+ JackAudioDriver(const char* name, JackEngine* engine, JackSynchro** table);
+ virtual ~JackAudioDriver();
+
+ virtual int Process();
+
+ virtual int Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency);
+
+ virtual int Attach();
+ virtual int Detach();
+ virtual int Write();
+
+ virtual void NotifyXRun(jack_time_t callback_usecs); // XRun notification sent by the driver
+
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackChannel.h b/common/JackChannel.h
new file mode 100644
index 00000000..4036aede
--- /dev/null
+++ b/common/JackChannel.h
@@ -0,0 +1,210 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackChannel__
+#define __JackChannel__
+
+#include "types.h"
+#include "JackError.h"
+#include "JackTransportEngine.h"
+
+namespace Jack
+{
+
+class JackClientInterface;
+class JackClient;
+class JackServer;
+struct JackEngineControl;
+class JackGraphManager;
+
+/*!
+\brief Inter process channel for server/client bidirectionnal communication : request and (receiving) notifications.
+*/
+
+class JackClientChannelInterface
+{
+
+ public:
+
+ JackClientChannelInterface()
+ {}
+ virtual ~JackClientChannelInterface()
+ {}
+
+ // Open the Server/Client connection
+ virtual int Open(const char* name, JackClient* obj)
+ {
+ return 0;
+ }
+
+ // Close the Server/Client connection
+ virtual void Close()
+ {}
+
+ // Start listening for messages from the server
+ virtual int Start()
+ {
+ return 0;
+ }
+
+ // Stop listening for messages from the server
+ virtual void Stop()
+ {}
+
+ virtual void ClientNew(const char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result)
+ {}
+ virtual void ClientNew(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, int* result)
+ {}
+ virtual void ClientClose(int refnum, int* result)
+ {}
+
+ virtual void ClientActivate(int refnum, int* result)
+ {}
+ virtual void ClientDeactivate(int refnum, int* result)
+ {}
+
+ virtual void PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result)
+ {}
+ virtual void PortUnRegister(int refnum, jack_port_id_t port_index, int* result)
+ {}
+
+ virtual void PortConnect(int refnum, const char* src, const char* dst, int* result)
+ {}
+ virtual void PortDisconnect(int refnum, const char* src, const char* dst, int* result)
+ {}
+ virtual void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
+ {}
+ virtual void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
+ {}
+
+ virtual void SetBufferSize(jack_nframes_t nframes, int* result)
+ {}
+ virtual void SetFreewheel(int onoff, int* result)
+ {}
+
+ virtual void ReleaseTimebase(int refnum, int* result)
+ {}
+
+ virtual void SetTimebaseCallback(int refnum, int conditional, int* result)
+ {}
+
+};
+
+/*!
+\brief Inter process channel for server to client notifications.
+*/
+
+class JackNotifyChannelInterface
+{
+
+ public:
+
+ JackNotifyChannelInterface()
+ {}
+ virtual ~JackNotifyChannelInterface()
+ {}
+
+ // Open the Server/Client connection
+ virtual int Open(const char* name)
+ {
+ return 0;
+ }
+ // Close the Server/Client connection
+ virtual void Close()
+ {}
+
+ /*
+ The "sync" parameter allows to choose between "synchronous" and "asynchronous" notification
+ */
+ virtual void ClientNotify(int refnum, const char* name, int notify, int sync, int value, int* result)
+ {}
+
+ typedef enum {
+ kAddClient = 0,
+ kRemoveClient = 1,
+ kXRunCallback = 2,
+ kGraphOrderCallback = 3,
+ kBufferSizeCallback = 4,
+ kStartFreewheel = 5,
+ kStopFreewheel = 6,
+ kPortRegistrationOn = 7,
+ kPortRegistrationOff = 8,
+ kZombifyClient = 9,
+ kDeadClient = 10
+ } NotificationType;
+
+};
+
+/*!
+\brief Entry point channel for client/server communication.
+*/
+
+class JackServerChannelInterface
+{
+
+ public:
+
+ JackServerChannelInterface()
+ {}
+ virtual ~JackServerChannelInterface()
+ {}
+
+ // Open the Server/Client connection
+ virtual int Open(JackServer* server)
+ {
+ return 0;
+ }
+ // Close the Server/Client connection
+ virtual void Close()
+ {}
+};
+
+/*!
+\brief Channel for server RT thread to request server thread communication.
+*/
+
+class JackServerNotifyChannelInterface
+{
+
+ public:
+
+ JackServerNotifyChannelInterface()
+ {}
+ virtual ~JackServerNotifyChannelInterface()
+ {}
+
+ // Open the Server RT/Server connection
+ virtual int Open()
+ {
+ return 0;
+ }
+ // Close the Server RT/Server connection
+ virtual void Close()
+ {}
+
+ virtual void ClientNotify(int refnum, int notify, int value)
+ {}
+
+};
+
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackChannelTransaction.h b/common/JackChannelTransaction.h
new file mode 100644
index 00000000..d83d4780
--- /dev/null
+++ b/common/JackChannelTransaction.h
@@ -0,0 +1,48 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackChannelTransaction__
+#define __JackChannelTransaction__
+
+
+namespace Jack
+{
+
+/*!
+\brief Channel input/output communication.
+*/
+
+class JackChannelTransaction
+{
+
+ public:
+
+ JackChannelTransaction()
+ {}
+ virtual ~JackChannelTransaction()
+ {}
+
+ virtual int Read(void* data, int len) = 0;
+ virtual int Write(void* data, int len) = 0;
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackClient.cpp b/common/JackClient.cpp
new file mode 100644
index 00000000..ec1e0468
--- /dev/null
+++ b/common/JackClient.cpp
@@ -0,0 +1,767 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+
+#include "JackClient.h"
+#include "JackGraphManager.h"
+#include "JackClientControl.h"
+#include "JackEngineControl.h"
+#include "JackGlobals.h"
+#include "JackChannel.h"
+#include "JackTransportEngine.h"
+#include <math.h>
+#include <string>
+
+int verbose = 0;
+
+using namespace std;
+
+namespace Jack
+{
+
+JackClient::JackClient()
+{}
+
+JackClient::JackClient(JackSynchro** table)
+{
+ fThread = JackGlobals::MakeThread(this);
+ fSynchroTable = table;
+ fProcess = NULL;
+ fGraphOrder = NULL;
+ fXrun = NULL;
+ fShutdown = NULL;
+ fInit = NULL;
+ fBufferSize = NULL;
+ fFreewheel = NULL;
+ fPortRegistration = NULL;
+ fSync = NULL;
+ fProcessArg = NULL;
+ fGraphOrderArg = NULL;
+ fXrunArg = NULL;
+ fShutdownArg = NULL;
+ fInitArg = NULL;
+ fBufferSizeArg = NULL;
+ fFreewheelArg = NULL;
+ fPortRegistrationArg = NULL;
+ fSyncArg = NULL;
+ fConditionnal = 0; // Temporary??
+}
+
+JackClient::~JackClient()
+{
+ delete fThread;
+}
+
+int JackClient::Close()
+{
+ JackLog("JackClient::Close ref = %ld\n", GetClientControl()->fRefNum);
+ Deactivate();
+ int result = -1;
+ fChannel->ClientClose(GetClientControl()->fRefNum, &result);
+ fChannel->Stop();
+ fChannel->Close();
+ fSynchroTable[GetClientControl()->fRefNum]->Disconnect();
+ return result;
+}
+
+bool JackClient::IsActive()
+{
+ return (GetClientControl()) ? GetClientControl()->fActive : false;
+}
+
+pthread_t JackClient::GetThreadID()
+{
+ return fThread->GetThreadID();
+}
+
+/*!
+\brief
+ In ASYNC mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
+ The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
+ Drivers synchro are setup in "flush" mode if server is ASYNC and NOT freewheel.
+*/
+void JackClient::SetupDriverSync(bool freewheel)
+{
+ if (!freewheel && !GetEngineControl()->fSyncMode) {
+ JackLog("JackClient::SetupDriverSync driver sem in flush mode\n");
+ fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(true);
+ fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(true);
+ fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(true);
+ } else {
+ JackLog("JackClient::SetupDriverSync driver sem in normal mode\n");
+ fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(false);
+ fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(false);
+ fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(false);
+ }
+}
+
+/*!
+\brief Notification received from the server.
+*/
+
+int JackClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value)
+{
+ return 0;
+}
+
+int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, int value)
+{
+ int res = 0;
+
+ // Done all time: redirected on subclass implementation JackLibClient and JackInternalClient
+ switch (notify) {
+
+ case JackNotifyChannelInterface::kAddClient:
+ case JackNotifyChannelInterface::kRemoveClient:
+ res = ClientNotifyImp(refnum, name, notify, sync, value);
+ break;
+ }
+
+ /*
+ The current semantic is that notifications can only be received when the client has been activated,
+ although is this implementation, one could imagine calling notifications as soon as the client has be opened.
+ */
+ if (IsActive()) {
+
+ switch (notify) {
+
+ case JackNotifyChannelInterface::kBufferSizeCallback:
+ JackLog("JackClient::kBufferSizeCallback buffer_size = %ld\n", value);
+ if (fBufferSize)
+ res = fBufferSize(value, fBufferSizeArg);
+ break;
+
+ case JackNotifyChannelInterface::kGraphOrderCallback:
+ JackLog("JackClient::kGraphOrderCallback\n");
+ if (fGraphOrder)
+ res = fGraphOrder(fGraphOrderArg);
+ break;
+
+ case JackNotifyChannelInterface::kStartFreewheel:
+ JackLog("JackClient::kStartFreewheel\n");
+ SetupDriverSync(true);
+ fThread->DropRealTime();
+ if (fFreewheel)
+ fFreewheel(1, fFreewheelArg);
+ break;
+
+ case JackNotifyChannelInterface::kStopFreewheel:
+ JackLog("JackClient::kStopFreewheel\n");
+ SetupDriverSync(false);
+ if (fFreewheel)
+ fFreewheel(0, fFreewheelArg);
+ fThread->AcquireRealTime();
+ break;
+
+ case JackNotifyChannelInterface::kPortRegistrationOn:
+ JackLog("JackClient::kPortRegistrationOn port_index = %ld\n", value);
+ if (fPortRegistration)
+ fPortRegistration(value, 1, fPortRegistrationArg);
+ break;
+
+ case JackNotifyChannelInterface::kPortRegistrationOff:
+ JackLog("JackClient::kPortRegistrationOff port_index = %ld \n", value);
+ if (fPortRegistration)
+ fPortRegistration(value, 0, fPortRegistrationArg);
+ break;
+
+ case JackNotifyChannelInterface::kXRunCallback:
+ JackLog("JackClient::kXRunCallback\n");
+ if (fXrun)
+ res = fXrun(fXrunArg);
+ break;
+
+ case JackNotifyChannelInterface::kZombifyClient:
+ res = fThread->Kill();
+ JackLog("JackClient::kZombifyClient name = %s ref = %ld \n", name, refnum);
+ ShutDown();
+ break;
+ }
+ }
+
+ return res;
+}
+
+/*!
+\brief We need to start thread before activating in the server, otherwise the FW driver
+ connected to the client may not be activated.
+*/
+int JackClient::Activate()
+{
+ JackLog("JackClient::Activate \n");
+ if (IsActive())
+ return 0;
+
+ if (StartThread() < 0)
+ return -1;
+
+ int result = -1;
+ fChannel->ClientActivate(GetClientControl()->fRefNum, &result);
+ if (result < 0)
+ return result;
+
+ if (fSync != NULL) /* If a SyncCallback is pending... */
+ SetSyncCallback(fSync, fSyncArg);
+
+ if (fTimebase != NULL) /* If a TimebaseCallback is pending... */
+ SetTimebaseCallback(fConditionnal, fTimebase, fTimebaseArg);
+
+ GetClientControl()->fActive = true;
+ return 0;
+}
+
+/*!
+\brief Need to stop thread after deactivating in the server.
+*/
+int JackClient::Deactivate()
+{
+ JackLog("JackClient::Deactivate \n");
+ if (!IsActive())
+ return 0;
+
+ GetClientControl()->fActive = false;
+ int result = -1;
+ fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
+
+ JackLog("JackClient::Deactivate res = %ld \n", result);
+ // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
+ fThread->Kill();
+ return result;
+}
+
+//----------------------
+// RT thread management
+//----------------------
+
+bool JackClient::CallProcessCallback()
+{
+ return (fProcess == NULL) ? true : (fProcess(GetEngineControl()->fBufferSize, fProcessArg) == 0);
+}
+
+/*!
+\brief Called once when the thread starts.
+*/
+bool JackClient::Init()
+{
+ if (fInit) {
+ JackLog("JackClient::Init calling client thread init callback\n");
+ fInit(fInitArg);
+ }
+ return true;
+}
+
+int JackClient::StartThread()
+{
+ JackLog("JackClient::StartThread : period = %ld computation = %ld constraint = %ld\n",
+ long(int64_t(GetEngineControl()->fPeriod) / 1000.0f),
+ long(int64_t(GetEngineControl()->fComputation) / 1000.0f),
+ long(int64_t(GetEngineControl()->fConstraint) / 1000.0f));
+
+ // Will do "something" on OSX only...
+ fThread->SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
+
+ if (fThread->Start() < 0) {
+ jack_error("Start thread error");
+ return -1;
+ }
+
+ if (GetEngineControl()->fRealTime) {
+ if (fThread->AcquireRealTime(GetEngineControl()->fPriority - 1) < 0) {
+ jack_error("AcquireRealTime error");
+ }
+ }
+
+ return 0;
+}
+
+/*!
+\brief RT thread.
+*/
+bool JackClient::Execute()
+{
+ // Suspend itself: wait on the input synchro
+ if (GetGraphManager()->SuspendRefNum(GetClientControl(), fSynchroTable, 0x7FFFFFFF) < 0) {
+ jack_error("SuspendRefNum error");
+ goto error;
+ }
+
+ // Process call
+ if (IsActive()) {
+ CallSyncCallback();
+ bool res = CallProcessCallback();
+ CallTimebaseCallback();
+ if (!res)
+ goto end;
+ } else {
+ JackLog("Process called for an inactive client\n");
+ // Happens if client is still not activated (connected to the FW)
+ // or still runs while being desactivated by the server
+ }
+
+ // Resume: signal output clients connected to the running client
+ if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
+ jack_error("ResumeRefNum error");
+ }
+
+ return true;
+
+end:
+ JackLog("JackClient::Execute end name = %s\n", GetClientControl()->fName);
+
+ // Continue graph execution for this cycle
+ if (GetGraphManager()->ResumeRefNum(GetClientControl(), fSynchroTable) < 0) {
+ jack_error("ResumeRefNum error");
+ }
+
+ // Hum... not sure about this, the following "close" code is called in the RT thread...
+ int result;
+ fThread->DropRealTime();
+ fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
+ Close(); // Not sure...
+ return false;
+
+error:
+ jack_error("JackClient::Execute error name = %s", GetClientControl()->fName);
+ // Hum... not sure about this, the following "close" code is called in the RT thread...
+ fThread->DropRealTime();
+ ShutDown();
+ return false;
+}
+
+//-----------------
+// Port management
+//-----------------
+
+int JackClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
+{
+ // Check port name length
+ string port_name_str = string(port_name);
+ if (port_name_str.size() == 0) {
+ jack_error("port_name is empty.");
+ return 0; // Means failure here...
+ }
+
+ string name = string(GetClientControl()->fName) + string(":") + port_name_str;
+ if (name.size() >= JACK_PORT_NAME_SIZE) {
+ jack_error("\"%s:%s\" is too long to be used as a JACK port name.\n"
+ "Please use %lu characters or less.",
+ GetClientControl()->fName,
+ port_name,
+ JACK_PORT_NAME_SIZE - 1);
+ return 0; // Means failure here...
+ }
+
+ // Check if port name already exists
+ if (GetGraphManager()->GetPort(name.c_str()) != NO_PORT) {
+ jack_error("port_name \"%s\" already exists.", port_name);
+ return 0; // Means failure here...
+ }
+
+ JackLog("JackClient::PortRegister ref = %ld name = %s \n", GetClientControl()->fRefNum, name.c_str());
+
+ int result = -1;
+ jack_port_id_t port_index = NO_PORT;
+ fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), flags, buffer_size, &port_index, &result);
+ JackLog("JackClient::PortRegister port_index = %ld \n", port_index);
+
+ if (result == 0) {
+ fPortList.push_back(port_index);
+ return port_index;
+ } else {
+ return 0;
+ }
+}
+
+int JackClient::PortUnRegister(jack_port_id_t port_index)
+{
+ JackLog("JackClient::PortUnRegister port_index = %ld\n", port_index);
+ list<jack_port_id_t>::iterator it;
+ for (it = fPortList.begin(); it != fPortList.end() && *it != port_index; it++)
+ ;
+
+ if (it != fPortList.end()) {
+ fPortList.erase(it);
+ int result = -1;
+ fChannel->PortUnRegister(GetClientControl()->fRefNum, port_index, &result);
+ return result;
+ } else {
+ jack_error("unregistering a port %ld that is not own by the client", port_index);
+ return -1;
+ }
+}
+
+int JackClient::PortConnect(const char* src, const char* dst)
+{
+ JackLog("JackClient::Connect src = %s dst = %s\n", src, dst);
+ int result = -1;
+ fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
+ return result;
+}
+
+int JackClient::PortDisconnect(const char* src, const char* dst)
+{
+ JackLog("JackClient::Disconnect src = %s dst = %s\n", src, dst);
+ int result = -1;
+ fChannel->PortDisconnect(GetClientControl()->fRefNum, src, dst, &result);
+ return result;
+}
+
+int JackClient::PortConnect(jack_port_id_t src, jack_port_id_t dst)
+{
+ JackLog("JackClient::PortConnect src = %ld dst = %ld\n", src, dst);
+ int result = -1;
+ fChannel->PortConnect(GetClientControl()->fRefNum, src, dst, &result);
+ return result;
+}
+
+int JackClient::PortDisconnect(jack_port_id_t src)
+{
+ JackLog("JackClient::PortDisconnect src = %ld\n", src);
+ int result = -1;
+ fChannel->PortDisconnect(GetClientControl()->fRefNum, src, ALL_PORTS, &result);
+ return result;
+}
+
+int JackClient::PortIsMine(jack_port_id_t port_index)
+{
+ JackPort* port = GetGraphManager()->GetPort(port_index);
+ return GetClientControl()->fRefNum == port->GetRefNum();
+}
+
+//--------------------
+// Context management
+//--------------------
+
+int JackClient::SetBufferSize(jack_nframes_t nframes)
+{
+ int result = -1;
+ fChannel->SetBufferSize(nframes, &result);
+ return result;
+}
+
+int JackClient::SetFreeWheel(int onoff)
+{
+ int result = -1;
+ fChannel->SetFreewheel(onoff, &result);
+ return result;
+}
+
+/*
+ShutDown is called:
+- from the RT thread when Execute method fails
+- possibly from a "closed" notification channel
+(Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
+*/
+
+void JackClient::ShutDown()
+{
+ JackLog("ShutDown\n");
+ if (fShutdown) {
+ GetClientControl()->fActive = false;
+ fShutdown(fShutdownArg);
+ fShutdown = NULL;
+ }
+}
+
+//----------------------
+// Transport management
+//----------------------
+
+int JackClient::ReleaseTimebase()
+{
+ int result = -1;
+ fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result);
+ if (result == 0) {
+ fTimebase = NULL;
+ fTimebaseArg = NULL;
+ }
+ return result;
+}
+
+/* Call the server if the client is active, otherwise keeps the arguments */
+int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
+{
+ if (IsActive())
+ GetClientControl()->fTransportState = (sync_callback == NULL) ? JackTransportStopped : JackTransportSynching;
+ fSync = sync_callback;
+ fSyncArg = arg;
+ return 0;
+}
+
+int JackClient::SetSyncTimeout(jack_time_t timeout)
+{
+ GetEngineControl()->fTransport.SetSyncTimeout(timeout);
+ return 0;
+}
+
+/* Call the server if the client is active, otherwise keeps the arguments */
+int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
+{
+ if (IsActive()) {
+ int result = -1;
+ fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result);
+ JackLog("SetTimebaseCallback result = %ld\n", result);
+ if (result == 0) {
+ fTimebase = timebase_callback;
+ fTimebaseArg = arg;
+ } else {
+ fTimebase = NULL;
+ fTimebaseArg = NULL;
+ }
+ JackLog("SetTimebaseCallback OK result = %ld\n", result);
+ return result;
+ } else {
+ fTimebase = timebase_callback;
+ fTimebaseArg = arg;
+ fConditionnal = conditional;
+ return 0;
+ }
+}
+
+// Must be RT safe
+int JackClient::RequestNewPos(jack_position_t* pos)
+{
+ JackTransportEngine& transport = GetEngineControl()->fTransport;
+ jack_position_t* request = transport.WriteNextStateStart(2);
+ pos->unique_1 = pos->unique_2 = transport.GenerateUniqueID();
+ JackTransportEngine::TransportCopyPosition(pos, request);
+ JackLog("RequestNewPos pos = %ld\n", pos->frame);
+ transport.WriteNextStateStop(2);
+ return 0;
+}
+
+int JackClient::TransportLocate(jack_nframes_t frame)
+{
+ jack_position_t pos;
+ pos.frame = frame;
+ pos.valid = (jack_position_bits_t)0;
+ JackLog("TransportLocate pos = %ld\n", pos.frame);
+ return RequestNewPos(&pos);
+}
+
+int JackClient::TransportReposition(jack_position_t* pos)
+{
+ jack_position_t tmp = *pos;
+ JackLog("TransportReposition pos = %ld\n", pos->frame);
+ return (tmp.valid & ~JACK_POSITION_MASK) ? EINVAL : RequestNewPos(&tmp);
+}
+
+jack_transport_state_t JackClient::TransportQuery(jack_position_t* pos)
+{
+ if (pos)
+ GetEngineControl()->fTransport.ReadCurrentPos(pos);
+ return GetEngineControl()->fTransport.GetState();
+}
+
+jack_nframes_t JackClient::GetCurrentTransportFrame()
+{
+ jack_position_t pos;
+ jack_transport_state_t state = TransportQuery(&pos);
+
+ if (state == JackTransportRolling) {
+ float usecs = GetMicroSeconds() - pos.usecs;
+ jack_nframes_t elapsed = (jack_nframes_t)floor((((float) pos.frame_rate) / 1000000.0f) * usecs);
+ return pos.frame + elapsed;
+ } else {
+ return pos.frame;
+ }
+}
+
+// Must be RT safe: directly write in the transport shared mem
+void JackClient::TransportStart()
+{
+ GetEngineControl()->fTransport.SetCommand(TransportCommandStart);
+}
+
+// Must be RT safe: directly write in the transport shared mem
+void JackClient::TransportStop()
+{
+ GetEngineControl()->fTransport.SetCommand(TransportCommandStop);
+}
+
+// Never called concurently with the server
+// TODO check concurency with SetSyncCallback
+
+void JackClient::CallSyncCallback()
+{
+ JackTransportEngine& transport = GetEngineControl()->fTransport;
+ jack_position_t* cur_pos = transport.ReadCurrentState();
+ jack_transport_state_t transport_state = transport.GetState();
+
+ switch (transport_state) {
+
+ case JackTransportStarting: // Starting...
+ if (fSync == NULL) {
+ GetClientControl()->fTransportState = JackTransportRolling;
+ } else if (GetClientControl()->fTransportState == JackTransportStarting) {
+ if (fSync(transport_state, cur_pos, fSyncArg))
+ GetClientControl()->fTransportState = JackTransportRolling;
+ }
+ break;
+
+ case JackTransportRolling:
+ if (fSync != NULL && GetClientControl()->fTransportState == JackTransportStarting) { // Client still not ready
+ if (fSync(transport_state, cur_pos, fSyncArg))
+ GetClientControl()->fTransportState = JackTransportRolling;
+ }
+ break;
+
+ case JackTransportSynching:
+ // New pos when transport engine is stopped...
+ if (fSync != NULL) {
+ fSync(JackTransportStopped, cur_pos, fSyncArg);
+ GetClientControl()->fTransportState = JackTransportStopped;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void JackClient::CallTimebaseCallback()
+{
+ JackTransportEngine& transport = GetEngineControl()->fTransport;
+
+ if (fTimebase != NULL && fTimebaseArg != NULL && GetClientControl()->fRefNum == transport.GetTimebaseMaster()) {
+
+ jack_transport_state_t transport_state = transport.GetState();
+ jack_position_t* cur_pos = transport.WriteNextStateStart(1);
+
+ switch (transport_state) {
+
+ case JackTransportRolling:
+ fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg);
+ break;
+
+ case JackTransportSynching:
+ fTimebase(JackTransportStopped, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg);
+ break;
+
+ default:
+ break;
+ }
+
+ transport.WriteNextStateStop(1);
+ }
+}
+
+//---------------------
+// Callback management
+//---------------------
+
+void JackClient::OnShutdown(JackShutdownCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ } else {
+ fShutdownArg = arg;
+ fShutdown = callback;
+ }
+}
+
+int JackClient::SetProcessCallback(JackProcessCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fProcessArg = arg;
+ fProcess = callback;
+ return 0;
+ }
+}
+
+int JackClient::SetXRunCallback(JackXRunCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fXrunArg = arg;
+ fXrun = callback;
+ return 0;
+ }
+}
+
+int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fInitArg = arg;
+ fInit = callback;
+ return 0;
+ }
+}
+
+int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
+{
+ JackLog("SetGraphOrderCallback \n");
+
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fGraphOrder = callback;
+ fGraphOrderArg = arg;
+ return 0;
+ }
+}
+
+int JackClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fBufferSizeArg = arg;
+ fBufferSize = callback;
+ return 0;
+ }
+}
+
+int JackClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fFreewheelArg = arg;
+ fFreewheel = callback;
+ return 0;
+ }
+}
+
+int JackClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
+{
+ if (IsActive()) {
+ jack_error("You cannot set callbacks on an active client");
+ return -1;
+ } else {
+ fPortRegistrationArg = arg;
+ fPortRegistration = callback;
+ return 0;
+ }
+}
+
+} // end of namespace
+
diff --git a/common/JackClient.h b/common/JackClient.h
new file mode 100644
index 00000000..b1b5eee0
--- /dev/null
+++ b/common/JackClient.h
@@ -0,0 +1,162 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackClient__
+#define __JackClient__
+
+#include "JackClientInterface.h"
+#include "JackThread.h"
+#include "JackConstants.h"
+#include "JackSynchro.h"
+#include "types.h"
+#include "transport_types.h"
+#include <list>
+
+namespace Jack
+{
+
+class JackClientChannelInterface;
+class JackGraphManager;
+class JackServer;
+class JackEngine;
+class JackSynchro;
+struct JackClientControl;
+struct JackEngineControl;
+class JackSyncInterface;
+
+typedef void (*JackShutdownCallback)(void *arg);
+
+/*!
+\brief The base class for clients: share part of the implementation for JackInternalClient and JackLibClient.
+*/
+
+class JackClient : public JackClientInterface, public JackRunnableInterface
+{
+
+ protected:
+
+ JackProcessCallback fProcess;
+ JackGraphOrderCallback fGraphOrder;
+ JackXRunCallback fXrun;
+ JackShutdownCallback fShutdown;
+ JackThreadInitCallback fInit;
+ JackBufferSizeCallback fBufferSize;
+ JackFreewheelCallback fFreewheel;
+ JackPortRegistrationCallback fPortRegistration;
+ JackTimebaseCallback fTimebase;
+ JackSyncCallback fSync;
+ void* fProcessArg;
+ void* fGraphOrderArg;
+ void* fXrunArg;
+ void* fShutdownArg;
+ void* fInitArg;
+ void* fBufferSizeArg;
+ void* fFreewheelArg;
+ void* fPortRegistrationArg;
+ void* fTimebaseArg;
+ void* fSyncArg;
+ int fConditionnal;
+
+ JackThread* fThread; /*! Thread to execute the Process function */
+ JackClientChannelInterface* fChannel;
+ JackSynchro** fSynchroTable;
+ std::list<jack_port_id_t> fPortList;
+
+ int StartThread();
+ void SetupDriverSync(bool freewheel);
+ bool IsActive();
+
+ bool CallProcessCallback();
+ void CallSyncCallback();
+ void CallTimebaseCallback();
+ int RequestNewPos(jack_position_t* pos);
+
+ virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value);
+
+ public:
+
+ JackClient();
+ JackClient(JackSynchro** table);
+ virtual ~JackClient();
+
+ virtual int Open(const char* name) = 0;
+ virtual int Close();
+
+ virtual JackGraphManager* GetGraphManager() const = 0;
+ virtual JackEngineControl* GetEngineControl() const = 0;
+
+ // Notifications
+ virtual int ClientNotify(int refnum, const char* name, int notify, int sync, int value);
+
+ virtual int Activate();
+ virtual int Deactivate();
+
+ // Context
+ virtual int SetBufferSize(jack_nframes_t nframes);
+ virtual int SetFreeWheel(int onoff);
+ virtual void ShutDown();
+ virtual pthread_t GetThreadID();
+
+ // Port management
+ virtual int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size);
+ virtual int PortUnRegister(jack_port_id_t port);
+
+ virtual int PortConnect(const char* src, const char* dst);
+ virtual int PortDisconnect(const char* src, const char* dst);
+ virtual int PortConnect(jack_port_id_t src, jack_port_id_t dst);
+ virtual int PortDisconnect(jack_port_id_t src);
+
+ int PortIsMine(jack_port_id_t port_index);
+
+ // Transport
+ virtual int ReleaseTimebase();
+ virtual int SetSyncCallback(JackSyncCallback sync_callback, void* arg);
+ virtual int SetSyncTimeout(jack_time_t timeout);
+ virtual int SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg);
+ virtual int TransportLocate(jack_nframes_t frame);
+ virtual jack_transport_state_t TransportQuery(jack_position_t* pos);
+ virtual jack_nframes_t GetCurrentTransportFrame();
+ virtual int TransportReposition(jack_position_t* pos);
+ virtual void TransportStart();
+ virtual void TransportStop();
+
+ // Callbacks
+ virtual void OnShutdown(JackShutdownCallback callback, void *arg);
+ virtual int SetProcessCallback(JackProcessCallback callback, void* arg);
+ virtual int SetXRunCallback(JackXRunCallback callback, void* arg);
+ virtual int SetInitCallback(JackThreadInitCallback callback, void* arg);
+ virtual int SetGraphOrderCallback(JackGraphOrderCallback callback, void* arg);
+ virtual int SetBufferSizeCallback(JackBufferSizeCallback callback, void* arg);
+ virtual int SetFreewheelCallback(JackFreewheelCallback callback, void* arg);
+ virtual int SetPortRegistrationCallback(JackPortRegistrationCallback callback, void* arg);
+
+ // JackRunnableInterface interface
+ bool Init();
+ bool Execute();
+};
+
+// Each "side" server and client will implement this to get the shared graph manager, engine control and inter-process synchro table.
+extern JackGraphManager* GetGraphManager();
+extern JackEngineControl* GetEngineControl();
+extern JackSynchro** GetSynchroTable();
+
+} // end of namespace
+
+#endif
diff --git a/common/JackClientControl.h b/common/JackClientControl.h
new file mode 100644
index 00000000..e9e9ce5a
--- /dev/null
+++ b/common/JackClientControl.h
@@ -0,0 +1,76 @@
+/*
+Copyright (C) 2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackClientControl__
+#define __JackClientControl__
+
+#include "JackShmMem.h"
+#include "JackPort.h"
+#include "JackSynchro.h"
+#include "transport_types.h"
+
+namespace Jack
+{
+
+/*!
+\brief Client control in shared memory.
+*/
+
+struct JackClientControl : public JackShmMem
+{
+ char fName[JACK_CLIENT_NAME_SIZE + 1];
+ volatile jack_transport_state_t fTransportState;
+ int fRefNum;
+ bool fZombie;
+ bool fActive;
+
+ JackClientControl(const char* name, int refnum)
+ {
+ Init(name, refnum);
+ }
+
+ JackClientControl(const char* name)
+ {
+ Init(name, -1);
+ }
+
+ JackClientControl()
+ {
+ Init("", -1);
+ }
+
+ virtual ~JackClientControl()
+ {}
+
+ void Init(const char* name, int refnum)
+ {
+ strcpy(fName, name);
+ fRefNum = refnum;
+ fTransportState = JackTransportStopped;
+ fZombie = false;
+ fActive = false;
+ }
+
+};
+
+} // end of namespace
+
+
+#endif
diff --git a/common/JackClientInterface.h b/common/JackClientInterface.h
new file mode 100644
index 00000000..b329794b
--- /dev/null
+++ b/common/JackClientInterface.h
@@ -0,0 +1,56 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackClientInterface__
+#define __JackClientInterface__
+
+#include "JackExports.h"
+
+
+namespace Jack
+{
+
+struct JackClientControl;
+
+/*!
+\brief Client interface.
+*/
+
+class EXPORT JackClientInterface
+{
+
+ public:
+
+ JackClientInterface()
+ {}
+ virtual ~JackClientInterface()
+ {}
+
+ virtual int Close() = 0;
+
+ virtual int ClientNotify(int refnum, const char* name, int notify, int sync, int value) = 0;
+
+ virtual JackClientControl* GetClientControl() const = 0;
+};
+
+
+} // end of namespace
+
+#endif
diff --git a/common/JackConnectionManager.cpp b/common/JackConnectionManager.cpp
new file mode 100644
index 00000000..5a1de3f7
--- /dev/null
+++ b/common/JackConnectionManager.cpp
@@ -0,0 +1,452 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <assert.h>
+#include "JackConnectionManager.h"
+#include "JackClientControl.h"
+#include "JackError.h"
+
+namespace Jack
+{
+
+JackConnectionManager::JackConnectionManager()
+{
+ int i;
+ JackLog("JackConnectionManager::InitConnections size = %ld \n", sizeof(JackConnectionManager));
+
+ for (i = 0; i < PORT_NUM; i++) {
+ fConnection[i].Init();
+ }
+
+ fLoopFeedback.Init();
+
+ JackLog("JackConnectionManager::InitClients\n");
+ for (i = 0; i < CLIENT_NUM; i++) {
+ InitClient(i);
+ }
+}
+
+JackConnectionManager::~JackConnectionManager()
+{}
+
+//--------------
+// Internal API
+//--------------
+
+bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const
+{
+ JackLog("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld\n", ref1, ref2);
+
+ if (ref1 == AUDIO_DRIVER_REFNUM // Driver is reached
+ || ref2 == AUDIO_DRIVER_REFNUM
+ || ref1 == FREEWHEEL_DRIVER_REFNUM
+ || ref2 == FREEWHEEL_DRIVER_REFNUM
+ || ref1 == LOOPBACK_DRIVER_REFNUM
+ || ref2 == LOOPBACK_DRIVER_REFNUM) {
+ return false;
+ } else if (ref1 == ref2) { // Same refnum
+ return true;
+ } else {
+ jack_int_t output[CLIENT_NUM];
+ fConnectionRef.GetOutputTable(ref1, output);
+
+ if (fConnectionRef.IsInsideTable(ref2, output)) { // If ref2 is contained in the outputs of ref1
+ return true;
+ } else {
+ for (int i = 0; i < CLIENT_NUM && output[i] != EMPTY; i++) { // Otherwise recurse for all ref1 outputs
+ if (IsLoopPathAux(output[i], ref2))
+ return true; // Stop when a path is found
+ }
+ return false;
+ }
+ }
+}
+
+void JackConnectionManager::InitClient(int refnum)
+{
+ fInputPort[refnum].Init();
+ fOutputPort[refnum].Init();
+ fConnectionRef.Init(refnum);
+ fInputCounter[refnum].SetValue(0);
+}
+
+//--------------
+// External API
+//--------------
+
+int JackConnectionManager::GetActivation(int refnum) const
+{
+ return fInputCounter[refnum].GetValue();
+}
+
+/*!
+\brief Connect port_src to port_dst.
+*/
+int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ JackLog("JackConnectionManager::Connect port_src = %ld port_dst = %ld\n", port_src, port_dst);
+
+ if (fConnection[port_src].AddItem(port_dst)) {
+ return 0;
+ } else {
+ jack_error("Connection table is full !!");
+ return -1;
+ }
+}
+
+/*!
+\brief Disconnect port_src from port_dst.
+*/
+int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ JackLog("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld\n", port_src, port_dst);
+
+ if (fConnection[port_src].RemoveItem(port_dst)) {
+ return 0;
+ } else {
+ jack_error("Connection not found !!");
+ return -1;
+ }
+}
+
+/*!
+\brief Check if port_src and port_dst are connected.
+*/
+bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const
+{
+ return fConnection[port_src].CheckItem(port_dst);
+}
+
+/*!
+\brief Get the connection number of a given port.
+*/
+jack_int_t JackConnectionManager::Connections(jack_port_id_t port_index) const
+{
+ return fConnection[port_index].GetItemCount();
+}
+
+jack_port_id_t JackConnectionManager::GetPort(jack_port_id_t port_index, int connection) const
+{
+ assert(connection < CONNECTION_NUM);
+ return (jack_port_id_t)fConnection[port_index].GetItem(connection);
+}
+
+/*!
+\brief Get the connection port array.
+*/
+const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const
+{
+ return fConnection[port_index].GetItems();
+}
+
+//------------------------
+// Client port management
+//------------------------
+
+/*!
+\brief Add an input port to a client.
+*/
+int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index)
+{
+ if (fInputPort[refnum].AddItem(port_index)) {
+ JackLog("JackConnectionManager::AddInputPort ref = %ld port = %ld\n", refnum, port_index);
+ return 0;
+ } else {
+ jack_error("Maximum number of input ports is reached for application ref = %ld", refnum);
+ return -1;
+ }
+}
+
+/*!
+\brief Add an output port to a client.
+*/
+int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index)
+{
+ if (fOutputPort[refnum].AddItem(port_index)) {
+ JackLog("JackConnectionManager::AddOutputPort ref = %ld port = %ld\n", refnum, port_index);
+ return 0;
+ } else {
+ jack_error("Maximum number of output ports is reached for application ref = %ld", refnum);
+ return -1;
+ }
+}
+
+/*!
+\brief Remove an input port from a client.
+*/
+int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index)
+{
+ JackLog("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld \n", refnum, port_index);
+
+ if (fInputPort[refnum].RemoveItem(port_index)) {
+ return 0;
+ } else {
+ jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum);
+ return -1;
+ }
+}
+
+/*!
+\brief Remove an output port from a client.
+*/
+int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index)
+{
+ JackLog("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld \n", refnum, port_index);
+
+ if (fOutputPort[refnum].RemoveItem(port_index)) {
+ return 0;
+ } else {
+ jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum);
+ return -1;
+ }
+}
+
+/*!
+\brief Get the input port array of a given refnum.
+*/
+const jack_int_t* JackConnectionManager::GetInputPorts(int refnum)
+{
+ return fInputPort[refnum].GetItems();
+}
+
+/*!
+\brief Get the output port array of a given refnum.
+*/
+const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum)
+{
+ return fOutputPort[refnum].GetItems();
+}
+
+/*!
+\brief Return the first available refnum.
+*/
+int JackConnectionManager::AllocateRefNum()
+{
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ if (fInputPort[i].IsAvailable()) {
+ JackLog("JackConnectionManager::AllocateRefNum ref = %ld\n", i);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*!
+\brief Release the refnum.
+*/
+void JackConnectionManager::ReleaseRefNum(int refnum)
+{
+ JackLog("JackConnectionManager::ReleaseRefNum ref = %ld\n", refnum);
+ InitClient(refnum);
+}
+
+/*!
+\brief Reset all clients activation.
+*/
+void JackConnectionManager::ResetGraph(JackClientTiming* timing)
+{
+ // Reset activation counter : must be done *before* starting to resume clients
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ fInputCounter[i].Reset();
+ timing[i].fStatus = NotTriggered;
+ }
+}
+
+/*!
+\brief Wait on the input synchro.
+*/
+int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing, long time_out_usec)
+{
+ int res;
+ if ((res = table[control->fRefNum]->TimedWait(time_out_usec))) {
+ timing[control->fRefNum].fStatus = Running;
+ timing[control->fRefNum].fAwakeAt = GetMicroSeconds();
+ }
+ return (res) ? 0 : -1;
+}
+
+/*!
+\brief Signal clients connected to the given client.
+*/
+int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing)
+{
+ jack_time_t current_date = GetMicroSeconds();
+ const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum);
+ int res = 0;
+
+ // Update state and timestamp of current client
+ timing[control->fRefNum].fStatus = Finished;
+ timing[control->fRefNum].fFinishedAt = current_date;
+
+ for (int i = 0; i < CLIENT_NUM; i++) {
+
+ // Signal connected clients or drivers
+ if (outputRef[i] > 0) {
+
+ // Update state and timestamp of destination clients
+ timing[i].fStatus = Triggered;
+ timing[i].fSignaledAt = current_date;
+
+ if (!fInputCounter[i].Signal(table[i], control)) {
+ JackLog("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld \n", control->fRefNum, i);
+ res = -1;
+ }
+ }
+ }
+
+ return res;
+}
+
+/*!
+\brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated.
+*/
+void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ int ref1 = GetOutputRefNum(port_src);
+ int ref2 = GetInputRefNum(port_dst);
+
+ assert(ref1 >= 0 && ref2 >= 0);
+
+ DirectConnect(ref1, ref2);
+ JackLog("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld\n", ref1, ref2);
+}
+
+/*!
+\brief Decrement the number of ports between 2 clients, if the 2 clients become disconnected, then the Activation counter is updated.
+*/
+void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ int ref1 = GetOutputRefNum(port_src);
+ int ref2 = GetInputRefNum(port_dst);
+
+ assert(ref1 >= 0 && ref2 >= 0);
+
+ DirectDisconnect(ref1, ref2);
+ JackLog("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld\n", ref1, ref2);
+}
+
+/*!
+\brief Directly connect 2 reference numbers.
+*/
+void JackConnectionManager::DirectConnect(int ref1, int ref2)
+{
+ assert(ref1 >= 0 && ref2 >= 0);
+
+ if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2
+ JackLog("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld\n", ref1, ref2);
+ fInputCounter[ref2].IncValue();
+ }
+}
+
+/*!
+\brief Directly disconnect 2 reference numbers.
+*/
+void JackConnectionManager::DirectDisconnect(int ref1, int ref2)
+{
+ assert(ref1 >= 0 && ref2 >= 0);
+
+ if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2
+ JackLog("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld\n", ref1, ref2);
+ fInputCounter[ref2].DecValue();
+ }
+}
+
+/*!
+\brief Returns the connections state between 2 refnum.
+*/
+bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const
+{
+ assert(ref1 >= 0 && ref2 >= 0);
+ return fConnectionRef.GetItemCount(ref1, ref2);
+}
+
+/*!
+\brief Get the client refnum of a given input port.
+*/
+int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const
+{
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ if (fInputPort[i].CheckItem(port_index))
+ return i;
+ }
+
+ return -1;
+}
+
+/*!
+\brief Get the client refnum of a given ouput port.
+*/
+int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const
+{
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ if (fOutputPort[i].CheckItem(port_index))
+ return i;
+ }
+
+ return -1;
+}
+
+/*!
+\brief Test is a connection path exists between port_src and port_dst.
+*/
+bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const
+{
+ return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src));
+}
+
+bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const
+{
+ return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0);
+}
+
+bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ int ref1 = GetOutputRefNum(port_src);
+ int ref2 = GetInputRefNum(port_dst);
+
+ // Add an activation connection in the other direction
+ JackLog("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld\n", ref1, ref2);
+ assert(ref1 >= 0 && ref2 >= 0);
+
+ if (ref1 != ref2)
+ DirectConnect(ref2, ref1);
+
+ return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection
+}
+
+bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ int ref1 = GetOutputRefNum(port_src);
+ int ref2 = GetInputRefNum(port_dst);
+
+ // Remove an activation connection in the other direction
+ JackLog("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld\n", ref1, ref2);
+ assert(ref1 >= 0 && ref2 >= 0);
+
+ if (ref1 != ref2)
+ DirectDisconnect(ref2, ref1);
+
+ return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
+}
+
+} // end of namespace
+
+
diff --git a/common/JackConnectionManager.h b/common/JackConnectionManager.h
new file mode 100644
index 00000000..652cefc5
--- /dev/null
+++ b/common/JackConnectionManager.h
@@ -0,0 +1,468 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackConnectionManager__
+#define __JackConnectionManager__
+
+#include "JackConstants.h"
+#include "JackActivationCount.h"
+#include <assert.h>
+
+namespace Jack
+{
+
+#define NO_PORT 0xFFFE
+
+#define EMPTY 0xFFFD
+#define FREE 0xFFFC
+
+typedef uint16_t jack_int_t; // Internal type for ports and refnum
+
+struct JackClientControl;
+
+typedef enum {
+ NotTriggered,
+ Triggered,
+ Running,
+ Finished,
+} jack_client_state_t;
+
+/*!
+\brief Utility class.
+*/
+
+template <int SIZE>
+class JackFixedArray
+{
+
+ private:
+
+ jack_int_t fTable[SIZE];
+ uint32_t fCounter;
+
+ public:
+
+ JackFixedArray()
+ {
+ Init();
+ }
+
+ virtual ~JackFixedArray()
+ {}
+
+ void Init()
+ {
+ for (int i = 0; i < SIZE; i++)
+ fTable[i] = EMPTY;
+ fCounter = 0;
+ }
+
+ bool AddItem(jack_int_t index)
+ {
+ for (int i = 0; i < SIZE; i++) {
+ if (fTable[i] == EMPTY) {
+ fTable[i] = index;
+ fCounter++;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool RemoveItem(jack_int_t index)
+ {
+ for (int i = 0; i < SIZE; i++) {
+ if (fTable[i] == index) {
+ fCounter--;
+ // Shift all indexes
+ if (i == SIZE - 1) {
+ fTable[i] = EMPTY;
+ } else {
+ int j;
+ for (j = i; j <= SIZE - 2 && fTable[j] != EMPTY; j++) {
+ fTable[j] = fTable[j + 1];
+ }
+ fTable[j] = EMPTY;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ jack_int_t GetItem(jack_int_t index) const
+ {
+ return (index < SIZE) ? fTable[index] : EMPTY;
+ }
+
+ const jack_int_t* GetItems() const
+ {
+ return fTable;
+ }
+
+ bool CheckItem(jack_int_t index) const
+ {
+ for (int i = 0; i < SIZE && fTable[i] != EMPTY; i++) {
+ if (fTable[i] == index)
+ return true;
+ }
+ return false;
+ }
+
+ uint32_t GetItemCount() const
+ {
+ return fCounter;
+ }
+
+};
+
+/*!
+\brief Utility class.
+*/
+
+template <int SIZE>
+class JackFixedArray1 : public JackFixedArray<SIZE>
+{
+ private:
+
+ bool fUsed;
+
+ public:
+
+ JackFixedArray1()
+ {
+ Init();
+ }
+
+ virtual ~JackFixedArray1()
+ {}
+
+ void Init()
+ {
+ JackFixedArray<SIZE>::Init();
+ fUsed = false;
+ }
+
+ bool IsAvailable()
+ {
+ if (fUsed) {
+ return false;
+ } else {
+ fUsed = true;
+ return true;
+ }
+ }
+};
+
+/*!
+\brief Utility class.
+*/
+
+template <int SIZE>
+class JackFixedMatrix
+{
+ private:
+
+ jack_int_t fTable[SIZE][SIZE];
+
+ public:
+
+ JackFixedMatrix()
+ {}
+
+ virtual ~JackFixedMatrix()
+ {}
+
+ void Init(jack_int_t index)
+ {
+ for (int i = 0; i < SIZE; i++) {
+ fTable[index][i] = 0;
+ fTable[i][index] = 0;
+ }
+ }
+
+ const jack_int_t* GetItems(jack_int_t index) const
+ {
+ return fTable[index];
+ }
+
+ jack_int_t IncItem(jack_int_t index1, jack_int_t index2)
+ {
+ fTable[index1][index2]++;
+ return fTable[index1][index2];
+ }
+
+ jack_int_t DecItem(jack_int_t index1, jack_int_t index2)
+ {
+ fTable[index1][index2]--;
+ return fTable[index1][index2];
+ }
+
+ jack_int_t GetItemCount(jack_int_t index1, jack_int_t index2) const
+ {
+ return fTable[index1][index2];
+ }
+
+ /*!
+ \brief Get the output indexes of a given index.
+ */
+ void GetOutputTable(jack_int_t index, jack_int_t* output) const
+ {
+ int i, j;
+
+ for (i = 0; i < SIZE; i++)
+ output[i] = EMPTY;
+
+ for (i = 0, j = 0; i < SIZE; i++) {
+ if (fTable[index][i] > 0) {
+ output[j] = i;
+ j++;
+ }
+ }
+ }
+
+ bool IsInsideTable(jack_int_t index, jack_int_t* output) const
+ {
+ for (int i = 0; i < SIZE && output[i] != EMPTY; i++) {
+ if (output[i] == index)
+ return true;
+ }
+ return false;
+ }
+
+};
+
+/*!
+\brief Utility class.
+*/
+
+template <int SIZE>
+class JackLoopFeedback
+{
+ private:
+
+ int fTable[SIZE][3];
+
+ /*!
+ \brief Add a feedback connection between 2 refnum.
+ */
+ bool AddConnectionAux(int ref1, int ref2)
+ {
+ for (int i = 0; i < SIZE; i++) {
+ if (fTable[i][0] == EMPTY) {
+ fTable[i][0] = ref1;
+ fTable[i][1] = ref2;
+ fTable[i][2] = 1;
+ JackLog("JackLoopFeedback::AddConnectionAux ref1 = %ld ref2 = %ld\n", ref1, ref2);
+ return true;
+ }
+ }
+ jack_error("Feedback table is full !!\n");
+ return false;
+ }
+
+ /*!
+ \brief Remove a feedback connection between 2 refnum.
+ */
+ bool RemoveConnectionAux(int ref1, int ref2)
+ {
+ for (int i = 0; i < SIZE; i++) {
+ if (fTable[i][0] == ref1 && fTable[i][1] == ref2) {
+ fTable[i][0] = EMPTY;
+ fTable[i][1] = EMPTY;
+ fTable[i][2] = 0;
+ JackLog("JackLoopFeedback::RemoveConnectionAux ref1 = %ld ref2 = %ld\n", ref1, ref2);
+ return true;
+ }
+ }
+ jack_error("Feedback connection not found\n");
+ return false;
+ }
+
+ int IncConnection(int index)
+ {
+ fTable[index][2]++;
+ return fTable[index][2];
+ }
+
+ int DecConnection(int index)
+ {
+ fTable[index][2]--;
+ return fTable[index][2];
+ }
+
+ public:
+
+ JackLoopFeedback()
+ {
+ Init();
+ }
+ virtual ~JackLoopFeedback()
+ {}
+
+ void Init()
+ {
+ for (int i = 0; i < SIZE; i++) {
+ fTable[i][0] = EMPTY;
+ fTable[i][1] = EMPTY;
+ fTable[i][2] = 0;
+ }
+ }
+
+ bool IncConnection(int ref1, int ref2)
+ {
+ int index = GetConnectionIndex(ref1, ref2);
+
+ if (index >= 0) { // Feedback connection is already added, increment counter
+ IncConnection(index);
+ return true;
+ } else {
+ return AddConnectionAux(ref1, ref2); // Add the feedback connection
+ }
+ }
+
+ bool DecConnection(int ref1, int ref2)
+ {
+ int index = GetConnectionIndex(ref1, ref2);
+
+ if (index >= 0) {
+ JackLog("JackLoopFeedback::DecConnection ref1 = %ld ref2 = %ld index = %ld\n", ref1, ref2, index);
+ return (DecConnection(index) == 0) ? RemoveConnectionAux(ref1, ref2) : true;
+ } else {
+ return false;
+ }
+ }
+
+ /*!
+ \brief Test if a connection between 2 refnum is a feedback connection.
+ */
+ int GetConnectionIndex(int ref1, int ref2) const
+ {
+ for (int i = 0; i < SIZE; i++) {
+ if (fTable[i][0] == ref1 && fTable[i][1] == ref2)
+ return i;
+ }
+ return -1;
+ }
+
+};
+
+/*!
+\brief For client timing measurements.
+*/
+
+struct JackClientTiming
+{
+ jack_time_t fSignaledAt;
+ jack_time_t fAwakeAt;
+ jack_time_t fFinishedAt;
+ jack_client_state_t fStatus;
+
+ JackClientTiming():fSignaledAt(0), fAwakeAt(0), fFinishedAt(0), fStatus(NotTriggered)
+ {}
+ ~JackClientTiming()
+ {}
+};
+
+/*!
+\brief Connection manager.
+
+<UL>
+<LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port.
+<LI>The <B>fConnectionCount</B> array contains the number of connected ports to a given port.
+<LI>The <B>fInputPort</B> array contains the list (array line) of input connected ports for a given client.
+<LI>The <B>fOutputPort</B> array contains the list (array line) of ouput connected ports for a given client.
+<LI>The <B>fConnectionRef</B> array contains the number of ports connected between two clients.
+<LI>The <B>fInputRef</B> array contains the number of input clients connected to a given client.
+<LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose.
+</UL>
+*/
+
+class JackConnectionManager
+{
+
+ private:
+
+ JackFixedArray<CONNECTION_NUM> fConnection[PORT_NUM]; /*! Connection matrix: list of connected ports for a given port: needed to compute Mix buffer */
+ JackFixedArray1<PORT_NUM_FOR_CLIENT> fInputPort[CLIENT_NUM]; /*! Table of input port per refnum : to find a refnum for a given port */
+ JackFixedArray<PORT_NUM_FOR_CLIENT> fOutputPort[CLIENT_NUM]; /*! Table of output port per refnum : to find a refnum for a given port */
+ JackFixedMatrix<CLIENT_NUM> fConnectionRef; /*! Table of port connections by (refnum , refnum) */
+ JackActivationCount fInputCounter[CLIENT_NUM]; /*! Activation counter per refnum */
+ JackLoopFeedback<CONNECTION_NUM> fLoopFeedback; /*! Loop feedback connections */
+
+ bool IsLoopPathAux(int ref1, int ref2) const;
+ void InitClient(int refnum);
+
+ public:
+
+ JackConnectionManager();
+ virtual ~JackConnectionManager();
+
+ // Connections management
+ int Connect(jack_port_id_t port_src, jack_port_id_t port_dst);
+ int Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst);
+ bool IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const;
+
+ jack_int_t Connections(jack_port_id_t port_index) const;
+ jack_port_id_t GetPort(jack_port_id_t port_index, int connection) const;
+ const jack_int_t* GetConnections(jack_port_id_t port_index) const;
+
+ bool IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
+ bool DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
+ bool IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const;
+
+ bool IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const;
+ void IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
+ void DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst);
+
+ // Ports management
+ int AddInputPort(int refnum, jack_port_id_t port_index);
+ int AddOutputPort(int refnum, jack_port_id_t port_index);
+
+ int RemoveInputPort(int refnum, jack_port_id_t port_index);
+ int RemoveOutputPort(int refnum, jack_port_id_t port_index);
+
+ const jack_int_t* GetInputPorts(int refnum);
+ const jack_int_t* GetOutputPorts(int refnum);
+
+ // Client management
+ int AllocateRefNum();
+ void ReleaseRefNum(int refnum);
+
+ int GetInputRefNum(jack_port_id_t port_index) const;
+ int GetOutputRefNum(jack_port_id_t port_index) const;
+
+ // Connect/Disconnect 2 refnum "directly"
+ bool IsDirectConnection(int ref1, int ref2) const;
+ void DirectConnect(int ref1, int ref2);
+ void DirectDisconnect(int ref1, int ref2);
+
+ int GetActivation(int refnum) const;
+
+ // Graph
+ void ResetGraph(JackClientTiming* timing);
+ int ResumeRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing);
+ int SuspendRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing, long time_out_usec);
+
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackConstants.h b/common/JackConstants.h
new file mode 100644
index 00000000..917f692b
--- /dev/null
+++ b/common/JackConstants.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define PRINTDEBUG
+
+#define VERSION "0.58"
+
+#define FORK_SERVER 1
+
+#define BUFFER_SIZE_MAX 8192
+#define SAMPLE_RATE 44100
+
+#define JACK_PORT_NAME_SIZE 256
+#define JACK_PORT_TYPE_SIZE 32
+
+#define JACK_CLIENT_NAME_SIZE 64
+
+#define PORT_NUM 512
+#define PORT_NUM_FOR_CLIENT 256
+
+#define CONNECTION_NUM 256
+
+#define CLIENT_NUM 64
+
+#define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0
+#define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1
+#define LOOPBACK_DRIVER_REFNUM 2 // Loopback driver is initialized third, it will get the refnum 2
+#define REAL_REFNUM LOOPBACK_DRIVER_REFNUM + 1 // Real clients start at LOOPBACK_DRIVER_REFNUM + 1
+
+#define SOCKET_TIME_OUT 5
+
+#ifdef WIN32
+ #define jack_server_dir "server"
+ #define jack_client_dir "client"
+#else
+ #define jack_server_dir "/dev/shm"
+ #define jack_client_dir "/dev/shm"
+#endif
+
+/*
+#define jack_server_dir "/mnt/ramfs"
+#define jack_client_dir "/mnt/ramfs"
+*/
+
+#define jack_server_entry "jackdmp_entry"
+#define jack_client_entry "jack_client"
+
+#define ALL_CLIENTS -1 // for notification
diff --git a/common/JackDebugClient.cpp b/common/JackDebugClient.cpp
new file mode 100644
index 00000000..be066e40
--- /dev/null
+++ b/common/JackDebugClient.cpp
@@ -0,0 +1,457 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackDebugClient.h"
+#include "JackError.h"
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <time.h>
+
+using namespace std;
+
+namespace Jack
+{
+
+JackDebugClient::JackDebugClient(JackClient * client)
+{
+ fTotalPortNumber = 1; // The total number of port opened and maybe closed. Historical view.
+ fOpenPortNumber = 0; // The current number of opened port.
+ fIsActivated = 0;
+ fIsDeactivated = 0;
+ fIsClosed = 0;
+ fClient = client;
+}
+
+JackDebugClient::~JackDebugClient()
+{
+ fTotalPortNumber--; // fTotalPortNumber start at 1
+ *fStream << endl << endl << "----------------------------------- JackDebugClient summary ------------------------------- " << endl << endl;
+ *fStream << "Client flags ( 1:yes / 0:no ) :" << endl;
+ *fStream << setw(5) << "- Client call activated : " << fIsActivated << endl;
+ *fStream << setw(5) << "- Client call deactivated : " << fIsDeactivated << endl;
+ *fStream << setw(5) << "- Client call closed : " << fIsClosed << endl;
+ *fStream << setw(5) << "- Total number of instantiated port : " << fTotalPortNumber << endl;
+ *fStream << setw(5) << "- Number of port remaining open when exiting client : " << fOpenPortNumber << endl;
+ if (fOpenPortNumber != 0)
+ *fStream << "!!! WARNING !!! Some ports have not been unregistrated ! Incorrect exiting !" << endl;
+ if (fIsDeactivated != fIsActivated)
+ *fStream << "!!! ERROR !!! Client seem do not perform symetric activation-deactivation ! (not the same number of activate and deactivate)" << endl;
+ if (fIsClosed == 0)
+ *fStream << "!!! ERROR !!! Client have not been closed with jack_client_close() !" << endl;
+
+ *fStream << endl << endl << "---------------------------- JackDebugClient detailed port summary ------------------------ " << endl << endl;
+ //for (int i = 0; i < fTotalPortNumber ; i++) {
+ for (int i = 1; i <= fTotalPortNumber ; i++) {
+ *fStream << endl << "Port index (internal debug test value) : " << i << endl;
+ *fStream << setw(5) << "- Name : " << fPortList[i].name << endl;
+ *fStream << setw(5) << "- idport : " << fPortList[i].idport << endl;
+ *fStream << setw(5) << "- IsConnected : " << fPortList[i].IsConnected << endl;
+ *fStream << setw(5) << "- IsUnregistrated : " << fPortList[i].IsUnregistrated << endl;
+ if (fPortList[i].IsUnregistrated == 0)
+ *fStream << "!!! WARNING !!! Port have not been unregistrated ! Incorrect exiting !" << endl;
+ }
+ *fStream << "delete object JackDebugClient : end of tracing" << endl;
+ delete fStream;
+ delete fClient;
+}
+
+int JackDebugClient::Open(const char* name)
+{
+ int Tidport;
+ Tidport = fClient->Open(name);
+ char provstr[256];
+ char buffer[256];
+ time_t curtime;
+ struct tm *loctime;
+ /* Get the current time. */
+ curtime = time (NULL);
+ /* Convert it to local time representation. */
+ loctime = localtime (&curtime);
+ strftime (buffer, 256, "%I-%M", loctime);
+ sprintf(provstr, "JackClientDebug-%s-%s.log", name, buffer);
+ fStream = new ofstream(provstr, ios_base::ate);
+ if (fStream->is_open()) {
+ if (Tidport == -1) {
+ *fStream << "Trying to Open Client with name '" << name << "' with bad result (client not opened)." << Tidport << endl;
+ } else {
+ *fStream << "Open Client with name '" << name << "'." << endl;
+ }
+ } else {
+ JackLog("JackDebugClient::Open : cannot open log file\n");
+ }
+ strcpy(fClientName, name);
+ return Tidport;
+}
+
+int JackDebugClient::Close()
+{
+ fIsClosed++;
+ *fStream << "Client '" << fClientName << "' was Closed" << endl;
+ return fClient->Close();
+}
+
+pthread_t JackDebugClient::GetThreadID()
+{
+ return fClient->GetThreadID();
+}
+
+JackGraphManager* JackDebugClient::GetGraphManager() const
+{
+ return fClient->GetGraphManager();
+}
+JackEngineControl* JackDebugClient::GetEngineControl() const
+{
+ return fClient->GetEngineControl();
+}
+/*!
+\brief Notification received from the server.
+*/
+
+int JackDebugClient::ClientNotify(int refnum, const char* name, int notify, int sync, int value)
+{
+ return fClient->ClientNotify( refnum, name, notify, sync, value);
+}
+
+int JackDebugClient::Activate()
+{
+ int Tidport;
+ Tidport = fClient->Activate();
+ fIsActivated++;
+ if (fIsDeactivated)
+ *fStream << "Client '" << fClientName << "' call activate a new time (it already call 'activate' previously)." << endl;
+ *fStream << "Client '" << fClientName << "' Activated" << endl;
+ if (Tidport != 0)
+ *fStream << "Client '" << fClientName << "' try to activate but server return " << Tidport << " ." << endl;
+ return Tidport;
+}
+
+int JackDebugClient::Deactivate()
+{
+ int Tidport;
+ Tidport = fClient->Deactivate();
+ fIsDeactivated++;
+ if (fIsActivated == 0)
+ *fStream << "Client '" << fClientName << "' deactivate while it hasn't been previoulsy activated !" << endl;
+ *fStream << "Client '" << fClientName << "' Deactivated" << endl;
+ if (Tidport != 0)
+ *fStream << "Client '" << fClientName << "' try to deactivate but server return " << Tidport << " ." << endl;
+ return Tidport;
+}
+
+//-----------------
+// Port management
+//-----------------
+
+int JackDebugClient::PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size)
+{
+ int Tidport;
+ Tidport = fClient->PortRegister(port_name, port_type, flags, buffer_size);
+ if (Tidport <= 0) {
+ *fStream << "Client '" << fClientName << "' try port Register ('" << port_name << "') and server return error " << Tidport << " ." << endl;
+ } else {
+ if (fTotalPortNumber < MAX_PORT_HISTORY) {
+ fPortList[fTotalPortNumber].idport = Tidport;
+ strcpy(fPortList[fTotalPortNumber].name, port_name);
+ fPortList[fTotalPortNumber].IsConnected = 0;
+ fPortList[fTotalPortNumber].IsUnregistrated = 0;
+ } else {
+ *fStream << "!!! WARNING !!! History is full : no more port history will be recorded." << endl;
+ }
+ fTotalPortNumber++;
+ fOpenPortNumber++;
+ *fStream << "Client '" << fClientName << "' port Register with portname '" << port_name << " port " << Tidport << "' ." << endl;
+ }
+ return Tidport;
+}
+
+int JackDebugClient::PortUnRegister(jack_port_id_t port_index)
+{
+ int Tidport;
+ Tidport = fClient->PortUnRegister(port_index);
+ fOpenPortNumber--;
+ int i;
+ for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
+ if (fPortList[i].idport == port_index) { // We found the last record
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! : '" << fClientName << "' id deregistering port '" << fPortList[i].name << "' that have already been unregistered !" << endl;
+ fPortList[i].IsUnregistrated++;
+ break;
+ }
+ }
+ if (i == 0) // Port is not found
+ *fStream << "JackClientDebug : PortUnregister : port " << port_index << " was not previously registered !" << endl;
+ if (Tidport != 0)
+ *fStream << "Client '" << fClientName << "' try to do PortUnregister and server return " << Tidport << " )." << endl;
+ *fStream << "Client '" << fClientName << "' unregister port '" << port_index << "'." << endl;
+ return Tidport;
+}
+
+int JackDebugClient::PortConnect(const char* src, const char* dst)
+{
+ if (!(fIsActivated))
+ *fStream << "!!! ERROR !!! Trying to connect a port ( " << src << " to " << dst << ") while the client has not been activated !" << endl;
+ int Tidport;
+ int i;
+ Tidport = fClient->PortConnect( src, dst);
+ for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
+ if (strcmp(fPortList[i].name, src) == 0) { // We found the last record in sources
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! Connecting port " << src << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected++;
+ *fStream << "Connecting port " << src << " to " << dst << ". ";
+ break;
+ } else if (strcmp(fPortList[i].name, dst) == 0 ) { // We found the record in dest
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! Connecting port " << dst << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected++;
+ *fStream << "Connecting port " << src << " to " << dst << ". ";
+ break;
+ }
+ }
+ if (i == 0) // Port is not found
+ *fStream << "JackClientDebug : PortConnect : port was not found in debug database !" << endl;
+ if (Tidport != 0)
+ *fStream << "Client '" << fClientName << "' try to do PortConnect but server return " << Tidport << " ." << endl;
+ //*fStream << "Client Port Connect done with names" << endl;
+ return Tidport;
+}
+
+int JackDebugClient::PortDisconnect(const char* src, const char* dst)
+{
+ if (!(fIsActivated))
+ *fStream << "!!! ERROR !!! Trying to disconnect a port ( " << src << " to " << dst << ") while the client has not been activated !" << endl;
+ int Tidport;
+ Tidport = fClient->PortDisconnect( src, dst);
+ int i;
+ for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
+ if (strcmp(fPortList[i].name, src) == 0) { // We found the record in sources
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected--;
+ *fStream << "disconnecting port " << src << ". ";
+ break;
+ } else if (strcmp(fPortList[i].name, dst) == 0 ) { // We found the record in dest
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! : Disonnecting port " << dst << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected--;
+ *fStream << "disconnecting port " << dst << ". ";
+ break;
+ }
+ }
+ if (i == 0) // Port is not found
+ *fStream << "JackClientDebug : PortDisConnect : port was not found in debug database !" << endl;
+ if (Tidport != 0)
+ *fStream << "Client '" << fClientName << "' try to do PortDisconnect but server return " << Tidport << " ." << endl;
+ //*fStream << "Client Port Disconnect done." << endl;
+ return Tidport;
+}
+
+int JackDebugClient::PortConnect(jack_port_id_t src, jack_port_id_t dst)
+{
+ if (!(fIsActivated))
+ *fStream << "!!! ERROR !!! : Trying to connect port " << src << " to " << dst << " while the client has not been activated !" << endl;
+ int Tidport;
+ Tidport = fClient->PortConnect(src, dst);
+ int i;
+ for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
+ if (fPortList[i].idport == src) { // We found the record in sources
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! : Connecting port " << src << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected++;
+ *fStream << "Connecting port " << src << ". ";
+ break;
+ } else if (fPortList[i].idport == dst) { // We found the record in dest
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! : Connecting port " << dst << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected++;
+ *fStream << "Connecting port " << dst << ". ";
+ break;
+ }
+ }
+ if (i == 0) // Port is not found
+ *fStream << "JackClientDebug : PortConnect : port was not found in debug database !" << endl;
+ if (Tidport == -1)
+ *fStream << "Client '" << fClientName << "' try to do Portconnect but server return " << Tidport << " ." << endl;
+ //*fStream << "Client Port Connect with ID done." << endl;
+ return Tidport;
+}
+
+int JackDebugClient::PortDisconnect(jack_port_id_t src)
+{
+ if (!(fIsActivated))
+ *fStream << "!!! ERROR !!! : Trying to disconnect port " << src << " while that client has not been activated !" << endl;
+ int Tidport;
+ Tidport = fClient->PortDisconnect(src);
+ int i;
+ for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history
+ if (fPortList[i].idport == src) { // We found the record in sources
+ if (fPortList[i].IsUnregistrated != 0)
+ *fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl;
+ fPortList[i].IsConnected--;
+ *fStream << "Disconnecting port " << src << ". " << endl;
+ break;
+ }
+ }
+ if (i == 0) // Port is not found
+ *fStream << "JackClientDebug : PortDisconnect : port was not found in debug database !" << endl;
+ if (Tidport != 0)
+ *fStream << "Client '" << fClientName << "' try to do PortDisconnect but server return " << Tidport << " ." << endl;
+ //*fStream << "Client Port Disconnect with ID done." << endl;
+ return Tidport;
+}
+
+int JackDebugClient::PortIsMine(jack_port_id_t port_index)
+{
+ return fClient->PortIsMine(port_index);
+}
+
+//--------------------
+// Context management
+//--------------------
+
+int JackDebugClient::SetBufferSize(jack_nframes_t nframes)
+{
+ return fClient->SetBufferSize(nframes);
+}
+
+int JackDebugClient::SetFreeWheel(int onoff)
+{
+ return fClient->SetFreeWheel(onoff);
+}
+
+/*
+ShutDown is called:
+- from the RT thread when Execute method fails
+- possibly from a "closed" notification channel
+(Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
+*/
+
+void JackDebugClient::ShutDown()
+{
+ fClient->ShutDown();
+}
+
+//---------------------
+// Transport management
+//---------------------
+
+int JackDebugClient::ReleaseTimebase()
+{
+ return fClient->ReleaseTimebase();
+}
+
+int JackDebugClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg)
+{
+ return fClient->SetSyncCallback(sync_callback, arg);
+}
+
+int JackDebugClient::SetSyncTimeout(jack_time_t timeout)
+{
+ return fClient->SetSyncTimeout(timeout);
+}
+
+int JackDebugClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg)
+{
+ return fClient->SetTimebaseCallback( conditional, timebase_callback, arg);
+}
+
+int JackDebugClient::TransportLocate(jack_nframes_t frame)
+{
+ return fClient->TransportLocate(frame);
+}
+
+jack_transport_state_t JackDebugClient::TransportQuery(jack_position_t* pos)
+{
+ return fClient->TransportQuery(pos);
+}
+
+jack_nframes_t JackDebugClient::GetCurrentTransportFrame()
+{
+ return fClient->GetCurrentTransportFrame();
+}
+
+int JackDebugClient::TransportReposition(jack_position_t* pos)
+{
+ return fClient->TransportReposition(pos);
+}
+
+void JackDebugClient::TransportStart()
+{
+ fClient->TransportStart();
+}
+
+void JackDebugClient::TransportStop()
+{
+ fClient->TransportStop();
+}
+
+//---------------------
+// Callback management
+//---------------------
+
+void JackDebugClient::OnShutdown(JackShutdownCallback callback, void *arg)
+{
+ fClient->OnShutdown(callback, arg);
+}
+
+int JackDebugClient::SetProcessCallback(JackProcessCallback callback, void *arg)
+{
+ return fClient->SetProcessCallback( callback, arg);
+}
+
+int JackDebugClient::SetXRunCallback(JackXRunCallback callback, void *arg)
+{
+ return fClient->SetXRunCallback(callback, arg);
+}
+
+int JackDebugClient::SetInitCallback(JackThreadInitCallback callback, void *arg)
+{
+ return fClient->SetInitCallback(callback, arg);
+}
+
+int JackDebugClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
+{
+ return fClient->SetGraphOrderCallback(callback, arg);
+}
+
+int JackDebugClient::SetBufferSizeCallback(JackBufferSizeCallback callback, void *arg)
+{
+ return fClient->SetBufferSizeCallback(callback, arg);
+}
+
+int JackDebugClient::SetFreewheelCallback(JackFreewheelCallback callback, void *arg)
+{
+ return fClient->SetFreewheelCallback(callback, arg);
+}
+
+int JackDebugClient::SetPortRegistrationCallback(JackPortRegistrationCallback callback, void *arg)
+{
+ return fClient->SetPortRegistrationCallback(callback, arg);
+}
+
+JackClientControl* JackDebugClient::GetClientControl() const
+{
+ return fClient->GetClientControl();
+}
+
+} // end of namespace
+
diff --git a/common/JackDebugClient.h b/common/JackDebugClient.h
new file mode 100644
index 00000000..9a2c1094
--- /dev/null
+++ b/common/JackDebugClient.h
@@ -0,0 +1,127 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackDebugClient__
+#define __JackDebugClient__
+
+#define MAX_PORT_HISTORY 2048
+
+#include "JackClient.h"
+#include <list>
+
+namespace Jack
+{
+
+/*!
+\brief Follow a single port.
+*/
+
+typedef struct
+{
+ jack_port_id_t idport;
+ char name[JACK_PORT_NAME_SIZE]; //portname
+ int IsConnected;
+ int IsUnregistrated;
+}
+PortFollower;
+
+/*!
+\brief A "decorator" debug client to validate API use.
+*/
+
+class JackDebugClient : public JackClient
+{
+ private:
+
+ JackClient* fClient;
+ std::ofstream* fStream;
+
+ protected:
+ PortFollower fPortList[MAX_PORT_HISTORY]; // Arbitrary value... To be tuned...
+ int fTotalPortNumber; // The total number of port opened and maybe closed. Historical view.
+ int fOpenPortNumber; // The current number of opened port.
+ int fIsActivated;
+ int fIsDeactivated;
+ int fIsClosed;
+ char fClientName[JACK_CLIENT_NAME_SIZE];
+
+ public:
+
+ JackDebugClient(JackClient *fTheClient);
+
+ virtual ~JackDebugClient();
+
+ virtual int Open(const char* name);
+ int Close();
+
+ virtual JackGraphManager* GetGraphManager() const;
+ virtual JackEngineControl* GetEngineControl() const;
+
+ // Notifications
+ int ClientNotify(int refnum, const char* name, int notify, int sync, int value);
+
+ int Activate();
+ int Deactivate();
+
+ // Context
+ int SetBufferSize(jack_nframes_t nframes);
+ int SetFreeWheel(int onoff);
+ void ShutDown();
+ pthread_t GetThreadID();
+
+ // Port management
+ int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size);
+ int PortUnRegister(jack_port_id_t port);
+
+ int PortConnect(const char* src, const char* dst);
+ int PortDisconnect(const char* src, const char* dst);
+ int PortConnect(jack_port_id_t src, jack_port_id_t dst);
+ int PortDisconnect(jack_port_id_t src);
+
+ int PortIsMine(jack_port_id_t port_index);
+
+ // Transport
+ int ReleaseTimebase();
+ int SetSyncCallback(JackSyncCallback sync_callback, void* arg);
+ int SetSyncTimeout(jack_time_t timeout);
+ int SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg);
+ int TransportLocate(jack_nframes_t frame);
+ jack_transport_state_t TransportQuery(jack_position_t* pos);
+ jack_nframes_t GetCurrentTransportFrame();
+ int TransportReposition(jack_position_t* pos);
+ void TransportStart();
+ void TransportStop();
+
+ // Callbacks
+ void OnShutdown(JackShutdownCallback callback, void *arg);
+ int SetProcessCallback(JackProcessCallback callback, void* arg);
+ int SetXRunCallback(JackXRunCallback callback, void* arg);
+ int SetInitCallback(JackThreadInitCallback callback, void* arg);
+ int SetGraphOrderCallback(JackGraphOrderCallback callback, void* arg);
+ int SetBufferSizeCallback(JackBufferSizeCallback callback, void* arg);
+ int SetFreewheelCallback(JackFreewheelCallback callback, void* arg);
+ int SetPortRegistrationCallback(JackPortRegistrationCallback callback, void* arg);
+ JackClientControl* GetClientControl() const;
+
+};
+
+
+} // end of namespace
+
+#endif
diff --git a/common/JackDriver.cpp b/common/JackDriver.cpp
new file mode 100644
index 00000000..6e3a67c3
--- /dev/null
+++ b/common/JackDriver.cpp
@@ -0,0 +1,204 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackDriver.h"
+#include "JackTime.h"
+#include "JackError.h"
+#include "JackPort.h"
+#include "JackGraphManager.h"
+#include "JackGlobals.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include "JackEngine.h"
+#include <math.h>
+#include <assert.h>
+
+using namespace std;
+
+namespace Jack
+{
+
+JackDriver::JackDriver(const char* name, JackEngine* engine, JackSynchro** table)
+{
+ assert(strlen(name) < JACK_CLIENT_NAME_SIZE);
+ fSynchroTable = table;
+ fClientControl = new JackClientControl(name);
+ fEngine = engine;
+ fGraphManager = NULL;
+ fLastWaitUst = 0;
+ fIsMaster = true;
+}
+
+JackDriver::JackDriver()
+{
+ fSynchroTable = NULL;
+ fClientControl = NULL;
+ fEngine = NULL;
+ fGraphManager = NULL;
+ fLastWaitUst = 0;
+ fIsMaster = true;
+}
+
+JackDriver::~JackDriver()
+{
+ JackLog("~JackDriver\n");
+ delete fClientControl;
+}
+
+int JackDriver::Open()
+{
+ int refnum = -1;
+
+ if (fEngine->ClientCheckName(fClientControl->fName)) {
+ jack_error("client %s already registered", fClientControl->fName);
+ return -1;
+ }
+
+ if (fEngine->ClientInternalNew(fClientControl->fName, &refnum, &fEngineControl, &fGraphManager, this) != 0) {
+ jack_error("Cannot allocate internal client for audio driver");
+ return -1;
+ }
+
+ fClientControl->fRefNum = refnum;
+ fClientControl->fActive = true;
+ fGraphManager->DirectConnect(fClientControl->fRefNum, fClientControl->fRefNum); // Connect driver to itself for sync
+
+ /*
+ In ASYNC mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
+ The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
+ */
+ if (!fEngineControl->fSyncMode) {
+ fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(true);
+ fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(true);
+ fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(true);
+ }
+ return 0;
+}
+
+int JackDriver::Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency)
+{
+ JackLog("JackDriver::Open capture_driver_name = %s\n", capture_driver_name);
+ JackLog("JackDriver::Open playback_driver_name = %s\n", playback_driver_name);
+ int refnum = -1;
+
+ if (fEngine->ClientCheckName(fClientControl->fName)) {
+ jack_error("client %s already registered", fClientControl->fName);
+ return -1;
+ }
+
+ if (fEngine->ClientInternalNew(fClientControl->fName, &refnum, &fEngineControl, &fGraphManager, this) != 0) {
+ jack_error("Cannot allocate internal client for audio driver");
+ return -1;
+ }
+
+ fClientControl->fRefNum = refnum;
+ fClientControl->fActive = true;
+ fEngineControl->fBufferSize = nframes;
+ fEngineControl->fSampleRate = samplerate;
+ fCaptureLatency = capture_latency;
+ fPlaybackLatency = playback_latency;
+
+ assert(strlen(capture_driver_name) < JACK_CLIENT_NAME_SIZE);
+ assert(strlen(playback_driver_name) < JACK_CLIENT_NAME_SIZE);
+
+ strcpy(fCaptureDriverName, capture_driver_name);
+ strcpy(fPlaybackDriverName, playback_driver_name);
+
+ fEngineControl->fPeriodUsecs = (jack_time_t)floor((((float)nframes) / (float)samplerate) * 1000000.0f);
+ if (fEngineControl->fTimeOutUsecs == 0) /* usecs; if zero, use 2 period size. */
+ fEngineControl->fTimeOutUsecs = (jack_time_t)(2.f * fEngineControl->fPeriodUsecs);
+
+ fGraphManager->DirectConnect(fClientControl->fRefNum, fClientControl->fRefNum); // Connect driver to itself for sync
+
+ /*
+ In ASYNC mode, the server does not synchronize itself on the output drivers, thus it would never "consume" the activations.
+ The synchronization primitives for drivers are setup in "flush" mode that to not keep unneeded activations.
+ */
+ if (!fEngineControl->fSyncMode) {
+ fSynchroTable[AUDIO_DRIVER_REFNUM]->SetFlush(true);
+ fSynchroTable[FREEWHEEL_DRIVER_REFNUM]->SetFlush(true);
+ fSynchroTable[LOOPBACK_DRIVER_REFNUM]->SetFlush(true);
+ }
+ return 0;
+}
+
+int JackDriver::Close()
+{
+ JackLog("JackDriver::Close\n");
+ fGraphManager->DirectDisconnect(fClientControl->fRefNum, fClientControl->fRefNum); // Disconnect driver from itself for sync
+ fClientControl->fActive = false;
+ return fEngine->ClientInternalCloseIm(fClientControl->fRefNum);
+}
+
+bool JackDriver::IsRealTime()
+{
+ return fEngineControl->fRealTime;
+}
+
+JackClientControl* JackDriver::GetClientControl() const
+{
+ return fClientControl;
+}
+
+void JackDriver::NotifyXRun(jack_time_t callback_usecs)
+{
+ fEngine->NotifyXRun(callback_usecs);
+}
+
+void JackDriverClient::SetMaster(bool onoff)
+{
+ fIsMaster = onoff;
+}
+
+bool JackDriverClient::GetMaster()
+{
+ return fIsMaster;
+}
+
+void JackDriverClient::AddSlave(JackDriverInterface* slave)
+{
+ fSlaveList.push_back(slave);
+}
+
+void JackDriverClient::RemoveSlave(JackDriverInterface* slave)
+{
+ fSlaveList.remove(slave);
+}
+
+void JackDriverClient::ProcessSlaves()
+{
+ list<JackDriverInterface*>::const_iterator it;
+ for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) {
+ JackDriverInterface* slave = *it;
+ slave->Process();
+ }
+}
+
+} // end of namespace
diff --git a/common/JackDriver.h b/common/JackDriver.h
new file mode 100644
index 00000000..89427697
--- /dev/null
+++ b/common/JackDriver.h
@@ -0,0 +1,215 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackDriver__
+#define __JackDriver__
+
+#include "types.h"
+#include "JackClientInterface.h"
+#include "JackConstants.h"
+#include <list>
+
+namespace Jack
+{
+
+class JackEngine;
+class JackGraphManager;
+class JackSynchro;
+struct JackEngineControl;
+struct JackClientControl;
+
+/*!
+\brief The base interface for drivers.
+*/
+
+class EXPORT JackDriverInterface
+{
+
+ public:
+
+ JackDriverInterface()
+ {}
+ virtual ~JackDriverInterface()
+ {}
+
+ virtual int Open() = 0;
+
+ virtual int Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency) = 0;
+
+ virtual int Attach() = 0;
+ virtual int Detach() = 0;
+
+ virtual int Read() = 0;
+ virtual int Write() = 0;
+ virtual int Start() = 0;
+ virtual int Stop() = 0;
+ virtual int SetBufferSize(jack_nframes_t nframes) = 0;
+
+ virtual int Process() = 0;
+
+ virtual void SetMaster(bool onoff) = 0;
+ virtual bool GetMaster() = 0;
+ virtual void AddSlave(JackDriverInterface* slave) = 0;
+ virtual void RemoveSlave(JackDriverInterface* slave) = 0;
+ virtual void ProcessSlaves() = 0;
+
+ virtual bool IsRealTime() = 0;
+
+ virtual void PrintState() = 0;
+};
+
+/*!
+\brief The base interface for drivers clients.
+*/
+
+class EXPORT JackDriverClientInterface : public JackDriverInterface, public JackClientInterface
+{};
+
+/*!
+\brief The base class for drivers clients.
+*/
+
+class EXPORT JackDriverClient : public JackDriverClientInterface
+{
+ private:
+
+ std::list<JackDriverInterface*> fSlaveList;
+
+ protected:
+
+ bool fIsMaster;
+
+ public:
+
+ virtual void SetMaster(bool onoff);
+ virtual bool GetMaster();
+ virtual void AddSlave(JackDriverInterface* slave);
+ virtual void RemoveSlave(JackDriverInterface* slave);
+ virtual void ProcessSlaves();
+};
+
+/*!
+\brief The base class for drivers.
+*/
+
+class EXPORT JackDriver : public JackDriverClient
+{
+
+ protected:
+
+ char fCaptureDriverName[JACK_CLIENT_NAME_SIZE];
+ char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE];
+ jack_nframes_t fCaptureLatency;
+ jack_nframes_t fPlaybackLatency;
+ jack_time_t fLastWaitUst;
+ JackEngine* fEngine;
+ JackGraphManager* fGraphManager;
+ JackSynchro** fSynchroTable;
+ JackEngineControl* fEngineControl;
+ JackClientControl* fClientControl;
+
+ JackClientControl* GetClientControl() const;
+
+ public:
+
+ JackDriver(const char* name, JackEngine* engine, JackSynchro** table);
+ JackDriver();
+ virtual ~JackDriver();
+
+ virtual int Open();
+
+ virtual int Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency);
+
+ virtual int Close();
+
+ virtual int Process()
+ {
+ return 0;
+ }
+
+ virtual int Attach()
+ {
+ return 0;
+ }
+ virtual int Detach()
+ {
+ return 0;
+ }
+
+ virtual int Read()
+ {
+ return 0;
+ }
+ virtual int Write()
+ {
+ return 0;
+ }
+
+ virtual int Start()
+ {
+ return 0;
+ }
+ virtual int Stop()
+ {
+ return 0;
+ }
+
+ virtual int SetBufferSize(jack_nframes_t nframes)
+ {
+ return 0;
+ }
+
+ void NotifyXRun(jack_time_t callback_usecs); // XRun notification sent by the driver
+
+ virtual bool IsRealTime();
+
+ virtual void PrintState()
+ {}
+
+ int ClientNotify(int refnum, const char* name, int notify, int sync, int value)
+ {
+ return 0;
+ }
+
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackDriverLoader.cpp b/common/JackDriverLoader.cpp
new file mode 100644
index 00000000..359abe79
--- /dev/null
+++ b/common/JackDriverLoader.cpp
@@ -0,0 +1,498 @@
+/*
+Copyright (C) 2001-2005 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackDriverLoader.h"
+#include "JackError.h"
+#include <getopt.h>
+
+#ifdef WIN32
+#define ADDON_DIR "jackmp" // TO IMPROVE
+#else
+#include <dirent.h>
+#define ADDON_DIR "/usr/local/lib/jackmp" // TO IMPROVE
+#endif
+
+static void
+jack_print_driver_options (jack_driver_desc_t * desc, FILE *file)
+{
+ unsigned long i;
+ char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
+
+ for (i = 0; i < desc->nparams; i++) {
+ switch (desc->params[i].type) {
+ case JackDriverParamInt:
+ //sprintf (arg_default, "%" PRIi32, desc->params[i].value.i);
+ sprintf (arg_default, "%" "i", desc->params[i].value.i);
+ break;
+ case JackDriverParamUInt:
+ //sprintf (arg_default, "%" PRIu32, desc->params[i].value.ui);
+ sprintf (arg_default, "%" "u", desc->params[i].value.ui);
+ break;
+ case JackDriverParamChar:
+ sprintf (arg_default, "%c", desc->params[i].value.c);
+ break;
+ case JackDriverParamString:
+ if (desc->params[i].value.str &&
+ strcmp (desc->params[i].value.str, "") != 0)
+ sprintf (arg_default, "%s", desc->params[i].value.str);
+ else
+ sprintf (arg_default, "none");
+ break;
+ case JackDriverParamBool:
+ sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
+ break;
+ }
+
+ fprintf (file, "\t-%c, --%s \t%s (default: %s)\n",
+ desc->params[i].character,
+ desc->params[i].name,
+ desc->params[i].short_desc,
+ arg_default);
+ }
+}
+
+static void
+jack_print_driver_param_usage (jack_driver_desc_t * desc, unsigned long param, FILE *file)
+{
+ fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
+ desc->params[param].name, desc->name);
+
+ fprintf (file, "%s\n", desc->params[param].long_desc);
+}
+
+EXPORT int
+jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr)
+{
+ struct option * long_options;
+ char * options, * options_ptr;
+ unsigned long i;
+ int opt;
+ unsigned int param_index;
+ JSList * params = NULL;
+ jack_driver_param_t * driver_param;
+
+ if (argc <= 1) {
+ *param_ptr = NULL;
+ return 0;
+ }
+
+ /* check for help */
+ if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
+ if (argc > 2) {
+ for (i = 0; i < desc->nparams; i++) {
+ if (strcmp (desc->params[i].name, argv[2]) == 0) {
+ jack_print_driver_param_usage (desc, i, stdout);
+ return 1;
+ }
+ }
+
+ fprintf (stderr, "jackd: unknown option '%s' "
+ "for driver '%s'\n", argv[2],
+ desc->name);
+ }
+
+ printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name);
+ jack_print_driver_options (desc, stdout);
+ return 1;
+ }
+
+ /* set up the stuff for getopt */
+ options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
+ long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
+
+ options_ptr = options;
+ for (i = 0; i < desc->nparams; i++) {
+ sprintf (options_ptr, "%c::", desc->params[i].character);
+ options_ptr += 3;
+
+ long_options[i].name = desc->params[i].name;
+ long_options[i].flag = NULL;
+ long_options[i].val = desc->params[i].character;
+ long_options[i].has_arg = optional_argument;
+ }
+
+ /* create the params */
+ optind = 0;
+ opterr = 0;
+ while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
+
+ if (opt == ':' || opt == '?') {
+ if (opt == ':') {
+ fprintf (stderr, "Missing option to argument '%c'\n", optopt);
+ } else {
+ fprintf (stderr, "Unknownage with option '%c'\n", optopt);
+ }
+
+ fprintf (stderr, "Options for driver '%s':\n", desc->name);
+ jack_print_driver_options (desc, stderr);
+ exit (1);
+ }
+
+ for (param_index = 0; param_index < desc->nparams; param_index++) {
+ if (opt == desc->params[param_index].character) {
+ break;
+ }
+ }
+
+ driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
+ driver_param->character = desc->params[param_index].character;
+
+ if (!optarg && optind < argc &&
+ strlen(argv[optind]) &&
+ argv[optind][0] != '-') {
+ optarg = argv[optind];
+ }
+
+ if (optarg) {
+ switch (desc->params[param_index].type) {
+ case JackDriverParamInt:
+ driver_param->value.i = atoi (optarg);
+ break;
+ case JackDriverParamUInt:
+ driver_param->value.ui = strtoul (optarg, NULL, 10);
+ break;
+ case JackDriverParamChar:
+ driver_param->value.c = optarg[0];
+ break;
+ case JackDriverParamString:
+ strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
+ break;
+ case JackDriverParamBool:
+
+ /*
+ if (strcasecmp ("false", optarg) == 0 ||
+ strcasecmp ("off", optarg) == 0 ||
+ strcasecmp ("no", optarg) == 0 ||
+ strcasecmp ("0", optarg) == 0 ||
+ strcasecmp ("(null)", optarg) == 0 ) {
+ */
+ // steph
+ if (strcmp ("false", optarg) == 0 ||
+ strcmp ("off", optarg) == 0 ||
+ strcmp ("no", optarg) == 0 ||
+ strcmp ("0", optarg) == 0 ||
+ strcmp ("(null)", optarg) == 0 ) {
+ driver_param->value.i = false;
+
+ } else {
+
+ driver_param->value.i = true;
+
+ }
+ break;
+ }
+ } else {
+ if (desc->params[param_index].type == JackDriverParamBool) {
+ driver_param->value.i = true;
+ } else {
+ driver_param->value = desc->params[param_index].value;
+ }
+ }
+
+ params = jack_slist_append (params, driver_param);
+ }
+
+ free (options);
+ free (long_options);
+
+ if (param_ptr)
+ *param_ptr = params;
+
+ return 0;
+}
+
+EXPORT jack_driver_desc_t *
+jack_find_driver_descriptor (JSList * drivers, const char * name)
+{
+ jack_driver_desc_t * desc = 0;
+ JSList * node;
+
+ for (node = drivers; node; node = jack_slist_next (node)) {
+ desc = (jack_driver_desc_t *) node->data;
+
+ if (strcmp (desc->name, name) != 0) {
+ desc = NULL;
+ } else {
+ break;
+ }
+ }
+
+ return desc;
+}
+
+jack_driver_desc_t *
+jack_drivers_get_descriptor (JSList * drivers, const char * sofile)
+{
+ jack_driver_desc_t * descriptor, * other_descriptor;
+ JackDriverDescFunction so_get_descriptor = NULL;
+ JSList * node;
+ void * dlhandle;
+ char * filename;
+#ifdef WIN32
+ int dlerr;
+#else
+ const char * dlerr;
+#endif
+
+ int err;
+ char* driver_dir;
+
+ if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
+ driver_dir = ADDON_DIR;
+ }
+
+#ifdef WIN32
+ if (strcmp(ADDON_DIR, "") == 0) {
+ char temp_driver_dir1[512];
+ char temp_driver_dir2[512];
+ GetCurrentDirectory(512, temp_driver_dir1);
+ sprintf (temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
+ driver_dir = temp_driver_dir2;
+ }
+#endif
+
+ filename = (char *)malloc (strlen (driver_dir) + 1 + strlen (sofile) + 1);
+ sprintf (filename, "%s/%s", driver_dir, sofile);
+
+ if ((dlhandle = LoadDriverModule (filename)) == NULL) {
+#ifdef WIN32
+ jack_error ("could not open driver .dll '%s': %ld\n", filename, GetLastError());
+#else
+ jack_error ("could not open driver .so '%s': %s\n", filename, dlerror ());
+#endif
+
+ free (filename);
+ return NULL;
+ }
+
+ so_get_descriptor = (JackDriverDescFunction)
+ GetProc (dlhandle, "driver_get_descriptor");
+
+#ifdef WIN32
+ if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
+ fprintf(stderr, "%ld\n", dlerr);
+#else
+ if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
+ fprintf(stderr, "%s\n", dlerr);
+#endif
+
+ UnloadDriverModule (dlhandle);
+ free (filename);
+ return NULL;
+ }
+
+ if ((descriptor = so_get_descriptor ()) == NULL) {
+ jack_error ("driver from '%s' returned NULL descriptor\n", filename);
+ UnloadDriverModule (dlhandle);
+ free (filename);
+ return NULL;
+ }
+
+#ifdef WIN32
+ if ((err = UnloadDriverModule (dlhandle)) == 0) {
+ jack_error ("error closing driver .so '%s': %ld\n", filename, GetLastError ());
+ }
+#else
+ if ((err = UnloadDriverModule (dlhandle)) != 0) {
+ jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ());
+ }
+#endif
+
+ /* check it doesn't exist already */
+ for (node = drivers; node; node = jack_slist_next (node)) {
+ other_descriptor = (jack_driver_desc_t *) node->data;
+
+ if (strcmp (descriptor->name, other_descriptor->name) == 0) {
+ jack_error ("the drivers in '%s' and '%s' both have the name '%s'; using the first\n",
+ other_descriptor->file, filename, other_descriptor->name);
+ /* FIXME: delete the descriptor */
+ free (filename);
+ return NULL;
+ }
+ }
+
+ strncpy (descriptor->file, filename, PATH_MAX);
+ free (filename);
+ return descriptor;
+}
+
+#ifdef WIN32
+
+EXPORT JSList *
+jack_drivers_load (JSList * drivers) {
+ char driver_dir[512];
+ char dll_filename[512];
+ WIN32_FIND_DATA filedata;
+ HANDLE file;
+ const char * ptr = NULL;
+ JSList * driver_list = NULL;
+ jack_driver_desc_t * desc;
+
+ GetCurrentDirectory(512, driver_dir);
+
+ sprintf (dll_filename, "%s/%s", ADDON_DIR, "*.dll");
+ file = (HANDLE )FindFirstFile(dll_filename, &filedata);
+
+ if (file == INVALID_HANDLE_VALUE) {
+ printf("error\n");
+ return NULL;
+ }
+
+ do {
+ ptr = strrchr (filedata.cFileName, '.');
+ if (!ptr) {
+ continue;
+ }
+ ptr++;
+ if (strncmp ("dll", ptr, 3) != 0) {
+ continue;
+ }
+
+ desc = jack_drivers_get_descriptor (drivers, filedata.cFileName);
+ if (desc) {
+ driver_list = jack_slist_append (driver_list, desc);
+ }
+
+ } while ((file = (HANDLE )FindNextFile(file, &filedata)) != 0);
+
+ if (!driver_list) {
+ jack_error ("could not find any drivers in %s!\n", driver_dir);
+ return NULL;
+ }
+
+ return driver_list;
+}
+
+#else
+
+JSList *
+jack_drivers_load (JSList * drivers) {
+ struct dirent * dir_entry;
+ DIR * dir_stream;
+ const char * ptr;
+ int err;
+ JSList * driver_list = NULL;
+ jack_driver_desc_t * desc;
+ char* driver_dir;
+
+ if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
+ driver_dir = ADDON_DIR;
+ }
+
+ /* search through the driver_dir and add get descriptors
+ from the .so files in it */
+ dir_stream = opendir (driver_dir);
+ if (!dir_stream) {
+ jack_error ("could not open driver directory %s: %s\n",
+ driver_dir, strerror (errno));
+ return NULL;
+ }
+
+ while ((dir_entry = readdir(dir_stream))) {
+
+ /* check the filename is of the right format */
+ if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
+ continue;
+ }
+
+ ptr = strrchr (dir_entry->d_name, '.');
+ if (!ptr) {
+ continue;
+ }
+ ptr++;
+ if (strncmp ("so", ptr, 2) != 0) {
+ continue;
+ }
+
+ desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name);
+ if (desc) {
+ driver_list = jack_slist_append (driver_list, desc);
+ }
+ }
+
+ err = closedir (dir_stream);
+ if (err) {
+ jack_error ("error closing driver directory %s: %s\n",
+ driver_dir, strerror (errno));
+ }
+
+ if (!driver_list) {
+ jack_error ("could not find any drivers in %s!\n", driver_dir);
+ return NULL;
+ }
+
+ return driver_list;
+}
+
+#endif
+
+jack_driver_info_t *
+jack_load_driver (jack_driver_desc_t * driver_desc) {
+#ifdef WIN32
+ int errstr;
+#else
+ const char * errstr;
+#endif
+
+ jack_driver_info_t *info;
+
+ info = (jack_driver_info_t *) calloc (1, sizeof (*info));
+ info->handle = LoadDriverModule (driver_desc->file);
+
+ if (info->handle == NULL) {
+#ifdef WIN32
+ if ((errstr = GetLastError ()) != 0) {
+ jack_error ("can't load \"%s\": %ld", driver_desc->file,
+ errstr);
+#else
+ if ((errstr = dlerror ()) != 0) {
+ jack_error ("can't load \"%s\": %s", driver_desc->file,
+ errstr);
+#endif
+
+ } else {
+ jack_error ("bizarre error loading driver shared "
+ "object %s", driver_desc->file);
+ }
+ goto fail;
+ }
+
+ info->initialize = (initialize)GetProc(info->handle, "driver_initialize");
+
+#ifdef WIN32
+ if ((info->initialize == NULL) && (errstr = GetLastError ()) != 0) {
+#else
+ if ((info->initialize == NULL) && (errstr = dlerror ()) != 0) {
+#endif
+ jack_error ("no initialize function in shared object %s\n",
+ driver_desc->file);
+ goto fail;
+ }
+
+ return info;
+
+fail:
+ if (info->handle) {
+ UnloadDriverModule(info->handle);
+ }
+ free (info);
+ return NULL;
+}
+
diff --git a/common/JackDriverLoader.h b/common/JackDriverLoader.h
new file mode 100644
index 00000000..9205d773
--- /dev/null
+++ b/common/JackDriverLoader.h
@@ -0,0 +1,66 @@
+/*
+Copyright (C) 2001-2005 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackDriverLoader__
+#define __JackDriverLoader__
+
+#include "jslist.h"
+#include "driver_interface.h"
+#include "JackDriver.h"
+
+
+#ifdef WIN32
+
+#include <windows.h>
+#define DRIVER_HANDLE HINSTANCE
+#define LoadDriverModule(name) LoadLibrary((name))
+#define UnloadDriverModule(handle) (FreeLibrary(((HMODULE)handle)))
+#define GetProc(handle, name) GetProcAddress(((HMODULE)handle),(name))
+
+#else
+
+#include <dlfcn.h>
+#define DRIVER_HANDLE void*
+#define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL)
+#define UnloadDriverModule(handle) dlclose((handle))
+#define GetProc(handle, name) dlsym((handle), (name))
+
+#endif
+
+typedef jack_driver_desc_t * (*JackDriverDescFunction) ();
+typedef Jack::JackDriverClientInterface* (*initialize) (Jack::JackEngine*, Jack::JackSynchro**, const JSList *);
+
+typedef struct _jack_driver_info
+{
+ Jack::JackDriverClientInterface* (*initialize)(Jack::JackEngine*, Jack::JackSynchro**, const JSList *);
+ DRIVER_HANDLE handle;
+}
+jack_driver_info_t;
+
+EXPORT jack_driver_desc_t * jack_find_driver_descriptor (JSList * drivers, const char * name);
+
+jack_driver_desc_t * jack_drivers_get_descriptor (JSList * drivers, const char * sofile);
+
+EXPORT JSList * jack_drivers_load (JSList * drivers);
+
+jack_driver_info_t * jack_load_driver (jack_driver_desc_t * driver_desc);
+
+#endif
+
diff --git a/common/JackDummyDriver.cpp b/common/JackDummyDriver.cpp
new file mode 100644
index 00000000..da74cc55
--- /dev/null
+++ b/common/JackDummyDriver.cpp
@@ -0,0 +1,224 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackDummyDriver.h"
+#include "JackEngineControl.h"
+#include "JackGraphManager.h"
+#include "driver_interface.h"
+#include "JackDriverLoader.h"
+#include <iostream>
+#include <unistd.h>
+
+namespace Jack
+{
+
+int JackDummyDriver::Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency)
+{
+ int res = JackAudioDriver::Open(nframes,
+ samplerate,
+ capturing,
+ playing,
+ inchannels,
+ outchannels,
+ monitor,
+ capture_driver_name,
+ playback_driver_name,
+ capture_latency,
+ playback_latency);
+ fEngineControl->fPeriod = 0;
+ fEngineControl->fComputation = 500 * 1000;
+ fEngineControl->fConstraint = 500 * 1000;
+ return res;
+}
+
+int JackDummyDriver::Process()
+{
+ fLastWaitUst = GetMicroSeconds(); // Take callback date here
+ JackAudioDriver::Process();
+ usleep(std::max(0L, long(fWaitTime - (GetMicroSeconds() - fLastWaitUst))));
+ return 0;
+}
+
+int JackDummyDriver::SetBufferSize(jack_nframes_t nframes)
+{
+ fEngineControl->fBufferSize = nframes;
+ fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // In microsec
+ return 0;
+}
+
+void JackDummyDriver::PrintState()
+{
+ std::cout << "JackDummyDriver state" << std::endl;
+
+ jack_port_id_t port_index;
+
+ std::cout << "Input ports" << std::endl;
+
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ port_index = fCapturePortList[i];
+ JackPort* port = fGraphManager->GetPort(port_index);
+ std::cout << port->GetName() << std::endl;
+ if (fGraphManager->GetConnectionsNum(port_index)) {}
+ }
+
+ std::cout << "Output ports" << std::endl;
+
+ for (int i = 0; i < fCaptureChannels; i++) {
+ port_index = fPlaybackPortList[i];
+ JackPort* port = fGraphManager->GetPort(port_index);
+ std::cout << port->GetName() << std::endl;
+ if (fGraphManager->GetConnectionsNum(port_index)) {}
+ }
+}
+
+} // end of namespace
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ jack_driver_desc_t * driver_get_descriptor () {
+ jack_driver_desc_t * desc;
+ unsigned int i;
+
+ desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
+ strcpy(desc->name, "dummy");
+ desc->nparams = 6;
+ desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
+
+ i = 0;
+ strcpy(desc->params[i].name, "capture");
+ desc->params[i].character = 'C';
+ desc->params[i].type = JackDriverParamUInt;
+ desc->params[i].value.ui = 2U;
+ strcpy(desc->params[i].short_desc, "Number of capture ports");
+ strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
+
+ i++;
+ strcpy(desc->params[i].name, "playback");
+ desc->params[i].character = 'P';
+ desc->params[i].type = JackDriverParamUInt;
+ desc->params[1].value.ui = 2U;
+ strcpy(desc->params[i].short_desc, "Number of playback ports");
+ strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
+
+ i++;
+ strcpy(desc->params[i].name, "rate");
+ desc->params[i].character = 'r';
+ desc->params[i].type = JackDriverParamUInt;
+ desc->params[i].value.ui = 48000U;
+ strcpy(desc->params[i].short_desc, "Sample rate");
+ strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
+
+ i++;
+ strcpy(desc->params[i].name, "monitor");
+ desc->params[i].character = 'm';
+ desc->params[i].type = JackDriverParamBool;
+ desc->params[i].value.i = 0;
+ strcpy(desc->params[i].short_desc, "Provide monitor ports for the output");
+ strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
+
+ i++;
+ strcpy(desc->params[i].name, "period");
+ desc->params[i].character = 'p';
+ desc->params[i].type = JackDriverParamUInt;
+ desc->params[i].value.ui = 1024U;
+ strcpy(desc->params[i].short_desc, "Frames per period");
+ strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
+
+ i++;
+ strcpy(desc->params[i].name, "wait");
+ desc->params[i].character = 'w';
+ desc->params[i].type = JackDriverParamUInt;
+ desc->params[i].value.ui = 21333U;
+ strcpy(desc->params[i].short_desc,
+ "Number of usecs to wait between engine processes");
+ strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
+
+ return desc;
+ }
+
+ Jack::JackDriverClientInterface* driver_initialize(Jack::JackEngine* engine, Jack::JackSynchro** table, const JSList* params) {
+ jack_nframes_t sample_rate = 48000;
+ jack_nframes_t period_size = 1024;
+ unsigned int capture_ports = 2;
+ unsigned int playback_ports = 2;
+ unsigned long wait_time = 0;
+ const JSList * node;
+ const jack_driver_param_t * param;
+ bool monitor = false;
+
+ for (node = params; node; node = jack_slist_next (node)) {
+ param = (const jack_driver_param_t *) node->data;
+
+ switch (param->character) {
+
+ case 'C':
+ capture_ports = param->value.ui;
+ break;
+
+ case 'P':
+ playback_ports = param->value.ui;
+ break;
+
+ case 'r':
+ sample_rate = param->value.ui;
+ break;
+
+ case 'p':
+ period_size = param->value.ui;
+ break;
+
+ case 'w':
+ wait_time = param->value.ui;
+ break;
+
+ case 'm':
+ monitor = param->value.i;
+ break;
+ }
+ }
+
+ if (wait_time == 0) // Not set
+ wait_time = (unsigned long)((((float)period_size) / ((float)sample_rate)) * 1000000.0f);
+
+ Jack::JackDriverClientInterface* driver = new Jack::JackThreadedDriver(new Jack::JackDummyDriver("dummy_pcm", engine, table, wait_time));
+ if (driver->Open(period_size, sample_rate, 1, 1, capture_ports, playback_ports, monitor, "dummy", "dummy", 0, 0) == 0) {
+ return driver;
+ } else {
+ delete driver;
+ return NULL;
+ }
+ }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/common/JackDummyDriver.h b/common/JackDummyDriver.h
new file mode 100644
index 00000000..ee5436b9
--- /dev/null
+++ b/common/JackDummyDriver.h
@@ -0,0 +1,68 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackDummyDriver__
+#define __JackDummyDriver__
+
+#include "JackAudioDriver.h"
+#include "JackThreadedDriver.h"
+#include "JackTime.h"
+
+namespace Jack
+{
+
+/*!
+\brief The dummy driver.
+*/
+
+class JackDummyDriver : public JackAudioDriver
+{
+ private:
+
+ long fWaitTime;
+
+ public:
+
+ JackDummyDriver(const char* name, JackEngine* engine, JackSynchro** table, unsigned long wait_time)
+ : JackAudioDriver(name, engine, table), fWaitTime(wait_time)
+ {}
+ virtual ~JackDummyDriver()
+ {}
+
+ int Open(jack_nframes_t frames_per_cycle,
+ jack_nframes_t rate,
+ int capturing,
+ int playing,
+ int chan_in,
+ int chan_out,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency);
+
+ int Process();
+ int SetBufferSize(jack_nframes_t nframe);
+ void PrintState();
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackEngine.cpp b/common/JackEngine.cpp
new file mode 100644
index 00000000..1f2345ec
--- /dev/null
+++ b/common/JackEngine.cpp
@@ -0,0 +1,644 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <fstream>
+#include <assert.h>
+
+#include "JackEngine.h"
+#include "JackExternalClient.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include "JackEngineTiming.h"
+#include "JackGlobals.h"
+#include "JackChannel.h"
+#include "JackSyncInterface.h"
+
+namespace Jack
+{
+
+JackEngine::JackEngine(JackGraphManager* manager, JackSynchro** table, JackEngineControl* control, JackSyncInterface* signal, bool sync, long time_out_ms, bool rt, long priority, bool ve)
+{
+ fGraphManager = manager;
+ fSynchroTable = table;
+ fEngineControl = control;
+ fEngineControl->fSyncMode = sync;
+ fEngineControl->fTimeOutUsecs = time_out_ms * 1000;
+ fEngineControl->fRealTime = rt;
+ fEngineControl->fPriority = priority;
+ fEngineControl->fVerbose = ve;
+ verbose = ve;
+ fChannel = JackGlobals::MakeServerNotifyChannel();
+ fTiming = new JackEngineTiming(fClientTable, fGraphManager, fEngineControl);
+ fSignal = signal;
+ for (int i = 0; i < CLIENT_NUM; i++)
+ fClientTable[i] = 0;
+ fTiming->ClearTimeMeasures();
+ fTiming->ResetRollingUsecs();
+}
+
+JackEngine::~JackEngine()
+{
+ delete fChannel;
+ delete fTiming;
+}
+
+//-------------------
+// Client management
+//-------------------
+
+int JackEngine::Open()
+{
+ JackLog("JackEngine::Open\n");
+
+ // Open audio thread => request thread communication channel
+ if (fChannel->Open() < 0) {
+ jack_error("Cannot connect to server");
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+int JackEngine::Close()
+{
+ JackLog("JackEngine::Close\n");
+ fChannel->Close();
+
+ // Close (possibly) remaining clients (RT is stopped)
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ if (client) {
+ JackLog("JackEngine::Close remaining client %ld\n", i);
+ ClientCloseAux(i, client, false);
+ client->Close();
+ delete client;
+ }
+ }
+
+ return 0;
+}
+
+//------------------
+// Graph management
+//------------------
+
+void JackEngine::Process(jack_time_t callback_usecs)
+{
+ // Transport
+ fEngineControl->fTransport.CycleBegin(fEngineControl->fSampleRate, callback_usecs);
+
+ //JackLog("Process: callback_usecs %lld\n",callback_usecs/1000);
+
+ // Timing
+ fEngineControl->fFrameTimer.IncFrameTime(fEngineControl->fBufferSize, callback_usecs, fEngineControl->fPeriodUsecs);
+ fTiming->UpdateTiming(callback_usecs);
+
+ // Graph
+ if (fGraphManager->IsFinishedGraph()) {
+ fLastSwitchUsecs = callback_usecs;
+ if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state
+ fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kGraphOrderCallback, 0);
+ fSignal->SignalAll(); // Signal for threads waiting for next cycle
+ } else {
+ JackLog("Process: graph not finished!\n");
+ if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
+ JackLog("Process: switch to next state %ld\n", long(callback_usecs - fLastSwitchUsecs));
+ //RemoveZombifiedClients(callback_usecs); TODO
+ fLastSwitchUsecs = callback_usecs;
+ if (fGraphManager->RunNextGraph())
+ fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kGraphOrderCallback, 0);
+ fSignal->SignalAll(); // Signal for threads waiting for next cycle
+ } else {
+ JackLog("Process: waiting to switch %ld\n", long(callback_usecs - fLastSwitchUsecs));
+ if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failling cycle
+ CheckXRun(callback_usecs);
+ fGraphManager->RunCurrentGraph();
+ }
+ }
+
+ // Transport
+ fEngineControl->fTransport.CycleEnd(fClientTable, fEngineControl->fSampleRate, fEngineControl->fBufferSize);
+}
+
+/*
+Client that finish *after* the callback date are considered late even if their output buffers may have been
+correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
+*/
+
+void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions de fin
+{
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++)
+ {
+ JackClientInterface* client = fClientTable[i];
+ if (client && client->GetClientControl()->fActive) {
+ JackClientTiming* timing = fGraphManager->GetClientTiming(i);
+ jack_client_state_t status = timing->fStatus;
+ jack_time_t finished_date = timing->fFinishedAt;
+
+ if (status != NotTriggered && status != Finished) {
+ jack_error("JackEngine::XRun: client = %s was not runned: state = %ld", client->GetClientControl()->fName, status);
+ //fChannel->ClientNotify(i, kXRunCallback, 0); // Notify the failing client
+ fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0); // Notify all clients
+ }
+ if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
+ jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
+ //fChannel->ClientNotify(i, kXRunCallback, 0); // Notify the failing client
+ fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0); // Notify all clients
+ }
+ }
+ }
+}
+
+//---------------
+// Zombification
+//---------------
+
+bool JackEngine::IsZombie(JackClientInterface* client, jack_time_t current_time)
+{
+ return ((current_time - fGraphManager->GetClientTiming(client->GetClientControl()->fRefNum)->fFinishedAt) > 2 * fEngineControl->fTimeOutUsecs); // A VERIFIER
+}
+
+// TODO : check what happens with looped sub-graph....
+void JackEngine::GetZombifiedClients(bool zombi_clients[CLIENT_NUM], jack_time_t current_time)
+{
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
+ JackClientInterface* client1 = fClientTable[i];
+ if (client1 && IsZombie(client1, current_time)) {
+ JackLog("JackEngine::GetZombifiedClients: %s\n", client1->GetClientControl()->fName);
+ zombi_clients[i] = true; // Assume client is dead
+ // If another dead client is connected to the scanned one, then the scanned one is not the first of the dead subgraph
+ for (int j = REAL_REFNUM; j < CLIENT_NUM; j++) {
+ JackClientInterface* client2 = fClientTable[j];
+ if (client2 && IsZombie(client2, current_time) && fGraphManager->IsDirectConnection(j, i)) {
+ zombi_clients[i] = false;
+ break;
+ }
+ }
+ } else {
+ zombi_clients[i] = false;
+ }
+ }
+}
+
+void JackEngine::RemoveZombifiedClients(jack_time_t current_time)
+{
+ bool zombi_clients[CLIENT_NUM];
+ GetZombifiedClients(zombi_clients, current_time);
+
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
+ if (zombi_clients[i] && !fClientTable[i]->GetClientControl()->fZombie) {
+ fClientTable[i]->GetClientControl()->fZombie = true;
+ JackLog("RemoveZombifiedCients: name = %s\n", fClientTable[i]->GetClientControl()->fName);
+ fGraphManager->DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, i);
+ fGraphManager->DirectDisconnect(i, FREEWHEEL_DRIVER_REFNUM);
+ fGraphManager->DisconnectAllPorts(i);
+ fChannel->ClientNotify(i, JackNotifyChannelInterface::kZombifyClient, 0); // Signal engine
+ }
+ }
+}
+
+void JackEngine::ZombifyClient(int refnum)
+{
+ NotifyClient(refnum, JackNotifyChannelInterface::kZombifyClient, false, 0);
+}
+
+//---------------
+// Notifications
+//---------------
+
+void JackEngine::NotifyClient(int refnum, int event, int sync, int value)
+{
+ JackClientInterface* client = fClientTable[refnum];
+ // The client may be notified by the RT thread while closing
+ if (client && (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value) < 0)) {
+ jack_error("NotifyClient fails name = %s event = %ld = val = %ld", client->GetClientControl()->fName, event, value);
+ } else {
+ JackLog("JackEngine::NotifyClient: client not available anymore\n");
+ }
+}
+
+void JackEngine::NotifyClients(int event, int sync, int value)
+{
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ if (client && (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value) < 0)) {
+ jack_error("NotifyClient fails name = %s event = %ld = val = %ld", client->GetClientControl()->fName, event, value);
+ }
+ }
+}
+
+int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
+{
+ // Notify existing clients of the new client and new client of existing clients.
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* old_client = fClientTable[i];
+ if (old_client) {
+ if (old_client->ClientNotify(refnum, name, JackNotifyChannelInterface::kAddClient, true, 0) < 0)
+ return -1;
+ if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, JackNotifyChannelInterface::kAddClient, true, 0) < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void JackEngine::NotifyRemoveClient(const char* name, int refnum)
+{
+ // Notify existing clients (including the one beeing suppressed) of the removed client
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ if (client) {
+ client->ClientNotify(refnum, name, JackNotifyChannelInterface::kRemoveClient, true, 0);
+ }
+ }
+}
+
+// Coming from the driver
+void JackEngine::NotifyXRun(jack_time_t callback_usecs)
+{
+ // Use the audio thread => request thread communication channel
+ fEngineControl->fFrameTimer.ResetFrameTime(fEngineControl->fSampleRate, callback_usecs, fEngineControl->fPeriodUsecs);
+ fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);
+}
+
+void JackEngine::NotifyXRun(int refnum)
+{
+ if (refnum == ALL_CLIENTS) {
+ NotifyClients(JackNotifyChannelInterface::kXRunCallback, false, 0);
+ } else {
+ NotifyClient(refnum, JackNotifyChannelInterface::kXRunCallback, false, 0);
+ }
+}
+
+void JackEngine::NotifyGraphReorder()
+{
+ NotifyClients(JackNotifyChannelInterface::kGraphOrderCallback, false, 0);
+}
+
+void JackEngine::NotifyBufferSize(jack_nframes_t nframes)
+{
+ NotifyClients(JackNotifyChannelInterface::kBufferSizeCallback, true, nframes);
+}
+
+void JackEngine::NotifyFreewheel(bool onoff)
+{
+ fEngineControl->fRealTime = !onoff;
+ NotifyClients((onoff ? JackNotifyChannelInterface::kStartFreewheel : JackNotifyChannelInterface::kStopFreewheel), true, 0);
+}
+
+void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
+{
+ NotifyClients((onoff ? JackNotifyChannelInterface::kPortRegistrationOn : JackNotifyChannelInterface::kPortRegistrationOff), false, port_index);
+}
+
+//-------------------
+// Client management
+//-------------------
+
+bool JackEngine::ClientCheckName(const char* name)
+{
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
+ return true;
+ }
+
+ return false;
+}
+
+// Used for external clients
+int JackEngine::ClientNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
+{
+ if (ClientCheckName(name)) {
+ jack_error("client %s already registered", name);
+ return -1;
+ }
+
+ JackExternalClient* client = new JackExternalClient();
+ if (ClientExternalNew(name, ref, shared_engine, shared_client, shared_graph_manager, client) < 0) {
+ delete client;
+ return -1;
+ }
+
+ return 0;
+}
+
+// Used for external clients
+int JackEngine::ClientExternalNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager, JackExternalClient* client)
+{
+ JackLog("JackEngine::ClientNew: name %s \n", name);
+ int refnum = fGraphManager->AllocateRefNum();
+
+ if (refnum < 0) {
+ jack_error("No more refnum available");
+ return -1;
+ }
+
+ if (!fSynchroTable[refnum]->Allocate(name, 0)) {
+ jack_error("Cannot allocate synchro");
+ goto error;
+ }
+
+ if (client->Open(name, refnum, shared_client) < 0) {
+ jack_error("Cannot open client");
+ goto error;
+ }
+
+ if (!fSignal->TimedWait(5 * 1000000)) {
+ // Failure if RT thread is not running (problem with the driver...)
+ jack_error("Driver is not running");
+ goto error;
+ }
+
+ if (NotifyAddClient(client, name, refnum) < 0) {
+ jack_error("Cannot notify add client");
+ goto error;
+ }
+
+ fClientTable[refnum] = client;
+ fTiming->ResetRollingUsecs();
+ *shared_engine = fEngineControl->GetShmIndex();
+ *shared_graph_manager = fGraphManager->GetShmIndex();
+ *ref = refnum;
+ return 0;
+
+error:
+ fGraphManager->ReleaseRefNum(refnum);
+ ClientCloseAux(refnum, client, false);
+ client->Close();
+ return -1;
+}
+
+// Used for server driver clients
+int JackEngine::ClientInternalNew(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client)
+{
+ JackLog("JackEngine::ClientInternalNew: name %s\n", name);
+ int refnum = fGraphManager->AllocateRefNum();
+
+ if (refnum < 0) {
+ jack_error("No more refnum available");
+ return -1;
+ }
+
+ if (!fSynchroTable[refnum]->Allocate(name, 0)) {
+ jack_error("Cannot allocate synchro");
+ goto error;
+ }
+
+ if (NotifyAddClient(client, name, refnum) < 0) {
+ jack_error("Cannot notify add client");
+ goto error;
+ }
+
+ fClientTable[refnum] = client;
+ fTiming->ResetRollingUsecs();
+ *shared_engine = fEngineControl;
+ *shared_manager = fGraphManager;
+ *ref = refnum;
+ return 0;
+
+error:
+ fGraphManager->ReleaseRefNum(refnum);
+ return -1;
+}
+
+// Used for externall clients
+int JackEngine::ClientClose(int refnum)
+{
+ JackClientInterface* client = fClientTable[refnum];
+ if (client) {
+ fEngineControl->fTransport.ResetTimebase(refnum);
+ int res = ClientCloseAux(refnum, client, true);
+ client->Close();
+ delete client;
+ return res;
+ } else {
+ return -1;
+ }
+}
+
+// Used for server internal clients
+int JackEngine::ClientInternalClose(int refnum)
+{
+ JackClientInterface* client = fClientTable[refnum];
+ return (client) ? ClientCloseAux(refnum, client, true) : -1;
+}
+
+// Used for drivers that close when the RT thread is stopped
+int JackEngine::ClientInternalCloseIm(int refnum)
+{
+ JackClientInterface* client = fClientTable[refnum];
+ return (client) ? ClientCloseAux(refnum, client, false) : -1;
+}
+
+int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
+{
+ JackLog("JackEngine::ClientCloseAux ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
+
+ // Remove the client from the table
+ fClientTable[refnum] = NULL;
+
+ // Remove ports
+ fGraphManager->RemoveAllPorts(refnum);
+
+ // Wait until next cycle to be sure client is not used anymore
+ if (wait) {
+ if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
+ JackLog("JackEngine::ClientCloseAux wait error ref = %ld \n", refnum);
+ }
+ }
+
+ // Notify running clients
+ NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
+
+ // Cleanup...
+ fSynchroTable[refnum]->Destroy();
+ fGraphManager->ReleaseRefNum(refnum);
+ fTiming->ResetRollingUsecs();
+ return 0;
+}
+
+int JackEngine::ClientActivate(int refnum)
+{
+ JackClientInterface* client = fClientTable[refnum];
+ assert(fClientTable[refnum]);
+
+ JackLog("JackEngine::ClientActivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
+ // Wait for graph state change to be effective
+ if (!fSignal->TimedWait(fEngineControl->fPeriodUsecs * 10)) {
+ JackLog("JackEngine::ClientActivate wait error ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+// May be called without client
+int JackEngine::ClientDeactivate(int refnum)
+{
+ JackClientInterface* client = fClientTable[refnum];
+ if (client == NULL)
+ return -1;
+
+ JackLog("JackEngine::ClientDeactivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
+ fGraphManager->DisconnectAllPorts(refnum);
+ // Wait for graph state change to be effective
+ if (!fSignal->TimedWait(fEngineControl->fPeriodUsecs * 10)) {
+ JackLog("JackEngine::ClientDeactivate wait error ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+//-----------------
+// Port management
+//-----------------
+
+int JackEngine::PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
+{
+ JackLog("JackEngine::PortRegister ref = %ld name = %s flags = %d buffer_size = %d\n", refnum, name, flags, buffer_size);
+ assert(fClientTable[refnum]);
+
+ *port_index = fGraphManager->AllocatePort(refnum, name, (JackPortFlags)flags);
+ if (*port_index != NO_PORT) {
+ NotifyPortRegistation(*port_index, true);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
+{
+ JackLog("JackEngine::PortUnRegister ref = %ld port_index = %ld\n", refnum, port_index);
+ assert(fClientTable[refnum]);
+
+ if (fGraphManager->RemovePort(refnum, port_index) == 0) {
+ fGraphManager->ReleasePort(port_index);
+ NotifyPortRegistation(port_index, false);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
+{
+ JackLog("JackEngine::PortConnect src = %s dst = %s\n", src, dst);
+ jack_port_id_t port_src, port_dst;
+
+ return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
+ ? -1
+ : PortConnect(refnum, port_src, port_dst);
+}
+
+int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
+{
+ JackLog("JackEngine::PortDisconnect src = %s dst = %s\n", src, dst);
+ jack_port_id_t port_src, port_dst;
+
+ return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
+ ? -1
+ : fGraphManager->Disconnect(port_src, port_dst);
+}
+
+int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
+{
+ JackLog("JackEngine::PortConnect src = %d dst = %d\n", src, dst);
+ JackClientInterface* client;
+ int ref;
+
+ if (fGraphManager->CheckPorts(src, dst) < 0)
+ return -1;
+
+ ref = fGraphManager->GetOutputRefNum(src);
+ assert(ref >= 0);
+ client = fClientTable[ref];
+ assert(client);
+ if (!client->GetClientControl()->fActive) {
+ jack_error("Cannot connect ports owned by inactive clients:"
+ " \"%s\" is not active", client->GetClientControl()->fName);
+ return -1;
+ }
+
+ ref = fGraphManager->GetInputRefNum(dst);
+ assert(ref >= 0);
+ client = fClientTable[ref];
+ assert(client);
+ if (!client->GetClientControl()->fActive) {
+ jack_error("Cannot connect ports owned by inactive clients:"
+ " \"%s\" is not active", client->GetClientControl()->fName);
+ return -1;
+ }
+
+ return fGraphManager->Connect(src, dst);
+}
+
+int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
+{
+ JackLog("JackEngine::PortDisconnect src = %d dst = %d\n", src, dst);
+
+ if (dst == ALL_PORTS) {
+ return (fGraphManager->CheckPort(src) < 0)
+ ? -1
+ : fGraphManager->DisconnectAll(src);
+ } else {
+ return (fGraphManager->CheckPorts(src, dst) < 0)
+ ? -1
+ : fGraphManager->Disconnect(src, dst);
+ }
+}
+
+//----------------------
+// Transport management
+//----------------------
+
+int JackEngine::ReleaseTimebase(int refnum)
+{
+ return fEngineControl->fTransport.ResetTimebase(refnum);
+}
+
+int JackEngine::SetTimebaseCallback(int refnum, int conditional)
+{
+ return fEngineControl->fTransport.SetTimebase(refnum, conditional);
+}
+
+//-----------
+// Debugging
+//-----------
+
+void JackEngine::PrintState()
+{
+ std::cout << "Engine State" << std::endl;
+
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ if (client)
+ std::cout << "Client : " << client->GetClientControl()->fName << " : " << i << std::endl;
+ }
+
+ //fGraphManager->PrintState();
+ fTiming->PrintState();
+}
+
+} // end of namespace
+
diff --git a/common/JackEngine.h b/common/JackEngine.h
new file mode 100644
index 00000000..63f2947b
--- /dev/null
+++ b/common/JackEngine.h
@@ -0,0 +1,119 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackEngine__
+#define __JackEngine__
+
+#include "JackConstants.h"
+#include "JackGraphManager.h"
+#include "JackSynchro.h"
+#include "JackTransportEngine.h"
+
+namespace Jack
+{
+
+class JackClientInterface;
+struct JackEngineControl;
+class JackServerNotifyChannelInterface;
+class JackEngineTiming;
+class JackExternalClient;
+class JackSyncInterface;
+
+/*!
+\brief Engine description.
+*/
+
+class JackEngine
+{
+ private:
+
+ JackGraphManager* fGraphManager;
+ JackEngineControl* fEngineControl;
+ JackClientInterface* fClientTable[CLIENT_NUM];
+ JackSynchro** fSynchroTable;
+ JackServerNotifyChannelInterface* fChannel; /*! To communicate between the RT thread and server */
+ JackEngineTiming* fTiming;
+ JackSyncInterface* fSignal;
+ jack_time_t fLastSwitchUsecs;
+
+ int ClientCloseAux(int refnum, JackClientInterface* client, bool wait);
+ void CheckXRun(jack_time_t callback_usecs);
+ int NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum);
+ void NotifyRemoveClient(const char* name, int refnum);
+ bool IsZombie(JackClientInterface* client, jack_time_t current_time);
+ void RemoveZombifiedClients(jack_time_t current_time);
+ void GetZombifiedClients(bool clients[CLIENT_NUM], jack_time_t current_time);
+
+ public:
+
+ JackEngine(JackGraphManager* manager, JackSynchro** table, JackEngineControl* control, JackSyncInterface* signal, bool sync, long time_out_ms, bool rt, long priority, bool verbose);
+ virtual ~JackEngine();
+
+ int Open();
+ int Close();
+
+ // Client management
+ bool ClientCheckName(const char* name);
+ int ClientNew(const char* name, int* refnum, int* shared_engine, int* shared_client, int* shared_graph_manager);
+ int ClientExternalNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager, JackExternalClient* client);
+ int ClientInternalNew(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client);
+
+ int ClientClose(int refnum);
+ int ClientInternalClose(int refnum);
+ int ClientInternalCloseIm(int refnum);
+
+ int ClientActivate(int refnum);
+ int ClientDeactivate(int refnum);
+
+ // Port management
+ int PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index);
+ int PortUnRegister(int refnum, jack_port_id_t port);
+
+ int PortConnect(int refnum, const char* src, const char* dst);
+ int PortDisconnect(int refnum, const char* src, const char* dst);
+
+ int PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst);
+ int PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst);
+
+ // Transport management
+ int ReleaseTimebase(int refnum);
+ int SetTimebaseCallback(int refnum, int conditional);
+
+ // Graph
+ void Process(jack_time_t callback_usecs);
+ void ZombifyClient(int refnum);
+
+ // Notifications
+ void NotifyClient(int refnum, int event, int sync, int value);
+ void NotifyClients(int event, int sync, int value);
+ void NotifyXRun(jack_time_t callback_usecs);
+ void NotifyXRun(int refnum);
+ void NotifyGraphReorder();
+ void NotifyBufferSize(jack_nframes_t nframes);
+ void NotifyFreewheel(bool onoff);
+ void NotifyPortRegistation(jack_port_id_t port_index, bool onoff);
+
+ void PrintState();
+};
+
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackEngineControl.h b/common/JackEngineControl.h
new file mode 100644
index 00000000..975a888a
--- /dev/null
+++ b/common/JackEngineControl.h
@@ -0,0 +1,58 @@
+/*
+Copyright (C) 2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackEngineControl__
+#define __JackEngineControl__
+
+#include "JackShmMem.h"
+#include "JackFrameTimer.h"
+#include "JackTransportEngine.h"
+#include "types.h"
+
+namespace Jack
+{
+
+/*!
+\brief Engine control in shared memory.
+*/
+
+struct JackEngineControl : public JackShmMem
+{
+ jack_nframes_t fBufferSize;
+ jack_nframes_t fSampleRate;
+ bool fRealTime;
+ int32_t fPriority;
+ float fCPULoad;
+ jack_time_t fPeriodUsecs;
+ jack_time_t fTimeOutUsecs;
+ UInt64 fPeriod;
+ UInt64 fComputation;
+ UInt64 fConstraint;
+ JackFrameTimer fFrameTimer;
+ JackTransportEngine fTransport;
+ bool fSyncMode;
+ bool fVerbose;
+};
+
+
+} // end of namespace
+
+
+#endif
diff --git a/common/JackEngineTiming.cpp b/common/JackEngineTiming.cpp
new file mode 100644
index 00000000..521dcbd1
--- /dev/null
+++ b/common/JackEngineTiming.cpp
@@ -0,0 +1,229 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackEngineTiming.h"
+#include "JackClientInterface.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include <math.h>
+#include <algorithm>
+#include <iostream>
+//#include <fstream>
+#include <assert.h>
+
+namespace Jack
+{
+
+inline jack_time_t MAX(jack_time_t a, jack_time_t b)
+{
+ return (a < b) ? b : a;
+}
+
+JackEngineTiming::JackEngineTiming(JackClientInterface** table, JackGraphManager* manager, JackEngineControl* control)
+{
+ fClientTable = table;
+ fGraphManager = manager;
+ fEngineControl = control;
+ fLastTime = 0;
+ fCurTime = 0;
+ fProcessTime = 0;
+ fLastProcessTime = 0;
+ fSpareUsecs = 0;
+ fMaxUsecs = 0;
+ fAudioCycle = 0;
+}
+
+void JackEngineTiming::UpdateTiming(jack_time_t callback_usecs)
+{
+ GetTimeMeasure(callback_usecs);
+ CalcCPULoad();
+}
+
+void JackEngineTiming::CalcCPULoad()
+{
+ jack_time_t lastCycleEnd = fLastProcessTime;
+
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ JackClientTiming* timing = fGraphManager->GetClientTiming(i);
+ if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) {
+ lastCycleEnd = MAX(lastCycleEnd, timing->fFinishedAt);
+ }
+ }
+
+ /* store the execution time for later averaging */
+ fRollingClientUsecs[fRollingClientUsecsIndex++] = lastCycleEnd - fLastTime;
+
+ if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) {
+ fRollingClientUsecsIndex = 0;
+ }
+
+ /* every so often, recompute the current maximum use over the
+ last JACK_ENGINE_ROLLING_COUNT client iterations.
+ */
+
+ if (++fRollingClientUsecsCnt % fRollingInterval == 0) {
+
+ jack_time_t maxUsecs = 0;
+ for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) {
+ maxUsecs = MAX(fRollingClientUsecs[i], maxUsecs);
+ }
+
+ fMaxUsecs = MAX(fMaxUsecs, maxUsecs);
+ fSpareUsecs = jack_time_t((maxUsecs < fEngineControl->fPeriodUsecs) ? fEngineControl->fPeriodUsecs - maxUsecs : 0);
+ fEngineControl->fCPULoad
+ = ((1.0f - (float(fSpareUsecs) / float(fEngineControl->fPeriodUsecs))) * 50.0f + (fEngineControl->fCPULoad * 0.5f));
+ }
+}
+
+void JackEngineTiming::ResetRollingUsecs()
+{
+ memset(fRollingClientUsecs, 0, sizeof(fRollingClientUsecs));
+ fRollingClientUsecsIndex = 0;
+ fRollingClientUsecsCnt = 0;
+ fSpareUsecs = 0;
+ fRollingInterval = (int)floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.0f) / fEngineControl->fPeriodUsecs);
+}
+
+void JackEngineTiming::GetTimeMeasure(jack_time_t callbackUsecs)
+{
+ int pos = (++fAudioCycle) % TIME_POINTS;
+
+ fLastTime = fCurTime;
+ fCurTime = callbackUsecs;
+
+ fLastProcessTime = fProcessTime;
+ fProcessTime = GetMicroSeconds();
+
+ if (fLastTime > 0) {
+ fMeasure[pos].fEngineTime = fLastTime;
+ fMeasure[pos].fAudioCycle = fAudioCycle;
+
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = fClientTable[i];
+ JackClientTiming* timing = fGraphManager->GetClientTiming(i);
+ if (client && client->GetClientControl()->fActive) {
+ fMeasure[pos].fClientTable[i].fRefNum = i;
+ fMeasure[pos].fClientTable[i].fSignaledAt = timing->fSignaledAt;
+ fMeasure[pos].fClientTable[i].fAwakeAt = timing->fAwakeAt;
+ fMeasure[pos].fClientTable[i].fFinishedAt = timing->fFinishedAt;
+ fMeasure[pos].fClientTable[i].fStatus = timing->fStatus;
+ }
+ }
+ }
+}
+
+void JackEngineTiming::PrintState()
+{
+ jack_time_t prevtime, time;
+ prevtime = time = fMeasure[0].fEngineTime;
+ int cycle, prevcycle = fMeasure[0].fAudioCycle;
+ /*
+
+ std::ofstream f("measure.txt");
+
+ if (f.is_open()) {
+
+ //std::cout << "---------------------------------------------" << std::endl;
+
+ for (int i = 0; i < CLIENT_NUM; i++) { // client
+ JackClientInterface* client = fClientTable[i];
+ if (client && client->GetClientControl()->fActive) {
+ // f << "Client : " << i << std::endl;
+ long maxsignalledat = 0;
+ long maxawakedat = 0;
+ long maxfinisheddat = 0;
+ bool max = false;
+ prevtime = fMeasure[0].fEngineTime;
+ prevcycle = fMeasure[0].fAudioCycle;
+
+ // TODO
+
+ for (int j = 0; j < TIME_POINTS; j++) { // measure
+ time = fMeasure[j].fEngineTime;
+ cycle = fMeasure[j].fAudioCycle;
+
+ if (fMeasure[j].fClientTable[i].fRefNum > 0) {
+
+ if (fMeasure[j].fClientTable[i].fStatus != Finished) {
+ f << "error status " << '\t'
+ << prevtime << '\t'
+ << time << '\t'
+ << fMeasure[j + 1].fEngineTime << '\t'
+ << prevcycle << '\t'
+ << cycle << '\t'
+ << fMeasure[j].fClientTable[i].fSignaledAt << '\t'
+ << fMeasure[j].fClientTable[i].fAwakeAt << '\t'
+ << fMeasure[j].fClientTable[i].fFinishedAt
+ << std::endl;
+ }
+
+ if (long(time - prevtime) > 0) {
+
+ f << long(time - prevtime) << '\t'
+ << fMeasure[j].fClientTable[i].fSignaledAt - time << '\t'
+ << fMeasure[j].fClientTable[i].fAwakeAt - time << '\t'
+ << fMeasure[j].fClientTable[i].fFinishedAt - time << '\t'
+ << fMeasure[j].fClientTable[i].fStatus
+ << std::endl;
+ } else {
+ f << "error time : " << j << " " << long(time - prevtime) << std::endl;
+ }
+
+ maxsignalledat = MAX(maxsignalledat, long(fMeasure[j].fClientTable[i].fSignaledAt - time));
+ maxawakedat = MAX(maxawakedat, long(fMeasure[j].fClientTable[i].fAwakeAt - time));
+ maxfinisheddat = MAX(maxfinisheddat, long(fMeasure[j].fClientTable[i].fFinishedAt - time));
+ max = true;
+ }
+ prevtime = time;
+ prevcycle = cycle;
+ }
+
+
+ f << std::endl;
+ if (max) {
+ f << "maxsignalledat: " << maxsignalledat
+ << '\t' << "maxawakedat: " << maxawakedat
+ << '\t' << "maxfinisheddat: " << maxfinisheddat
+ << '\t' << std::endl;
+ }
+ }
+ }
+
+ f.close();
+ }
+ */
+}
+
+void JackEngineTiming::ClearTimeMeasures()
+{
+ for (int i = 0; i < TIME_POINTS; i++) {
+ for (int j = 0; j < CLIENT_NUM; j++) {
+ fMeasure[i].fClientTable[j].fRefNum = 0;
+ fMeasure[i].fClientTable[j].fSignaledAt = 0;
+ fMeasure[i].fClientTable[j].fAwakeAt = 0;
+ fMeasure[i].fClientTable[j].fFinishedAt = 0;
+ }
+ }
+ fLastTime = fCurTime = 0;
+}
+
+
+} // end of namespace
+
diff --git a/common/JackEngineTiming.h b/common/JackEngineTiming.h
new file mode 100644
index 00000000..986e548d
--- /dev/null
+++ b/common/JackEngineTiming.h
@@ -0,0 +1,105 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackEngineTiming__
+#define __JackEngineTiming__
+
+#include "types.h"
+#include "JackGraphManager.h"
+
+namespace Jack
+{
+
+#define TIME_POINTS 1000
+#define JACK_ENGINE_ROLLING_COUNT 32
+#define JACK_ENGINE_ROLLING_INTERVAL 1024
+
+class JackClientInterface;
+struct JackEngineControl;
+
+/*!
+\brief Timing stucture for a client.
+*/
+
+struct JackTimingMeasureClient
+{
+ int fRefNum;
+ jack_time_t fSignaledAt;
+ jack_time_t fAwakeAt;
+ jack_time_t fFinishedAt;
+ jack_client_state_t fStatus;
+};
+
+/*!
+\brief Timing stucture for a table of clients.
+*/
+
+struct JackTimingMeasure
+{
+ long fAudioCycle;
+ jack_time_t fEngineTime;
+ JackTimingMeasureClient fClientTable[CLIENT_NUM];
+};
+
+/*!
+\brief Engine timing management.
+*/
+
+class JackEngineTiming
+{
+ private:
+
+ JackClientInterface** fClientTable;
+ JackGraphManager* fGraphManager;
+ JackEngineControl* fEngineControl;
+
+ JackTimingMeasure fMeasure[TIME_POINTS];
+ jack_time_t fLastTime;
+ jack_time_t fCurTime;
+ jack_time_t fProcessTime;
+ jack_time_t fLastProcessTime;
+ jack_time_t fSpareUsecs;
+ jack_time_t fMaxUsecs;
+ uint32_t fAudioCycle;
+
+ jack_time_t fRollingClientUsecs[JACK_ENGINE_ROLLING_COUNT];
+ int fRollingClientUsecsCnt;
+ int fRollingClientUsecsIndex;
+ int fRollingInterval;
+
+ void CalcCPULoad();
+ void GetTimeMeasure(jack_time_t callback_usecs);
+
+ public:
+
+ JackEngineTiming(JackClientInterface** table, JackGraphManager* manager, JackEngineControl* control);
+ virtual ~JackEngineTiming()
+ {}
+
+ void UpdateTiming(jack_time_t callback_usecs);
+ void ResetRollingUsecs();
+
+ void ClearTimeMeasures();
+ void PrintState();
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackError.c b/common/JackError.c
new file mode 100644
index 00000000..ed463e5f
--- /dev/null
+++ b/common/JackError.c
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "JackError.h"
+
+EXPORT void jack_error (const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[300];
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ //jack_error_callback(buffer);
+ fprintf(stderr, "%s\n", buffer);
+ va_end(ap);
+}
+
+EXPORT void JackLog(char *fmt,...)
+{
+#ifdef PRINTDEBUG
+ if (verbose) {
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr,"Jack: ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+#endif
+}
+
diff --git a/common/JackError.h b/common/JackError.h
new file mode 100644
index 00000000..42baefb4
--- /dev/null
+++ b/common/JackError.h
@@ -0,0 +1,48 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+*/
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "JackConstants.h"
+#include "JackExports.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef WIN32
+ #define vsnprintf _vsnprintf
+ #define snprintf _snprintf
+#endif
+
+ EXPORT void jack_error(const char *fmt, ...);
+
+ EXPORT void JackLog(char *fmt, ...);
+
+ extern int verbose;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/common/JackExports.h b/common/JackExports.h
new file mode 100644
index 00000000..3e3edf6d
--- /dev/null
+++ b/common/JackExports.h
@@ -0,0 +1,30 @@
+/*
+Copyright (C) 2004-2005 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackExports__
+#define __JackExports__
+
+#ifdef WIN32
+ #define EXPORT __declspec(dllexport)
+#else
+ #define EXPORT
+#endif
+
+#endif
+
diff --git a/common/JackExternalClient.cpp b/common/JackExternalClient.cpp
new file mode 100644
index 00000000..a637e6c7
--- /dev/null
+++ b/common/JackExternalClient.cpp
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackExternalClient.h"
+#include "JackClientControl.h"
+#include "JackGlobals.h"
+#include "JackChannel.h"
+
+namespace Jack
+{
+
+JackExternalClient::JackExternalClient(): fClientControl(NULL)
+{
+ fChannel = JackGlobals::MakeNotifyChannel();
+}
+
+JackExternalClient::~JackExternalClient()
+{
+ delete fChannel;
+}
+
+int JackExternalClient::ClientNotify(int refnum, const char* name, int notify, int sync, int value)
+{
+ int result = -1;
+ JackLog("JackExternalClient::ClientNotify ref = %ld name = %s notify = %ld\n", refnum, name, notify);
+ fChannel->ClientNotify(refnum, name, notify, sync, value, &result);
+ return result;
+}
+
+int JackExternalClient::Open(const char* name, int refnum, int* shared_client)
+{
+ try {
+
+ if (fChannel->Open(name) < 0) {
+ jack_error("Cannot connect to client name = %s port\n", name);
+ return -1;
+ }
+
+ fClientControl = new JackClientControl(name, refnum);
+ if (!fClientControl) {
+ jack_error("Cannot allocate client shared memory segment");
+ return -1;
+ }
+
+ *shared_client = fClientControl->GetShmIndex();
+ JackLog("JackExternalClient::Open name = %s index = %ld base = %x\n", name, fClientControl->GetShmIndex(), fClientControl->GetShmAddress());
+ return 0;
+
+ } catch (std::exception e) {
+ return -1;
+ }
+}
+
+int JackExternalClient::Close()
+{
+ fChannel->Close();
+ delete fClientControl;
+ return 0;
+}
+
+JackClientControl* JackExternalClient::GetClientControl() const
+{
+ return fClientControl;
+}
+
+} // end of namespace
diff --git a/common/JackExternalClient.h b/common/JackExternalClient.h
new file mode 100644
index 00000000..0b895140
--- /dev/null
+++ b/common/JackExternalClient.h
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackExternalClient__
+#define __JackExternalClient__
+
+#include "JackClientInterface.h"
+
+namespace Jack
+{
+
+class JackNotifyChannelInterface;
+struct JackClientControl;
+
+/*!
+\brief Server side implementation of library clients.
+*/
+
+class JackExternalClient : public JackClientInterface
+{
+
+ private:
+
+ JackNotifyChannelInterface* fChannel; /*! Server/client communication channel */
+ JackClientControl* fClientControl; /*! Client control in shared memory */
+
+ public:
+
+ JackExternalClient();
+ virtual ~JackExternalClient();
+
+ int Open(const char* name, int refnum, int* shared_client);
+ int Close();
+
+ int ClientNotify(int refnum, const char* name, int notify, int sync, int value);
+
+ JackClientControl* GetClientControl() const;
+};
+
+
+} // end of namespace
+
+#endif
diff --git a/common/JackFifo.cpp b/common/JackFifo.cpp
new file mode 100755
index 00000000..3a072ef3
--- /dev/null
+++ b/common/JackFifo.cpp
@@ -0,0 +1,209 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackFifo.h"
+#include "JackError.h"
+#include "JackChannel.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+namespace Jack
+{
+
+void JackFifo::BuildName(const char* name, char* res)
+{
+ sprintf(res, "%s/jack_fifo.%s", jack_client_dir, name);
+}
+
+bool JackFifo::Signal()
+{
+ bool res;
+ char c = 0;
+ assert(fFifo >= 0);
+
+ if (fFlush)
+ return true;
+
+ if ((res = (write(fFifo, &c, sizeof(c)) != sizeof(c)))) {
+ jack_error("JackFifo::Signal name = %s err = %s", fName, strerror(errno));
+ }
+ return !res;
+}
+
+bool JackFifo::SignalAll()
+{
+ bool res;
+ char c = 0;
+ assert(fFifo >= 0);
+
+ if (fFlush)
+ return true;
+
+ if ((res = (write(fFifo, &c, sizeof(c)) != sizeof(c)))) {
+ jack_error("JackFifo::SignalAll name = %s err = %s", fName, strerror(errno));
+ }
+ return !res;
+}
+
+bool JackFifo::Wait()
+{
+ bool res;
+ char c;
+ assert(fFifo >= 0);
+
+ if ((res = (read(fFifo, &c, sizeof(c)) != sizeof(c)))) {
+ jack_error("JackFifo::Wait name = %s err = %s", fName, strerror(errno));
+ }
+ return !res;
+}
+
+#ifdef __APPLE__
+#warning JackFifo::TimedWait not available : synchronous mode may not work correctly if FIFO are used
+bool JackFifo::TimedWait(long usec)
+{
+ return Wait();
+}
+#else
+// Does not work on OSX ??
+bool JackFifo::TimedWait(long usec)
+{
+ assert(fFifo >= 0);
+
+ if ((poll(&fPoll, 1, usec / 1000) < 0) && (errno != EINTR)) {
+ jack_error("JackFifo::TimedWait name = %s err = %s", fName, strerror(errno));
+ return false;
+ }
+
+ if (fPoll.revents & POLLIN) {
+ return Wait();
+ } else {
+ jack_error("JackFifo::TimedWait fails name = %s revents %ld ", fName, fPoll.revents);
+ return false;
+ }
+}
+#endif
+
+// Server side
+bool JackFifo::Allocate(const char* name, int value)
+{
+ struct stat statbuf;
+ BuildName(name, fName);
+
+ JackLog("JackFifo::Allocate name = %s\n", fName);
+
+ if (stat(fName, &statbuf)) {
+ if (errno == ENOENT) {
+ if (mkfifo(fName, 0666) < 0) {
+ jack_error("Cannot create inter-client FIFO [%s] (%s)\n", name, strerror(errno));
+ return false;
+ }
+ } else {
+ jack_error("Cannot check on FIFO %s\n", name);
+ return false;
+ }
+ } else {
+ if (!S_ISFIFO(statbuf.st_mode)) {
+ jack_error("FIFO (%s) already exists, but is not a FIFO!\n", name);
+ return false;
+ }
+ }
+
+ if ((fFifo = open(fName, O_RDWR | O_CREAT, 0666)) < 0) {
+ jack_error("Cannot open fifo [%s] (%s)", name, strerror(errno));
+ return false;
+ } else {
+ fPoll.fd = fFifo;
+ fPoll.events = POLLERR | POLLIN | POLLHUP | POLLNVAL;
+ return true;
+ }
+}
+
+// Client side
+bool JackFifo::ConnectAux(const char* name, int access)
+{
+ BuildName(name, fName);
+ JackLog("JackFifo::ConnectAux name = %s\n", fName);
+
+ // Temporary...
+ if (fFifo >= 0) {
+ JackLog("Already connected name = %s\n", name);
+ return true;
+ }
+
+ if ((fFifo = open(fName, access)) < 0) {
+ jack_error("Connect: can't connect named fifo name = %s err = %s", fName, strerror(errno));
+ return false;
+ } else {
+ fPoll.fd = fFifo;
+ fPoll.events = POLLERR | POLLIN | POLLHUP | POLLNVAL;
+ return true;
+ }
+}
+
+bool JackFifo::Connect(const char* name)
+{
+ return ConnectAux(name, O_RDWR);
+}
+
+bool JackFifo::ConnectOutput(const char* name)
+{
+ return ConnectAux(name, O_WRONLY | O_NONBLOCK);
+}
+
+bool JackFifo::ConnectInput(const char* name)
+{
+ return ConnectAux(name, O_RDONLY);
+}
+
+bool JackFifo::Disconnect()
+{
+ if (fFifo >= 0) {
+ JackLog("JackFifo::Disconnect %s\n", fName);
+ if (close(fFifo) != 0) {
+ jack_error("Disconnect: can't disconnect named fifo name = %s err = %s", fName, strerror(errno));
+ return false;
+ } else {
+ fFifo = -1;
+ return true;
+ }
+ } else {
+ return true;
+ }
+}
+
+// Server side : destroy the fifo
+void JackFifo::Destroy()
+{
+ if (fFifo > 0) {
+ JackLog("JackFifo::Destroy name = %s\n", fName);
+ unlink(fName);
+ if (close(fFifo) != 0) {
+ jack_error("Destroy: can't destroy fifo name = %s err = %s", fName, strerror(errno));
+ }
+ fFifo = -1;
+ } else {
+ jack_error("JackFifo::Destroy fifo < 0");
+ }
+}
+
+} // end of namespace
+
diff --git a/common/JackFifo.h b/common/JackFifo.h
new file mode 100755
index 00000000..e91d212a
--- /dev/null
+++ b/common/JackFifo.h
@@ -0,0 +1,73 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackFifo__
+#define __JackFifo__
+
+#include "JackSynchro.h"
+#include <assert.h>
+#include <stdio.h>
+#include <poll.h>
+
+namespace Jack
+{
+
+/*!
+\brief Inter process synchronization using Fifo.
+*/
+
+class JackFifo : public JackSynchro
+{
+
+ private:
+
+ int fFifo;
+ pollfd fPoll;
+
+ bool ConnectAux(const char* name, int access);
+
+ protected:
+
+ void BuildName(const char* name, char* res);
+
+ public:
+
+ JackFifo(): JackSynchro(), fFifo( -1)
+ {}
+ virtual ~JackFifo()
+ {}
+
+ bool Signal();
+ bool SignalAll();
+ bool Wait();
+ bool TimedWait(long usec);
+
+ bool Allocate(const char* name, int value);
+ bool Connect(const char* name);
+ bool ConnectInput(const char* name);
+ bool ConnectOutput(const char* name);
+ bool Disconnect();
+ void Destroy();
+};
+
+} // end of namespace
+
+
+#endif
+
diff --git a/common/JackFrameTimer.cpp b/common/JackFrameTimer.cpp
new file mode 100644
index 00000000..b0f4db2f
--- /dev/null
+++ b/common/JackFrameTimer.cpp
@@ -0,0 +1,109 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackFrameTimer.h"
+#include "JackError.h"
+#include <math.h>
+
+namespace Jack
+{
+
+JackTimer::JackTimer()
+{
+ fInitialized = false;
+ fFrames = 0;
+ fCurrentWakeup = 0;
+ fCurrentCallback = 0;
+ fNextWakeUp = 0;
+ fFilterCoefficient = 0.01f;
+ fSecondOrderIntegrator = 0.0f;
+}
+
+void JackFrameTimer::Init()
+{
+ fFirstWakeUp = true;
+}
+
+void JackFrameTimer::IncFrameTime(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs)
+{
+ if (fFirstWakeUp) {
+ InitFrameTime(callback_usecs, period_usecs);
+ fFirstWakeUp = false;
+ } else {
+ IncFrameTimeAux(nframes, callback_usecs, period_usecs);
+ }
+}
+
+void JackFrameTimer::InitFrameTime(jack_time_t callback_usecs, jack_time_t period_usecs)
+{
+ JackTimer* timer = WriteNextStateStart();
+ timer->fSecondOrderIntegrator = 0.0f;
+ timer->fCurrentCallback = callback_usecs;
+ timer->fNextWakeUp = callback_usecs + period_usecs;
+ WriteNextStateStop();
+ TrySwitchState();
+}
+
+void JackFrameTimer::ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs)
+{
+ if (!fFirstWakeUp) { // ResetFrameTime may be called by a xrun/delayed wakeup on the first cycle
+ JackTimer* timer = WriteNextStateStart();
+ jack_nframes_t period_size_guess = (jack_nframes_t)(frames_rate * ((timer->fNextWakeUp - timer->fCurrentWakeup) / 1000000.0));
+ timer->fFrames += ((callback_usecs - timer->fNextWakeUp) / period_size_guess) * period_size_guess;
+ timer->fCurrentWakeup = callback_usecs;
+ timer->fCurrentCallback = callback_usecs;
+ timer->fNextWakeUp = callback_usecs + period_usecs;
+ WriteNextStateStop();
+ TrySwitchState();
+ }
+}
+
+void JackFrameTimer::IncFrameTimeAux(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs)
+{
+ JackTimer* timer = WriteNextStateStart();
+ float delta = (int64_t)callback_usecs - (int64_t)timer->fNextWakeUp;
+ timer->fCurrentWakeup = timer->fNextWakeUp;
+ timer->fCurrentCallback = callback_usecs;
+ timer->fFrames += nframes;
+ timer->fSecondOrderIntegrator += 0.5f * timer->fFilterCoefficient * delta;
+ timer->fNextWakeUp = timer->fCurrentWakeup + period_usecs + (int64_t) floorf((timer->fFilterCoefficient * (delta + timer->fSecondOrderIntegrator)));
+ timer->fInitialized = true;
+ WriteNextStateStop();
+ TrySwitchState();
+}
+
+/*
+ Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
+ The operation is lock-free since there is no intermediate state in the write operation that could cause the
+ read to loop forever.
+*/
+void JackFrameTimer::ReadFrameTime(JackTimer* timer)
+{
+ UInt16 next_index = GetCurrentIndex();
+ UInt16 cur_index;
+ do {
+ cur_index = next_index;
+ memcpy(timer, ReadCurrentState(), sizeof(JackTimer));
+ next_index = GetCurrentIndex();
+ } while (cur_index != next_index); // Until a coherent state has been read
+}
+
+} // end of namespace
+
diff --git a/common/JackFrameTimer.h b/common/JackFrameTimer.h
new file mode 100644
index 00000000..552bc11e
--- /dev/null
+++ b/common/JackFrameTimer.h
@@ -0,0 +1,81 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackFrameTimer__
+#define __JackFrameTimer__
+
+#include "JackAtomicState.h"
+#include "types.h"
+
+namespace Jack
+{
+
+/*!
+\brief A structure used for time management.
+*/
+
+struct JackTimer
+{
+ jack_nframes_t fFrames;
+ jack_time_t fCurrentWakeup;
+ jack_time_t fCurrentCallback;
+ jack_time_t fNextWakeUp;
+ float fSecondOrderIntegrator;
+ bool fInitialized;
+
+ /* not accessed by clients */
+
+ float fFilterCoefficient; /* set once, never altered */
+
+ JackTimer();
+ ~JackTimer()
+ {}
+
+};
+
+/*!
+\brief A class using the JackAtomicState to manage jack time.
+*/
+
+class JackFrameTimer : public JackAtomicState<JackTimer>
+{
+ private:
+
+ bool fFirstWakeUp;
+ void IncFrameTimeAux(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs);
+
+ public:
+
+ JackFrameTimer(): fFirstWakeUp(true)
+ {}
+ ~JackFrameTimer()
+ {}
+
+ void Init();
+ void InitFrameTime(jack_time_t callback_usecs, jack_time_t period_usecs);
+ void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs);
+ void IncFrameTime(jack_nframes_t nframes, jack_time_t callback_usecs, jack_time_t period_usecs);
+ void ReadFrameTime(JackTimer* timer);
+};
+
+
+} // end of namespace
+
+#endif
diff --git a/common/JackFreewheelDriver.cpp b/common/JackFreewheelDriver.cpp
new file mode 100644
index 00000000..2fbe4233
--- /dev/null
+++ b/common/JackFreewheelDriver.cpp
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackFreewheelDriver.h"
+#include "JackEngineControl.h"
+#include "JackEngine.h"
+
+namespace Jack
+{
+
+int JackFreewheelDriver::Process()
+{
+ if (fIsMaster) {
+ JackLog("JackFreewheelDriver::Process master %lld\n", fEngineControl->fTimeOutUsecs);
+ fLastWaitUst = GetMicroSeconds();
+ fEngine->Process(fLastWaitUst);
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); // Signal all clients
+ if (fGraphManager->SuspendRefNum(fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs * 20) < 0) // Wait for all clients to finish
+ jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error");
+ } else {
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); // Signal all clients
+ if (fEngineControl->fSyncMode) {
+ if (fGraphManager->SuspendRefNum(fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs) < 0)
+ jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error");
+ }
+ }
+ return 0;
+}
+
+} // end of namespace
diff --git a/common/JackFreewheelDriver.h b/common/JackFreewheelDriver.h
new file mode 100644
index 00000000..f2f54d5a
--- /dev/null
+++ b/common/JackFreewheelDriver.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackFreewheelDriver__
+#define __JackFreewheelDriver__
+
+#include "JackDriver.h"
+
+namespace Jack
+{
+
+/*!
+\brief The FreeWheel driver : run Jack engine at full speed.
+*/
+
+class JackFreewheelDriver : public JackDriver
+{
+
+ public:
+
+ JackFreewheelDriver(const char* name, JackEngine* engine, JackSynchro** table): JackDriver(name, engine, table)
+ {}
+ virtual ~JackFreewheelDriver()
+ {}
+
+ bool IsRealTime() const
+ {
+ return false;
+ }
+
+ int Process();
+};
+
+} // end of namespace
+
+
+#endif
diff --git a/common/JackGlobals.cpp b/common/JackGlobals.cpp
new file mode 100644
index 00000000..8b72a9fd
--- /dev/null
+++ b/common/JackGlobals.cpp
@@ -0,0 +1,28 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+
+#include "JackGlobals.h"
+
+namespace Jack
+{
+
+JackFactoryImpl* JackGlobals::fInstance;
+
+} // end of namespace
diff --git a/common/JackGlobals.h b/common/JackGlobals.h
new file mode 100644
index 00000000..af4a8809
--- /dev/null
+++ b/common/JackGlobals.h
@@ -0,0 +1,282 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackGlobals__
+#define __JackGlobals__
+
+#include "JackError.h"
+
+namespace Jack
+{
+
+class JackSynchro;
+class JackServerNotifyChannelInterface;
+class JackClientChannelInterface;
+class JackNotifyChannelInterface;
+class JackServerChannelInterface;
+class JackSyncInterface;
+class JackThread;
+class JackDriverClientInterface;
+class JackRunnableInterface;
+class JackEngine;
+
+/*!
+\brief Factory description
+
+\totdo possibly use in a dynamic way to test different communication/synchro implementations.
+*/
+
+class JackFactoryImpl
+{
+ public:
+
+ JackFactoryImpl()
+ {}
+ virtual ~JackFactoryImpl()
+ {}
+
+ virtual JackSynchro* MakeSynchro() = 0;
+ virtual JackServerNotifyChannelInterface* MakeServerNotifyChannel() = 0;
+ virtual JackClientChannelInterface* MakeClientChannel() = 0;
+ virtual JackNotifyChannelInterface* MakeNotifyChannel() = 0;
+ virtual JackServerChannelInterface* MakeServerChannel() = 0;
+ virtual JackSyncInterface* MakeInterProcessSync() = 0;
+ virtual JackThread* MakeThread(JackRunnableInterface* runnable) = 0;
+};
+
+#ifdef __linux__
+
+class JackFactoryLinuxServer : public JackFactoryImpl
+{
+ public:
+
+ JackFactoryLinuxServer()
+ {}
+ virtual ~JackFactoryLinuxServer()
+ {}
+
+ JackSynchro* MakeSynchro();
+ JackServerNotifyChannelInterface* MakeServerNotifyChannel();
+ JackClientChannelInterface* MakeClientChannel();
+ JackNotifyChannelInterface* MakeNotifyChannel();
+ JackServerChannelInterface* MakeServerChannel();
+ JackSyncInterface* MakeInterProcessSync();
+ JackThread* MakeThread(JackRunnableInterface* runnable);
+};
+
+class JackFactoryLinuxClient : public JackFactoryImpl
+{
+ public:
+
+ JackFactoryLinuxClient()
+ {}
+ virtual ~JackFactoryLinuxClient()
+ {}
+
+ JackSynchro* MakeSynchro();
+ JackServerNotifyChannelInterface* MakeServerNotifyChannel();
+ JackClientChannelInterface* MakeClientChannel();
+ JackNotifyChannelInterface* MakeNotifyChannel();
+ JackServerChannelInterface* MakeServerChannel();
+ JackSyncInterface* MakeInterProcessSync();
+ JackThread* MakeThread(JackRunnableInterface* runnable);
+};
+
+#endif
+
+#ifdef WIN32
+
+class JackFactoryWindowsServer : public JackFactoryImpl
+{
+ public:
+
+ JackFactoryWindowsServer()
+ {}
+ virtual ~JackFactoryWindowsServer()
+ {}
+
+ JackSynchro* MakeSynchro();
+ JackServerNotifyChannelInterface* MakeServerNotifyChannel();
+ JackClientChannelInterface* MakeClientChannel();
+ JackNotifyChannelInterface* MakeNotifyChannel();
+ JackServerChannelInterface* MakeServerChannel();
+ JackSyncInterface* MakeInterProcessSync();
+ JackThread* MakeThread(JackRunnableInterface* runnable);
+};
+
+class JackFactoryWindowsClient : public JackFactoryImpl
+{
+ public:
+
+ JackFactoryWindowsClient()
+ {}
+ virtual ~JackFactoryWindowsClient()
+ {}
+
+ JackSynchro* MakeSynchro();
+ JackServerNotifyChannelInterface* MakeServerNotifyChannel();
+ JackClientChannelInterface* MakeClientChannel();
+ JackNotifyChannelInterface* MakeNotifyChannel();
+ JackServerChannelInterface* MakeServerChannel();
+ JackSyncInterface* MakeInterProcessSync();
+ JackThread* MakeThread(JackRunnableInterface* runnable);
+};
+
+#endif
+
+#if defined(__APPLE__)
+
+class JackFactoryOSXServer : public JackFactoryImpl
+{
+ public:
+
+ JackFactoryOSXServer()
+ {}
+ virtual ~JackFactoryOSXServer()
+ {}
+
+ JackSynchro* MakeSynchro();
+ JackServerNotifyChannelInterface* MakeServerNotifyChannel();
+ JackClientChannelInterface* MakeClientChannel();
+ JackNotifyChannelInterface* MakeNotifyChannel();
+ JackServerChannelInterface* MakeServerChannel();
+ JackSyncInterface* MakeInterProcessSync();
+ JackThread* MakeThread(JackRunnableInterface* runnable);
+};
+
+class JackFactoryOSXClient : public JackFactoryImpl
+{
+ public:
+
+ JackFactoryOSXClient()
+ {}
+ virtual ~JackFactoryOSXClient()
+ {}
+
+ JackSynchro* MakeSynchro();
+ JackServerNotifyChannelInterface* MakeServerNotifyChannel();
+ JackClientChannelInterface* MakeClientChannel();
+ JackNotifyChannelInterface* MakeNotifyChannel();
+ JackServerChannelInterface* MakeServerChannel();
+ JackSyncInterface* MakeInterProcessSync();
+ JackThread* MakeThread(JackRunnableInterface* runnable);
+};
+
+#endif
+
+/*!
+\brief Factory for OS specific ressources.
+*/
+
+class JackGlobals
+{
+ private:
+
+ static JackFactoryImpl* fInstance;
+
+ public:
+
+ JackGlobals()
+ {}
+ virtual ~JackGlobals()
+ {}
+
+ static JackSynchro* MakeSynchro()
+ {
+ return fInstance->MakeSynchro();
+ }
+ static JackServerNotifyChannelInterface* MakeServerNotifyChannel()
+ {
+ return fInstance->MakeServerNotifyChannel();
+ }
+ static JackClientChannelInterface* MakeClientChannel()
+ {
+ return fInstance->MakeClientChannel();
+ }
+ static JackNotifyChannelInterface* MakeNotifyChannel()
+ {
+ return fInstance->MakeNotifyChannel();
+ }
+ static JackServerChannelInterface* MakeServerChannel()
+ {
+ return fInstance->MakeServerChannel();
+ }
+ static JackSyncInterface* MakeInterProcessSync()
+ {
+ return fInstance->MakeInterProcessSync();
+ }
+ static JackThread* MakeThread(JackRunnableInterface* runnable)
+ {
+ return fInstance->MakeThread(runnable);
+ }
+
+ static void InitServer()
+ {
+ JackLog("JackGlobals InitServer\n");
+ if (!fInstance) {
+
+#ifdef __APPLE__
+ fInstance = new JackFactoryOSXServer();
+#endif
+
+#ifdef WIN32
+ fInstance = new JackFactoryWindowsServer();
+#endif
+
+#ifdef __linux__
+ fInstance = new JackFactoryLinuxServer();
+#endif
+
+ }
+ }
+
+ static void InitClient()
+ {
+ JackLog("JackGlobals InitClient\n");
+ if (!fInstance) {
+
+#ifdef __APPLE__
+ fInstance = new JackFactoryOSXClient();
+#endif
+
+#ifdef WIN32
+ fInstance = new JackFactoryWindowsClient();
+#endif
+
+#ifdef __linux__
+ fInstance = new JackFactoryLinuxClient();
+#endif
+
+ }
+ }
+
+ static void Destroy()
+ {
+ JackLog("JackGlobals Destroy\n");
+ if (fInstance) {
+ delete fInstance;
+ fInstance = NULL;
+ }
+ }
+
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackGlobalsClient.cpp b/common/JackGlobalsClient.cpp
new file mode 100644
index 00000000..4f168917
--- /dev/null
+++ b/common/JackGlobalsClient.cpp
@@ -0,0 +1,460 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackGlobals.h"
+
+// OSX
+#if defined(__APPLE__)
+#include "JackCoreAudioDriver.h"
+#include "JackMachServerNotifyChannel.h"
+#include "JackMachNotifyChannel.h"
+#include "JackMachServerChannel.h"
+#include "JackMachClientChannel.h"
+#include "JackMachThread.h"
+#include "JackMachSemaphore.h"
+#include "JackProcessSync.h"
+#include "JackSocketServerNotifyChannel.h"
+#include "JackSocketNotifyChannel.h"
+#include "JackSocketServerChannel.h"
+#include "JackSocketClientChannel.h"
+#include "JackPosixThread.h"
+#include "JackPosixSemaphore.h"
+#include "JackFifo.h"
+#endif
+
+// WINDOWS
+#ifdef WIN32
+#include "JackWinProcessSync.h"
+#include "JackWinNamedPipeClientChannel.h"
+#include "JackWinEvent.h"
+#include "JackWinThread.h"
+#endif
+
+// LINUX
+#ifdef __linux__
+#include "JackAlsaDriver.h"
+#include "JackProcessSync.h"
+#include "JackSocketServerNotifyChannel.h"
+#include "JackSocketNotifyChannel.h"
+#include "JackSocketServerChannel.h"
+#include "JackSocketClientChannel.h"
+#include "JackPosixThread.h"
+#include "JackPosixSemaphore.h"
+#include "JackFifo.h"
+#endif
+
+
+using namespace std;
+
+namespace Jack
+{
+
+#ifdef WIN32
+
+JackSynchro* JackFactoryWindowsClient::MakeSynchro()
+{
+ return new JackWinEvent();
+}
+
+JackServerNotifyChannelInterface* JackFactoryWindowsClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryWindowsClient::MakeClientChannel()
+{
+ return new JackWinNamedPipeClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryWindowsClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryWindowsClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryWindowsClient::MakeInterProcessSync()
+{
+ return new JackWinProcessSync();
+}
+
+JackThread* JackFactoryWindowsClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackWinThread(runnable);
+}
+#endif
+
+#ifdef __linux__
+
+#if defined(SOCKET_RPC_POSIX_SEMA)
+JackSynchro* JackFactoryLinuxClient::MakeSynchro()
+{
+ return new JackPosixSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryLinuxClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryLinuxClient::MakeClientChannel()
+{
+ return new JackSocketClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryLinuxClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryLinuxClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryLinuxClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryLinuxClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackPosixThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_FIFO_SEMA)
+JackSynchro* JackFactoryLinuxClient::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryLinuxClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryLinuxClient::MakeClientChannel()
+{
+ return new JackSocketClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryLinuxClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryLinuxClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryLinuxClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryLinuxClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackPosixThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_FIFO_SEMA_DUMMY)
+JackSynchro* JackFactoryLinuxClient::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryLinuxClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryLinuxClient::MakeClientChannel()
+{
+ return new JackSocketClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryLinuxClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryLinuxClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryLinuxClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryLinuxClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackPosixThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#endif
+
+#if defined(__APPLE__)
+
+#if defined(MACH_RPC_MACH_SEMA)
+// Mach RPC + Mach Semaphore
+JackSynchro* JackFactoryOSXClient::MakeSynchro()
+{
+ return new JackMachSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryOSXClient::MakeClientChannel()
+{
+ return new JackMachClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryOSXClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryOSXClient::MakeServerChannel()
+{
+ return NULL;
+} // Not used
+
+JackSyncInterface* JackFactoryOSXClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_POSIX_SEMA)
+// Socket RPC + Posix Semaphore
+JackSynchro* JackFactoryOSXClient::MakeSynchro()
+{
+ return new JackPosixSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryOSXClient::MakeClientChannel()
+{
+ return new JackSocketClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryOSXClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryOSXClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryOSXClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_FIFO_SEMA)
+// Socket RPC + Fifo Semaphore
+JackSynchro* JackFactoryOSXClient::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryOSXClient::MakeClientChannel()
+{
+ return new JackSocketClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryOSXClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryOSXClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryOSXClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable, int priority)
+{
+ return new JackMachThread(runnable, false, priority, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(MACH_RPC_FIFO_SEMA)
+// Mach RPC + Fifo Semaphore
+JackSynchro* JackFactoryOSXClient::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryOSXClient::MakeClientChannel()
+{
+ return new JackMachClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryOSXClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryOSXClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryOSXClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(MACH_RPC_POSIX_SEMA)
+// Mach RPC + Posix Semaphore
+JackSynchro* JackFactoryOSXClient::MakeSynchro()
+{
+ return new JackPosixSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryOSXClient::MakeClientChannel()
+{
+ return new JackMachClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryOSXClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryOSXClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryOSXClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined SOCKET_RPC_MACH_SEMA
+// Socket RPC + Mach Semaphore
+JackSynchro* JackFactoryOSXClient::MakeSynchro()
+{
+ return new JackMachSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXClient::MakeServerNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackClientChannelInterface* JackFactoryOSXClient::MakeClientChannel()
+{
+ return new JackSocketClientChannel();
+}
+
+JackNotifyChannelInterface* JackFactoryOSXClient::MakeNotifyChannel()
+{
+ return NULL;
+}
+// Not used
+JackServerChannelInterface* JackFactoryOSXClient::MakeServerChannel()
+{
+ return NULL;
+}
+// Not used
+JackSyncInterface* JackFactoryOSXClient::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXClient::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#endif
+
+} // end of namespace
+
+
diff --git a/common/JackGlobalsServer.cpp b/common/JackGlobalsServer.cpp
new file mode 100644
index 00000000..79f9ef64
--- /dev/null
+++ b/common/JackGlobalsServer.cpp
@@ -0,0 +1,460 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackGlobals.h"
+
+// OSX
+#if defined(__APPLE__)
+#include "JackCoreAudioDriver.h"
+#include "JackMachServerNotifyChannel.h"
+#include "JackMachNotifyChannel.h"
+#include "JackMachServerChannel.h"
+#include "JackMachClientChannel.h"
+#include "JackMachThread.h"
+#include "JackMachSemaphore.h"
+#include "JackProcessSync.h"
+
+#include "JackSocketServerNotifyChannel.h"
+#include "JackSocketNotifyChannel.h"
+#include "JackSocketServerChannel.h"
+#include "JackSocketClientChannel.h"
+#include "JackPosixThread.h"
+#include "JackPosixSemaphore.h"
+#include "JackFifo.h"
+#endif
+
+// WINDOWS
+#ifdef WIN32
+#include "JackWinProcessSync.h"
+#include "JackWinNamedPipeServerNotifyChannel.h"
+#include "JackWinNamedPipeNotifyChannel.h"
+#include "JackWinNamedPipeServerChannel.h"
+#include "JackWinNamedPipeClientChannel.h"
+#include "JackWinEvent.h"
+#include "JackWinThread.h"
+#endif
+
+// LINUX
+#ifdef __linux__
+#include "JackAlsaDriver.h"
+#include "JackProcessSync.h"
+#include "JackSocketServerNotifyChannel.h"
+#include "JackSocketNotifyChannel.h"
+#include "JackSocketServerChannel.h"
+#include "JackSocketClientChannel.h"
+#include "JackPosixThread.h"
+#include "JackPosixSemaphore.h"
+#include "JackFifo.h"
+#endif
+
+// COMMON
+#include "JackDummyDriver.h"
+#include "JackAudioDriver.h"
+
+
+using namespace std;
+
+namespace Jack
+{
+
+#ifdef WIN32
+JackSynchro* JackFactoryWindowsServer::MakeSynchro()
+{
+ return new JackWinEvent();
+}
+
+JackServerNotifyChannelInterface* JackFactoryWindowsServer::MakeServerNotifyChannel()
+{
+ return new JackWinNamedPipeServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryWindowsServer::MakeClientChannel()
+{
+ return NULL;
+} // Not used
+
+JackNotifyChannelInterface* JackFactoryWindowsServer::MakeNotifyChannel()
+{
+ return new JackWinNamedPipeNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryWindowsServer::MakeServerChannel()
+{
+ return new JackWinNamedPipeServerChannel();
+}
+
+JackSyncInterface* JackFactoryWindowsServer::MakeInterProcessSync()
+{
+ return new JackWinProcessSync();
+}
+
+JackThread* JackFactoryWindowsServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackWinThread(runnable);
+}
+#endif
+
+#ifdef __linux__
+
+#if defined(SOCKET_RPC_POSIX_SEMA)
+JackSynchro* JackFactoryLinuxServer::MakeSynchro()
+{
+ return new JackPosixSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryLinuxServer::MakeServerNotifyChannel()
+{
+ return new JackSocketServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryLinuxServer::MakeClientChannel()
+{
+ return NULL;
+} // Not used
+
+JackNotifyChannelInterface* JackFactoryLinuxServer::MakeNotifyChannel()
+{
+ return new JackSocketNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryLinuxServer::MakeServerChannel()
+{
+ return new JackSocketServerChannel();
+}
+
+JackSyncInterface* JackFactoryLinuxServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryLinuxServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackPosixThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_FIFO_SEMA)
+JackSynchro* JackFactoryLinuxServer::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryLinuxServer::MakeServerNotifyChannel()
+{
+ return new JackSocketServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryLinuxServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryLinuxServer::MakeNotifyChannel()
+{
+ return new JackSocketNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryLinuxServer::MakeServerChannel()
+{
+ return new JackSocketServerChannel();
+}
+
+JackSyncInterface* JackFactoryLinuxServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryLinuxServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackPosixThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_FIFO_SEMA_DUMMY)
+JackSynchro* JackFactoryLinuxServer::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryLinuxServer::MakeServerNotifyChannel()
+{
+ return new JackSocketServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryLinuxServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryLinuxServer::MakeNotifyChannel()
+{
+ return new JackSocketNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryLinuxServer::MakeServerChannel()
+{
+ return new JackSocketServerChannel();
+}
+
+JackSyncInterface* JackFactoryLinuxServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryLinuxServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackPosixThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#endif
+
+#if defined(__APPLE__)
+
+#if defined(MACH_RPC_MACH_SEMA)
+// Mach RPC + Mach Semaphore
+JackSynchro* JackFactoryOSXServer::MakeSynchro()
+{
+ return new JackMachSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXServer::MakeServerNotifyChannel()
+{
+ return new JackMachServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryOSXServer::MakeClientChannel()
+{
+ return NULL;
+} // Not used
+
+JackNotifyChannelInterface* JackFactoryOSXServer::MakeNotifyChannel()
+{
+ return new JackMachNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryOSXServer::MakeServerChannel()
+{
+ return new JackMachServerChannel();
+}
+
+JackSyncInterface* JackFactoryOSXServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_POSIX_SEMA)
+// Socket RPC + Posix Semaphore
+JackSynchro* JackFactoryOSXServer::MakeSynchro()
+{
+ return new JackPosixSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXServer::MakeServerNotifyChannel()
+{
+ return new JackSocketServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryOSXServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryOSXServer::MakeNotifyChannel()
+{
+ return new JackSocketNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryOSXServer::MakeServerChannel()
+{
+ return new JackSocketServerChannel();
+}
+
+JackSyncInterface* JackFactoryOSXServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_FIFO_SEMA)
+// Socket RPC + Fifo Semaphore
+JackSynchro* JackFactoryOSXServer::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXServer::MakeServerNotifyChannel()
+{
+ return new JackSocketServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryOSXServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryOSXServer::MakeNotifyChannel()
+{
+ return new JackSocketNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryOSXServer::MakeServerChannel()
+{
+ return new JackSocketServerChannel();
+}
+
+JackSyncInterface* JackFactoryOSXServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(MACH_RPC_FIFO_SEMA)
+// Mach RPC + Fifo Semaphore
+JackSynchro* JackFactoryOSXServer::MakeSynchro()
+{
+ return new JackFifo();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXServer::MakeServerNotifyChannel()
+{
+ return new JackMachServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryOSXServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryOSXServer::MakeNotifyChannel()
+{
+ return new JackMachNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryOSXServer::MakeServerChannel()
+{
+ return new JackMachServerChannel();
+}
+
+JackSyncInterface* JackFactoryOSXServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(MACH_RPC_POSIX_SEMA)
+// Mach RPC + Posix Semaphore
+JackSynchro* JackFactoryOSXServer::MakeSynchro()
+{
+ return new JackPosixSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXServer::MakeServerNotifyChannel()
+{
+ return new JackMachServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryOSXServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryOSXServer::MakeNotifyChannel()
+{
+ return new JackMachNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryOSXServer::MakeServerChannel()
+{
+ return new JackMachServerChannel();
+}
+
+JackSyncInterface* JackFactoryOSXServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#if defined(SOCKET_RPC_MACH_SEMA)
+// Socket RPC + Mac Semaphore
+JackSynchro* JackFactoryOSXServer::MakeSynchro()
+{
+ return new JackMachSemaphore();
+}
+
+JackServerNotifyChannelInterface* JackFactoryOSXServer::MakeServerNotifyChannel()
+{
+ return new JackSocketServerNotifyChannel();
+}
+
+JackClientChannelInterface* JackFactoryOSXServer::MakeClientChannel()
+{
+ return NULL;
+}
+// Not used
+JackNotifyChannelInterface* JackFactoryOSXServer::MakeNotifyChannel()
+{
+ return new JackSocketNotifyChannel();
+}
+
+JackServerChannelInterface* JackFactoryOSXServer::MakeServerChannel()
+{
+ return new JackSocketServerChannel();
+}
+
+JackSyncInterface* JackFactoryOSXServer::MakeInterProcessSync()
+{
+ return new JackProcessSync();
+}
+
+JackThread* JackFactoryOSXServer::MakeThread(JackRunnableInterface* runnable)
+{
+ return new JackMachThread(runnable, PTHREAD_CANCEL_ASYNCHRONOUS);
+}
+#endif
+
+#endif
+
+} // end of namespace
diff --git a/common/JackGraphManager.cpp b/common/JackGraphManager.cpp
new file mode 100644
index 00000000..ee32d8b5
--- /dev/null
+++ b/common/JackGraphManager.cpp
@@ -0,0 +1,777 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "JackGraphManager.h"
+#include "JackConstants.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <regex.h>
+
+namespace Jack
+{
+
+static inline jack_nframes_t MAX(jack_nframes_t a, jack_nframes_t b)
+{
+ return (a < b) ? b : a;
+}
+
+static void AssertPort(jack_port_id_t port_index)
+{
+ if (port_index >= PORT_NUM) {
+ JackLog("JackGraphManager::AssertPort port_index = %ld\n", port_index);
+ assert(port_index < PORT_NUM);
+ }
+}
+
+static void AssertBufferSize(jack_nframes_t frames)
+{
+ if (frames > BUFFER_SIZE_MAX) {
+ JackLog("JackGraphManager::AssertBufferSize frames = %ld\n", frames);
+ assert(frames <= BUFFER_SIZE_MAX);
+ }
+}
+
+JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
+{
+ AssertPort(port_index);
+ return &fPortArray[port_index];
+}
+
+float* JackGraphManager::GetBuffer(jack_port_id_t port_index)
+{
+ return fPortArray[port_index].GetBuffer();
+}
+
+// RT, client
+int JackGraphManager::GetConnectionsNum(jack_port_id_t port_index)
+{
+ JackConnectionManager* manager = ReadCurrentState();
+ return manager->Connections(port_index);
+}
+
+// Server
+int JackGraphManager::AllocateRefNum()
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ int res = manager->AllocateRefNum();
+ WriteNextStateStop();
+ return res;
+}
+
+// Server
+void JackGraphManager::ReleaseRefNum(int refnum)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ manager->ReleaseRefNum(refnum);
+ WriteNextStateStop();
+}
+
+// RT
+void JackGraphManager::RunCurrentGraph()
+{
+ JackConnectionManager* manager = ReadCurrentState();
+ manager->ResetGraph(fClientTiming);
+}
+
+// RT
+bool JackGraphManager::RunNextGraph()
+{
+ bool res;
+ JackConnectionManager* manager = TrySwitchState(&res);
+ manager->ResetGraph(fClientTiming);
+ return res;
+}
+
+// RT
+bool JackGraphManager::IsFinishedGraph()
+{
+ JackConnectionManager* manager = ReadCurrentState();
+ return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
+}
+
+// RT
+int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro** table)
+{
+ JackConnectionManager* manager = ReadCurrentState();
+ return manager->ResumeRefNum(control, table, fClientTiming);
+}
+
+// RT
+int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro** table, long usec)
+{
+ JackConnectionManager* manager = ReadCurrentState();
+ return manager->SuspendRefNum(control, table, fClientTiming, usec);
+}
+
+JackClientTiming* JackGraphManager::GetClientTiming(int ref)
+{
+ return &fClientTiming[ref];
+}
+
+// Server
+void JackGraphManager::DirectConnect(int ref1, int ref2)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ manager->DirectConnect(ref1, ref2);
+ JackLog("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld\n", CurIndex(fCounter), ref1, ref2);
+ WriteNextStateStop();
+}
+
+// Server
+void JackGraphManager::DirectDisconnect(int ref1, int ref2)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ manager->DirectDisconnect(ref1, ref2);
+ JackLog("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld\n", CurIndex(fCounter), ref1, ref2);
+ WriteNextStateStop();
+}
+
+// Server
+bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
+{
+ JackConnectionManager* manager = ReadCurrentState();
+ return manager->IsDirectConnection(ref1, ref2);
+}
+
+// RT
+void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t frames)
+{
+ AssertPort(port_index);
+ AssertBufferSize(frames);
+
+ JackConnectionManager* manager = ReadCurrentState();
+ JackPort* port = GetPort(port_index);
+
+ if (!port->IsUsed()) {
+ // This happens when a port has just been unregistered and is still used by the RT code.
+ JackLog("JackGraphManager::GetBuffer : port = %ld is released state\n", port_index);
+ return GetBuffer(0); // port_index 0 is not used
+ }
+
+ // Output port
+ if (port->fFlags & JackPortIsOutput) {
+ return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, frames) : GetBuffer(port_index);
+ }
+
+ // Input port
+ jack_int_t len = manager->Connections(port_index);
+
+ if (len == 0) { // No connections: return a zero-filled buffer
+ float* buffer = GetBuffer(port_index);
+ memset(buffer, 0, frames * sizeof(float)); // Clear buffer
+ return buffer;
+ } else if (len == 1) { // One connection: use zero-copy mode - just pass the buffer of the connected (output) port.
+ assert(manager->GetPort(port_index, 0) != port_index); // Check recursion
+ return GetBuffer(manager->GetPort(port_index, 0), frames);
+ } else { // Multiple connections
+ const jack_int_t* connections = manager->GetConnections(port_index);
+ float* mixbuffer = GetBuffer(port_index);
+ jack_port_id_t src_index;
+ float* buffer;
+
+ // Copy first buffer
+ src_index = connections[0];
+ AssertPort(src_index);
+ buffer = (float*)GetBuffer(src_index, frames);
+ memcpy(mixbuffer, buffer, frames * sizeof(float));
+
+ // Mix remaining buffers
+ for (int i = 1; (i < CONNECTION_NUM) && ((src_index = connections[i]) != EMPTY); i++) {
+ AssertPort(src_index);
+ buffer = (float*)GetBuffer(src_index, frames);
+ JackPort::MixBuffer(mixbuffer, buffer, frames);
+ }
+ return mixbuffer;
+ }
+}
+
+int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
+{
+ AssertPort(port_index);
+ JackPort* port = GetPort(port_index);
+
+ /**
+ jackd.h
+ * If @ref JackPortCanMonitor is set for this @a port, turn input
+ * monitoring on or off. Otherwise, do nothing.
+
+ if (!(fFlags & JackPortCanMonitor))
+ return -1;
+ */
+
+ port->RequestMonitor(onoff);
+
+ const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
+ if ((port->fFlags & JackPortIsOutput) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ?
+ jack_port_id_t src_index;
+ for (int i = 0; (i < CONNECTION_NUM) && ((src_index = connections[i]) != EMPTY); i++) {
+ // XXX much worse things will happen if there is a feedback loop !!!
+ RequestMonitor(src_index, onoff);
+ }
+ }
+
+ return 0;
+}
+
+jack_nframes_t JackGraphManager::GetTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
+{
+ const jack_int_t* connections = manager->GetConnections(port_index);
+ jack_nframes_t latency = GetPort(port_index)->GetLatency();
+ jack_nframes_t max_latency = 0;
+ jack_port_id_t dst_index;
+
+ if (hop_count > 8)
+ return latency;
+
+ for (int i = 0; (i < CONNECTION_NUM) && ((dst_index = connections[i]) != EMPTY); i++) {
+ if (src_port_index != dst_index) {
+ AssertPort(dst_index);
+ JackPort* dst_port = GetPort(dst_index);
+ jack_nframes_t this_latency = (dst_port->fFlags & JackPortIsTerminal)
+ ? dst_port->GetLatency()
+ : GetTotalLatencyAux(dst_index, port_index, manager, hop_count + 1);
+ max_latency = MAX(max_latency, this_latency);
+ }
+ }
+
+ return max_latency + latency;
+}
+
+jack_nframes_t JackGraphManager::GetTotalLatency(jack_port_id_t port_index)
+{
+ UInt16 cur_index;
+ UInt16 next_index;
+ jack_nframes_t total_latency;
+ AssertPort(port_index);
+ JackLog("JackGraphManager::GetTotalLatency port_index = %ld\n", port_index);
+
+ do {
+ cur_index = GetCurrentIndex();
+ total_latency = GetTotalLatencyAux(port_index, port_index, ReadCurrentState(), 0);
+ next_index = GetCurrentIndex();
+ } while (cur_index != next_index); // Until a coherent state has been read
+
+ return total_latency;
+}
+
+// Server
+jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, JackPortFlags flags)
+{
+ jack_port_id_t port_index;
+
+ // Look for first available port Port index start at 1, otherwise a port_index of 0 is "seen" as a NULL port by the external API...
+ for (port_index = 1; port_index < PORT_NUM; port_index++) {
+ JackPort* port = GetPort(port_index);
+ if (!port->IsUsed()) {
+ JackLog("JackGraphManager::AllocatePortAux port_index = %ld name = %s\n", port_index, port_name);
+ port->Allocate(refnum, port_name, flags);
+ break;
+ }
+ }
+
+ return (port_index < PORT_NUM) ? port_index : NO_PORT;
+}
+
+// Server
+jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, JackPortFlags flags)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ jack_port_id_t port_index = AllocatePortAux(refnum, port_name, flags);
+
+ if (port_index != NO_PORT) {
+ int res;
+ if (flags & JackPortIsOutput) {
+ res = manager->AddOutputPort(refnum, port_index);
+ } else {
+ res = manager->AddInputPort(refnum, port_index);
+ }
+ if (res < 0) {
+ JackPort* port = GetPort(port_index);
+ assert(port);
+ port->Release();
+ port_index = NO_PORT;
+ }
+ }
+
+ WriteNextStateStop();
+ return port_index;
+}
+
+// Server
+void JackGraphManager::ReleasePort(jack_port_id_t port_index)
+{
+ JackPort* port = GetPort(port_index);
+ port->Release();
+}
+
+// Server
+int JackGraphManager::RemovePort(int refnum, jack_port_id_t port_index)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ JackPort* port = GetPort(port_index);
+ int res;
+
+ if (port->fFlags & JackPortIsOutput) {
+ DisconnectAllOutput(port_index);
+ res = manager->RemoveOutputPort(refnum, port_index);
+ } else {
+ DisconnectAllInput(port_index);
+ res = manager->RemoveInputPort(refnum, port_index);
+ }
+
+ WriteNextStateStop();
+ return res;
+}
+
+// Server
+void JackGraphManager::RemoveAllPorts(int refnum)
+{
+ JackLog("JackGraphManager::RemoveAllPorts ref = %ld\n", refnum);
+ JackConnectionManager* manager = WriteNextStateStart();
+ jack_port_id_t port_index;
+
+ // Warning : RemovePort shift port to left, thus we always remove the first port until the "input" table is empty
+ const jack_int_t* input = manager->GetInputPorts(refnum);
+ while ((port_index = input[0]) != EMPTY) {
+ RemovePort(refnum, port_index);
+ ReleasePort(port_index);
+ }
+
+ // Warning : RemovePort shift port to left, thus we always remove the first port until the "output" table is empty
+ const jack_int_t* output = manager->GetOutputPorts(refnum);
+ while ((port_index = output[0]) != EMPTY) {
+ RemovePort(refnum, port_index);
+ ReleasePort(port_index);
+ }
+
+ WriteNextStateStop();
+}
+
+// Server
+void JackGraphManager::DisconnectAllPorts(int refnum)
+{
+ int i;
+ JackLog("JackGraphManager::DisconnectAllPorts ref = %ld\n", refnum);
+ JackConnectionManager* manager = WriteNextStateStart();
+
+ const jack_int_t* input = manager->GetInputPorts(refnum);
+ for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) {
+ DisconnectAllInput(input[i]);
+ }
+
+ const jack_int_t* output = manager->GetOutputPorts(refnum);
+ for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) {
+ DisconnectAllOutput(output[i]);
+ }
+
+ WriteNextStateStop();
+}
+
+// Server
+void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
+{
+ JackLog("JackGraphManager::DisconnectAllInput port_index = %ld \n", port_index);
+ JackConnectionManager* manager = WriteNextStateStart();
+
+ for (int i = 0; i < PORT_NUM; i++) {
+ if (manager->IsConnected(i, port_index)) {
+ JackLog("JackGraphManager::Disconnect i = %ld port_index = %ld\n", i, port_index);
+ Disconnect(i, port_index);
+ }
+ }
+ WriteNextStateStop();
+}
+
+// Server
+void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
+{
+ JackLog("JackGraphManager::DisconnectAllOutput port_index = %ld \n", port_index);
+ JackConnectionManager* manager = WriteNextStateStart();
+
+ const jack_int_t* connections = manager->GetConnections(port_index);
+ while (connections[0] != EMPTY) {
+ Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left
+ }
+ WriteNextStateStop();
+}
+
+// Server
+int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
+{
+ AssertPort(port_index);
+
+ JackPort* port = GetPort(port_index);
+ if (port->fFlags & JackPortIsOutput) {
+ DisconnectAllOutput(port_index);
+ } else {
+ DisconnectAllInput(port_index);
+ }
+ return 0;
+}
+
+// Server
+int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
+{
+ AssertPort(port_index);
+ JackConnectionManager* manager = WriteNextStateStart();
+ int res = manager->GetInputRefNum(port_index);
+ WriteNextStateStop();
+ return res;
+}
+
+// Server
+int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
+{
+ AssertPort(port_index);
+ JackConnectionManager* manager = WriteNextStateStart();
+ int res = manager->GetOutputRefNum(port_index);
+ WriteNextStateStop();
+ return res;
+}
+
+int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ JackLog("JackGraphManager::Connect port_src = %ld port_dst = %ld\n", port_src, port_dst);
+ bool in_use_src = GetPort(port_src)->fInUse;
+ bool in_use_dst = GetPort(port_src)->fInUse;
+ int res = 0;
+
+ if (!in_use_src || !in_use_dst) {
+ if (!in_use_src)
+ jack_error("JackGraphManager::Connect: port_src not %ld used name = %s", port_src, GetPort(port_src)->fName);
+ if (!in_use_dst)
+ jack_error("JackGraphManager::Connect: port_dst not %ld used name = %s", port_dst, GetPort(port_dst)->fName);
+ res = -1;
+ goto end;
+ }
+ if (manager->IsConnected(port_src, port_dst)) {
+ jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst);
+ res = EEXIST;
+ goto end;
+ }
+
+ res = manager->Connect(port_src, port_dst);
+ if (res < 0) {
+ jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
+ goto end;
+ }
+ manager->Connect(port_dst, port_src);
+ if (res < 0) {
+ jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_dst, port_src);
+ goto end;
+ }
+
+ if (manager->IsLoopPath(port_src, port_dst)) {
+ JackLog("JackGraphManager::Connect: LOOP detected\n");
+ manager->IncFeedbackConnection(port_src, port_dst);
+ } else {
+ manager->IncDirectConnection(port_src, port_dst);
+ }
+
+end:
+ WriteNextStateStop();
+ if (res < 0)
+ jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_dst, port_src);
+ return res;
+}
+
+// Server
+int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ JackLog("JackGraphManager::Disconnect port_src = %ld port_dst = %ld\n", port_src, port_dst);
+ bool in_use_src = GetPort(port_src)->fInUse;
+ bool in_use_dst = GetPort(port_src)->fInUse;
+ int res = 0;
+
+ if (!in_use_src || !in_use_dst) {
+ if (!in_use_src)
+ jack_error("JackGraphManager::Disconnect: port_src not %ld used name = %s", port_src, GetPort(port_src)->fName);
+ if (!in_use_dst)
+ jack_error("JackGraphManager::Disconnect: port_src not %ld used name = %s", port_dst, GetPort(port_dst)->fName);
+ res = -1;
+ goto end;
+ }
+ if (!manager->IsConnected(port_src, port_dst)) {
+ jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst);
+ res = -1;
+ goto end;
+ }
+
+ manager->Disconnect(port_src, port_dst);
+ if (res < 0) {
+ jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
+ goto end;
+ }
+ manager->Disconnect(port_dst, port_src);
+ if (res < 0) {
+ jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_dst, port_src);
+ goto end;
+ }
+
+ if (manager->IsFeedbackConnection(port_src, port_dst)) {
+ JackLog("JackGraphManager::Disconnect: FEEDBACK removed\n");
+ manager->DecFeedbackConnection(port_src, port_dst);
+ } else {
+ manager->DecDirectConnection(port_src, port_dst);
+ }
+
+end:
+ WriteNextStateStop();
+ return res;
+}
+
+// Client
+int JackGraphManager::ConnectedTo(jack_port_id_t port_src, const char* port_name)
+{
+ JackLog("JackGraphManager::ConnectedTo port_src = %ld port_name = %s\n", port_src, port_name);
+ JackConnectionManager* manager = ReadCurrentState();
+ jack_port_id_t port_dst;
+
+ if ((port_dst = GetPort(port_name)) == NO_PORT) {
+ jack_error("Unknown destination port port_name = %s", port_name);
+ return 0;
+ } else {
+ return manager->IsConnected(port_src, port_dst);
+ }
+}
+
+// Server
+int JackGraphManager::CheckPort(jack_port_id_t port_index)
+{
+ JackPort* port = GetPort(port_index);
+
+ if (port->fLocked) {
+ jack_error("Port %s is locked against connection changes", port->fName);
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
+{
+ JackPort* src = GetPort(port_src);
+ JackPort* dst = GetPort(port_dst);
+
+ if ((dst->Flags() & JackPortIsInput) == 0) {
+ jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName);
+ return -1;
+ }
+
+ if ((src->Flags() & JackPortIsOutput) == 0) {
+ jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName);
+ return -1;
+ }
+
+ if (src->fLocked) {
+ jack_error("Source port %s is locked against connection changes", src->fName);
+ return -1;
+ }
+
+ if (dst->fLocked) {
+ jack_error("Destination port %s is locked against connection changes", dst->fName);
+ return -1;
+ }
+
+ return 0;
+}
+
+int JackGraphManager::CheckPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
+{
+ JackLog("JackGraphManager::CheckConnect src_name = %s dst_name = %s\n", src_name, dst_name);
+
+ if ((*port_src = GetPort(src_name)) == NO_PORT) {
+ jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
+ return -1;
+ }
+
+ if ((*port_dst = GetPort(dst_name)) == NO_PORT) {
+ jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
+ return -1;
+ }
+
+ return CheckPorts(*port_src, *port_dst);
+}
+
+// Client : port array
+jack_port_id_t JackGraphManager::GetPort(const char* name)
+{
+ for (int i = 0; i < PORT_NUM; i++) {
+ JackPort* port = GetPort(i);
+ if (port->IsUsed() && strcmp(port->fName, name) == 0)
+ return i;
+ }
+ return NO_PORT;
+}
+
+/*!
+\brief Get the connection port name array.
+*/
+
+// Client
+void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
+{
+ const jack_int_t* connections = manager->GetConnections(port_index);
+ jack_int_t index;
+ int i;
+
+ for (i = 0; (i < CONNECTION_NUM) && ((index = connections[i]) != EMPTY) ; i++) {
+ JackPort* port = GetPort(index);
+ res[i] = port->fName;
+ }
+
+ res[i] = NULL;
+}
+
+// Client
+/*
+ Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
+ The operation is lock-free since there is no intermediate state in the write operation that could cause the
+ read to loop forever.
+*/
+const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
+{
+ const char** res = (const char**)malloc(sizeof(char*) * (CONNECTION_NUM + 1));
+ UInt16 cur_index;
+ UInt16 next_index;
+ AssertPort(port_index);
+
+ do {
+ cur_index = GetCurrentIndex();
+ GetConnectionsAux(ReadCurrentState(), res, port_index);
+ next_index = GetCurrentIndex();
+ } while (cur_index != next_index); // Until a coherent state has been read
+
+ return res;
+}
+
+// Client
+const char** JackGraphManager::GetPortsAux(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
+{
+ const char** matching_ports;
+ unsigned long match_cnt = 0;
+ regex_t port_regex;
+ regex_t type_regex;
+ bool matching;
+
+ if (port_name_pattern && port_name_pattern[0]) {
+ regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
+ }
+ if (type_name_pattern && type_name_pattern[0]) {
+ regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
+ }
+
+ matching_ports = (const char**)malloc(sizeof(char*) * PORT_NUM);
+
+ for (int i = 0; i < PORT_NUM; i++) {
+ matching = true;
+
+ JackPort* port = GetPort(i);
+
+ if (port->IsUsed()) {
+
+ if (flags) {
+ if ((port->fFlags & flags) != flags) {
+ matching = false;
+ }
+ }
+
+ if (matching && port_name_pattern && port_name_pattern[0]) {
+ if (regexec(&port_regex, port->fName, 0, NULL, 0)) {
+ matching = false;
+ }
+ }
+
+ /*
+ if (matching && type_name_pattern && type_name_pattern[0]) {
+ jack_port_type_id_t ptid = psp[i].ptype_id;
+ if (regexec (&type_regex,engine->port_types[ptid].type_name,0, NULL, 0)) {
+ matching = false;
+ }
+ }
+ */
+
+ // TO BE IMPROVED
+ if (matching && type_name_pattern && type_name_pattern[0]) {
+ if (regexec(&type_regex, JACK_DEFAULT_AUDIO_TYPE, 0, NULL, 0)) {
+ matching = false;
+ }
+ }
+
+ if (matching) {
+ matching_ports[match_cnt++] = port->fName;
+ }
+ }
+ }
+
+ matching_ports[match_cnt] = 0;
+
+ if (match_cnt == 0) {
+ free(matching_ports);
+ matching_ports = NULL;
+ }
+
+ return matching_ports;
+}
+
+// Client
+/*
+ Check that the state was not changed during the read operation.
+ The operation is lock-free since there is no intermediate state in the write operation that could cause the
+ read to loop forever.
+*/
+const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
+{
+ const char** matching_ports = NULL;
+ UInt16 cur_index;
+ UInt16 next_index;
+
+ do {
+ cur_index = GetCurrentIndex();
+ if (matching_ports)
+ free(matching_ports);
+ matching_ports = GetPortsAux(port_name_pattern, type_name_pattern, flags);
+ next_index = GetCurrentIndex();
+ } while (cur_index != next_index); // Until a coherent state has been read
+
+ return matching_ports;
+}
+
+// Server
+void JackGraphManager::Save(JackConnectionManager* dst)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ memcpy(dst, manager, sizeof(JackConnectionManager));
+ WriteNextStateStop();
+}
+
+// Server
+void JackGraphManager::Restore(JackConnectionManager* src)
+{
+ JackConnectionManager* manager = WriteNextStateStart();
+ memcpy(manager, src, sizeof(JackConnectionManager));
+ WriteNextStateStop();
+}
+
+} // end of namespace
+
+
diff --git a/common/JackGraphManager.h b/common/JackGraphManager.h
new file mode 100644
index 00000000..1c2a1d5d
--- /dev/null
+++ b/common/JackGraphManager.h
@@ -0,0 +1,121 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackGraphManager__
+#define __JackGraphManager__
+
+#include "JackShmMem.h"
+#include "JackPort.h"
+#include "JackConstants.h"
+#include "JackConnectionManager.h"
+#include "JackAtomicState.h"
+
+namespace Jack
+{
+
+/*!
+\brief Graph manager: contains the connection manager and the port array.
+*/
+
+class JackGraphManager : public JackShmMem, public JackAtomicState<JackConnectionManager>
+{
+
+ private:
+
+ JackPort fPortArray[PORT_NUM];
+ JackClientTiming fClientTiming[CLIENT_NUM];
+
+ jack_port_id_t AllocatePortAux(int refnum, const char* port_name, JackPortFlags flags);
+ void GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index);
+ const char** GetPortsAux(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags);
+ float* GetBuffer(jack_port_id_t port_index);
+ void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames);
+ jack_nframes_t GetTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count);
+
+ public:
+
+ JackGraphManager()
+ {}
+ virtual ~JackGraphManager()
+ {}
+
+ // Ports management
+ jack_port_id_t AllocatePort(int refnum, const char* port_name, JackPortFlags flags);
+ void ReleasePort(jack_port_id_t port_index);
+ JackPort* GetPort(jack_port_id_t index);
+ jack_port_id_t GetPort(const char* name);
+ jack_nframes_t GetTotalLatency(jack_port_id_t port_index);
+ int RequestMonitor(jack_port_id_t port_index, bool onoff);
+
+ // Connections management
+ int Connect(jack_port_id_t src_index, jack_port_id_t dst_index);
+ int Disconnect(jack_port_id_t src_index, jack_port_id_t dst_index);
+ int GetConnectionsNum(jack_port_id_t port_index);
+
+ int ConnectedTo(jack_port_id_t port_src, const char* port_name);
+ const char** GetConnections(jack_port_id_t port_index);
+ const char** GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags);
+
+ int CheckPorts(const char* src, const char* dst, jack_port_id_t* src_index, jack_port_id_t* dst_index);
+ int CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst);
+ int CheckPort(jack_port_id_t port_index);
+
+ void DisconnectAllInput(jack_port_id_t port_index);
+ void DisconnectAllOutput(jack_port_id_t port_index);
+ int DisconnectAll(jack_port_id_t port_index);
+
+ // Client management
+ int AllocateRefNum();
+ void ReleaseRefNum(int refnum);
+
+ bool IsDirectConnection(int ref1, int ref2);
+ void DirectConnect(int ref1, int ref2);
+ void DirectDisconnect(int ref1, int ref2);
+
+ int RemovePort(int refnum, jack_port_id_t port_index);
+ void RemoveAllPorts(int refnum);
+ void DisconnectAllPorts(int refnum);
+
+ int GetInputRefNum(jack_port_id_t port_index);
+ int GetOutputRefNum(jack_port_id_t port_index);
+
+ // Buffer management
+ void* GetBuffer(jack_port_id_t port_index, jack_nframes_t frames);
+
+ // Activation management
+ void RunCurrentGraph();
+ bool RunNextGraph();
+ bool IsFinishedGraph();
+
+ int ResumeRefNum(JackClientControl* control, JackSynchro** table);
+ int SuspendRefNum(JackClientControl* control, JackSynchro** table, long usecs);
+
+ JackClientTiming* GetClientTiming(int ref);
+
+ void Save(JackConnectionManager* dst);
+ void Restore(JackConnectionManager* src);
+
+};
+
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackInternalClient.cpp b/common/JackInternalClient.cpp
new file mode 100644
index 00000000..d9a0a80b
--- /dev/null
+++ b/common/JackInternalClient.cpp
@@ -0,0 +1,105 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackInternalClient.h"
+#include "JackEngine.h"
+#include "JackServer.h"
+#include "JackGraphManager.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include "JackInternalClientChannel.h"
+#include <assert.h>
+
+
+namespace Jack
+{
+
+JackGraphManager* JackInternalClient::fGraphManager = NULL;
+JackEngineControl* JackInternalClient::fEngineControl = NULL;
+
+// Used for external C API (JackAPI.cpp)
+JackGraphManager* GetGraphManager()
+{
+ return JackServer::fInstance->GetGraphManager();
+}
+
+JackEngineControl* GetEngineControl()
+{
+ return JackServer::fInstance->GetEngineControl();
+}
+
+JackSynchro** GetSynchroTable()
+{
+ return JackServer::fInstance->GetSynchroTable();
+}
+
+JackInternalClient::JackInternalClient(JackServer* server, JackSynchro** table): JackClient(table)
+{
+ fClientControl = new JackClientControl();
+ fChannel = new JackInternalClientChannel(server);
+}
+
+JackInternalClient::~JackInternalClient()
+{
+ delete fClientControl;
+ delete fChannel;
+}
+
+int JackInternalClient::Open(const char* name)
+{
+ int result;
+ JackLog("JackInternalClient::Open name = %s\n", name);
+ strcpy(fClientControl->fName, name);
+
+ // Require new client
+ fChannel->ClientNew(name, &fClientControl->fRefNum, &fEngineControl, &fGraphManager, this, &result);
+ if (result < 0) {
+ jack_error("Cannot open client name = %s", name);
+ goto error;
+ }
+
+ SetupDriverSync(false);
+ return 0;
+
+error:
+ fChannel->Stop();
+ fChannel->Close();
+ return -1;
+}
+
+JackGraphManager* JackInternalClient::GetGraphManager() const
+{
+ assert(fGraphManager);
+ return fGraphManager;
+}
+
+JackEngineControl* JackInternalClient::GetEngineControl() const
+{
+ assert(fEngineControl);
+ return fEngineControl;
+}
+
+JackClientControl* JackInternalClient::GetClientControl() const
+{
+ return fClientControl;
+}
+
+} // end of namespace
+
diff --git a/common/JackInternalClient.h b/common/JackInternalClient.h
new file mode 100644
index 00000000..fc9ed5b4
--- /dev/null
+++ b/common/JackInternalClient.h
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackInternalClient__
+#define __JackInternalClient__
+
+#include "JackClient.h"
+
+namespace Jack
+{
+
+struct JackEngineControl;
+class JackClientChannelInterface;
+
+/*!
+\brief Internal clients in the server.
+*/
+
+class JackInternalClient : public JackClient
+{
+
+ private:
+
+ JackClientControl* fClientControl; /*! Client control */
+
+ public:
+
+ JackInternalClient(JackServer* server, JackSynchro** table);
+ virtual ~JackInternalClient();
+
+ int Open(const char* name);
+
+ JackGraphManager* GetGraphManager() const;
+ JackEngineControl* GetEngineControl() const;
+ JackClientControl* GetClientControl() const;
+
+ static JackGraphManager* fGraphManager; /*! Shared memory Port manager */
+ static JackEngineControl* fEngineControl; /*! Shared engine cotrol */
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackInternalClientChannel.h b/common/JackInternalClientChannel.h
new file mode 100644
index 00000000..516b0c2f
--- /dev/null
+++ b/common/JackInternalClientChannel.h
@@ -0,0 +1,116 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackInternalClientChannel__
+#define __JackInternalClientChannel__
+
+#include "JackChannel.h"
+
+namespace Jack
+{
+
+/*!
+\brief JackClientChannel for server internal clients.
+*/
+
+class JackInternalClientChannel : public JackClientChannelInterface
+{
+
+ private:
+
+ JackServer* fServer;
+ JackEngine* fEngine;
+
+ public:
+
+ JackInternalClientChannel(JackServer* server): fServer(server), fEngine(server->GetEngine())
+ {}
+ virtual ~JackInternalClientChannel()
+ {}
+
+ void ClientNew(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, int* result)
+ {
+ *result = fEngine->ClientInternalNew(name, ref, shared_engine, shared_manager, client);
+ }
+ void ClientClose(int refnum, int* result)
+ {
+ *result = fEngine->ClientInternalClose(refnum);
+ }
+ void ClientActivate(int refnum, int* result)
+ {
+ *result = fServer->Activate(refnum);
+ }
+ void ClientDeactivate(int refnum, int* result)
+ {
+ *result = fServer->Deactivate(refnum);
+ }
+
+ void PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result)
+ {
+ *result = fEngine->PortRegister(refnum, name, flags, buffer_size, port_index);
+ }
+ void PortUnRegister(int refnum, jack_port_id_t port_index, int* result)
+ {
+ *result = fEngine->PortUnRegister(refnum, port_index);
+ }
+
+ void PortConnect(int refnum, const char* src, const char* dst, int* result)
+ {
+ *result = fEngine->PortConnect(refnum, src, dst);
+ }
+ void PortDisconnect(int refnum, const char* src, const char* dst, int* result)
+ {
+ *result = fEngine->PortDisconnect(refnum, src, dst);
+ }
+
+ void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
+ {
+ *result = fEngine->PortConnect(refnum, src, dst);
+ }
+ void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
+ {
+ *result = fEngine->PortDisconnect(refnum, src, dst);
+ }
+
+ void SetBufferSize(jack_nframes_t nframes, int* result)
+ {
+ *result = fServer->SetBufferSize(nframes);
+ }
+ void SetFreewheel(int onoff, int* result)
+ {
+ *result = fServer->SetFreewheel(onoff);
+ }
+
+ // A FINIR
+ virtual void ReleaseTimebase(int refnum, int* result)
+ {
+ *result = fEngine->ReleaseTimebase(refnum);
+ }
+
+ virtual void SetTimebaseCallback(int refnum, int conditional, int* result)
+ {
+ *result = fEngine->SetTimebaseCallback(refnum, conditional);
+ }
+
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackLibAPI.cpp b/common/JackLibAPI.cpp
new file mode 100644
index 00000000..87730d53
--- /dev/null
+++ b/common/JackLibAPI.cpp
@@ -0,0 +1,133 @@
+/*
+Copyright (C) 2001-2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "JackDebugClient.h"
+#include "JackLibClient.h"
+#include "JackChannel.h"
+#include "JackGraphManager.h"
+#include "JackLibGlobals.h"
+#include "JackGlobals.h"
+#include "varargs.h"
+
+using namespace Jack;
+
+#ifdef WIN32
+ #define EXPORT __declspec(dllexport)
+#else
+ #define EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ EXPORT jack_client_t * jack_client_open (const char *client_name,
+ jack_options_t options,
+ jack_status_t *status, ...);
+ EXPORT jack_client_t * jack_client_new (const char *client_name);
+ EXPORT int jack_client_close (jack_client_t *client);
+
+#ifdef __cplusplus
+}
+#endif
+
+JackLibGlobals* JackLibGlobals::fGlobals = NULL;
+long JackLibGlobals::fClientCount = 0;
+
+static inline bool CheckPort(jack_port_id_t port_index)
+{
+ return (port_index < PORT_NUM);
+}
+
+EXPORT jack_client_t* jack_client_new(const char* client_name)
+{
+ int options = JackUseExactName;
+ if (getenv("JACK_START_SERVER") == NULL)
+ options |= JackNoStartServer;
+
+ return jack_client_open(client_name, (jack_options_t)options, NULL);
+}
+
+// TO BE IMPLEMENTED PROPERLY
+EXPORT jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...)
+{
+ va_list ap; /* variable argument pointer */
+ jack_varargs_t va; /* variable arguments */
+ jack_status_t my_status;
+
+ if (status == NULL) /* no status from caller? */
+ status = &my_status; /* use local status word */
+ *status = (jack_status_t)0;
+
+ /* validate parameters */
+ if ((options & ~JackOpenOptions)) {
+ int my_status1 = *status | (JackFailure | JackInvalidOption);
+ *status = (jack_status_t)my_status1;
+ return NULL;
+ }
+
+ /* parse variable arguments */
+ va_start(ap, status);
+ jack_varargs_parse(options, ap, &va);
+ va_end(ap);
+
+ JackLog("jack_client_open %s\n", client_name);
+ if (client_name == NULL) {
+ jack_error("jack_client_new called with a NULL client_name");
+ return NULL;
+ }
+
+ JackLibGlobals::Init(); // jack library initialisation
+
+#ifdef __CLIENTDEBUG__
+ JackClient* client = new JackDebugClient(new JackLibClient(GetSynchroTable())); // Debug mode
+#else
+ JackClient* client = new JackLibClient(GetSynchroTable());
+#endif
+
+ int res = client->Open(client_name);
+ if (res < 0) {
+ delete client;
+ JackLibGlobals::Destroy(); // jack library destruction
+ return NULL;
+ } else {
+ *status = (jack_status_t)0;
+ return (jack_client_t*)client;
+ }
+ return NULL;
+}
+
+EXPORT int jack_client_close(jack_client_t* ext_client)
+{
+ JackLog("jack_client_close\n");
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_client_close called with a NULL client");
+ return -1;
+ }
+ int res = client->Close();
+ delete client;
+ JackLog("jack_client_close OK\n");
+ JackLibGlobals::Destroy(); // jack library destruction
+ return res;
+}
+
+
diff --git a/common/JackLibClient.cpp b/common/JackLibClient.cpp
new file mode 100644
index 00000000..45b49e09
--- /dev/null
+++ b/common/JackLibClient.cpp
@@ -0,0 +1,162 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackLibClient.h"
+#include "JackTime.h"
+#include "JackLibGlobals.h"
+#include "JackGlobals.h"
+#include "JackChannel.h"
+
+namespace Jack
+{
+
+// Used for external C API (JackAPI.cpp)
+JackGraphManager* GetGraphManager()
+{
+ assert(JackLibGlobals::fGlobals->fGraphManager);
+ return JackLibGlobals::fGlobals->fGraphManager;
+}
+
+JackEngineControl* GetEngineControl()
+{
+ assert(JackLibGlobals::fGlobals->fEngineControl);
+ return JackLibGlobals::fGlobals->fEngineControl;
+}
+
+JackSynchro** GetSynchroTable()
+{
+ assert(JackLibGlobals::fGlobals);
+ return JackLibGlobals::fGlobals->fSynchroTable;
+}
+
+//-------------------
+// Client management
+//-------------------
+
+JackLibClient::JackLibClient(JackSynchro** table): JackClient(table)
+{
+ JackLog("JackLibClient::JackLibClient table = %x\n", table);
+ fChannel = JackGlobals::MakeClientChannel();
+}
+
+JackLibClient::~JackLibClient()
+{
+ JackLog("JackLibClient::~JackLibClient\n");
+ delete fChannel;
+}
+
+int JackLibClient::Open(const char* name)
+{
+ int shared_engine, shared_client, shared_ports, result;
+ JackLog("JackLibClient::Open %s\n", name);
+
+ // Open server/client channel
+ if (fChannel->Open(name, this) < 0) {
+ jack_error("Cannot connect to the server");
+ goto error;
+ }
+
+ // Start receiving notifications
+ if (fChannel->Start() < 0) {
+ jack_error("Cannot start channel");
+ goto error;
+ }
+
+ // Require new client
+ fChannel->ClientNew(name, &shared_engine, &shared_client, &shared_ports, &result);
+ if (result < 0) {
+ jack_error("Cannot open %s client", name);
+ goto error;
+ }
+
+ try {
+ // Map shared memory segments
+ JackLibGlobals::fGlobals->fEngineControl = shared_engine;
+ JackLibGlobals::fGlobals->fGraphManager = shared_ports;
+ fClientControl = shared_client;
+ verbose = GetEngineControl()->fVerbose;
+ } catch (int n) {
+ jack_error("Map shared memory segments exception %d", n);
+ goto error;
+ }
+
+ SetupDriverSync(false);
+
+ // Connect shared synchro : the synchro must be usable in I/O mode when several clients live in the same process
+ if (!fSynchroTable[fClientControl->fRefNum]->Connect(name)) {
+ jack_error("Cannot ConnectSemaphore %s client", name);
+ goto error;
+ }
+
+ JackLog("JackLibClient::Open: name, refnum %s %ld\n", name, fClientControl->fRefNum);
+ return 0;
+
+error:
+ fChannel->Stop();
+ fChannel->Close();
+ return -1;
+}
+
+// Notifications received from the server
+// TODO this should be done once for all clients in the process, when a shared notification channel
+// will be shared by all clients...
+int JackLibClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value)
+{
+ int res = 0;
+
+ // Done all time
+ switch (notify) {
+
+ case JackNotifyChannelInterface::kAddClient:
+ JackLog("JackClient::AddClient name = %s, ref = %ld \n", name, refnum);
+ // the synchro must be usable in I/O mode when several clients live in the same process
+ res = fSynchroTable[refnum]->Connect(name) ? 0 : -1;
+ break;
+
+ case JackNotifyChannelInterface::kRemoveClient:
+ JackLog("JackClient::RemoveClient name = %s, ref = %ld \n", name, refnum);
+ if (strcmp(GetClientControl()->fName, name) != 0)
+ res = fSynchroTable[refnum]->Disconnect() ? 0 : -1;
+ break;
+ }
+
+ return res;
+}
+
+JackGraphManager* JackLibClient::GetGraphManager() const
+{
+ assert(JackLibGlobals::fGlobals->fGraphManager);
+ return JackLibGlobals::fGlobals->fGraphManager;
+}
+
+JackEngineControl* JackLibClient::GetEngineControl() const
+{
+ assert(JackLibGlobals::fGlobals->fEngineControl);
+ return JackLibGlobals::fGlobals->fEngineControl;
+}
+
+JackClientControl* JackLibClient::GetClientControl() const
+{
+ return fClientControl;
+}
+
+} // end of namespace
+
+
+
diff --git a/common/JackLibClient.h b/common/JackLibClient.h
new file mode 100644
index 00000000..75e30837
--- /dev/null
+++ b/common/JackLibClient.h
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackLibClient__
+#define __JackLibClient__
+
+#include "JackClient.h"
+#include "JackShmMem.h"
+#include "JackClientControl.h"
+#include "JackEngineControl.h"
+
+namespace Jack
+{
+
+/*!
+\brief Client on the library side.
+*/
+
+class JackLibClient : public JackClient
+{
+
+ private:
+
+ JackShmReadWritePtr1<JackClientControl> fClientControl; /*! Shared client control */
+
+ public:
+
+ JackLibClient(JackSynchro** table);
+ virtual ~JackLibClient();
+
+ int Open(const char* name);
+
+ int ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value);
+
+ JackGraphManager* GetGraphManager() const;
+ JackEngineControl* GetEngineControl() const;
+ JackClientControl* GetClientControl() const;
+};
+
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackLibGlobals.h b/common/JackLibGlobals.h
new file mode 100644
index 00000000..5f857625
--- /dev/null
+++ b/common/JackLibGlobals.h
@@ -0,0 +1,97 @@
+/*
+Copyright (C) 2005 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackLibGlobals__
+#define __JackLibGlobals__
+
+#include "JackShmMem.h"
+#include "JackEngineControl.h"
+#ifdef __APPLE__
+#include "JackMachPort.h"
+#include <map>
+#endif
+#include "JackGlobals.h"
+#include "JackTime.h"
+#include <assert.h>
+
+namespace Jack
+{
+
+class JackClient;
+
+/*!
+\brief Global library static structure: singleton kind of pattern.
+*/
+
+struct JackLibGlobals
+{
+ JackShmReadWritePtr<JackGraphManager> fGraphManager; /*! Shared memory Port manager */
+ JackShmReadWritePtr<JackEngineControl> fEngineControl; /*! Shared engine control */ // transport engine has to be writable
+ JackSynchro* fSynchroTable[CLIENT_NUM]; /*! Shared synchro table */
+#ifdef __APPLE__
+ std::map<mach_port_t, JackClient*> fClientTable; /*! Client table */
+#endif
+
+ static long fClientCount;
+ static JackLibGlobals* fGlobals;
+
+ JackLibGlobals()
+ {
+ JackLog("JackLibGlobals\n");
+ for (int i = 0; i < CLIENT_NUM; i++)
+ fSynchroTable[i] = JackGlobals::MakeSynchro();
+ fGraphManager = -1;
+ fEngineControl = -1;
+ }
+
+ virtual ~JackLibGlobals()
+ {
+ JackLog("~JackLibGlobals\n");
+ for (int i = 0; i < CLIENT_NUM; i++) {
+ fSynchroTable[i]->Disconnect();
+ delete fSynchroTable[i];
+ }
+ }
+
+ static void Init()
+ {
+ if (fClientCount++ == 0 && !fGlobals) {
+ JackLog("JackLibGlobals Init %x\n", fGlobals);
+ JackGlobals::InitClient();
+ InitTime();
+ fGlobals = new JackLibGlobals();
+ }
+ }
+
+ static void Destroy()
+ {
+ if (--fClientCount == 0 && fGlobals) {
+ JackLog("JackLibGlobals Destroy %x\n", fGlobals);
+ delete fGlobals;
+ fGlobals = NULL;
+ JackGlobals::Destroy();
+ }
+ }
+
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackLoopbackDriver.cpp b/common/JackLoopbackDriver.cpp
new file mode 100644
index 00000000..79550c5e
--- /dev/null
+++ b/common/JackLoopbackDriver.cpp
@@ -0,0 +1,209 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackLoopbackDriver.h"
+#include "JackEngineControl.h"
+#include "JackGraphManager.h"
+#include <iostream>
+#include <assert.h>
+
+namespace Jack
+{
+
+int JackLoopbackDriver::Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency)
+{
+ return JackAudioDriver::Open(nframes,
+ samplerate,
+ capturing,
+ playing,
+ inchannels,
+ outchannels,
+ monitor,
+ capture_driver_name,
+ playback_driver_name,
+ capture_latency,
+ playback_latency);
+}
+
+int JackLoopbackDriver::Process()
+{
+ assert(fCaptureChannels == fPlaybackChannels);
+
+ // Loopback copy
+ for (int i = 0; i < fCaptureChannels; i++) {
+ memcpy(fGraphManager->GetBuffer(fCapturePortList[i], fEngineControl->fBufferSize),
+ fGraphManager->GetBuffer(fPlaybackPortList[i], fEngineControl->fBufferSize),
+ sizeof(float) * fEngineControl->fBufferSize);
+ }
+
+ fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); // Signal all clients
+ if (fEngineControl->fSyncMode) {
+ if (fGraphManager->SuspendRefNum(fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs) < 0)
+ jack_error("JackLoopbackDriver::ProcessSync SuspendRefNum error");
+ }
+ return 0;
+}
+
+void JackLoopbackDriver::PrintState()
+{
+ int i;
+ jack_port_id_t port_index;
+
+ std::cout << "JackLoopbackDriver state" << std::endl;
+ std::cout << "Input ports" << std::endl;
+
+ for (i = 0; i < fPlaybackChannels; i++) {
+ port_index = fCapturePortList[i];
+ JackPort* port = fGraphManager->GetPort(port_index);
+ std::cout << port->GetName() << std::endl;
+ if (fGraphManager->GetConnectionsNum(port_index)) {}
+ }
+
+ std::cout << "Output ports" << std::endl;
+
+ for (i = 0; i < fCaptureChannels; i++) {
+ port_index = fPlaybackPortList[i];
+ JackPort* port = fGraphManager->GetPort(port_index);
+ std::cout << port->GetName() << std::endl;
+ if (fGraphManager->GetConnectionsNum(port_index)) {}
+ }
+}
+
+} // end of namespace
+
+/*
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+jack_driver_desc_t * driver_get_descriptor ()
+{
+ jack_driver_desc_t * desc;
+ jack_driver_param_desc_t * params;
+ unsigned int i;
+
+ desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
+ strcpy (desc->name, "dummy");
+ desc->nparams = 5;
+
+ params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
+
+ i = 0;
+ strcpy (params[i].name, "capture");
+ params[i].character = 'C';
+ params[i].type = JackDriverParamUInt;
+ params[i].value.ui = 2U;
+ strcpy (params[i].short_desc, "Number of capture ports");
+ strcpy (params[i].long_desc, params[i].short_desc);
+
+ i++;
+ strcpy (params[i].name, "playback");
+ params[i].character = 'P';
+ params[i].type = JackDriverParamUInt;
+ params[1].value.ui = 2U;
+ strcpy (params[i].short_desc, "Number of playback ports");
+ strcpy (params[i].long_desc, params[i].short_desc);
+
+ i++;
+ strcpy (params[i].name, "rate");
+ params[i].character = 'r';
+ params[i].type = JackDriverParamUInt;
+ params[i].value.ui = 48000U;
+ strcpy (params[i].short_desc, "Sample rate");
+ strcpy (params[i].long_desc, params[i].short_desc);
+
+ i++;
+ strcpy (params[i].name, "period");
+ params[i].character = 'p';
+ params[i].type = JackDriverParamUInt;
+ params[i].value.ui = 1024U;
+ strcpy (params[i].short_desc, "Frames per period");
+ strcpy (params[i].long_desc, params[i].short_desc);
+
+ i++;
+ strcpy (params[i].name, "wait");
+ params[i].character = 'w';
+ params[i].type = JackDriverParamUInt;
+ params[i].value.ui = 21333U;
+ strcpy (params[i].short_desc,
+ "Number of usecs to wait between engine processes");
+ strcpy (params[i].long_desc, params[i].short_desc);
+
+ desc->params = params;
+
+ return desc;
+}
+
+Jack::JackDriverClientInterface* driver_initialize(Jack::JackEngine* engine, Jack::JackSynchro** table, const JSList* params)
+{
+ jack_nframes_t sample_rate = 48000;
+ jack_nframes_t period_size = 1024;
+ unsigned int capture_ports = 2;
+ unsigned int playback_ports = 2;
+ const JSList * node;
+ const jack_driver_param_t * param;
+
+ for (node = params; node; node = jack_slist_next (node)) {
+ param = (const jack_driver_param_t *) node->data;
+
+ switch (param->character) {
+
+ case 'C':
+ capture_ports = param->value.ui;
+ break;
+
+ case 'P':
+ playback_ports = param->value.ui;
+ break;
+
+ case 'r':
+ sample_rate = param->value.ui;
+ break;
+
+ case 'p':
+ period_size = param->value.ui;
+ break;
+
+ }
+ }
+ Jack::JackDriverClientInterface* driver = new Jack::JackLoopbackDriver("loopback", engine, table);
+ if (driver->Open(period_size, sample_rate, 1, 1, capture_ports, playback_ports, "loopback") == 0) {
+ return driver;
+ } else {
+ delete driver;
+ return NULL;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+*/
+
diff --git a/common/JackLoopbackDriver.h b/common/JackLoopbackDriver.h
new file mode 100644
index 00000000..4610822e
--- /dev/null
+++ b/common/JackLoopbackDriver.h
@@ -0,0 +1,63 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackLoopbackDriver__
+#define __JackLoopbackDriver__
+
+#include "JackAudioDriver.h"
+#include "JackTime.h"
+
+namespace Jack
+{
+
+/*!
+\brief The loopback driver : to be used to "pipeline" applications connected in sequence.
+*/
+
+class JackLoopbackDriver : public JackAudioDriver
+{
+
+ public:
+
+ JackLoopbackDriver(const char* name, JackEngine* engine, JackSynchro** table)
+ : JackAudioDriver(name, engine, table)
+ {}
+ virtual ~JackLoopbackDriver()
+ {}
+
+ int Open(jack_nframes_t frames_per_cycle,
+ jack_nframes_t rate,
+ int capturing,
+ int playing,
+ int chan_in,
+ int chan_out,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency);
+
+ int Process();
+ void PrintState();
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackPort.cpp b/common/JackPort.cpp
new file mode 100644
index 00000000..c3898e2d
--- /dev/null
+++ b/common/JackPort.cpp
@@ -0,0 +1,229 @@
+/*
+Copyright (C) 2001-2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackPort.h"
+#include "JackError.h"
+#include <stdio.h>
+
+namespace Jack
+{
+
+JackPort::JackPort()
+ : fFlags(JackPortIsInput), fRefNum( -1), fLatency(0), fMonitorRequests(0), fInUse(false), fLocked(false), fTied(NO_PORT)
+{}
+
+JackPort::~JackPort()
+{}
+
+void JackPort::Allocate(int refnum, const char* port_name, JackPortFlags flags)
+{
+ fFlags = flags;
+ fRefNum = refnum;
+ strcpy(fName, port_name);
+ memset(fBuffer, 0, BUFFER_SIZE_MAX * sizeof(float));
+ fInUse = true;
+ fLocked = false;
+ fLatency = 0;
+ fTied = NO_PORT;
+}
+
+void JackPort::Release()
+{
+ fFlags = JackPortIsInput;
+ fRefNum = -1;
+ fInUse = false;
+ fLocked = false;
+ fLatency = 0;
+ fTied = NO_PORT;
+}
+
+bool JackPort::IsUsed() const
+{
+ return fInUse;
+}
+
+float* JackPort::GetBuffer()
+{
+ return fBuffer;
+}
+
+int JackPort::GetRefNum() const
+{
+ return fRefNum;
+}
+
+int JackPort::Lock()
+{
+ fLocked = true;
+ return 0;
+}
+
+int JackPort::Unlock()
+{
+ fLocked = false;
+ return 0;
+}
+
+jack_nframes_t JackPort::GetLatency() const
+{
+ return fLatency;
+}
+
+void JackPort::SetLatency(jack_nframes_t nframes)
+{
+ fLatency = nframes;
+}
+
+int JackPort::Tie(jack_port_id_t port_index)
+{
+ fTied = port_index;
+ return 0;
+}
+
+int JackPort::UnTie()
+{
+ fTied = NO_PORT;
+ return 0;
+}
+
+int JackPort::RequestMonitor(bool onoff)
+{
+ /**
+ jackd.h
+ * If @ref JackPortCanMonitor is set for this @a port, turn input
+ * monitoring on or off. Otherwise, do nothing.
+
+ if (!(fFlags & JackPortCanMonitor))
+ return -1;
+ */
+
+ if (onoff) {
+ fMonitorRequests++;
+ } else if (fMonitorRequests) {
+ fMonitorRequests--;
+ }
+
+ return 0;
+}
+
+int JackPort::EnsureMonitor(bool onoff)
+{
+ /**
+ jackd.h
+ * If @ref JackPortCanMonitor is set for this @a port, turn input
+ * monitoring on or off. Otherwise, do nothing.
+
+ if (!(fFlags & JackPortCanMonitor))
+ return -1;
+ */
+
+ if (onoff) {
+ if (fMonitorRequests == 0) {
+ fMonitorRequests++;
+ }
+ } else {
+ if (fMonitorRequests > 0) {
+ fMonitorRequests = 0;
+ }
+ }
+
+ return 0;
+}
+
+bool JackPort::MonitoringInput()
+{
+ return (fMonitorRequests > 0);
+}
+
+const char* JackPort::GetName() const
+{
+ return fName;
+}
+
+const char* JackPort::GetShortName() const
+{
+ /* we know there is always a colon, because we put
+ it there ...
+ */
+ return strchr(fName, ':') + 1;
+}
+
+int JackPort::Flags() const
+{
+ return fFlags;
+}
+
+const char* JackPort::Type() const
+{
+ // TO IMPROVE
+ return "Audio";
+}
+
+int JackPort::SetName(const char* new_name)
+{
+ char* colon = strchr(fName, ':');
+ int len = sizeof(fName) - ((int) (colon - fName)) - 2;
+ snprintf(colon + 1, len, "%s", new_name);
+ return 0;
+}
+
+void JackPort::MixBuffer(float* mixbuffer, float* buffer, jack_nframes_t frames)
+{
+ jack_nframes_t frames_group = frames / 4;
+ frames = frames % 4;
+
+ while (frames_group > 0) {
+ register float mixFloat1 = *mixbuffer;
+ register float sourceFloat1 = *buffer;
+ register float mixFloat2 = *(mixbuffer + 1);
+ register float sourceFloat2 = *(buffer + 1);
+ register float mixFloat3 = *(mixbuffer + 2);
+ register float sourceFloat3 = *(buffer + 2);
+ register float mixFloat4 = *(mixbuffer + 3);
+ register float sourceFloat4 = *(buffer + 3);
+
+ buffer += 4;
+ frames_group--;
+
+ mixFloat1 += sourceFloat1;
+ mixFloat2 += sourceFloat2;
+ mixFloat3 += sourceFloat3;
+ mixFloat4 += sourceFloat4;
+
+ *mixbuffer = mixFloat1;
+ *(mixbuffer + 1) = mixFloat2;
+ *(mixbuffer + 2) = mixFloat3;
+ *(mixbuffer + 3) = mixFloat4;
+
+ mixbuffer += 4;
+ }
+
+ while (frames > 0) {
+ register float mixFloat1 = *mixbuffer;
+ register float sourceFloat1 = *buffer;
+ buffer++;
+ frames--;
+ mixFloat1 += sourceFloat1;
+ *mixbuffer = mixFloat1;
+ mixbuffer++;
+ }
+}
+
+} // end of namespace
diff --git a/common/JackPort.h b/common/JackPort.h
new file mode 100644
index 00000000..84823842
--- /dev/null
+++ b/common/JackPort.h
@@ -0,0 +1,98 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackPort__
+#define __JackPort__
+
+#include "types.h"
+#include "JackConstants.h"
+
+namespace Jack
+{
+
+#define ALL_PORTS 0xFFFF
+#define NO_PORT 0xFFFE
+
+/*!
+\brief Base class for port.
+*/
+
+class JackPort
+{
+
+ friend class JackGraphManager;
+
+ private:
+
+ enum JackPortFlags fFlags;
+ char fName[JACK_PORT_NAME_SIZE + 2];
+ int fRefNum;
+
+ jack_nframes_t fLatency;
+ uint8_t fMonitorRequests;
+
+ bool fInUse;
+ bool fLocked;
+ jack_port_id_t fTied; // Locally tied source port
+
+ float fBuffer[BUFFER_SIZE_MAX];
+
+ bool IsUsed() const;
+
+ static void MixBuffer(float* mixbuffer, float* buffer, jack_nframes_t frames);
+
+ public:
+
+ JackPort();
+ virtual ~JackPort();
+
+ void Allocate(int refnum, const char* port_name, JackPortFlags flags);
+ void Release();
+ const char* GetName() const;
+ const char* GetShortName() const;
+ int SetName(const char * name);
+
+ int Flags() const;
+ const char* Type() const;
+
+ int Lock();
+ int Unlock();
+
+ int Tie(jack_port_id_t port_index);
+ int UnTie();
+
+ jack_nframes_t GetLatency() const;
+ void SetLatency(jack_nframes_t latency);
+
+ int RequestMonitor(bool onoff);
+ int EnsureMonitor(bool onoff);
+ bool MonitoringInput();
+
+ float* GetBuffer();
+ int GetRefNum() const;
+
+};
+
+
+} // end of namespace
+
+
+#endif
+
diff --git a/common/JackPosixSemaphore.cpp b/common/JackPosixSemaphore.cpp
new file mode 100644
index 00000000..18e7a0f5
--- /dev/null
+++ b/common/JackPosixSemaphore.cpp
@@ -0,0 +1,205 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackPosixSemaphore.h"
+#include "JackChannel.h"
+#include "JackError.h"
+#include <fcntl.h>
+#include <sys/time.h>
+
+namespace Jack
+{
+
+void JackPosixSemaphore::BuildName(const char* name, char* res)
+{
+ sprintf(res, "%s/jack_sem.%s", jack_client_dir, name);
+}
+
+bool JackPosixSemaphore::Signal()
+{
+ int res;
+ assert(fSemaphore);
+
+ if (fFlush)
+ return true;
+
+ if ((res = sem_post(fSemaphore)) != 0) {
+ jack_error("JackPosixSemaphore::Signal name = %s err = %s", fName, strerror(errno));
+ }
+ return (res == 0);
+}
+
+bool JackPosixSemaphore::SignalAll()
+{
+ int res;
+ assert(fSemaphore);
+
+ if (fFlush)
+ return true;
+
+ if ((res = sem_post(fSemaphore)) != 0) {
+ jack_error("JackPosixSemaphore::SignalAll name = %s err = %s", fName, strerror(errno));
+ }
+ return (res == 0);
+}
+
+/*
+bool JackPosixSemaphore::Wait()
+{
+ int res;
+ assert(fSemaphore);
+ if ((res = sem_wait(fSemaphore)) != 0) {
+ jack_error("JackPosixSemaphore::Wait name = %s err = %s", fName, strerror(errno));
+ }
+ return (res == 0);
+}
+*/
+
+bool JackPosixSemaphore::Wait()
+{
+ int res;
+
+ while ((res = sem_wait(fSemaphore) < 0)) {
+ jack_error("JackPosixSemaphore::Wait name = %s err = %s", fName, strerror(errno));
+ if (errno != EINTR)
+ break;
+ }
+ return (res == 0);
+}
+
+
+/*
+#ifdef __linux__
+
+bool JackPosixSemaphore::TimedWait(long usec) // unusable semantic !!
+{
+ int res;
+ struct timeval now;
+ timespec time;
+ assert(fSemaphore);
+ gettimeofday(&now, 0);
+ time.tv_sec = now.tv_sec + usec / 1000000;
+ time.tv_nsec = (now.tv_usec + (usec % 1000000)) * 1000;
+
+ if ((res = sem_timedwait(fSemaphore, &time)) != 0) {
+ jack_error("JackPosixSemaphore::TimedWait err = %s", strerror(errno));
+ JackLog("now %ld %ld \n", now.tv_sec, now.tv_usec);
+ JackLog("next %ld %ld \n", time.tv_sec, time.tv_nsec/1000);
+ }
+ return (res == 0);
+}
+
+#else
+#warning "JackPosixSemaphore::TimedWait is not supported: Jack in SYNC mode with JackPosixSemaphore will not run properly !!"
+
+bool JackPosixSemaphore::TimedWait(long usec)
+{
+ return Wait();
+}
+#endif
+*/
+
+#warning JackPosixSemaphore::TimedWait not available : synchronous mode may not work correctly if POSIX semaphore are used
+
+bool JackPosixSemaphore::TimedWait(long usec)
+{
+ return Wait();
+}
+
+// Server side : publish the semaphore in the global namespace
+bool JackPosixSemaphore::Allocate(const char* name, int value)
+{
+ BuildName(name, fName);
+ JackLog("JackPosixSemaphore::Allocate name = %s val = %ld\n", fName, value);
+
+ if ((fSemaphore = sem_open(fName, O_CREAT, 0777, value)) == (sem_t*)SEM_FAILED) {
+ jack_error("Allocate: can't check in named semaphore name = %s err = %s", fName, strerror(errno));
+ return false;
+ } else {
+ return true;
+ }
+}
+
+// Client side : get the published semaphore from server
+bool JackPosixSemaphore::ConnectInput(const char* name)
+{
+ BuildName(name, fName);
+ JackLog("JackPosixSemaphore::Connect %s\n", fName);
+
+ // Temporary...
+ if (fSemaphore) {
+ JackLog("Already connected name = %s\n", name);
+ return true;
+ }
+
+ if ((fSemaphore = sem_open(fName, O_CREAT)) == (sem_t*)SEM_FAILED) {
+ jack_error("Connect: can't connect named semaphore name = %s err = %s", fName, strerror(errno));
+ return false;
+ } else {
+ int val = 0;
+ sem_getvalue(fSemaphore, &val);
+ JackLog("JackPosixSemaphore::Connect sem_getvalue %ld\n", val);
+ return true;
+ }
+}
+
+bool JackPosixSemaphore::Connect(const char* name)
+{
+ return ConnectInput(name);
+}
+
+bool JackPosixSemaphore::ConnectOutput(const char* name)
+{
+ return ConnectInput(name);
+}
+
+bool JackPosixSemaphore::Disconnect()
+{
+ JackLog("JackPosixSemaphore::Disconnect %s\n", fName);
+
+ if (fSemaphore) {
+ if (sem_close(fSemaphore) != 0) {
+ jack_error("Disconnect: can't disconnect named semaphore name = %s err = %s", fName, strerror(errno));
+ return false;
+ } else {
+ fSemaphore = NULL;
+ return true;
+ }
+ } else {
+ return true;
+ }
+}
+
+// Server side : destroy the semaphore
+void JackPosixSemaphore::Destroy()
+{
+ if (fSemaphore != NULL) {
+ JackLog("JackPosixSemaphore::Destroy\n");
+ sem_unlink(fName);
+ if (sem_close(fSemaphore) != 0) {
+ jack_error("Destroy: can't destroy semaphore name = %s err = %s", fName, strerror(errno));
+ }
+ fSemaphore = NULL;
+ } else {
+ jack_error("JackPosixSemaphore::Destroy semaphore == NULL");
+ }
+}
+
+} // end of namespace
+
diff --git a/common/JackPosixSemaphore.h b/common/JackPosixSemaphore.h
new file mode 100644
index 00000000..dadfcc91
--- /dev/null
+++ b/common/JackPosixSemaphore.h
@@ -0,0 +1,71 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackPosixSemaphore__
+#define __JackPosixSemaphore__
+
+#include "JackSynchro.h"
+#include <semaphore.h>
+#include <time.h>
+#include <stdio.h>
+#include <assert.h>
+
+namespace Jack
+{
+
+/*!
+\brief Inter process synchronization using POSIX semaphore.
+*/
+
+class JackPosixSemaphore : public JackSynchro
+{
+
+ private:
+
+ sem_t* fSemaphore;
+
+ protected:
+
+ void BuildName(const char* name, char* res);
+
+ public:
+
+ JackPosixSemaphore(): JackSynchro(), fSemaphore(NULL)
+ {}
+ virtual ~JackPosixSemaphore()
+ {}
+
+ bool Signal();
+ bool SignalAll();
+ bool Wait();
+ bool TimedWait(long usec);
+
+ bool Allocate(const char* name, int value);
+ bool Connect(const char* name);
+ bool ConnectInput(const char* name);
+ bool ConnectOutput(const char* name);
+ bool Disconnect();
+ void Destroy();
+};
+
+} // end of namespace
+
+
+#endif
+
diff --git a/common/JackPosixThread.cpp b/common/JackPosixThread.cpp
new file mode 100644
index 00000000..32b3b686
--- /dev/null
+++ b/common/JackPosixThread.cpp
@@ -0,0 +1,209 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackPosixThread.h"
+#include "JackError.h"
+#include <string.h> // for memset
+
+namespace Jack
+{
+
+void* JackPosixThread::ThreadHandler(void* arg)
+{
+ JackPosixThread* obj = (JackPosixThread*)arg;
+ JackRunnableInterface* runnable = obj->fRunnable;
+ int err;
+
+ if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) {
+ jack_error("pthread_setcanceltype err = %s", strerror(err));
+ }
+
+ // Call Init method
+ if (!runnable->Init()) {
+ jack_error("Thread init fails: thread quits");
+ return 0;
+ }
+
+ JackLog("ThreadHandler: start\n");
+
+ // If Init succeed start the thread loop
+ bool res = true;
+ while (obj->fRunning && res) {
+ res = runnable->Execute();
+ //pthread_testcancel();
+ }
+
+ JackLog("ThreadHandler: exit\n");
+ return 0;
+}
+
+int JackPosixThread::Start()
+{
+ int res;
+ fRunning = true;
+
+ if (fRealTime) {
+
+ JackLog("Create RT thread\n");
+
+ /* Get the client thread to run as an RT-FIFO
+ scheduled thread of appropriate priority.
+ */
+ pthread_attr_t attributes;
+ struct sched_param rt_param;
+ pthread_attr_init(&attributes);
+
+ if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
+ jack_error("Cannot request explicit scheduling for RT thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
+ jack_error("Cannot request joinable thread creation for RT thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
+ jack_error("Cannot set scheduling scope for RT thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ //if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO))) {
+
+ if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_RR))) {
+ jack_error("Cannot set FIFO scheduling class for RT thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
+ jack_error("Cannot set scheduling scope for RT thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ memset(&rt_param, 0, sizeof(rt_param));
+ rt_param.sched_priority = fPriority;
+
+ if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
+ jack_error("Cannot set scheduling priority for RT thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ if ((res = pthread_create(&fThread, &attributes, ThreadHandler, this))) {
+ jack_error("Cannot set create thread %d %s", res, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+ } else {
+ JackLog("Create non RT thread\n");
+
+ if ((res = pthread_create(&fThread, 0, ThreadHandler, this))) {
+ jack_error("Cannot set create thread %d %s", res, strerror(errno));
+ return -1;
+ }
+ return 0;
+ }
+}
+
+int JackPosixThread::StartSync()
+{
+ jack_error("Not implemented yet");
+ return -1;
+}
+
+int JackPosixThread::Kill()
+{
+ if (fThread) { // If thread has been started
+ JackLog("JackPosixThread::Kill\n");
+ void* status;
+ pthread_cancel(fThread);
+ pthread_join(fThread, &status);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int JackPosixThread::Stop()
+{
+ if (fThread) { // If thread has been started
+ JackLog("JackPosixThread::Stop\n");
+ void* status;
+ fRunning = false; // Request for the thread to stop
+ pthread_join(fThread, &status);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int JackPosixThread::AcquireRealTime()
+{
+ struct sched_param rtparam;
+ int res;
+
+ if (!fThread)
+ return -1;
+
+ memset(&rtparam, 0, sizeof(rtparam));
+ rtparam.sched_priority = fPriority;
+
+ //if ((res = pthread_setschedparam(fThread, SCHED_FIFO, &rtparam)) != 0) {
+
+ if ((res = pthread_setschedparam(fThread, SCHED_RR, &rtparam)) != 0) {
+ jack_error("Cannot use real-time scheduling (FIFO/%d) "
+ "(%d: %s)", rtparam.sched_priority, res,
+ strerror(res));
+ return -1;
+ }
+ return 0;
+}
+
+int JackPosixThread::AcquireRealTime(int priority)
+{
+ fPriority = priority;
+ return AcquireRealTime();
+}
+
+int JackPosixThread::DropRealTime()
+{
+ struct sched_param rtparam;
+ int res;
+
+ if (!fThread)
+ return -1;
+
+ memset(&rtparam, 0, sizeof(rtparam));
+ rtparam.sched_priority = 0;
+
+ if ((res = pthread_setschedparam(fThread, SCHED_OTHER, &rtparam)) != 0) {
+ jack_error("Cannot switch to normal scheduling priority(%s)\n", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+pthread_t JackPosixThread::GetThreadID()
+{
+ return fThread;
+}
+
+} // end of namespace
+
diff --git a/common/JackPosixThread.h b/common/JackPosixThread.h
new file mode 100644
index 00000000..34927984
--- /dev/null
+++ b/common/JackPosixThread.h
@@ -0,0 +1,73 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackPosixThread__
+#define __JackPosixThread__
+
+#include "JackThread.h"
+#include <pthread.h>
+
+namespace Jack
+{
+
+/*!
+\brief The POSIX thread base class.
+*/
+
+class JackPosixThread : public JackThread
+{
+
+ protected:
+
+ pthread_t fThread;
+
+ static void* ThreadHandler(void* arg);
+
+ public:
+
+ JackPosixThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation)
+ : JackThread(runnable, priority, real_time, cancellation), fThread((pthread_t)NULL)
+ {}
+ JackPosixThread(JackRunnableInterface* runnable)
+ : JackThread(runnable, 0, false, PTHREAD_CANCEL_DEFERRED), fThread((pthread_t)NULL)
+ {}
+ JackPosixThread(JackRunnableInterface* runnable, int cancellation)
+ : JackThread(runnable, 0, false, cancellation), fThread((pthread_t)NULL)
+ {}
+
+ virtual ~JackPosixThread()
+ {}
+
+ virtual int Start();
+ virtual int StartSync();
+ virtual int Kill();
+ virtual int Stop();
+
+ virtual int AcquireRealTime();
+ virtual int AcquireRealTime(int priority);
+ virtual int DropRealTime();
+
+ pthread_t GetThreadID();
+};
+
+} // end of namespace
+
+
+#endif
diff --git a/common/JackProcessSync.h b/common/JackProcessSync.h
new file mode 100644
index 00000000..c8ddd99e
--- /dev/null
+++ b/common/JackProcessSync.h
@@ -0,0 +1,180 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackProcessSync__
+#define __JackProcessSync__
+
+#include "JackSyncInterface.h"
+#include "JackSynchro.h"
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+namespace Jack
+{
+
+/*!
+\brief A synchronization primitive built using a condition variable.
+*/
+
+class JackProcessSync : public JackSyncInterface
+{
+
+ private:
+
+ pthread_mutex_t fLock; // Mutex
+ pthread_cond_t fCond; // Condition variable
+
+ public:
+
+ JackProcessSync(): JackSyncInterface()
+ {
+ pthread_mutex_init(&fLock, NULL);
+ pthread_cond_init(&fCond, NULL);
+ }
+ virtual ~JackProcessSync()
+ {
+ pthread_mutex_destroy(&fLock);
+ pthread_cond_destroy(&fCond);
+ }
+
+ bool Allocate(const char* name)
+ {
+ return true;
+ }
+
+ bool Connect(const char* name)
+ {
+ return true;
+ }
+
+ void Destroy()
+ {}
+
+ bool TimedWait(long usec)
+ {
+ struct timeval T0, T1;
+ timespec time;
+ struct timeval now;
+ int res;
+
+ pthread_mutex_lock(&fLock);
+ JackLog("JackProcessSync::Wait time out = %ld\n", usec);
+ gettimeofday(&T0, 0);
+
+ static const UInt64 kNanosPerSec = 1000000000ULL;
+ static const UInt64 kNanosPerUsec = 1000ULL;
+ gettimeofday(&now, 0);
+ UInt64 nextDateNanos = now.tv_sec * kNanosPerSec + (now.tv_usec + usec) * kNanosPerUsec;
+ time.tv_sec = nextDateNanos / kNanosPerSec;
+ time.tv_nsec = nextDateNanos % kNanosPerSec;
+ res = pthread_cond_timedwait(&fCond, &fLock, &time);
+ if (res != 0)
+ jack_error("pthread_cond_timedwait error usec = %ld err = %s", usec, strerror(res));
+
+ gettimeofday(&T1, 0);
+ pthread_mutex_unlock(&fLock);
+ JackLog("JackProcessSync::Wait finished delta = %5.1lf\n",
+ (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec));
+ return (res == 0);
+ }
+
+ void Wait()
+ {
+ int res;
+ pthread_mutex_lock(&fLock);
+ JackLog("JackProcessSync::Wait...\n");
+ if ((res = pthread_cond_wait(&fCond, &fLock)) != 0)
+ jack_error("pthread_cond_wait error err = %s", strerror(errno));
+ pthread_mutex_unlock(&fLock);
+ JackLog("JackProcessSync::Wait finished\n");
+ }
+
+ void SignalAll()
+ {
+ //pthread_mutex_lock(&fLock);
+ pthread_cond_broadcast(&fCond);
+ //pthread_mutex_unlock(&fLock);
+ }
+
+};
+
+/*!
+\brief A synchronization primitive built using an inter-process synchronization object.
+*/
+
+class JackInterProcessSync : public JackSyncInterface
+{
+
+ private:
+
+ JackSynchro* fSynchro;
+
+ public:
+
+ JackInterProcessSync(JackSynchro* synchro): fSynchro(synchro)
+ {}
+ virtual ~JackInterProcessSync()
+ {
+ delete fSynchro;
+ }
+
+ bool Allocate(const char* name)
+ {
+ return fSynchro->Allocate(name, 0);
+ }
+
+ void Destroy()
+ {
+ fSynchro->Destroy();
+ }
+
+ bool Connect(const char* name)
+ {
+ return fSynchro->Connect(name);
+ }
+
+ bool TimedWait(long usec)
+ {
+ struct timeval T0, T1;
+ JackLog("JackInterProcessSync::Wait...\n");
+ gettimeofday(&T0, 0);
+ bool res = fSynchro->TimedWait(usec);
+ gettimeofday(&T1, 0);
+ JackLog("JackInterProcessSync::Wait finished delta = %5.1lf\n",
+ (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec));
+ return res;
+ }
+
+ void Wait()
+ {
+ fSynchro->Wait();
+ }
+
+ void SignalAll()
+ {
+ fSynchro->SignalAll();
+ }
+};
+
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackPthreadCond.cpp b/common/JackPthreadCond.cpp
new file mode 100644
index 00000000..eb72a21a
--- /dev/null
+++ b/common/JackPthreadCond.cpp
@@ -0,0 +1,207 @@
+/*
+Copyright (C) 2004-2005 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackPthreadCond.h"
+#include "JackError.h"
+
+namespace Jack
+{
+
+JackPthreadCondArray* JackPthreadCondServer::fTable = NULL;
+long JackPthreadCondServer::fCount = 0;
+
+JackShmReadWritePtr1<JackPthreadCondArray> JackPthreadCondClient::fTable;
+long JackPthreadCondClient::fCount = 0;
+
+JackPthreadCondArray::JackPthreadCondArray()
+{
+ for (int i = 0; i < MAX_ITEM; i++) {
+ strcpy(fTable[i].fName, "");
+ }
+}
+
+void JackPthreadCond::BuildName(const char* name, char* res)
+{
+ sprintf(res, "%s/jack_sem.%s", jack_client_dir, name);
+}
+
+bool JackPthreadCond::Signal()
+{
+ //pthread_mutex_lock(&fSynchro->fLock);
+ //JackLog("JackPthreadCond::Signal...\n");
+ pthread_cond_signal(&fSynchro->fCond);
+ //pthread_mutex_unlock(&fSynchro->fLock);
+ return true;
+}
+
+bool JackPthreadCond::SignalAll()
+{
+ pthread_cond_broadcast(&fSynchro->fCond);
+ return true;
+}
+
+bool JackPthreadCond::Wait()
+{
+ pthread_mutex_lock(&fSynchro->fLock);
+ //JackLog("JackPthreadCond::Wait...\n");
+ pthread_cond_wait(&fSynchro->fCond, &fSynchro->fLock);
+ pthread_mutex_unlock(&fSynchro->fLock);
+ //JackLog("JackProcessSync::Wait finished\n");
+ return true;
+}
+
+bool JackPthreadCond::TimedWait(long usec)
+{
+ timespec time;
+ struct timeval now;
+ gettimeofday(&now, 0);
+ time.tv_sec = now.tv_sec + usec / 1000000;
+ time.tv_nsec = (now.tv_usec + (usec % 1000000)) * 1000;
+ pthread_mutex_lock(&fSynchro->fLock);
+ JackLog("JackProcessSync::Wait...\n");
+ pthread_cond_timedwait(&fSynchro->fCond, &fSynchro->fLock, &time);
+ pthread_mutex_unlock(&fSynchro->fLock);
+ JackLog("JackProcessSync::Wait finished\n");
+ return true;
+}
+
+// Client side : get the published semaphore from server
+bool JackPthreadCond::ConnectInput(const char* name)
+{
+ BuildName(name, fName);
+ JackLog("JackPthreadCond::Connect %s\n", fName);
+
+ // Temporary...
+ if (fSynchro) {
+ JackLog("Already connected name = %s\n", name);
+ return true;
+ }
+
+ for (int i = 0; i < MAX_ITEM; i++) {
+ JackPthreadCondItem* synchro = &(GetTable()->fTable[i]);
+ if (strcmp(fName, synchro->fName) == 0) {
+ fSynchro = synchro;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool JackPthreadCond::Connect(const char* name)
+{
+ return ConnectInput(name);
+}
+
+bool JackPthreadCond::ConnectOutput(const char* name)
+{
+ return ConnectInput(name);
+}
+
+bool JackPthreadCond::Disconnect()
+{
+ JackLog("JackPthreadCond::Disconnect %s\n", fName);
+
+ if (fSynchro) {
+ strcpy(fSynchro->fName, "");
+ fSynchro = NULL;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+JackPthreadCondServer::JackPthreadCondServer(): JackPthreadCond()
+{
+ if (fCount++ == 0 && !fTable) {
+ fTable = new JackPthreadCondArray();
+ }
+ if (fCount == MAX_ITEM)
+ throw new std::bad_alloc;
+}
+
+JackPthreadCondServer::~JackPthreadCondServer()
+{
+ if (--fCount == 0 && fTable) {
+ delete fTable;
+ fTable = NULL;
+ }
+}
+
+bool JackPthreadCondServer::Allocate(const char* name, int value)
+{
+ BuildName(name, fName);
+ JackLog("JackPthreadCond::Allocate name = %s val = %ld\n", fName, value);
+
+ pthread_mutexattr_t mutex_attr;
+ pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
+
+ pthread_condattr_t cond_attr;
+ pthread_condattr_init(&cond_attr);
+ pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
+
+ for (int i = 0; i < MAX_ITEM; i++) {
+ if (strcmp(fTable->fTable[i].fName, "") == 0) { // first empty place
+ fSynchro = &fTable->fTable[i];
+ if (pthread_mutex_init(&fSynchro->fLock, &mutex_attr) != 0) {
+ jack_error("Allocate: can't check in named semaphore name = %s err = %s", fName, strerror(errno));
+ return false;
+ }
+ if (pthread_cond_init(&fSynchro->fCond, &cond_attr) != 0) {
+ jack_error("Allocate: can't check in named semaphore name = %s err = %s", fName, strerror(errno));
+ return false;
+ }
+ strcpy(fSynchro->fName, fName);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void JackPthreadCondServer::Destroy()
+{
+ if (fSynchro != NULL) {
+ pthread_mutex_destroy(&fSynchro->fLock);
+ pthread_cond_destroy(&fSynchro->fCond);
+ strcpy(fSynchro->fName, "");
+ fSynchro = NULL;
+ } else {
+ jack_error("JackPthreadCond::Destroy semaphore == NULL");
+ }
+}
+
+JackPthreadCondClient::JackPthreadCondClient(int shared_index): JackPthreadCond()
+{
+ if (fCount++ == 0 && !fTable) {
+ fTable = shared_index;
+ }
+ if (fCount == MAX_ITEM)
+ throw new std::bad_alloc;
+}
+
+JackPthreadCondClient::~JackPthreadCondClient()
+{
+ if (--fCount == 0 && fTable)
+ delete fTable;
+}
+
+} // end of namespace
+
diff --git a/common/JackPthreadCond.h b/common/JackPthreadCond.h
new file mode 100644
index 00000000..de1c818b
--- /dev/null
+++ b/common/JackPthreadCond.h
@@ -0,0 +1,133 @@
+/*
+Copyright (C) 2004-2005 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackPthreadCond__
+#define __JackPthreadCond__
+
+#include "JackSynchro.h"
+#include "JackShmMem.h"
+#include <pthread.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define MAX_ITEM 8
+
+namespace Jack
+{
+
+struct JackPthreadCondItem
+{
+ char fName[SYNC_MAX_NAME_SIZE];
+ pthread_mutex_t fLock;
+ pthread_cond_t fCond;
+};
+
+struct JackPthreadCondArray : public JackShmMem
+{
+ JackPthreadCondItem fTable[MAX_ITEM];
+
+ JackPthreadCondArray();
+ virtual ~JackPthreadCondArray()
+ {}
+}
+;
+
+/*!
+\brief Inter process synchronization using pthread condition variables.
+*/
+
+class JackPthreadCond : public JackSynchro
+{
+
+ protected:
+
+ JackPthreadCondItem* fSynchro;
+ void BuildName(const char* name, char* res);
+ virtual JackPthreadCondArray* GetTable() = 0;
+
+ public:
+
+ JackPthreadCond(): fSynchro(NULL)
+ {}
+ virtual ~JackPthreadCond()
+ {}
+
+ bool Signal();
+ bool SignalAll();
+ bool Wait();
+ bool TimedWait(long usec);
+
+ bool Connect(const char* name);
+ bool ConnectInput(const char* name);
+ bool ConnectOutput(const char* name);
+ bool Disconnect();
+
+};
+
+class JackPthreadCondServer : public JackPthreadCond
+{
+
+ private:
+
+ static JackPthreadCondArray* fTable;
+ static long fCount;
+
+ protected:
+
+ JackPthreadCondArray* GetTable()
+ {
+ return fTable;
+ }
+
+ public:
+
+ JackPthreadCondServer();
+ virtual ~JackPthreadCondServer();
+
+ bool Allocate(const char* name, int value);
+ void Destroy();
+};
+
+class JackPthreadCondClient : public JackPthreadCond
+{
+
+ private:
+
+ static JackShmReadWritePtr1<JackPthreadCondArray> fTable;
+ static long fCount;
+
+ protected:
+
+ JackPthreadCondArray* GetTable()
+ {
+ return fTable;
+ }
+
+ public:
+
+ JackPthreadCondClient(int shared_index);
+ virtual ~JackPthreadCondClient();
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackRequest.h b/common/JackRequest.h
new file mode 100644
index 00000000..e096ed8f
--- /dev/null
+++ b/common/JackRequest.h
@@ -0,0 +1,612 @@
+
+/*
+ Copyright (C) 2001 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackRequest__
+#define __JackRequest__
+
+#include "JackPort.h"
+#include "JackChannelTransaction.h"
+#include "JackError.h"
+#include <stdio.h>
+
+namespace Jack
+{
+
+/*!
+\brief Request from client to server.
+*/
+
+struct JackRequest
+{
+
+public:
+
+ typedef enum {
+ kRegisterPort = 1,
+ kUnRegisterPort = 2,
+ kConnectPorts = 3,
+ kDisconnectPorts = 4,
+ kSetTimeBaseClient = 5,
+ kActivateClient = 6,
+ kDeactivateClient = 7,
+ kDisconnectPort = 8,
+ kSetClientCapabilities = 9,
+ kGetPortConnections = 10,
+ kGetPortNConnections = 11,
+
+ kReleaseTimebase = 12,
+ kSetTimebaseCallback = 13,
+
+ kSetBufferSize = 20,
+ kSetFreeWheel = 21,
+ kClientNew = 22,
+ kClientClose = 23,
+ kConnectNamePorts = 24,
+ kDisconnectNamePorts = 25,
+
+ kNotification = 26
+ } RequestType;
+
+ RequestType fType;
+
+ JackRequest()
+ {}
+
+ JackRequest(RequestType type): fType(type)
+ {}
+
+ virtual ~JackRequest()
+ {}
+
+ virtual int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(this, sizeof(JackRequest));
+ }
+
+ virtual int Write(JackChannelTransaction* trans)
+ {
+ return -1;
+ }
+
+};
+
+/*!
+\brief Result from the server.
+*/
+
+struct JackResult
+{
+
+ int fResult;
+
+ JackResult(): fResult( -1)
+ {}
+ JackResult(int status): fResult(status)
+ {}
+ virtual ~JackResult()
+ {}
+
+ virtual int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(this, sizeof(JackResult));
+ }
+
+ virtual int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackResult));
+ }
+};
+
+/*!
+\brief NewClient request.
+*/
+
+struct JackClientNewRequest : public JackRequest
+{
+
+ char fName[JACK_CLIENT_NAME_SIZE + 1];
+
+ JackClientNewRequest()
+ {}
+ JackClientNewRequest(const char* name): JackRequest(kClientNew)
+ {
+ snprintf(fName, sizeof(fName), "%s", name);
+ }
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fName, sizeof(JackClientNewRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackClientNewRequest));
+ }
+};
+
+/*!
+\brief NewClient result.
+*/
+
+struct JackClientNewResult : public JackResult
+{
+
+ int fSharedEngine;
+ int fSharedClient;
+ int fSharedPorts;
+ uint32_t fProtocolVersion;
+
+ JackClientNewResult()
+ {}
+ JackClientNewResult(int32_t status, int index1, int index2, int index3)
+ : JackResult(status), fSharedEngine(index1), fSharedClient(index2), fSharedPorts(index3), fProtocolVersion(0)
+ {}
+
+ virtual int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(this, sizeof(JackClientNewResult));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackClientNewResult));
+ }
+};
+
+/*!
+\brief CloseClient request.
+*/
+
+struct JackClientCloseRequest : public JackRequest
+{
+
+ int fRefNum;
+
+ JackClientCloseRequest()
+ {}
+ JackClientCloseRequest(int refnum): JackRequest(kClientClose), fRefNum(refnum)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackClientCloseRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackClientCloseRequest));
+ }
+};
+
+/*!
+\brief Activate request.
+*/
+
+struct JackActivateRequest : public JackRequest
+{
+
+ int fRefNum;
+
+ JackActivateRequest()
+ {}
+ JackActivateRequest(int refnum): JackRequest(kActivateClient), fRefNum(refnum)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackActivateRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackActivateRequest));
+ }
+
+};
+
+/*!
+\brief Deactivate request.
+*/
+
+struct JackDeactivateRequest : public JackRequest
+{
+
+ int fRefNum;
+
+ JackDeactivateRequest()
+ {}
+ JackDeactivateRequest(int refnum): JackRequest(kDeactivateClient), fRefNum(refnum)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackDeactivateRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackDeactivateRequest));
+ }
+
+};
+
+/*!
+\brief PortRegister request.
+*/
+
+struct JackPortRegisterRequest : public JackRequest
+{
+
+ int fRefNum;
+ char fName[JACK_PORT_NAME_SIZE + 1];
+ char fPortType[JACK_PORT_TYPE_SIZE + 1];
+ unsigned int fFlags;
+ unsigned int fBufferSize;
+
+ JackPortRegisterRequest()
+ {}
+ JackPortRegisterRequest(int refnum, const char* name, const char* port_type, unsigned int flags, unsigned int buffer_size)
+ : JackRequest(kRegisterPort), fRefNum(refnum), fFlags(flags), fBufferSize(buffer_size)
+ {
+ strcpy(fName, name);
+ strcpy(fPortType, port_type);
+ }
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackPortRegisterRequest) - sizeof(JackRequest)) ;
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortRegisterRequest));
+ }
+};
+
+/*!
+\brief PortRegister result.
+*/
+
+struct JackPortRegisterResult : public JackResult
+{
+
+ jack_port_id_t fPortIndex;
+
+ JackPortRegisterResult(): fPortIndex(NO_PORT)
+ {}
+
+ virtual int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(this, sizeof(JackPortRegisterResult));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortRegisterResult));
+ }
+};
+
+/*!
+\brief PortUnregister request.
+*/
+
+struct JackPortUnRegisterRequest : public JackRequest
+{
+
+ int fRefNum;
+ int fPortIndex;
+
+ JackPortUnRegisterRequest()
+ {}
+ JackPortUnRegisterRequest(int refnum, int index): JackRequest(kUnRegisterPort), fRefNum(refnum), fPortIndex(index)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackPortUnRegisterRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortUnRegisterRequest));
+ }
+};
+
+/*!
+\brief PortConnectName request.
+*/
+
+struct JackPortConnectNameRequest : public JackRequest
+{
+
+ int fRefNum;
+ char fSrc[JACK_PORT_NAME_SIZE + 1];
+ char fDst[JACK_PORT_NAME_SIZE + 1];
+
+ JackPortConnectNameRequest()
+ {}
+ JackPortConnectNameRequest(int refnum, const char* src_name, const char* dst_name): JackRequest(kConnectNamePorts), fRefNum(refnum)
+ {
+ strcpy(fSrc, src_name);
+ strcpy(fDst, dst_name);
+ }
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackPortConnectNameRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortConnectNameRequest));
+ }
+};
+
+/*!
+\brief PortDisconnectName request.
+*/
+
+struct JackPortDisconnectNameRequest : public JackRequest
+{
+
+ int fRefNum;
+ char fSrc[JACK_PORT_NAME_SIZE + 1];
+ char fDst[JACK_PORT_NAME_SIZE + 1];
+
+ JackPortDisconnectNameRequest()
+ {}
+ JackPortDisconnectNameRequest(int refnum, const char* src_name, const char* dst_name): JackRequest(kDisconnectNamePorts), fRefNum(refnum)
+ {
+ strcpy(fSrc, src_name);
+ strcpy(fDst, dst_name);
+ }
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackPortDisconnectNameRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortDisconnectNameRequest));
+ }
+};
+
+/*!
+\brief PortConnect request.
+*/
+
+struct JackPortConnectRequest : public JackRequest
+{
+
+ int fRefNum;
+ jack_port_id_t fSrc;
+ jack_port_id_t fDst;
+
+ JackPortConnectRequest()
+ {}
+ JackPortConnectRequest(int refnum, jack_port_id_t src, jack_port_id_t dst): JackRequest(kConnectPorts), fRefNum(refnum), fSrc(src), fDst(dst)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackPortConnectRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortConnectRequest));
+ }
+};
+
+
+/*!
+\brief PortDisconnect request.
+*/
+
+struct JackPortDisconnectRequest : public JackRequest
+{
+
+ int fRefNum;
+ jack_port_id_t fSrc;
+ jack_port_id_t fDst;
+
+ JackPortDisconnectRequest()
+ {}
+ JackPortDisconnectRequest(int refnum, jack_port_id_t src, jack_port_id_t dst): JackRequest(kDisconnectPorts), fRefNum(refnum), fSrc(src), fDst(dst)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackPortDisconnectRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackPortDisconnectRequest));
+ }
+};
+
+/*!
+\brief SetBufferSize request.
+*/
+
+struct JackSetBufferSizeRequest : public JackRequest
+{
+
+ jack_nframes_t fBufferSize;
+
+ JackSetBufferSizeRequest()
+ {}
+ JackSetBufferSizeRequest(jack_nframes_t buffer_size): JackRequest(kSetBufferSize), fBufferSize(buffer_size)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fBufferSize, sizeof(JackSetBufferSizeRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackSetBufferSizeRequest));
+ }
+};
+
+/*!
+\brief SetFreeWheel request.
+*/
+
+struct JackSetFreeWheelRequest : public JackRequest
+{
+
+ int fOnOff;
+
+ JackSetFreeWheelRequest()
+ {}
+ JackSetFreeWheelRequest(int onoff): JackRequest(kSetFreeWheel), fOnOff(onoff)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fOnOff, sizeof(JackSetFreeWheelRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackSetFreeWheelRequest));
+ }
+};
+
+/*!
+\brief ReleaseTimebase request.
+*/
+
+struct JackReleaseTimebaseRequest : public JackRequest
+{
+
+ int fRefNum;
+
+ JackReleaseTimebaseRequest()
+ {}
+ JackReleaseTimebaseRequest(int refnum): JackRequest(kReleaseTimebase), fRefNum(refnum)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackReleaseTimebaseRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackReleaseTimebaseRequest));
+ }
+
+};
+
+/*!
+\brief SetTimebaseCallback request.
+*/
+
+struct JackSetTimebaseCallbackRequest : public JackRequest
+{
+
+ int fRefNum;
+ int fConditionnal;
+
+ JackSetTimebaseCallbackRequest()
+ {}
+ JackSetTimebaseCallbackRequest(int refnum, int conditional): JackRequest(kSetTimebaseCallback), fRefNum(refnum), fConditionnal(conditional)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackSetTimebaseCallbackRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackSetTimebaseCallbackRequest));
+ }
+};
+
+/*!
+\brief ClientNotification request.
+*/
+
+struct JackClientNotificationRequest : public JackRequest
+{
+
+ int fRefNum;
+ int fNotify;
+ int fValue;
+
+ JackClientNotificationRequest()
+ {}
+ JackClientNotificationRequest(int refnum, int notify, int value)
+ : JackRequest(kNotification), fRefNum(refnum), fNotify(notify), fValue(value)
+ {}
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(&fRefNum, sizeof(JackClientNotificationRequest) - sizeof(JackRequest));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackClientNotificationRequest));
+ }
+
+};
+
+/*!
+\brief ClientNotification.
+*/
+
+struct JackClientNotification
+{
+ char fName[JACK_CLIENT_NAME_SIZE + 1];
+ int fRefNum;
+ int fNotify;
+ int fValue;
+ int fSync;
+
+ JackClientNotification(): fNotify( -1), fValue( -1)
+ {}
+ JackClientNotification(const char* name, int refnum, int notify, int sync, int value)
+ : fRefNum(refnum), fNotify(notify), fValue(value), fSync(sync)
+ {
+ snprintf(fName, sizeof(fName), "%s", name);
+ }
+
+ int Read(JackChannelTransaction* trans)
+ {
+ return trans->Read(this, sizeof(JackClientNotification));
+ }
+
+ int Write(JackChannelTransaction* trans)
+ {
+ return trans->Write(this, sizeof(JackClientNotification));
+ }
+
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackServer.cpp b/common/JackServer.cpp
new file mode 100644
index 00000000..269b41fd
--- /dev/null
+++ b/common/JackServer.cpp
@@ -0,0 +1,339 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackServer.h"
+#include "JackTime.h"
+#include "JackFreewheelDriver.h"
+#include "JackLoopbackDriver.h"
+#include "JackThreadedDriver.h"
+#include "JackGlobals.h"
+#include "JackEngine.h"
+#include "JackAudioDriver.h"
+#include "JackChannel.h"
+#include "JackClientControl.h"
+#include "JackEngineControl.h"
+#include "JackSyncInterface.h"
+#include "JackGraphManager.h"
+
+#ifdef __APPLE_
+#include <CoreFoundation/CFNotificationCenter.h>
+#endif
+
+namespace Jack
+{
+
+JackServer* JackServer::fInstance = NULL;
+
+JackServer::JackServer(bool sync, long timeout, bool rt, long priority, long loopback, bool verbose)
+{
+ JackGlobals::InitServer();
+ for (int i = 0; i < CLIENT_NUM; i++)
+ fSynchroTable[i] = JackGlobals::MakeSynchro();
+ fGraphManager = new JackGraphManager();
+ fEngineControl = new JackEngineControl();
+ fSignal = JackGlobals::MakeInterProcessSync();
+ fEngine = new JackEngine(fGraphManager, fSynchroTable, fEngineControl, fSignal, sync, timeout, rt, priority, verbose);
+ fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver("freewheel", fEngine, fSynchroTable));
+ fLoopbackDriver = new JackLoopbackDriver("loopback", fEngine, fSynchroTable);
+ fChannel = JackGlobals::MakeServerChannel();
+ fState = new JackConnectionManager();
+ fFreewheel = false;
+ fSyncMode = sync;
+ fLoopback = loopback;
+ fDriverInfo = NULL;
+ fAudioDriver = NULL;
+ fInstance = this; // Unique instance
+}
+
+JackServer::~JackServer()
+{
+ for (int i = 0; i < CLIENT_NUM; i++)
+ delete fSynchroTable[i];
+ delete fGraphManager;
+ delete fAudioDriver;
+ delete fFreewheelDriver;
+ delete fLoopbackDriver;
+ delete fEngine;
+ delete fChannel;
+ delete fEngineControl;
+ delete fSignal;
+ delete fState;
+ if (fDriverInfo) {
+ UnloadDriverModule(fDriverInfo->handle);
+ free(fDriverInfo);
+ }
+ JackGlobals::Destroy();
+}
+
+// TODO : better handling of intermediate failing cases...
+
+int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
+{
+ if (fChannel->Open(this) < 0) {
+ jack_error("Server channel open error");
+ return -1;
+ }
+
+ if (fEngine->Open() != 0) {
+ jack_error("Cannot open engine");
+ return -1;
+ }
+
+ if ((fDriverInfo = jack_load_driver(driver_desc)) == NULL) {
+ return -1;
+ }
+
+ if ((fAudioDriver = fDriverInfo->initialize(fEngine, fSynchroTable, driver_params)) == NULL) {
+ jack_error("Cannot initialize driver");
+ return -1;
+ }
+
+ if (fFreewheelDriver->Open() != 0) { // before engine open
+ jack_error("Cannot open driver");
+ return -1;
+ }
+
+ // Before engine open
+ if (fLoopbackDriver->Open(fEngineControl->fBufferSize, fEngineControl->fSampleRate, 1, 1, fLoopback, fLoopback, false, "loopback", "loopback", 0, 0) != 0) {
+ jack_error("Cannot open driver");
+ return -1;
+ }
+
+ if (fAudioDriver->Attach() != 0) {
+ jack_error("Cannot attach audio driver");
+ return -1;
+ }
+
+ if (fLoopback > 0 && fLoopbackDriver->Attach() != 0) {
+ jack_error("Cannot attach loopback driver");
+ return -1;
+ }
+
+ fFreewheelDriver->SetMaster(false);
+ fAudioDriver->SetMaster(true);
+ if (fLoopback > 0)
+ fAudioDriver->AddSlave(fLoopbackDriver);
+ fAudioDriver->AddSlave(fFreewheelDriver); // After ???
+ InitTime();
+
+#ifdef __APPLE__
+ // Send notification to be used in the Jack Router
+ CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
+ CFSTR("com.grame.jackserver.start"),
+ CFSTR("com.grame.jackserver"),
+ NULL,
+ true);
+#endif
+
+ return 0;
+}
+
+int JackServer::Close()
+{
+ JackLog("JackServer::Close\n");
+ fChannel->Close();
+ fSignal->Destroy(); // A REVOIR
+ fAudioDriver->Detach();
+ if (fLoopback > 0)
+ fLoopbackDriver->Detach();
+ fAudioDriver->Close();
+ fFreewheelDriver->Close();
+ fLoopbackDriver->Close();
+ fEngine->Close();
+
+#ifdef __APPLE__
+ // Send notification to be used in the Jack Router
+ CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
+ CFSTR("com.grame.jackserver.stop"),
+ CFSTR("com.grame.jackserver"),
+ NULL,
+ true);
+#endif
+
+ return 0;
+}
+
+int JackServer::Start()
+{
+ JackLog("JackServer::Start\n");
+ fEngineControl->fFrameTimer.Init();
+ return fAudioDriver->Start();
+}
+
+int JackServer::Stop()
+{
+ JackLog("JackServer::Stop\n");
+ return fAudioDriver->Stop();
+}
+
+int JackServer::Activate(int refnum)
+{
+ fGraphManager->DirectConnect(fFreewheelDriver->GetClientControl()->fRefNum, refnum);
+ fGraphManager->DirectConnect(refnum, fFreewheelDriver->GetClientControl()->fRefNum);
+ return fEngine->ClientActivate(refnum);
+}
+
+// Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
+// (thus unactivated) state may happen where the client is still checked for its end.
+int JackServer::Deactivate(int refnum)
+{
+ int res = fEngine->ClientDeactivate(refnum);
+
+ // Disconnect only when needed
+ if (fGraphManager->IsDirectConnection(fFreewheelDriver->GetClientControl()->fRefNum, refnum)) {
+ fGraphManager->DirectDisconnect(fFreewheelDriver->GetClientControl()->fRefNum, refnum);
+ } else {
+ JackLog("JackServer::Deactivate: client = %ld was not activated \n", refnum);
+ }
+
+ // Disconnect only when needed
+ if (fGraphManager->IsDirectConnection(refnum, fFreewheelDriver->GetClientControl()->fRefNum)) {
+ fGraphManager->DirectDisconnect(refnum, fFreewheelDriver->GetClientControl()->fRefNum);
+ } else {
+ JackLog("JackServer::Deactivate: client = %ld was not activated \n", refnum);
+ }
+
+ return res;
+}
+
+int JackServer::SetBufferSize(jack_nframes_t nframes)
+{
+ JackLog("JackServer::SetBufferSize nframes = %ld\n", nframes);
+
+ if (nframes > BUFFER_SIZE_MAX)
+ return -1;
+
+ if (fAudioDriver->Stop() != 0) {
+ jack_error("Cannot stop audio driver");
+ return -1;
+ }
+
+ if (fAudioDriver->SetBufferSize(nframes) != 0) {
+ jack_error("Cannot SetBufferSize for audio driver");
+ return -1;
+ }
+
+ if (fFreewheelDriver->SetBufferSize(nframes) != 0) {
+ jack_error("Cannot SetBufferSize for freewheel driver");
+ return -1;
+ }
+
+ fEngine->NotifyBufferSize(nframes);
+
+ fEngineControl->fFrameTimer.Init();
+ return fAudioDriver->Start();
+}
+
+/*
+Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
+
+ - "global" connection state is saved
+ - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
+ - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
+ - the freewheel driver becomes the "master"
+
+Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
+no graph state change can be done during freewheel mode.
+*/
+
+int JackServer::SetFreewheel(bool onoff)
+{
+ JackLog("JackServer::SetFreewheel state = %ld\n", onoff);
+
+ if (fFreewheel) {
+ if (onoff) {
+ return -1;
+ } else {
+ fFreewheel = false;
+ fFreewheelDriver->Stop();
+ fGraphManager->Restore(fState); // Restore previous connection state
+ fEngine->NotifyFreewheel(onoff);
+ fFreewheelDriver->SetMaster(false);
+ fEngineControl->fFrameTimer.Init();
+ return fAudioDriver->Start();
+ }
+ } else {
+ if (onoff) {
+ fFreewheel = true;
+ fAudioDriver->Stop();
+ fGraphManager->Save(fState); // Save connection state
+ fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
+ fEngine->NotifyFreewheel(onoff);
+ fFreewheelDriver->SetMaster(true);
+ return fFreewheelDriver->Start();
+ } else {
+ return -1;
+ }
+ }
+}
+
+// Coming from the RT thread or server channel
+void JackServer::Notify(int refnum, int notify, int value)
+{
+ switch (notify) {
+
+ case JackNotifyChannelInterface::kGraphOrderCallback:
+ fEngine->NotifyGraphReorder();
+ break;
+
+ case JackNotifyChannelInterface::kXRunCallback:
+ fEngine->NotifyXRun(refnum);
+ break;
+
+ case JackNotifyChannelInterface::kZombifyClient:
+ fEngine->ZombifyClient(refnum);
+ break;
+
+ case JackNotifyChannelInterface::kDeadClient:
+ JackLog("JackServer: kDeadClient ref = %ld\n", refnum);
+ Deactivate(refnum);
+ fEngine->ClientClose(refnum);
+ break;
+ }
+}
+
+JackEngine* JackServer::GetEngine()
+{
+ return fEngine;
+}
+
+JackSynchro** JackServer::GetSynchroTable()
+{
+ return fSynchroTable;
+}
+
+JackEngineControl* JackServer::GetEngineControl()
+{
+ return fEngineControl;
+}
+
+JackGraphManager* JackServer::GetGraphManager()
+{
+ return fGraphManager;
+}
+
+void JackServer::PrintState()
+{
+ fAudioDriver->PrintState();
+ fEngine->PrintState();
+}
+
+} // end of namespace
+
diff --git a/common/JackServer.h b/common/JackServer.h
new file mode 100644
index 00000000..8766844b
--- /dev/null
+++ b/common/JackServer.h
@@ -0,0 +1,96 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackServer__
+#define __JackServer__
+
+#include "JackExports.h"
+#include "driver_interface.h"
+#include "JackDriverLoader.h"
+#include "jslist.h"
+
+namespace Jack
+{
+
+class JackGraphManager;
+class JackConnectionManager;
+class JackDriverClientInterface;
+class JackServerChannelInterface;
+class JackSyncInterface;
+struct JackEngineControl;
+class JackEngine;
+
+/*!
+\brief The Jack server.
+*/
+
+class EXPORT JackServer
+{
+
+ private:
+
+ jack_driver_info_t* fDriverInfo;
+ JackDriverClientInterface* fAudioDriver;
+ JackDriverClientInterface* fFreewheelDriver;
+ JackDriverClientInterface* fLoopbackDriver;
+ JackEngine* fEngine;
+ JackEngineControl* fEngineControl;
+ JackGraphManager* fGraphManager;
+ JackServerChannelInterface* fChannel;
+ JackConnectionManager* fState;
+ JackSynchro* fSynchroTable[CLIENT_NUM];
+ JackSyncInterface* fSignal;
+ bool fSyncMode;
+ bool fFreewheel;
+ long fLoopback;
+
+ public:
+
+ JackServer(bool sync, long timeout, bool rt, long priority, long loopback, bool verbose);
+ virtual ~JackServer();
+
+ int Open(jack_driver_desc_t* driver_desc, JSList* driver_params);
+
+ int Close();
+
+ int Start();
+ int Stop();
+
+ int Activate(int refnum);
+ int Deactivate(int refnum);
+
+ int SetBufferSize(jack_nframes_t nframes);
+ int SetFreewheel(bool onoff);
+ void Notify(int refnum, int notify, int value);
+
+ JackEngine* GetEngine();
+ JackEngineControl* GetEngineControl();
+ JackSynchro** GetSynchroTable();
+ JackGraphManager* GetGraphManager();
+
+ void PrintState();
+
+ static JackServer* fInstance; // Unique instance
+};
+
+} // end of namespace
+
+
+#endif
diff --git a/common/JackServerAPI.cpp b/common/JackServerAPI.cpp
new file mode 100644
index 00000000..0edbfc42
--- /dev/null
+++ b/common/JackServerAPI.cpp
@@ -0,0 +1,174 @@
+/*
+Copyright (C) 2001-2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackInternalClient.h"
+#include "JackGraphManager.h"
+#include "JackServer.h"
+#include "JackDebugClient.h"
+#include "JackServerGlobals.h"
+#include "JackError.h"
+#include "varargs.h"
+
+/*
+TODO:
+
+- implement the "jack_client_new", "jack_client_open", "jack_client_close" API so that we can provide a libjackdmp shared library
+to be used by clients for direct access.
+
+- automatic launch of the jack server with the first client open, automatic close when the last client exit. Use of a jackd.rsc configuration file.
+
+*/
+
+#ifdef WIN32
+ #define EXPORT __declspec(dllexport)
+#else
+ #define EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ EXPORT jack_client_t* my_jack_internal_client_new(const char* client_name);
+ EXPORT void my_jack_internal_client_close(jack_client_t* ext_client);
+
+ EXPORT jack_client_t * jack_client_open (const char *client_name,
+ jack_options_t options,
+ jack_status_t *status, ...);
+ EXPORT jack_client_t * jack_client_new (const char *client_name);
+ EXPORT int jack_client_close (jack_client_t *client);
+
+#ifdef __cplusplus
+}
+#endif
+
+using namespace Jack;
+
+EXPORT jack_client_t* my_jack_internal_client_new(const char* client_name)
+{
+ JackLog("jack_internal_client_new %s", client_name);
+ if (client_name == NULL) {
+ jack_error("jack_internal_client_new called with a NULL client_name");
+ return NULL;
+ }
+#ifdef __CLIENTDEBUG__
+ JackClient* client = new JackDebugClient(new JackInternalClient(JackServer::fInstance, GetSynchroTable())); // Debug mode
+#else
+ JackClient* client = new JackInternalClient(JackServer::fInstance, GetSynchroTable()); // To improve...
+#endif
+
+ int res = client->Open(client_name);
+ if (res < 0) {
+ delete client;
+ return NULL;
+ } else {
+ return (jack_client_t*)client;
+ }
+}
+
+EXPORT void my_jack_internal_client_close(jack_client_t* ext_client)
+{
+ JackLog("jack_internal_client_close");
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_internal_client_close called with a NULL client");
+ } else {
+ int res = client->Deactivate();
+ JackLog("jack_internal_client_close Deactivate %ld", res);
+ res = client->Close();
+ delete client;
+ JackLog("jack_internal_client_close OK");
+ }
+}
+
+EXPORT jack_client_t* jack_client_new(const char* client_name)
+{
+ int options = JackUseExactName;
+ if (getenv("JACK_START_SERVER") == NULL)
+ options |= JackNoStartServer;
+
+ return jack_client_open(client_name, (jack_options_t)options, NULL);
+}
+
+// TO BE IMPLEMENTED PROPERLY
+EXPORT jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...)
+{
+ va_list ap; /* variable argument pointer */
+ jack_varargs_t va; /* variable arguments */
+ jack_status_t my_status;
+
+ if (status == NULL) /* no status from caller? */
+ status = &my_status; /* use local status word */
+ *status = (jack_status_t)0;
+
+ /* validate parameters */
+ if ((options & ~JackOpenOptions)) {
+ int my_status1 = *status | (JackFailure | JackInvalidOption);
+ *status = (jack_status_t)my_status1;
+ return NULL;
+ }
+
+ /* parse variable arguments */
+ va_start(ap, status);
+ jack_varargs_parse(options, ap, &va);
+ va_end(ap);
+
+ JackLog("jack_client_open %s\n", client_name);
+ if (client_name == NULL) {
+ jack_error("jack_client_new called with a NULL client_name");
+ return NULL;
+ }
+
+ JackServerGlobals::Init(); // jack server initialisation
+
+#ifdef __CLIENTDEBUG__
+ JackClient* client = new JackDebugClient(new JackInternalClient(JackServer::fInstance, GetSynchroTable())); // Debug mode
+#else
+ JackClient* client = new JackInternalClient(JackServer::fInstance, GetSynchroTable()); // To improve...
+#endif
+
+ int res = client->Open(client_name);
+ if (res < 0) {
+ delete client;
+ JackServerGlobals::Destroy(); // jack server destruction
+ return NULL;
+ } else {
+ *status = (jack_status_t)0;
+ return (jack_client_t*)client;
+ }
+ return NULL;
+}
+
+EXPORT int jack_client_close(jack_client_t* ext_client)
+{
+ JackLog("jack_client_close\n");
+ JackClient* client = (JackClient*)ext_client;
+ if (client == NULL) {
+ jack_error("jack_client_close called with a NULL client");
+ return -1;
+ }
+ int res = client->Close();
+ delete client;
+ JackLog("jack_client_close OK\n");
+ JackServerGlobals::Destroy(); // jack library destruction
+ return res;
+}
+
diff --git a/common/JackServerGlobals.cpp b/common/JackServerGlobals.cpp
new file mode 100644
index 00000000..96b21e83
--- /dev/null
+++ b/common/JackServerGlobals.cpp
@@ -0,0 +1,389 @@
+/*
+Copyright (C) 2005 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackServerGlobals.h"
+#include "JackError.h"
+#include "shm.h"
+#include <getopt.h>
+
+#ifndef WIN32
+ #include <dirent.h>
+#endif
+
+#define DEFAULT_TMP_DIR "/tmp"
+char* jack_tmpdir = DEFAULT_TMP_DIR;
+static char* server_name = "default";
+static int realtime = 0;
+static int client_timeout = 0; /* msecs; if zero, use period size. */
+static int realtime_priority = 10;
+static int verbose_aux = 0;
+static int do_mlock = 1;
+static unsigned int port_max = 128;
+static int loopback = 0;
+static int do_unlock = 0;
+static int temporary = 0;
+
+namespace Jack
+{
+
+JackServerGlobals* JackServerGlobals::fGlobals = NULL;
+long JackServerGlobals::fClientCount = 0;
+JackServer* JackServerGlobals::fServer = NULL;
+
+#ifndef WIN32
+
+static char* jack_default_server_name(void)
+{
+ char *server_name;
+ if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
+ server_name = "default";
+ return server_name;
+}
+
+/* returns the name of the per-user subdirectory of jack_tmpdir */
+static char* jack_user_dir(void)
+{
+ static char user_dir[PATH_MAX] = "";
+
+ /* format the path name on the first call */
+ if (user_dir[0] == '\0') {
+ snprintf (user_dir, sizeof (user_dir), "%s/jack-%d",
+ jack_tmpdir, getuid ());
+ }
+
+ return user_dir;
+}
+
+/* returns the name of the per-server subdirectory of jack_user_dir() */
+
+static char* get_jack_server_dir(const char* toto)
+{
+ static char server_dir[PATH_MAX] = "";
+
+ // format the path name on the first call
+ if (server_dir[0] == '\0') {
+ snprintf (server_dir, sizeof (server_dir), "%s/%s",
+ jack_user_dir (), server_name);
+ }
+
+ return server_dir;
+}
+
+static void
+jack_cleanup_files (const char *server_name)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ char *dir_name = get_jack_server_dir (server_name);
+
+ /* On termination, we remove all files that jackd creates so
+ * subsequent attempts to start jackd will not believe that an
+ * instance is already running. If the server crashes or is
+ * terminated with SIGKILL, this is not possible. So, cleanup
+ * is also attempted when jackd starts.
+ *
+ * There are several tricky issues. First, the previous JACK
+ * server may have run for a different user ID, so its files
+ * may be inaccessible. This is handled by using a separate
+ * JACK_TMP_DIR subdirectory for each user. Second, there may
+ * be other servers running with different names. Each gets
+ * its own subdirectory within the per-user directory. The
+ * current process has already registered as `server_name', so
+ * we know there is no other server actively using that name.
+ */
+
+ /* nothing to do if the server directory does not exist */
+ if ((dir = opendir (dir_name)) == NULL) {
+ return ;
+ }
+
+ /* unlink all the files in this directory, they are mine */
+ while ((dirent = readdir (dir)) != NULL) {
+
+ char fullpath[PATH_MAX];
+
+ if ((strcmp (dirent->d_name, ".") == 0)
+ || (strcmp (dirent->d_name, "..") == 0)) {
+ continue;
+ }
+
+ snprintf (fullpath, sizeof (fullpath), "%s/%s",
+ dir_name, dirent->d_name);
+
+ if (unlink (fullpath)) {
+ jack_error ("cannot unlink `%s' (%s)", fullpath,
+ strerror (errno));
+ }
+ }
+
+ closedir (dir);
+
+ /* now, delete the per-server subdirectory, itself */
+ if (rmdir (dir_name)) {
+ jack_error ("cannot remove `%s' (%s)", dir_name,
+ strerror (errno));
+ }
+
+ /* finally, delete the per-user subdirectory, if empty */
+ if (rmdir (jack_user_dir ())) {
+ if (errno != ENOTEMPTY) {
+ jack_error ("cannot remove `%s' (%s)",
+ jack_user_dir (), strerror (errno));
+ }
+ }
+}
+
+#endif
+
+int JackServerGlobals::JackStart(jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int time_out_ms, int rt, int priority, int loopback, int verbose)
+{
+ JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose);
+ fServer = new JackServer(sync, time_out_ms, rt, priority, loopback, verbose);
+ int res = fServer->Open(driver_desc, driver_params);
+ return (res < 0) ? res : fServer->Start();
+}
+
+int JackServerGlobals::JackStop()
+{
+ fServer->Stop();
+ fServer->Close();
+ JackLog("Jackdmp: server close\n");
+ delete fServer;
+ JackLog("Jackdmp: delete server\n");
+ return 0;
+}
+
+int JackServerGlobals::JackDelete()
+{
+ delete fServer;
+ JackLog("Jackdmp: delete server\n");
+ return 0;
+}
+
+// Temporary : to test
+
+JackServerGlobals::JackServerGlobals()
+{
+ jack_driver_desc_t* driver_desc;
+ const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:";
+ struct option long_options[] = {
+ { "driver", 1, 0, 'd'
+ },
+ { "verbose", 0, 0, 'v' },
+ { "help", 0, 0, 'h' },
+ { "port-max", 1, 0, 'p' },
+ { "no-mlock", 0, 0, 'm' },
+ { "name", 0, 0, 'n' },
+ { "unlock", 0, 0, 'u' },
+ { "realtime", 0, 0, 'R' },
+ { "loopback", 0, 0, 'L' },
+ { "realtime-priority", 1, 0, 'P' },
+ { "timeout", 1, 0, 't' },
+ { "temporary", 0, 0, 'T' },
+ { "version", 0, 0, 'V' },
+ { "silent", 0, 0, 's' },
+ { "sync", 0, 0, 'S' },
+ { 0, 0, 0, 0 }
+ };
+ int opt = 0;
+ int option_index = 0;
+ int seen_driver = 0;
+ char *driver_name = NULL;
+ char **driver_args = NULL;
+ JSList* driver_params;
+ int driver_nargs = 1;
+ JSList* drivers = NULL;
+ char* server_name = NULL;
+ int show_version = 0;
+ int sync = 0;
+ int rc, i;
+
+ int argc = 8;
+ //char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512"};
+ char* argv[] = {"jackdmp", "-R", "-S", "-v", "-d", "portaudio", "-p", "512"};
+
+ for (i = 0; i < argc; i++) {
+ printf("arg %i %s\n", i, argv[i]);
+ }
+
+ opterr = 0;
+ while (!seen_driver &&
+ (opt = getopt_long(argc, argv, options,
+ long_options, &option_index)) != EOF) {
+ switch (opt) {
+
+ case 'd':
+ seen_driver = 1;
+ driver_name = optarg;
+ break;
+
+ case 'v':
+ verbose_aux = 1;
+ break;
+
+ case 's':
+ // jack_set_error_function(silent_jack_error_callback);
+ break;
+
+ case 'S':
+ sync = 1;
+ break;
+
+ case 'n':
+ server_name = optarg;
+ break;
+
+ case 'm':
+ do_mlock = 0;
+ break;
+
+ case 'p':
+ port_max = (unsigned int)atol(optarg);
+ break;
+
+ case 'P':
+ realtime_priority = atoi(optarg);
+ break;
+
+ case 'R':
+ realtime = 1;
+ break;
+
+ case 'L':
+ loopback = atoi(optarg);
+ break;
+
+ case 'T':
+ temporary = 1;
+ break;
+
+ case 't':
+ client_timeout = atoi(optarg);
+ break;
+
+ case 'u':
+ do_unlock = 1;
+ break;
+
+ case 'V':
+ show_version = 1;
+ break;
+
+ default:
+ fprintf(stderr, "unknown option character %c\n",
+ optopt);
+ /*fallthru*/
+ case 'h':
+ //usage(stdout);
+ return ;
+ }
+ }
+
+ drivers = jack_drivers_load (drivers);
+ if (!drivers) {
+ fprintf (stderr, "jackdmp: no drivers found; exiting\n");
+ exit (1);
+ }
+
+ driver_desc = jack_find_driver_descriptor (drivers, driver_name);
+ if (!driver_desc) {
+ fprintf (stderr, "jackdmp: unknown driver '%s'\n", driver_name);
+ exit (1);
+ }
+
+ if (optind < argc) {
+ driver_nargs = 1 + argc - optind;
+ } else {
+ driver_nargs = 1;
+ }
+
+ if (driver_nargs == 0) {
+ fprintf (stderr, "No driver specified ... hmm. JACK won't do"
+ " anything when run like this.\n");
+ return ;
+ }
+
+ driver_args = (char **) malloc (sizeof (char *) * driver_nargs);
+ driver_args[0] = driver_name;
+
+ for (i = 1; i < driver_nargs; i++) {
+ driver_args[i] = argv[optind++];
+ }
+
+ if (jack_parse_driver_params (driver_desc, driver_nargs,
+ driver_args, &driver_params)) {
+ return ;
+ }
+
+#ifndef WIN32
+ if (server_name == NULL)
+ server_name = jack_default_server_name ();
+#endif
+
+ rc = jack_register_server (server_name);
+
+ /* clean up shared memory and files from any previous
+ * instance of this server name */
+ jack_cleanup_shm();
+#ifndef WIN32
+ jack_cleanup_files(server_name);
+#endif
+
+ if (!realtime && client_timeout == 0)
+ client_timeout = 500; /* 0.5 sec; usable when non realtime. */
+
+ int res = JackStart(driver_desc, driver_params, sync, client_timeout, realtime, realtime_priority, loopback, verbose_aux);
+ if (res < 0) {
+ jack_error("Cannot start server... exit");
+ JackDelete();
+ return ;
+ }
+}
+
+JackServerGlobals::~JackServerGlobals()
+{
+ JackLog("~JackServerGlobals\n");
+ JackStop();
+ jack_cleanup_shm();
+#ifndef WIN32
+ jack_cleanup_files(server_name);
+#endif
+ jack_unregister_server(server_name);
+}
+
+void JackServerGlobals::Init()
+{
+ if (fClientCount++ == 0 && !fGlobals) {
+ JackLog("JackServerGlobals Init %x\n", fGlobals);
+ fGlobals = new JackServerGlobals();
+ }
+}
+
+void JackServerGlobals::Destroy()
+{
+ if (--fClientCount == 0 && fGlobals) {
+ JackLog("JackServerGlobals Destroy %x\n", fGlobals);
+ delete fGlobals;
+ fGlobals = NULL;
+ }
+}
+
+} // end of namespace
+
+
diff --git a/common/JackServerGlobals.h b/common/JackServerGlobals.h
new file mode 100644
index 00000000..d043ecbe
--- /dev/null
+++ b/common/JackServerGlobals.h
@@ -0,0 +1,58 @@
+/*
+Copyright (C) 2005 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackServerGlobals__
+#define __JackServerGlobals__
+
+#include "driver_interface.h"
+#include "driver_parse.h"
+#include "JackDriverLoader.h"
+#include "JackServer.h"
+
+#include <assert.h>
+
+namespace Jack
+{
+
+class JackClient;
+
+/*!
+\brief Global server static structure: singleton kind of pattern.
+*/
+
+struct JackServerGlobals
+{
+ static long fClientCount;
+ static JackServerGlobals* fGlobals;
+ static JackServer* fServer;
+
+ JackServerGlobals();
+ virtual ~JackServerGlobals();
+
+ static void Init();
+ static void Destroy();
+ static int JackStart(jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int time_out_ms, int rt, int priority, int loopback, int verbose);
+ static int JackStop();
+ static int JackDelete();
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackShmMem.cpp b/common/JackShmMem.cpp
new file mode 100644
index 00000000..d9b93b24
--- /dev/null
+++ b/common/JackShmMem.cpp
@@ -0,0 +1,92 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackShmMem.h"
+#include "JackError.h"
+#include <stdio.h>
+
+namespace Jack
+{
+
+unsigned long JackShmMem::fSegmentNum = 0;
+unsigned long JackShmMem::fSegmentCount = 0;
+
+jack_shm_info_t JackShmMem::gInfo;
+
+void* JackShmMem::operator new(size_t size)
+{
+ jack_shm_info_t info;
+ JackShmMem* obj;
+ char name[64];
+
+ snprintf(name, sizeof(name), "/jack_shared%ld", JackShmMem::fSegmentNum++);
+
+ if (JackShmMem::fSegmentCount++ == 0) {
+ JackLog("jack_initialize_shm\n");
+ if (jack_initialize_shm_server() < 0) {
+ jack_error("cannot initialize shm", strerror(errno));
+ goto error;
+ }
+ }
+
+ if (jack_shmalloc(name, size, &info)) {
+ jack_error("cannot create shared memory segment of size = %d", size, strerror(errno));
+ goto error;
+ }
+
+ if (jack_attach_shm(&info)) {
+ jack_error("cannot attach shared memory segment name = %s err = %s", name, strerror(errno));
+ jack_destroy_shm(&info);
+ goto error;
+ }
+
+ obj = (JackShmMem*)jack_shm_addr(&info);
+ // It is unsafe to set object fields directly (may be overwritten during object initialization),
+ // so use an intermediate global data
+ gInfo.index = info.index;
+ gInfo.attached_at = info.attached_at;
+ JackLog("JackShmMem::new index = %ld attached = %x size = %ld \n", info.index, info.attached_at, size);
+ return obj;
+
+error:
+ jack_error("JackShmMem::new bad alloc", size);
+ throw new std::bad_alloc;
+}
+
+void JackShmMem::operator delete(void* p, size_t size)
+{
+ jack_shm_info_t info;
+ JackShmMem* obj = (JackShmMem*)p;
+ info.index = obj->fInfo.index;
+ info.attached_at = obj->fInfo.attached_at;
+
+ JackLog("JackShmMem::delete size = %ld index = %ld\n", size, info.index);
+
+ jack_release_shm(&info);
+ jack_destroy_shm(&info);
+
+ if (--JackShmMem::fSegmentCount == 0) {
+ JackLog("jack_cleanup_shm\n");
+ jack_cleanup_shm();
+ }
+}
+
+} // end of namespace
+
diff --git a/common/JackShmMem.h b/common/JackShmMem.h
new file mode 100644
index 00000000..cb9b5d6b
--- /dev/null
+++ b/common/JackShmMem.h
@@ -0,0 +1,308 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackShmMem__
+#define __JackShmMem__
+
+#include "shm.h"
+#include <new> // GCC 4.0
+#include "JackError.h"
+#include <errno.h>
+
+namespace Jack
+{
+
+/*!
+\brief The base class for shared memory management.
+
+A class which objects need to be allocated in shared memory derives from this class.
+*/
+
+class JackShmMem
+{
+
+ private:
+
+ jack_shm_info_t fInfo;
+ static unsigned long fSegmentNum;
+ static unsigned long fSegmentCount;
+ static jack_shm_info_t gInfo;
+
+ public:
+
+ void* operator new(size_t size);
+ void operator delete(void* p, size_t size);
+
+ JackShmMem()
+ {
+ fInfo.index = gInfo.index;
+ fInfo.attached_at = gInfo.attached_at;
+ }
+
+ virtual ~JackShmMem()
+ {}
+
+ int GetShmIndex()
+ {
+ return fInfo.index;
+ }
+
+ char* GetShmAddress()
+ {
+ return (char*)fInfo.attached_at;
+ }
+
+};
+
+/*!
+\brief Pointer on shared memory segment in the client side.
+*/
+
+template <class T>
+class JackShmReadWritePtr
+{
+
+ private:
+
+ jack_shm_info_t fInfo;
+
+ void Init(int index)
+ {
+ if (fInfo.index < 0 && index >= 0) {
+ JackLog("JackShmReadWritePtr::Init %ld %ld\n", index, fInfo.index);
+ if (jack_initialize_shm_client() < 0)
+ throw - 1;
+ fInfo.index = index;
+ if (jack_attach_shm(&fInfo)) {
+ //jack_error("cannot attach shared memory segment", strerror(errno));
+ throw - 2;
+ }
+ }
+ }
+
+ public:
+
+ JackShmReadWritePtr()
+ {
+ fInfo.index = -1;
+ fInfo.attached_at = NULL;
+ }
+
+ JackShmReadWritePtr(int index)
+ {
+ Init(index);
+ }
+
+ virtual ~JackShmReadWritePtr()
+ {
+ if (fInfo.index >= 0) {
+ JackLog("JackShmReadWritePtr::~JackShmReadWritePtr %ld\n", fInfo.index);
+ jack_release_shm(&fInfo);
+ fInfo.index = -1;
+ }
+ }
+
+ T* operator->() const
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+ operator T*() const
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+ JackShmReadWritePtr& operator=(int index)
+ {
+ Init(index);
+ return *this;
+ }
+
+ int GetShmIndex()
+ {
+ return fInfo.index;
+ }
+
+ T* GetShmAddress()
+ {
+ return (T*)fInfo.attached_at;
+ }
+};
+
+/*!
+\brief Pointer on shared memory segment in the client side: destroy the segment (used client control)
+*/
+
+template <class T>
+class JackShmReadWritePtr1
+{
+
+ private:
+
+ jack_shm_info_t fInfo;
+
+ void Init(int index)
+ {
+ if (fInfo.index < 0 && index >= 0) {
+ JackLog("JackShmReadWritePtr1::Init %ld %ld\n", index, fInfo.index);
+ if (jack_initialize_shm_client() < 0)
+ throw - 1;
+ fInfo.index = index;
+ if (jack_attach_shm(&fInfo)) {
+ //jack_error("cannot attach shared memory segment", strerror(errno));
+ throw - 2;
+ }
+ /*
+ nobody else needs to access this shared memory any more, so
+ destroy it. because we have our own attachment to it, it won't
+ vanish till we exit (and release it).
+ */
+ jack_destroy_shm(&fInfo);
+ }
+ }
+
+ public:
+
+ JackShmReadWritePtr1()
+ {
+ fInfo.index = -1;
+ fInfo.attached_at = NULL;
+ }
+
+ JackShmReadWritePtr1(int index)
+ {
+ Init(index);
+ }
+
+ virtual ~JackShmReadWritePtr1()
+ {
+ if (fInfo.index >= 0) {
+ JackLog("JackShmReadWritePtr1::~JackShmReadWritePtr1 %ld\n", fInfo.index);
+ jack_release_shm(&fInfo);
+ fInfo.index = -1;
+ }
+ }
+
+ T* operator->() const
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+ operator T*() const
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+ JackShmReadWritePtr1& operator=(int index)
+ {
+ Init(index);
+ return *this;
+ }
+
+ int GetShmIndex()
+ {
+ return fInfo.index;
+ }
+
+ T* GetShmAddress()
+ {
+ return (T*)fInfo.attached_at;
+ }
+};
+
+/*!
+\brief Pointer on shared memory segment in the client side.
+*/
+
+template <class T>
+class JackShmReadPtr
+{
+
+ private:
+
+ jack_shm_info_t fInfo;
+
+ void Init(int index)
+ {
+ if (fInfo.index < 0 && index >= 0) {
+ JackLog("JackShmPtrRead::Init %ld %ld\n", index, fInfo.index);
+ if (jack_initialize_shm_client() < 0)
+ throw - 1;
+ fInfo.index = index;
+ if (jack_attach_shm_read(&fInfo)) {
+ //jack_error("cannot attach shared memory segment", strerror(errno));
+ throw - 2;
+ }
+ }
+ }
+
+ public:
+
+ JackShmReadPtr()
+ {
+ fInfo.index = -1;
+ fInfo.attached_at = NULL;
+ }
+
+ JackShmReadPtr(int index)
+ {
+ Init(index);
+ }
+
+ virtual ~JackShmReadPtr()
+ {
+ if (fInfo.index >= 0) {
+ JackLog("JackShmPtrRead::~JackShmPtrRead %ld\n", fInfo.index);
+ jack_release_shm(&fInfo);
+ fInfo.index = -1;
+ }
+ }
+
+ T* operator->() const
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+ operator T*() const
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+ JackShmReadPtr& operator=(int index)
+ {
+ Init(index);
+ return *this;
+ }
+
+ int GetShmIndex()
+ {
+ return fInfo.index;
+ }
+
+ T* GetShmAddress()
+ {
+ return (T*)fInfo.attached_at;
+ }
+
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackSocket.cpp b/common/JackSocket.cpp
new file mode 100644
index 00000000..c0500081
--- /dev/null
+++ b/common/JackSocket.cpp
@@ -0,0 +1,312 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "JackSocket.h"
+#include "JackError.h"
+#include <string.h>
+
+namespace Jack
+{
+
+JackClientSocket::JackClientSocket(int socket): fSocket(socket)
+{}
+
+void JackClientSocket::SetReadTimeOut(long sec)
+{
+ struct timeval timout;
+ timout.tv_sec = sec;
+ timout.tv_usec = 0;
+ if (setsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timout, sizeof(timeval)) < 0) {
+ JackLog("setsockopt SO_RCVTIMEO fd = %ld err = (%s)\n", fSocket, strerror(errno));
+ }
+}
+
+void JackClientSocket::SetWriteTimeOut(long sec)
+{
+ struct timeval timout;
+ timout.tv_sec = sec ;
+ timout.tv_usec = 0;
+ if (setsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timout, sizeof(timeval)) < 0) {
+ JackLog("setsockopt SO_SNDTIMEO fd = %ld err = (%s)\n", fSocket, strerror(errno));
+ }
+}
+
+int JackClientSocket::Connect(const char* dir, const char* name, int which) // A revoir : utilisation de "which"
+{
+ struct sockaddr_un addr;
+
+ if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ jack_error("Cannot create socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, "%s/jack_%s", dir, name);
+
+ JackLog("Connect: addr.sun_path %s\n", addr.sun_path);
+
+ if (connect(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ jack_error("Cannot connect to server socket (%s)", strerror(errno));
+ close(fSocket);
+ return -1;
+ }
+
+#ifdef __APPLE__
+ int on = 1 ;
+ if (setsockopt(fSocket, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&on, sizeof(on)) < 0) {
+ JackLog("setsockopt SO_NOSIGPIPE fd = %ld err = %s\n", fSocket, strerror(errno));
+ }
+#endif
+
+ return 0;
+}
+
+int JackClientSocket::Connect(const char* dir, int which)
+{
+ struct sockaddr_un addr;
+
+ if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ jack_error("Cannot create socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, "%s/jack_%d", dir, which);
+
+ JackLog("Connect: addr.sun_path %s\n", addr.sun_path);
+
+ if (connect(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ jack_error("Cannot connect to server socket (%s)", strerror(errno));
+ close(fSocket);
+ return -1;
+ }
+
+#ifdef __APPLE__
+ int on = 1 ;
+ if (setsockopt(fSocket, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&on, sizeof(on)) < 0) {
+ JackLog("setsockopt SO_NOSIGPIPE fd = %ld err = %s\n", fSocket, strerror(errno));
+ }
+#endif
+
+ return 0;
+}
+
+int JackClientSocket::Close()
+{
+ JackLog("JackClientSocket::Close\n");
+ //shutdown(fSocket, SHUT_RDWR);
+ if (fSocket > 0) {
+ close(fSocket);
+ fSocket = -1;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int JackClientSocket::Read(void* data, int len)
+{
+ int len1;
+ JackLog("JackClientSocket::Read len = %ld\n", len);
+
+ if ((len1 = read(fSocket, data, len)) != len) {
+ jack_error("Cannot read socket %d %d (%s)", len, len1, strerror(errno));
+ if (errno == EWOULDBLOCK) {
+ JackLog("JackClientSocket::Read time out\n");
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+}
+
+int JackClientSocket::Write(void* data, int len)
+{
+ if (write(fSocket, data, len) != len) {
+ jack_error("Cannot write socket fd %ld (%s)", fSocket, strerror(errno));
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+void
+jack_cleanup_files ()
+{
+ DIR *dir;
+ struct dirent *dirent;
+
+ // its important that we remove all files that jackd creates
+ // because otherwise subsequent attempts to start jackd will
+ // believe that an instance is already running.
+
+
+ if ((dir = opendir (jack_server_dir)) == NULL) {
+ fprintf (stderr, "jack(%d): cannot open jack FIFO directory "
+ "(%s)\n", getpid(), strerror (errno));
+ return;
+ }
+
+ while ((dirent = readdir (dir)) != NULL) {
+ if (strncmp (dirent->d_name, "jack-", 5) == 0 ||
+ strncmp (dirent->d_name, "jack_", 5) == 0) {
+ char fullpath[PATH_MAX+1];
+ snprintf (fullpath, sizeof (fullpath), "%s/%s",
+ jack_server_dir, dirent->d_name);
+ unlink (fullpath);
+ }
+ }
+
+ closedir (dir);
+}
+*/
+
+int JackServerSocket::Bind(const char* dir, const char* name, int which) // A revoir : utilisation de "which"
+{
+ struct sockaddr_un addr;
+
+ if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ jack_error("Cannot create server socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+
+ // TO CORRECT: always reuse the same name for now...
+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, "%s/jack_%s", dir, name);
+ snprintf(fName, sizeof(addr.sun_path) - 1, "%s/jack_%s", dir, name);
+ /*
+ if (access(addr.sun_path, F_OK) == 0) {
+ goto error;
+ }
+ */
+
+ JackLog("Bind: addr.sun_path %s\n", addr.sun_path);
+ unlink(fName); // Security...
+
+ JackLog("Bind: addr.sun_path %s\n", addr.sun_path);
+ unlink(fName); // Security...
+
+ if (bind(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ jack_error("Cannot bind server to socket (%s)", strerror(errno));
+ goto error;
+ }
+
+ if (listen(fSocket, 1) < 0) {
+ jack_error("Cannot enable listen on server socket (%s)", strerror(errno));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ unlink(fName);
+ close(fSocket);
+ return -1;
+}
+
+int JackServerSocket::Bind(const char* dir, int which) // A revoir : utilisation de "which"
+{
+ struct sockaddr_un addr;
+
+ if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ jack_error ("Cannot create server socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+
+ /*
+ for (int i = 0; i < 999; i++) {
+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1,"%s/jack_%d", dir, i);
+ snprintf(fName, sizeof(addr.sun_path) - 1,"%s/jack_%d", dir, i);
+ if (access(addr.sun_path, F_OK) != 0) {
+ break;
+ }
+ }
+ */
+
+ // TO CORRECT: always reuse the same name for now...
+ snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, "%s/jack_%d", dir, which);
+ snprintf(fName, sizeof(addr.sun_path) - 1, "%s/jack_%d", dir, which);
+ /*
+ if (access(addr.sun_path, F_OK) == 0) {
+ goto error;
+ }
+ */
+
+ JackLog("Bind: addr.sun_path %s\n", addr.sun_path);
+ unlink(fName); // Security...
+
+ if (bind(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ jack_error("Cannot bind server to socket (%s)", strerror(errno));
+ goto error;
+ }
+
+ if (listen(fSocket, 1) < 0) {
+ jack_error("Cannot enable listen on server socket (%s)", strerror(errno));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ unlink(fName);
+ close(fSocket);
+ return -1;
+}
+
+JackClientSocket* JackServerSocket::Accept()
+{
+ struct sockaddr_un client_addr;
+ socklen_t client_addrlen;
+
+ memset(&client_addr, 0, sizeof(client_addr));
+ client_addrlen = sizeof(client_addr);
+
+ int fd = accept(fSocket, (struct sockaddr*) & client_addr, &client_addrlen);
+ if (fd < 0) {
+ jack_error("Cannot accept new connection (%s)", strerror(errno));
+ return 0;
+ } else {
+ return new JackClientSocket(fd);
+ }
+}
+
+int JackServerSocket::Close()
+{
+ JackLog("JackServerSocket::Close %s\n", fName);
+ //shutdown(fSocket, SHUT_RDWR);
+ if (fSocket > 0) {
+ //shutdown(fSocket, SHUT_RDWR);
+ close(fSocket);
+ unlink(fName);
+ fSocket = -1;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+} // end of namespace
+
+
diff --git a/common/JackSocket.h b/common/JackSocket.h
new file mode 100644
index 00000000..ad1b3640
--- /dev/null
+++ b/common/JackSocket.h
@@ -0,0 +1,104 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackSocket__
+#define __JackSocket__
+
+#include "JackChannelTransaction.h"
+
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace Jack
+{
+
+/*!
+\brief Client socket.
+*/
+
+class JackClientSocket : public JackChannelTransaction
+{
+
+ private:
+
+ int fSocket;
+
+ public:
+
+ JackClientSocket(): fSocket( -1)
+ {}
+ JackClientSocket(int socket);
+ virtual ~JackClientSocket()
+ {}
+
+ int Connect(const char* dir, int which);
+ int Connect(const char* dir, const char* name, int which);
+ int Close();
+ int Read(void* data, int len);
+ int Write(void* data, int len);
+ int GetFd()
+ {
+ return fSocket;
+ }
+ void SetReadTimeOut(long sec);
+ void SetWriteTimeOut(long sec);
+};
+
+/*!
+\brief Server socket.
+*/
+
+class JackServerSocket
+{
+
+ private:
+
+ int fSocket;
+ char fName[256];
+
+ public:
+
+ JackServerSocket(): fSocket( -1)
+ {}
+ virtual ~JackServerSocket()
+ {}
+
+ int Bind(const char* dir, int which);
+ int Bind(const char* dir, const char* name, int which);
+ JackClientSocket* Accept();
+ int Close();
+ int GetFd()
+ {
+ return fSocket;
+ }
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackSocketClientChannel.cpp b/common/JackSocketClientChannel.cpp
new file mode 100644
index 00000000..05c77c73
--- /dev/null
+++ b/common/JackSocketClientChannel.cpp
@@ -0,0 +1,264 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "JackSocketClientChannel.h"
+#include "JackRequest.h"
+#include "JackClient.h"
+#include "JackGlobals.h"
+
+namespace Jack
+{
+
+JackSocketClientChannel::JackSocketClientChannel()
+{
+ fThread = JackGlobals::MakeThread(this);
+ fNotificationSocket = NULL;
+ fClient = NULL;
+}
+
+JackSocketClientChannel::~JackSocketClientChannel()
+{
+ delete fThread;
+ delete fNotificationSocket;
+}
+
+int JackSocketClientChannel::Open(const char* name, JackClient* obj)
+{
+ JackLog("JackSocketClientChannel::Open name = %s\n", name);
+
+ if (fRequestSocket.Connect(jack_server_dir, 0) < 0) {
+ jack_error("Cannot connect to server socket");
+ goto error;
+ }
+
+ if (fNotificationListenSocket.Bind(jack_client_dir, name, 0) < 0) {
+ jack_error("Cannot bind socket");
+ goto error;
+ }
+
+ fClient = obj;
+ return 0;
+
+error:
+ fRequestSocket.Close();
+ fNotificationListenSocket.Close();
+ return -1;
+}
+
+void JackSocketClientChannel::Close()
+{
+ fRequestSocket.Close();
+ fNotificationListenSocket.Close();
+ if (fNotificationSocket)
+ fNotificationSocket->Close();
+}
+
+int JackSocketClientChannel::Start()
+{
+ JackLog("JackSocketClientChannel::Start\n");
+ if (fThread->Start() != 0) {
+ jack_error("Cannot start Jack client listener");
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+void JackSocketClientChannel::Stop()
+{
+ JackLog("JackSocketClientChannel::Stop\n");
+ fThread->Kill();
+}
+
+void JackSocketClientChannel::ServerSyncCall(JackRequest* req, JackResult* res, int* result)
+{
+ if (req->Write(&fRequestSocket) < 0) {
+ jack_error("Could not write request type = %ld", req->fType);
+ *result = -1;
+ return ;
+ }
+
+ if (res->Read(&fRequestSocket) < 0) {
+ jack_error("Could not read result type = %ld", req->fType);
+ *result = -1;
+ return ;
+ }
+
+ *result = res->fResult;
+}
+
+void JackSocketClientChannel::ServerAsyncCall(JackRequest* req, JackResult* res, int* result)
+{
+ if (req->Write(&fRequestSocket) < 0) {
+ jack_error("Could not write request type = %ld", req->fType);
+ *result = -1;
+ } else {
+ *result = 0;
+ }
+}
+
+void JackSocketClientChannel::ClientNew(const char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result)
+{
+ JackClientNewRequest req(name);
+ JackClientNewResult res;
+ ServerSyncCall(&req, &res, result);
+ *shared_engine = res.fSharedEngine;
+ *shared_client = res.fSharedClient;
+ *shared_ports = res.fSharedPorts;
+}
+
+void JackSocketClientChannel::ClientClose(int refnum, int* result)
+{
+ JackClientCloseRequest req(refnum);
+ JackResult res;
+ ServerAsyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::ClientActivate(int refnum, int* result)
+{
+ JackActivateRequest req(refnum);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::ClientDeactivate(int refnum, int* result)
+{
+ JackDeactivateRequest req(refnum);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result)
+{
+ JackPortRegisterRequest req(refnum, name, "audio", flags, buffer_size);
+ JackPortRegisterResult res;
+ ServerSyncCall(&req, &res, result);
+ *port_index = res.fPortIndex;
+}
+
+void JackSocketClientChannel::PortUnRegister(int refnum, jack_port_id_t port_index, int* result)
+{
+ JackPortUnRegisterRequest req(refnum, port_index);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::PortConnect(int refnum, const char* src, const char* dst, int* result)
+{
+ JackPortConnectNameRequest req(refnum, src, dst);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::PortDisconnect(int refnum, const char* src, const char* dst, int* result)
+{
+ JackPortDisconnectNameRequest req(refnum, src, dst);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
+{
+ JackPortConnectRequest req(refnum, src, dst);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
+{
+ JackPortDisconnectRequest req(refnum, src, dst);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::SetBufferSize(jack_nframes_t nframes, int* result)
+{
+ JackSetBufferSizeRequest req(nframes);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::SetFreewheel(int onoff, int* result)
+{
+ JackSetFreeWheelRequest req(onoff);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::ReleaseTimebase(int refnum, int* result)
+{
+ JackReleaseTimebaseRequest req(refnum);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+void JackSocketClientChannel::SetTimebaseCallback(int refnum, int conditional, int* result)
+{
+ JackSetTimebaseCallbackRequest req(refnum, conditional);
+ JackResult res;
+ ServerSyncCall(&req, &res, result);
+}
+
+bool JackSocketClientChannel::Init()
+{
+ JackLog("JackSocketClientChannel::Init \n");
+ fNotificationSocket = fNotificationListenSocket.Accept();
+ // No more needed
+ fNotificationListenSocket.Close();
+
+ if (!fNotificationSocket) {
+ jack_error("JackSocketClientChannel: cannot establish notication socket");
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool JackSocketClientChannel::Execute()
+{
+ JackClientNotification event;
+ JackResult res;
+
+ //fClient->Init(); // To be checked
+
+ if (event.Read(fNotificationSocket) < 0) {
+ fNotificationSocket->Close();
+ jack_error("JackSocketClientChannel read fail");
+ goto error;
+ }
+
+ res.fResult = fClient->ClientNotify(event.fRefNum, event.fName, event.fNotify, event.fSync, event.fValue);
+
+ if (event.fSync) {
+ if (res.Write(fNotificationSocket) < 0) {
+ fNotificationSocket->Close();
+ jack_error("JackSocketClientChannel write fail");
+ goto error;
+ }
+ }
+ return true;
+
+error:
+ fClient->ShutDown();
+ return false;
+}
+
+} // end of namespace
+
+
diff --git a/common/JackSocketClientChannel.h b/common/JackSocketClientChannel.h
new file mode 100644
index 00000000..14953141
--- /dev/null
+++ b/common/JackSocketClientChannel.h
@@ -0,0 +1,89 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackSocketClientChannel__
+#define __JackSocketClientChannel__
+
+#include "JackChannel.h"
+#include "JackSocket.h"
+#include "JackThread.h"
+#include "JackRequest.h"
+
+namespace Jack
+{
+
+/*!
+\brief JackClientChannel using sockets.
+*/
+
+class JackSocketClientChannel : public JackClientChannelInterface, public JackRunnableInterface
+{
+
+ private:
+
+ JackClientSocket fRequestSocket; // Socket to communicate with the server
+ JackServerSocket fNotificationListenSocket; // Socket listener for server notification
+ JackClientSocket* fNotificationSocket; // Socket for server notification
+ JackThread* fThread; // Thread to execute the event loop
+ JackClient* fClient;
+
+ void ServerSyncCall(JackRequest* req, JackResult* res, int* result);
+ void ServerAsyncCall(JackRequest* req, JackResult* res, int* result);
+
+ public:
+
+ JackSocketClientChannel();
+ virtual ~JackSocketClientChannel();
+
+ int Open(const char* name, JackClient* obj);
+ void Close();
+
+ int Start();
+ void Stop();
+
+ void ClientNew(const char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result);
+ void ClientClose(int refnum, int* result);
+
+ void ClientActivate(int refnum, int* result);
+ void ClientDeactivate(int refnum, int* result);
+
+ void PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result);
+ void PortUnRegister(int refnum, jack_port_id_t port_index, int* result);
+
+ void PortConnect(int refnum, const char* src, const char* dst, int* result);
+ void PortDisconnect(int refnum, const char* src, const char* dst, int* result);
+
+ void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result);
+ void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result);
+
+ void SetBufferSize(jack_nframes_t nframes, int* result);
+ void SetFreewheel(int onoff, int* result);
+
+ void ReleaseTimebase(int refnum, int* result);
+ void SetTimebaseCallback(int refnum, int conditional, int* result);
+
+ // JackRunnableInterface interface
+ bool Init();
+ bool Execute();
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackSocketNotifyChannel.cpp b/common/JackSocketNotifyChannel.cpp
new file mode 100644
index 00000000..c0c1a3fd
--- /dev/null
+++ b/common/JackSocketNotifyChannel.cpp
@@ -0,0 +1,79 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "JackRequest.h"
+#include "JackSocketNotifyChannel.h"
+#include "JackError.h"
+#include "JackConstants.h"
+
+namespace Jack
+{
+
+// Server to client
+int JackSocketNotifyChannel::Open(const char* name)
+{
+ JackLog("JackSocketNotifyChannel::Open name = %s\n", name);
+
+ // Connect to client listen socket
+ if (fNotifySocket.Connect(jack_client_dir, name, 0) < 0) {
+ jack_error("Cannot connect client socket");
+ return -1;
+ }
+ // Use a time out for notifications
+ fNotifySocket.SetReadTimeOut(SOCKET_TIME_OUT);
+ return 0;
+}
+
+void JackSocketNotifyChannel::Close()
+{
+ JackLog("JackSocketNotifyChannel::Close\n");
+ fNotifySocket.Close();
+}
+
+void JackSocketNotifyChannel::ClientNotify(int refnum, const char* name, int notify, int sync, int value, int* result)
+{
+ JackClientNotification event(name, refnum, notify, sync, value);
+ JackResult res;
+
+ // Send notification
+ if (event.Write(&fNotifySocket) < 0) {
+ jack_error("Could not write notification");
+ fNotifySocket.Close();
+ *result = -1;
+ return ;
+ }
+
+ // Read the result in "synchronous" mode only
+ if (sync) {
+ // Get result : use a time out
+ if (res.Read(&fNotifySocket) < 0) {
+ jack_error("Could not read result");
+ fNotifySocket.Close();
+ *result = -1;
+ } else {
+ *result = res.fResult;
+ }
+ } else {
+ *result = 0;
+ }
+}
+
+} // end of namespace
+
+
diff --git a/common/JackSocketNotifyChannel.h b/common/JackSocketNotifyChannel.h
new file mode 100644
index 00000000..a43d76b9
--- /dev/null
+++ b/common/JackSocketNotifyChannel.h
@@ -0,0 +1,56 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackSocketNotifyChannel__
+#define __JackSocketNotifyChannel__
+
+#include "JackChannel.h"
+#include "JackSocket.h"
+
+namespace Jack
+{
+
+/*!
+\brief JackNotifyChannel using sockets.
+*/
+
+class JackSocketNotifyChannel : public JackNotifyChannelInterface
+{
+
+ private:
+
+ JackClientSocket fNotifySocket; // Socket to communicate with the server : from server to client
+
+ public:
+
+ JackSocketNotifyChannel()
+ {}
+ virtual ~JackSocketNotifyChannel()
+ {}
+
+ int Open(const char* name); // Open the Server/Client connection
+ void Close(); // Close the Server/Client connection
+
+ void ClientNotify(int refnum, const char* name, int notify, int sync, int value, int* result);
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackSocketServerChannel.cpp b/common/JackSocketServerChannel.cpp
new file mode 100644
index 00000000..5ec70edb
--- /dev/null
+++ b/common/JackSocketServerChannel.cpp
@@ -0,0 +1,375 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "JackSocketServerChannel.h"
+#include "JackRequest.h"
+#include "JackServer.h"
+#include "JackEngine.h"
+#include "JackGlobals.h"
+#include "JackClient.h"
+#include <assert.h>
+
+using namespace std;
+
+namespace Jack
+{
+
+JackSocketServerChannel::JackSocketServerChannel()
+{
+ fThread = JackGlobals::MakeThread(this);
+ fPollTable = NULL;
+ fRebuild = true;
+}
+
+JackSocketServerChannel::~JackSocketServerChannel()
+{
+ delete fThread;
+ delete[] fPollTable;
+}
+
+int JackSocketServerChannel::Open(JackServer* server)
+{
+ JackLog("JackSocketServerChannel::Open \n");
+ fServer = server;
+
+ // Prepare request socket
+ if (fRequestListenSocket.Bind(jack_server_dir, 0) < 0) {
+ JackLog("JackSocketServerChannel::Open : cannot create result listen socket\n");
+ return -1;
+ }
+
+ // Prepare for poll
+ BuildPoolTable();
+
+ // Start listening
+ if (fThread->Start() != 0) {
+ jack_error("Cannot start Jack server listener");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ fRequestListenSocket.Close();
+ return -1;
+}
+
+void JackSocketServerChannel::Close()
+{
+ fThread->Kill();
+ fRequestListenSocket.Close();
+}
+
+void JackSocketServerChannel::CreateClient()
+{
+ JackLog("JackSocketServerChannel::CreateClient socket\n");
+ JackClientSocket* socket = fRequestListenSocket.Accept();
+ if (socket) {
+ fSocketTable[socket->GetFd()] = make_pair( -1, socket);
+ fRebuild = true;
+ } else {
+ jack_error("Client socket cannot be created");
+ }
+}
+
+void JackSocketServerChannel::AddClient(int fd, char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result)
+{
+ JackLog("JackSocketServerChannel::AddClient\n");
+ int refnum = -1;
+ *result = fServer->GetEngine()->ClientNew(name, &refnum, shared_engine, shared_client, shared_ports);
+ if (*result == 0) {
+ fSocketTable[fd].first = refnum;
+ fRebuild = true;
+ } else {
+ jack_error("Cannot create new client");
+ }
+}
+
+void JackSocketServerChannel::RemoveClient(int fd, int refnum)
+{
+ pair<int, JackClientSocket*> elem = fSocketTable[fd];
+ JackClientSocket* socket = elem.second;
+ assert(socket);
+ JackLog("JackSocketServerChannel::RemoveClient ref = %d\n", refnum);
+ fSocketTable.erase(fd);
+ socket->Close();
+ delete socket;
+ fRebuild = true;
+}
+
+void JackSocketServerChannel::KillClient(int fd)
+{
+ pair<int, JackClientSocket*> elem = fSocketTable[fd];
+ JackClientSocket* socket = elem.second;
+ int refnum = elem.first;
+
+ assert(socket);
+ JackLog("JackSocketServerChannel::KillClient ref = %d\n", refnum);
+
+ if (refnum == -1) { // Should never happen... correspond to a client that started the socket but never opened...
+ jack_error("Client not opened");
+ } else {
+ fServer->Notify(refnum, JackNotifyChannelInterface::kDeadClient, 0);
+ }
+
+ fSocketTable.erase(fd);
+ socket->Close();
+ delete socket;
+ fRebuild = true;
+}
+
+int JackSocketServerChannel::HandleRequest(int fd)
+{
+ pair<int, JackClientSocket*> elem = fSocketTable[fd];
+ JackClientSocket* socket = elem.second;
+ assert(socket);
+
+ // Read header
+ JackRequest header;
+ if (header.Read(socket) < 0) {
+ jack_error("HandleRequest: cannot read header");
+ return -1;
+ }
+
+ // Read data
+ switch (header.fType) {
+
+ case JackRequest::kClientNew: {
+ JackLog("JackRequest::ClientNew\n");
+ JackClientNewRequest req;
+ JackClientNewResult res;
+ req.Read(socket);
+ AddClient(fd, req.fName, &res.fSharedEngine, &res.fSharedClient, &res.fSharedPorts, &res.fResult);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kClientClose: {
+ JackLog("JackRequest::ClientClose\n");
+ JackClientCloseRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->ClientClose(req.fRefNum);
+ res.Write(socket);
+ RemoveClient(fd, req.fRefNum);
+ break;
+ }
+
+ case JackRequest::kActivateClient: {
+ JackActivateRequest req;
+ JackResult res;
+ JackLog("JackRequest::ActivateClient\n");
+ req.Read(socket);
+ res.fResult = fServer->Activate(req.fRefNum);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kDeactivateClient: {
+ JackLog("JackRequest::DeactivateClient\n");
+ JackDeactivateRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->Deactivate(req.fRefNum);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kRegisterPort: {
+ JackLog("JackRequest::RegisterPort\n");
+ JackPortRegisterRequest req;
+ JackPortRegisterResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->PortRegister(req.fRefNum, req.fName, req.fFlags, req.fBufferSize, &res.fPortIndex);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kUnRegisterPort: {
+ JackLog("JackRequest::UnRegisterPort\n");
+ JackPortUnRegisterRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kConnectNamePorts: {
+ JackLog("JackRequest::ConnectPorts\n");
+ JackPortConnectNameRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kDisconnectNamePorts: {
+ JackLog("JackRequest::DisconnectPorts\n");
+ JackPortDisconnectNameRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kConnectPorts: {
+ JackLog("JackRequest::ConnectPorts\n");
+ JackPortConnectRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kDisconnectPorts: {
+ JackLog("JackRequest::DisconnectPorts\n");
+ JackPortDisconnectRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kSetBufferSize: {
+ JackLog("JackRequest::SetBufferSize\n");
+ JackSetBufferSizeRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->SetBufferSize(req.fBufferSize);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kSetFreeWheel: {
+ JackLog("JackRequest::SetFreeWheel\n");
+ JackSetFreeWheelRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->SetFreewheel(req.fOnOff);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kReleaseTimebase: {
+ JackLog("JackRequest::kReleaseTimebase\n");
+ JackReleaseTimebaseRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->ReleaseTimebase(req.fRefNum);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kSetTimebaseCallback: {
+ JackLog("JackRequest::kSetTimebaseCallback\n");
+ JackSetTimebaseCallbackRequest req;
+ JackResult res;
+ req.Read(socket);
+ res.fResult = fServer->GetEngine()->SetTimebaseCallback(req.fRefNum, req.fConditionnal);
+ res.Write(socket);
+ break;
+ }
+
+ case JackRequest::kNotification: {
+ JackLog("JackRequest::Notification\n");
+ JackClientNotificationRequest req;
+ req.Read(socket);
+ fServer->Notify(req.fRefNum, req.fNotify, req.fValue);
+ break;
+ }
+
+ default:
+ JackLog("Unknown request %ld\n", header.fType);
+ break;
+ }
+
+ return 0;
+}
+
+void JackSocketServerChannel::BuildPoolTable()
+{
+ if (fRebuild) {
+ fRebuild = false;
+ delete[] fPollTable;
+ fPollTable = new pollfd[fSocketTable.size() + 1];
+
+ JackLog("JackSocketServerChannel::BuildPoolTable size = %d\n", fSocketTable.size() + 1);
+
+ // First fd is the server request socket
+ fPollTable[0].fd = fRequestListenSocket.GetFd();
+ fPollTable[0].events = POLLIN | POLLERR;
+
+ // Next fd for clients
+ map<int, pair<int, JackClientSocket*> >::iterator it;
+ int i;
+
+ for (i = 1, it = fSocketTable.begin(); it != fSocketTable.end(); it++, i++) {
+ JackLog("fSocketTable i = %ld fd = %ld\n", i, it->first);
+ fPollTable[i].fd = it->first;
+ fPollTable[i].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
+ }
+ }
+}
+
+bool JackSocketServerChannel::Execute()
+{
+ // Global poll
+ if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) {
+ jack_error("Engine poll failed err = %s request thread quits...", strerror(errno));
+ return false;
+ } else {
+
+ // Poll all clients
+ for (unsigned int i = 1; i < fSocketTable.size() + 1; i++) {
+ int fd = fPollTable[i].fd;
+ JackLog("fPollTable i = %ld fd = %ld\n", i, fd);
+ if (fPollTable[i].revents & ~POLLIN) {
+ jack_error("Poll client error err = %s", strerror(errno));
+ KillClient(fd);
+ } else if (fPollTable[i].revents & POLLIN) {
+ if (HandleRequest(fd) < 0) {
+ jack_error("Could not handle external client request");
+ //RemoveClient(fd); TO CHECK
+ }
+ }
+ }
+
+ // Check the server request socket */
+ if (fPollTable[0].revents & POLLERR) {
+ jack_error("Error on server request socket err = %s", strerror(errno));
+ //return false; TO CHECK
+ }
+
+ if (fPollTable[0].revents & POLLIN) {
+ CreateClient();
+ }
+ }
+
+ BuildPoolTable();
+ return true;
+}
+
+} // end of namespace
+
+
diff --git a/common/JackSocketServerChannel.h b/common/JackSocketServerChannel.h
new file mode 100644
index 00000000..0a00ae3c
--- /dev/null
+++ b/common/JackSocketServerChannel.h
@@ -0,0 +1,70 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackSocketServerChannel__
+#define __JackSocketServerChannel__
+
+#include "JackChannel.h"
+#include "JackSocket.h"
+#include "JackThread.h"
+#include <poll.h>
+#include <map>
+
+namespace Jack
+{
+
+/*!
+\brief JackServerChannel using sockets.
+*/
+
+class JackSocketServerChannel : public JackServerChannelInterface, public JackRunnableInterface
+{
+
+ private:
+
+ JackServerSocket fRequestListenSocket; // Socket to create request socket for the client
+ JackThread* fThread; // Thread to execute the event loop
+ JackServer* fServer;
+ pollfd* fPollTable;
+ bool fRebuild;
+ std::map<int, std::pair<int, JackClientSocket*> > fSocketTable;
+
+ int HandleRequest(int fd);
+ void CreateClient();
+ void AddClient(int fd, char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result);
+ void RemoveClient(int fd, int refnum);
+ void KillClient(int fd);
+ void BuildPoolTable();
+
+ public:
+
+ JackSocketServerChannel();
+ virtual ~JackSocketServerChannel();
+
+ int Open(JackServer* server); // Open the Server/Client connection
+ void Close(); // Close the Server/Client connection
+
+ // JackRunnableInterface interface
+ bool Execute();
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackSocketServerNotifyChannel.cpp b/common/JackSocketServerNotifyChannel.cpp
new file mode 100644
index 00000000..3ca024a1
--- /dev/null
+++ b/common/JackSocketServerNotifyChannel.cpp
@@ -0,0 +1,59 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackSocketServerNotifyChannel.h"
+#include "JackError.h"
+#include "JackRequest.h"
+#include "JackConstants.h"
+
+namespace Jack
+{
+
+int JackSocketServerNotifyChannel::Open()
+{
+ if (fRequestSocket.Connect(jack_server_dir, 0) < 0) {
+ jack_error("Cannot connect to server socket");
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+void JackSocketServerNotifyChannel::Close()
+{
+ fRequestSocket.Close();
+}
+
+/*
+The requirement is that the Notification from RT thread can be delivered... not sure using a socket is adequate here...
+Can the write operation block?
+A non blocking write operation shoud be used : check if write can succeed, and ignore the notification otherwise
+(since its mainly used for XRun, ignoring a notification is OK, successive XRun will come...)
+*/
+void JackSocketServerNotifyChannel::ClientNotify(int refnum, int notify, int value)
+{
+ JackClientNotificationRequest req(refnum, notify, value);
+ if (req.Write(&fRequestSocket) < 0) {
+ jack_error("Could not write request type = %ld", req.fType);
+ }
+}
+
+} // end of namespace
+
+
diff --git a/common/JackSocketServerNotifyChannel.h b/common/JackSocketServerNotifyChannel.h
new file mode 100644
index 00000000..f4ce0532
--- /dev/null
+++ b/common/JackSocketServerNotifyChannel.h
@@ -0,0 +1,55 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackSocketServerNotifyChannel__
+#define __JackSocketServerNotifyChannel__
+
+#include "JackChannel.h"
+#include "JackSocket.h"
+
+namespace Jack
+{
+
+/*!
+\brief JackServerNotifyChannel using sockets.
+*/
+
+class JackSocketServerNotifyChannel : public JackServerNotifyChannelInterface
+{
+ private:
+
+ JackClientSocket fRequestSocket;
+
+ public:
+
+ JackSocketServerNotifyChannel()
+ {}
+ virtual ~JackSocketServerNotifyChannel()
+ {}
+
+ int Open();
+ void Close();
+
+ void ClientNotify(int refnum, int notify, int value);
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackSyncInterface.h b/common/JackSyncInterface.h
new file mode 100644
index 00000000..a2f3cf9f
--- /dev/null
+++ b/common/JackSyncInterface.h
@@ -0,0 +1,51 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackSyncInterface__
+#define __JackSyncInterface__
+
+namespace Jack
+{
+
+/*!
+\brief A synchronization primitive interface.
+*/
+
+class JackSyncInterface
+{
+
+ public:
+
+ JackSyncInterface()
+ {}
+ virtual ~JackSyncInterface()
+ {}
+
+ virtual bool Allocate(const char* name) = 0;
+ virtual bool Connect(const char* name) = 0;
+ virtual bool TimedWait(long usec) = 0;
+ virtual void Wait() = 0;
+ virtual void SignalAll() = 0;
+ virtual void Destroy() = 0;
+};
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackSynchro.h b/common/JackSynchro.h
new file mode 100644
index 00000000..d067ecad
--- /dev/null
+++ b/common/JackSynchro.h
@@ -0,0 +1,102 @@
+/*
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackSynchro__
+#define __JackSynchro__
+
+#include "JackError.h"
+
+#define SYNC_MAX_NAME_SIZE 256
+
+namespace Jack
+{
+
+/*!
+\brief An inter process synchronization primitive.
+*/
+
+class JackSynchro
+{
+
+ protected:
+
+ char fName[SYNC_MAX_NAME_SIZE];
+ bool fFlush; // If true, signal are "flushed" : used for drivers that do no consume the signal
+
+ virtual void BuildName(const char* name, char* res)
+ {}
+
+ public:
+
+ JackSynchro(): fFlush(false)
+ {}
+ virtual ~JackSynchro()
+ {}
+
+ virtual bool Signal()
+ {
+ return true;
+ }
+ virtual bool SignalAll()
+ {
+ return true;
+ }
+ virtual bool Wait()
+ {
+ return true;
+ }
+ virtual bool TimedWait(long usec)
+ {
+ return true;
+ }
+ virtual bool Allocate(const char* name, int value)
+ {
+ return true;
+ }
+ virtual bool Connect(const char* name)
+ {
+ return true;
+ }
+ virtual bool ConnectInput(const char* name)
+ {
+ return true;
+ }
+ virtual bool ConnectOutput(const char* name)
+ {
+ return true;
+ }
+ virtual bool Disconnect()
+ {
+ return true;
+ }
+ virtual void Destroy()
+ {}
+
+ void SetFlush(bool mode)
+ {
+ fFlush = mode;
+ }
+
+};
+
+
+} // end of namespace
+
+#endif
+
diff --git a/common/JackThread.h b/common/JackThread.h
new file mode 100644
index 00000000..1a7aad00
--- /dev/null
+++ b/common/JackThread.h
@@ -0,0 +1,97 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackThread__
+#define __JackThread__
+
+#ifdef WIN32
+ #include <windows.h>
+typedef HANDLE pthread_t;
+typedef ULONGLONG UInt64;
+#else
+ #include <pthread.h>
+typedef unsigned long long UInt64;
+#endif
+
+namespace Jack
+{
+
+/*!
+\brief The base class for runnable objects, that have an <B> Init </B> and <B> Execute </B> method to be called in a thread.
+*/
+
+class JackRunnableInterface
+{
+
+ public:
+
+ JackRunnableInterface()
+ {}
+ virtual ~JackRunnableInterface()
+ {}
+
+ virtual bool Init() /*! Called once when the thread is started */
+ {
+ return true;
+ }
+ virtual bool Execute() = 0; /*! Must be implemented by subclasses */
+};
+
+/*!
+\brief The thread base class.
+*/
+
+class JackThread
+{
+
+ protected:
+
+ JackRunnableInterface* fRunnable;
+ int fPriority;
+ bool fRealTime;
+ volatile bool fRunning;
+ int fCancellation;
+
+ public:
+
+ JackThread(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation):
+ fRunnable(runnable), fPriority(priority), fRealTime(real_time), fRunning(false), fCancellation(cancellation)
+ {}
+ virtual ~JackThread()
+ {}
+
+ virtual int Start() = 0;
+ virtual int StartSync() = 0;
+ virtual int Kill() = 0;
+ virtual int Stop() = 0;
+
+ virtual int AcquireRealTime() = 0;
+ virtual int AcquireRealTime(int priority) = 0;
+ virtual int DropRealTime() = 0;
+
+ virtual void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX...
+ {}
+
+ virtual pthread_t GetThreadID() = 0;
+};
+
+} // end of namespace
+
+#endif
diff --git a/common/JackThreadedDriver.cpp b/common/JackThreadedDriver.cpp
new file mode 100644
index 00000000..9a7e89fc
--- /dev/null
+++ b/common/JackThreadedDriver.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackThreadedDriver.h"
+#include "JackError.h"
+#include "JackGlobals.h"
+#include "JackClient.h"
+#include "JackEngineControl.h"
+
+namespace Jack
+{
+
+JackThreadedDriver::JackThreadedDriver(JackDriverClient* driver)
+{
+ fThread = JackGlobals::MakeThread(this);
+ fDriver = driver;
+}
+
+JackThreadedDriver::~JackThreadedDriver()
+{
+ delete fThread;
+ delete fDriver;
+}
+
+int JackThreadedDriver::Start()
+{
+ JackLog("JackThreadedDriver::Start\n");
+ int res;
+
+ if ((res = fDriver->Start()) < 0) {
+ jack_error("Cannot start driver");
+ return res;
+ }
+ if ((res = fThread->Start()) < 0) {
+ jack_error("Cannot start thread");
+ return res;
+ }
+
+ if (fDriver->IsRealTime()) {
+ JackLog("JackThreadedDriver::Start IsRealTime\n");
+ // Will do "something" on OSX only...
+ // fThread->SetParams(fDriver->fEngineControl->fPeriod, fDriver->fEngineControl->fComputation, fDriver->fEngineControl->fConstraint);
+ if (fThread->AcquireRealTime(GetEngineControl()->fPriority) < 0) {
+ jack_error("AcquireRealTime error");
+ }
+ }
+
+ return 0;
+}
+
+int JackThreadedDriver::Stop()
+{
+ JackLog("JackThreadedDriver::Stop\n");
+ int res;
+
+ if ((res = fThread->Stop()) < 0) { // Stop when the thread cycle is finished
+ jack_error("Cannot stop thread");
+ return res;
+ }
+ if ((res = fDriver->Stop()) < 0) {
+ jack_error("Cannot stop driver");
+ return res;
+ }
+ return 0;
+}
+
+bool JackThreadedDriver::Execute()
+{
+ return (Process() == 0);
+}
+
+} // end of namespace
diff --git a/common/JackThreadedDriver.h b/common/JackThreadedDriver.h
new file mode 100644
index 00000000..66546c83
--- /dev/null
+++ b/common/JackThreadedDriver.h
@@ -0,0 +1,154 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackThreadedDriver__
+#define __JackThreadedDriver__
+
+#include "JackDriver.h"
+#include "JackThread.h"
+
+namespace Jack
+{
+
+/*!
+\brief The base class for threaded drivers. Threaded drivers are used with blocking devices.
+*/
+
+class JackThreadedDriver : public JackDriverClientInterface, public JackRunnableInterface
+{
+
+ private:
+
+ JackThread* fThread;
+ JackDriverClient* fDriver;
+
+ public:
+
+ JackThreadedDriver(JackDriverClient* driver);
+ virtual ~JackThreadedDriver();
+
+ virtual int Open()
+ {
+ return fDriver->Open();
+ }
+
+ virtual int Open(jack_nframes_t nframes,
+ jack_nframes_t samplerate,
+ int capturing,
+ int playing,
+ int inchannels,
+ int outchannels,
+ bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency)
+ {
+ return fDriver->Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
+ }
+
+ virtual int Close()
+ {
+ return fDriver->Close();
+ }
+
+ virtual int Process()
+ {
+ return fDriver->Process();
+ }
+
+ virtual int Attach()
+ {
+ return fDriver->Attach();
+ }
+ virtual int Detach()
+ {
+ return fDriver->Detach();
+ }
+
+ virtual int Read()
+ {
+ return fDriver->Read();
+ }
+ virtual int Write()
+ {
+ return fDriver->Write();
+ }
+
+ virtual int Start();
+ virtual int Stop();
+
+ virtual int SetBufferSize(jack_nframes_t nframes)
+ {
+ return fDriver->SetBufferSize(nframes);
+ }
+
+ virtual void SetMaster(bool onoff)
+ {
+ fDriver->SetMaster(onoff);
+ }
+ virtual bool GetMaster()
+ {
+ return fDriver->GetMaster();
+ }
+
+ virtual void AddSlave(JackDriverInterface* slave)
+ {
+ fDriver->AddSlave(slave);
+ }
+ virtual void RemoveSlave(JackDriverInterface* slave)
+ {
+ fDriver->RemoveSlave(slave);
+ }
+ virtual void ProcessSlaves()
+ {
+ fDriver->ProcessSlaves();
+ }
+
+ virtual void PrintState()
+ {
+ fDriver->PrintState();
+ }
+
+ virtual int ClientNotify(int refnum, const char* name, int notify, int sync, int value)
+ {
+ return fDriver->ClientNotify(refnum, name, notify, sync, value);
+ }
+
+ virtual JackClientControl* GetClientControl() const
+ {
+ return fDriver->GetClientControl();
+ }
+
+ virtual bool IsRealTime()
+ {
+ return fDriver->IsRealTime();
+ }
+
+ // JackRunnableInterface interface
+
+ virtual bool Execute();
+
+};
+
+} // end of namespace
+
+
+#endif
diff --git a/common/JackTime.c b/common/JackTime.c
new file mode 100644
index 00000000..dbbf6063
--- /dev/null
+++ b/common/JackTime.c
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2001-2003 Paul Davis
+ Copyright (C) 2004-2006 Grame
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackTime.h"
+#include "JackError.h"
+
+#ifdef __APPLE__
+
+double __jack_time_ratio;
+
+/* This should only be called ONCE per process. */
+void InitTime()
+{
+ JackLog("InitTime\n");
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ __jack_time_ratio = ((float)info.numer / info.denom) / 1000;
+}
+
+#endif
+
+#ifdef WIN32
+
+EXPORT LARGE_INTEGER _jack_freq;
+
+void InitTime()
+{
+ QueryPerformanceFrequency(&_jack_freq);
+ JackLog("InitTime freq = %ld %ld\n", _jack_freq.HighPart, _jack_freq.LowPart);
+ _jack_freq.QuadPart = _jack_freq.QuadPart / 1000000; // by usec
+}
+
+jack_time_t GetMicroSeconds(void)
+{
+ LARGE_INTEGER t1;
+ QueryPerformanceCounter (&t1);
+ return (jack_time_t)(((double)t1.QuadPart)/((double)_jack_freq.QuadPart));
+}
+
+// TODO
+#endif
+
+#ifdef linux
+
+#ifdef GETCYCLE_TIME
+
+#include <stdio.h>
+jack_time_t GetMhz(void)
+{
+ FILE *f = fopen("/proc/cpuinfo", "r");
+ if (f == 0)
+ {
+ perror("can't open /proc/cpuinfo\n");
+ exit(1);
+ }
+
+ for ( ; ; )
+ {
+ jack_time_t mhz;
+ int ret;
+ char buf[1000];
+
+ if (fgets(buf, sizeof(buf), f) == NULL) {
+ jack_error ("FATAL: cannot locate cpu MHz in "
+ "/proc/cpuinfo\n");
+ exit(1);
+ }
+
+#if defined(__powerpc__)
+ ret = sscanf(buf, "clock\t: %" SCNu64 "MHz", &mhz);
+#elif defined( __i386__ ) || defined (__hppa__) || defined (__ia64__) || \
+ defined(__x86_64__)
+ ret = sscanf(buf, "cpu MHz : %" SCNu64, &mhz);
+#elif defined( __sparc__ )
+ ret = sscanf(buf, "Cpu0Bogo : %" SCNu64, &mhz);
+#elif defined( __mc68000__ )
+ ret = sscanf(buf, "Clocking: %" SCNu64, &mhz);
+#elif defined( __s390__ )
+ ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz);
+#else /* MIPS, ARM, alpha */
+ ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz);
+#endif
+ if (ret == 1)
+ {
+ fclose(f);
+ return (jack_time_t)mhz;
+ }
+ }
+}
+
+jack_time_t __jack_cpu_mhz;
+
+void InitTime()
+{
+ __jack_cpu_mhz = GetMhz();
+}
+
+#else
+void InitTime()
+{}
+
+#endif
+
+#endif
diff --git a/common/JackTime.h b/common/JackTime.h
new file mode 100644
index 00000000..22c1379a
--- /dev/null
+++ b/common/JackTime.h
@@ -0,0 +1,111 @@
+/*
+Copyright (C) 2001-2003 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __JackTime__
+#define __JackTime__
+
+#include "types.h"
+#include "JackExports.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(__APPLE__)
+
+#include <mach/mach_time.h>
+ #include <unistd.h>
+
+ extern double __jack_time_ratio;
+
+ static inline jack_time_t GetMicroSeconds(void) {
+ return (jack_time_t) (mach_absolute_time () * __jack_time_ratio);
+ }
+
+ /* This should only be called ONCE per process. */
+ extern void InitTime();
+
+ static inline void JackSleep(long usec) {
+ usleep(usec);
+ }
+
+#endif
+
+#ifdef WIN32
+
+ extern EXPORT LARGE_INTEGER _jack_freq;
+
+ /*
+ static jack_time_t GetMicroSeconds(void) {
+ LARGE_INTEGER t1;
+ QueryPerformanceCounter (&t1);
+ return (jack_time_t)(((double)t1.QuadPart)/((double)_jack_freq.QuadPart));
+ }
+ */
+
+ extern EXPORT jack_time_t GetMicroSeconds(void) ;
+
+ extern void InitTime();
+
+ static void JackSleep(long usec) {
+ Sleep(usec / 1000);
+ }
+
+#endif
+
+#ifdef linux
+
+#include <unistd.h>
+
+ static inline void JackSleep(long usec) {
+ usleep(usec);
+ }
+
+#ifdef GETCYCLE_TIME
+ #include "cycles.h"
+ extern jack_time_t __jack_cpu_mhz;
+ extern jack_time_t GetMhz();
+ extern void InitTime();
+ static inline jack_time_t GetMicroSeconds (void) {
+ return get_cycles() / __jack_cpu_mhz;
+ }
+#else
+ #include <time.h>
+ extern void InitTime();
+ static inline jack_time_t GetMicroSeconds (void) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (jack_time_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+ }
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
diff --git a/common/JackTransportEngine.cpp b/common/JackTransportEngine.cpp
new file mode 100644
index 00000000..af484846
--- /dev/null
+++ b/common/JackTransportEngine.cpp
@@ -0,0 +1,259 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "JackTransportEngine.h"
+#include "JackClientControl.h"
+#include "JackError.h"
+#include "JackTime.h"
+#include <assert.h>
+#include <stdlib.h>
+
+using namespace std;
+
+namespace Jack
+{
+
+JackTransportEngine::JackTransportEngine(): JackAtomicArrayState<jack_position_t>()
+{
+ fTransportState = JackTransportStopped;
+ fTransportCmd = fPreviousCmd = TransportCommandStop;
+ fSyncTimeout = 2000000; /* 2 second default */
+ fSyncTimeLeft = 0;
+ fTimeBaseMaster = -1;
+ fWriteCounter = 0;
+ fPendingPos = false;
+}
+
+// compute the number of cycle for timeout
+void JackTransportEngine::SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size)
+{
+ long buf_usecs = (long)((buffer_size * (jack_time_t) 1000000) / frame_rate);
+ fSyncTimeLeft = fSyncTimeout / buf_usecs;
+ JackLog("SyncTimeout fSyncTimeout = %ld fSyncTimeLeft = %ld\n", (long)fSyncTimeout, (long)fSyncTimeLeft);
+}
+
+int JackTransportEngine::ResetTimebase(int refnum)
+{
+ if (fTimeBaseMaster == refnum) {
+ jack_position_t* request = WriteNextStateStart(2); // To check
+ request->valid = (jack_position_bits_t)0;
+ WriteNextStateStop(2);
+ fTimeBaseMaster = -1;
+ return 0;
+ } else {
+ return EINVAL;
+ }
+}
+
+int JackTransportEngine::SetTimebase(int refnum, bool conditionnal)
+{
+ if (conditionnal && fTimeBaseMaster > 0) {
+ if (refnum != fTimeBaseMaster) {
+ JackLog("conditional timebase for ref = %ld failed: %ld is already the master\n", refnum, fTimeBaseMaster);
+ return EBUSY;
+ } else {
+ JackLog("ref = %ld was already timebase master\n", refnum);
+ return 0;
+ }
+ } else {
+ fTimeBaseMaster = refnum;
+ JackLog("new timebase master: ref = %ld\n", refnum);
+ return 0;
+ }
+}
+
+bool JackTransportEngine::CheckOneSynching(JackClientInterface** table)
+{
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = table[i];
+ if (client && client->GetClientControl()->fTransportState == JackTransportSynching) {
+ JackLog("CheckOneSynching\n");
+ return true;
+ }
+ }
+ return false;
+}
+
+bool JackTransportEngine::CheckAllRolling(JackClientInterface** table)
+{
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = table[i];
+ if (client && client->GetClientControl()->fTransportState != JackTransportRolling) {
+ JackLog("CheckAllRolling refnum = %ld is not rolling\n", i);
+ return false;
+ }
+ }
+ JackLog("CheckAllRolling\n");
+ return true;
+}
+
+void JackTransportEngine::MakeAllStarting(JackClientInterface** table)
+{
+ for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
+ JackClientInterface* client = table[i];
+ if (client) {
+ // Unactive clients don't have their process function called at all, they appear as already "rolling" for the transport....
+ client->GetClientControl()->fTransportState = (client->GetClientControl()->fActive) ? JackTransportStarting : JackTransportRolling;
+ JackLog("MakeAllStarting refnum = %ld \n", i);
+ }
+ }
+ JackLog("MakeAllStarting\n");
+}
+
+void JackTransportEngine::CycleBegin(jack_nframes_t frame_rate, jack_time_t time) // really needed?? (woule be done in CycleEnd...)
+{
+ jack_position_t* pending = WriteNextStateStart(1); // Update "pending" state
+ pending->usecs = time;
+ pending->frame_rate = frame_rate;
+ WriteNextStateStop(1);
+}
+
+void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size)
+{
+ TrySwitchState(1); // Switch from "pending" to "current", it always works since there is always a pending state
+
+ /* Handle any new transport command from the last cycle. */
+ transport_command_t cmd = fTransportCmd;
+ if (cmd != fPreviousCmd) {
+ fPreviousCmd = cmd;
+ JackLog("transport command: %s\n", (cmd == TransportCommandStart ? "START" : "STOP"));
+ } else {
+ cmd = TransportCommandNone;
+ }
+
+ /* state transition switch */
+ switch (fTransportState) {
+
+ case JackTransportSynching:
+ if (cmd == TransportCommandStart) {
+ fTransportState = JackTransportStarting;
+ MakeAllStarting(table);
+ SyncTimeout(frame_rate, buffer_size);
+ JackLog("transport locate ==> starting....\n");
+ } else if (fPendingPos) {
+ fTransportState = JackTransportSynching;
+ JackLog("transport locate ==> locate....\n");
+ } else {
+ fTransportState = JackTransportStopped;
+ JackLog("transport locate ==> stopped....\n");
+ }
+ break;
+
+ case JackTransportStopped:
+ // Set a JackTransportStarting for the current cycle, if all clients are ready (now slow_sync) ==> JackTransportRolling next state
+ if (cmd == TransportCommandStart) {
+ fTransportState = JackTransportStarting;
+ MakeAllStarting(table);
+ SyncTimeout(frame_rate, buffer_size);
+ JackLog("transport stopped ==> starting....\n");
+ } else if (fPendingPos || CheckOneSynching(table)) {
+ fTransportState = JackTransportSynching;
+ JackLog("transport stopped ==> locate....\n");
+ }
+ break;
+
+ case JackTransportStarting:
+ JackLog("transport starting fSyncTimeLeft %ld\n", fSyncTimeLeft);
+
+ if (cmd == TransportCommandStop) {
+ fTransportState = JackTransportStopped;
+ JackLog("transport starting ==> stopped\n");
+ } else if (fPendingPos) {
+ fTransportState = JackTransportStarting;
+ MakeAllStarting(table);
+ SyncTimeout(frame_rate, buffer_size);
+ } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) {
+ fTransportState = JackTransportRolling;
+ JackLog("transport starting ==> rolling.... fSyncTimeLeft %ld\n", fSyncTimeLeft);
+ }
+ break;
+
+ case JackTransportRolling:
+ if (cmd == TransportCommandStop) {
+ fTransportState = JackTransportStopped;
+ JackLog("transport rolling ==> stopped\n");
+ } else if (fPendingPos || CheckOneSynching(table)) {
+ fTransportState = JackTransportStarting;
+ MakeAllStarting(table);
+ SyncTimeout(frame_rate, buffer_size);
+ JackLog("transport rolling ==> starting....\n");
+ }
+ break;
+
+ default:
+ jack_error("Invalid JACK transport state: %d", fTransportState);
+ }
+
+ /* Update timebase, if needed. */
+ if (fTransportState == JackTransportRolling) {
+ jack_position_t* pending = WriteNextStateStart(1); // Update "pending" state
+ pending->frame += buffer_size;
+ WriteNextStateStop(1);
+ }
+
+ /* See if an asynchronous position request arrived during the last cycle. */
+ jack_position_t* request = WriteNextStateStart(2, &fPendingPos);
+ if (fPendingPos) {
+ JackLog("New pos = %ld\n", request->frame);
+ jack_position_t* pending = WriteNextStateStart(1);
+ TransportCopyPosition(request, pending);
+ WriteNextStateStop(1);
+ }
+}
+
+void JackTransportEngine::ReadCurrentPos(jack_position_t* pos)
+{
+ UInt16 next_index = GetCurrentIndex();
+ UInt16 cur_index;
+ do {
+ cur_index = next_index;
+ memcpy(pos, ReadCurrentState(), sizeof(jack_position_t));
+ next_index = GetCurrentIndex();
+ } while (cur_index != next_index); // Until a coherent state has been read
+}
+
+void JackTransportEngine::TransportCopyPosition(jack_position_t* from, jack_position_t* to)
+{
+ int tries = 0;
+ long timeout = 1000;
+
+ do {
+ /* throttle the busy wait if we don't get the answer
+ * very quickly. See comment above about this
+ * design.
+ */
+ if (tries > 10) {
+ JackSleep(20);
+ tries = 0;
+
+ /* debug code to avoid system hangs... */
+ if (--timeout == 0) {
+ jack_error("hung in loop copying position B");
+ abort();
+ }
+ }
+ *to = *from;
+ tries++;
+
+ } while (to->unique_1 != to->unique_2);
+}
+
+
+} // end of namespace
diff --git a/common/JackTransportEngine.h b/common/JackTransportEngine.h
new file mode 100644
index 00000000..0936b94f
--- /dev/null
+++ b/common/JackTransportEngine.h
@@ -0,0 +1,137 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __JackTransportEngine__
+#define __JackTransportEngine__
+
+#include "transport_types.h"
+#include "JackClientInterface.h"
+#include "JackConstants.h"
+#include "JackAtomicArrayState.h"
+
+namespace Jack
+{
+
+typedef enum {
+ TransportCommandNone = 0,
+ TransportCommandStart = 1,
+ TransportCommandStop = 2,
+} transport_command_t;
+
+/*!
+\brief The client transport structure.
+
+We have:
+
+ - a "current" position
+ - a "pending" position prepared by the server at each cycle
+ - a "request" position wanted by a client
+
+ At the beginning of a cycle the server needs to select a new current position. When a request and a pending position are available,
+ the resquest takes precedence on the pending one. The server atomically switches to the new position.
+ The current position can be read by clients.
+
+ We use a JackAtomicArrayState pattern that allows to manage several "next" states independantly.
+*/
+
+class JackTransportEngine : public JackAtomicArrayState<jack_position_t>
+{
+
+ private:
+
+ jack_transport_state_t fTransportState;
+ volatile transport_command_t fTransportCmd;
+ transport_command_t fPreviousCmd; /* previous transport_cmd */
+ jack_time_t fSyncTimeout;
+ int fSyncTimeLeft;
+ int fTimeBaseMaster;
+ bool fPendingPos;
+ volatile SInt32 fWriteCounter;
+
+ bool CheckOneSynching(JackClientInterface** table);
+ bool CheckAllRolling(JackClientInterface** table);
+ void MakeAllStarting(JackClientInterface** table);
+ void SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size);
+
+ public:
+
+ JackTransportEngine();
+
+ ~JackTransportEngine()
+ {}
+
+ void SetCommand(transport_command_t state)
+ {
+ fTransportCmd = state;
+ }
+
+ jack_transport_state_t GetState() const
+ {
+ return fTransportState;
+ }
+
+ int GetTimebaseMaster() const
+ {
+ return fTimeBaseMaster;
+ }
+
+ /*
+ \brief
+ */
+ int ResetTimebase(int refnum);
+
+ /*
+ \brief
+ */
+ int SetTimebase(int refnum, bool conditionnal);
+
+ /*
+ \brief
+ */
+ void CycleBegin(jack_nframes_t frame_rate, jack_time_t time);
+
+ /*
+ \brief
+ */
+ void CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size);
+
+ /*
+ \brief
+ */
+ void SetSyncTimeout(jack_time_t timeout)
+ {
+ fSyncTimeout = timeout;
+ }
+
+ void ReadCurrentPos(jack_position_t* pos);
+
+ jack_unique_t GenerateUniqueID()
+ {
+ return (jack_unique_t)INC_ATOMIC(&fWriteCounter);
+ }
+
+ static void TransportCopyPosition(jack_position_t* from, jack_position_t* to);
+
+};
+
+
+} // end of namespace
+
+#endif
diff --git a/common/JackTypes.h b/common/JackTypes.h
new file mode 100644
index 00000000..96c4c41f
--- /dev/null
+++ b/common/JackTypes.h
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2001 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: JackTypes.h,v 1.2.2.1 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __JackTypes__
+#define __JackTypes__
+
+namespace Jack
+{
+
+typedef enum {
+ NotTriggered,
+ Triggered,
+ Running,
+ Finished,
+} jack_client_state_t;
+
+}
+
+#endif
diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp
new file mode 100644
index 00000000..747e880a
--- /dev/null
+++ b/common/Jackdmp.cpp
@@ -0,0 +1,569 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004-2006 Grame
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <assert.h>
+#include <signal.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <getopt.h>
+
+#include "JackServer.h"
+#include "JackConstants.h"
+#include "driver_interface.h"
+#include "driver_parse.h"
+#include "JackDriverLoader.h"
+#include "jslist.h"
+#include "JackError.h"
+#include "shm.h"
+#include "jack.h"
+
+using namespace Jack;
+
+static JackServer* fServer;
+static char* server_name = NULL;
+static int realtime_priority = 10;
+static int do_mlock = 1;
+static unsigned int port_max = 128;
+static int realtime = 0;
+static int loopback = 0;
+static int temporary = 0;
+static int client_timeout = 0; /* msecs; if zero, use period size. */
+static int do_unlock = 0;
+static JSList* drivers = NULL;
+
+static sigset_t signals;
+
+#define DEFAULT_TMP_DIR "/tmp"
+char* jack_tmpdir = DEFAULT_TMP_DIR;
+
+static void silent_jack_error_callback (const char *desc)
+{}
+
+static void copyright(FILE* file)
+{
+ fprintf (file, "jackdmp " VERSION "\n"
+ "Copyright 2001-2005 Paul Davis and others.\n"
+ "Copyright 2004-2006 Grame.\n"
+ "jackdmp comes with ABSOLUTELY NO WARRANTY\n"
+ "This is free software, and you are welcome to redistribute it\n"
+ "under certain conditions; see the file COPYING for details\n");
+}
+
+static void usage (FILE* file)
+{
+ copyright (file);
+ fprintf (file, "\n"
+ "usage: jackdmp [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n"
+ " [ --name OR -n server-name ]\n"
+ // " [ --no-mlock OR -m ]\n"
+ // " [ --unlock OR -u ]\n"
+ " [ --timeout OR -t client-timeout-in-msecs ]\n"
+ " [ --loopback OR -L loopback-port-number ]\n"
+ // " [ --port-max OR -p maximum-number-of-ports]\n"
+ " [ --verbose OR -v ]\n"
+ " [ --silent OR -s ]\n"
+ " [ --sync OR -S ]\n"
+ " [ --version OR -V ]\n"
+ " -d driver [ ... driver args ... ]\n"
+ " where driver can be `alsa', `coreaudio' or `dummy'\n"
+ " jackdmp -d driver --help\n"
+ " to display options for each driver\n\n");
+}
+
+
+static void DoNothingHandler(int sig)
+{
+ /* this is used by the child (active) process, but it never
+ gets called unless we are already shutting down after
+ another signal.
+ */
+ char buf[64];
+ snprintf(buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig);
+ write(1, buf, strlen(buf));
+}
+
+static int JackStart(jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int time_out_ms, int rt, int priority, int loopback, int verbose)
+{
+ JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose);
+ fServer = new JackServer(sync, time_out_ms, rt, priority, loopback, verbose);
+ int res = fServer->Open(driver_desc, driver_params);
+ return (res < 0) ? res : fServer->Start();
+}
+
+static int JackStop()
+{
+ fServer->Stop();
+ fServer->Close();
+ JackLog("Jackdmp: server close\n");
+ delete fServer;
+ JackLog("Jackdmp: delete server\n");
+ return 0;
+}
+
+static int JackDelete()
+{
+ delete fServer;
+ JackLog("Jackdmp: delete server\n");
+ return 0;
+}
+
+static void FilterSIGPIPE()
+{
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGPIPE);
+ //sigprocmask(SIG_BLOCK, &set, 0);
+ pthread_sigmask(SIG_BLOCK, &set, 0);
+}
+
+static char* jack_default_server_name(void)
+{
+ char *server_name;
+ if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
+ server_name = "default";
+ return server_name;
+}
+
+/* returns the name of the per-user subdirectory of jack_tmpdir */
+static char* jack_user_dir(void)
+{
+ static char user_dir[PATH_MAX] = "";
+
+ /* format the path name on the first call */
+ if (user_dir[0] == '\0') {
+ snprintf (user_dir, sizeof (user_dir), "%s/jack-%d",
+ jack_tmpdir, getuid ());
+ }
+
+ return user_dir;
+}
+
+/* returns the name of the per-server subdirectory of jack_user_dir() */
+
+static char* get_jack_server_dir(const char* toto)
+{
+ static char server_dir[PATH_MAX] = "";
+
+ // format the path name on the first call
+ if (server_dir[0] == '\0') {
+ snprintf (server_dir, sizeof (server_dir), "%s/%s",
+ jack_user_dir (), server_name);
+ }
+
+ return server_dir;
+}
+
+static void
+jack_cleanup_files (const char *server_name)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ char *dir_name = get_jack_server_dir (server_name);
+
+ /* On termination, we remove all files that jackd creates so
+ * subsequent attempts to start jackd will not believe that an
+ * instance is already running. If the server crashes or is
+ * terminated with SIGKILL, this is not possible. So, cleanup
+ * is also attempted when jackd starts.
+ *
+ * There are several tricky issues. First, the previous JACK
+ * server may have run for a different user ID, so its files
+ * may be inaccessible. This is handled by using a separate
+ * JACK_TMP_DIR subdirectory for each user. Second, there may
+ * be other servers running with different names. Each gets
+ * its own subdirectory within the per-user directory. The
+ * current process has already registered as `server_name', so
+ * we know there is no other server actively using that name.
+ */
+
+ /* nothing to do if the server directory does not exist */
+ if ((dir = opendir (dir_name)) == NULL) {
+ return ;
+ }
+
+ /* unlink all the files in this directory, they are mine */
+ while ((dirent = readdir (dir)) != NULL) {
+
+ char fullpath[PATH_MAX];
+
+ if ((strcmp (dirent->d_name, ".") == 0)
+ || (strcmp (dirent->d_name, "..") == 0)) {
+ continue;
+ }
+
+ snprintf (fullpath, sizeof (fullpath), "%s/%s",
+ dir_name, dirent->d_name);
+
+ if (unlink (fullpath)) {
+ jack_error ("cannot unlink `%s' (%s)", fullpath,
+ strerror (errno));
+ }
+ }
+
+ closedir (dir);
+
+ /* now, delete the per-server subdirectory, itself */
+ if (rmdir (dir_name)) {
+ jack_error ("cannot remove `%s' (%s)", dir_name,
+ strerror (errno));
+ }
+
+ /* finally, delete the per-user subdirectory, if empty */
+ if (rmdir (jack_user_dir ())) {
+ if (errno != ENOTEMPTY) {
+ jack_error ("cannot remove `%s' (%s)",
+ jack_user_dir (), strerror (errno));
+ }
+ }
+}
+
+#ifdef FORK_SERVER
+
+int main(int argc, char* argv[])
+{
+ int sig;
+ sigset_t allsignals;
+ struct sigaction action;
+ int waiting;
+
+ jack_driver_desc_t* driver_desc;
+ const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:";
+ struct option long_options[] = {
+ { "driver", 1, 0, 'd'
+ },
+ { "verbose", 0, 0, 'v' },
+ { "help", 0, 0, 'h' },
+ { "port-max", 1, 0, 'p' },
+ { "no-mlock", 0, 0, 'm' },
+ { "name", 0, 0, 'n' },
+ { "unlock", 0, 0, 'u' },
+ { "realtime", 0, 0, 'R' },
+ { "loopback", 0, 0, 'L' },
+ { "realtime-priority", 1, 0, 'P' },
+ { "timeout", 1, 0, 't' },
+ { "temporary", 0, 0, 'T' },
+ { "version", 0, 0, 'V' },
+ { "silent", 0, 0, 's' },
+ { "sync", 0, 0, 'S' },
+ { 0, 0, 0, 0 }
+ };
+ int opt = 0;
+ int option_index = 0;
+ int seen_driver = 0;
+ char *driver_name = NULL;
+ char **driver_args = NULL;
+ JSList* driver_params;
+ int driver_nargs = 1;
+ int show_version = 0;
+ int sync = 0;
+ int rc, i;
+
+ opterr = 0;
+ while (!seen_driver &&
+ (opt = getopt_long(argc, argv, options,
+ long_options, &option_index)) != EOF) {
+ switch (opt) {
+
+ case 'd':
+ seen_driver = 1;
+ driver_name = optarg;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 's':
+ jack_set_error_function(silent_jack_error_callback);
+ break;
+
+ case 'S':
+ sync = 1;
+ break;
+
+ case 'n':
+ server_name = optarg;
+ break;
+
+ case 'm':
+ do_mlock = 0;
+ break;
+
+ case 'p':
+ port_max = (unsigned int)atol(optarg);
+ break;
+
+ case 'P':
+ realtime_priority = atoi(optarg);
+ break;
+
+ case 'R':
+ realtime = 1;
+ break;
+
+ case 'L':
+ loopback = atoi(optarg);
+ break;
+
+ case 'T':
+ temporary = 1;
+ break;
+
+ case 't':
+ client_timeout = atoi(optarg);
+ break;
+
+ case 'u':
+ do_unlock = 1;
+ break;
+
+ case 'V':
+ show_version = 1;
+ break;
+
+ default:
+ fprintf(stderr, "unknown option character %c\n",
+ optopt);
+ /*fallthru*/
+ case 'h':
+ usage(stdout);
+ return -1;
+ }
+ }
+
+ /*
+ if (show_version) {
+ printf ( "jackd version " VERSION
+ " tmpdir " DEFAULT_TMP_DIR
+ " protocol " PROTOCOL_VERSION
+ "\n");
+ return -1;
+ }
+ */
+
+ if (!seen_driver) {
+ usage (stderr);
+ exit (1);
+ }
+
+ drivers = jack_drivers_load (drivers);
+ if (!drivers) {
+ fprintf (stderr, "jackdmp: no drivers found; exiting\n");
+ exit (1);
+ }
+
+ driver_desc = jack_find_driver_descriptor (drivers, driver_name);
+ if (!driver_desc) {
+ fprintf (stderr, "jackdmp: unknown driver '%s'\n", driver_name);
+ exit (1);
+ }
+
+ if (optind < argc) {
+ driver_nargs = 1 + argc - optind;
+ } else {
+ driver_nargs = 1;
+ }
+
+ if (driver_nargs == 0) {
+ fprintf (stderr, "No driver specified ... hmm. JACK won't do"
+ " anything when run like this.\n");
+ return -1;
+ }
+
+ driver_args = (char **) malloc (sizeof (char *) * driver_nargs);
+ driver_args[0] = driver_name;
+
+ for (i = 1; i < driver_nargs; i++) {
+ driver_args[i] = argv[optind++];
+ }
+
+ if (jack_parse_driver_params (driver_desc, driver_nargs,
+ driver_args, &driver_params)) {
+ exit (0);
+ }
+
+ if (server_name == NULL)
+ server_name = jack_default_server_name ();
+
+ copyright (stdout);
+
+ rc = jack_register_server (server_name);
+ switch (rc) {
+ case EEXIST:
+ fprintf (stderr, "`%s' server already active\n", server_name);
+ exit (1);
+ case ENOSPC:
+ fprintf (stderr, "too many servers already active\n");
+ exit (2);
+ case ENOMEM:
+ fprintf (stderr, "no access to shm registry\n");
+ exit (3);
+ default:
+ if (verbose)
+ fprintf (stderr, "server `%s' registered\n",
+ server_name);
+ }
+
+ /* clean up shared memory and files from any previous
+ * instance of this server name */
+ jack_cleanup_shm();
+ jack_cleanup_files(server_name);
+
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+ sigemptyset(&signals);
+ sigaddset(&signals, SIGHUP);
+ sigaddset(&signals, SIGINT);
+ sigaddset(&signals, SIGQUIT);
+ sigaddset(&signals, SIGPIPE);
+ sigaddset(&signals, SIGTERM);
+ sigaddset(&signals, SIGUSR1);
+ sigaddset(&signals, SIGUSR2);
+
+ // all child threads will inherit this mask unless they
+ // explicitly reset it
+
+ FilterSIGPIPE();
+ pthread_sigmask(SIG_BLOCK, &signals, 0);
+
+ if (!realtime && client_timeout == 0)
+ client_timeout = 500; /* 0.5 sec; usable when non realtime. */
+
+ int res = JackStart(driver_desc, driver_params, sync, client_timeout, realtime, realtime_priority, loopback, verbose);
+ if (res < 0) {
+ jack_error("Cannot start server... exit");
+ JackDelete();
+ return 0;
+ }
+
+ /*
+ For testing purpose...
+ InternalMetro* client1 = new InternalMetro(1200, 0.4, 20, 80, "metro1");
+ InternalMetro* client2 = new InternalMetro(600, 0.4, 20, 150, "metro2");
+ InternalMetro* client3 = new InternalMetro(1000, 0.4, 20, 110, "metro3");
+ InternalMetro* client4 = new InternalMetro(1200, 0.4, 20, 80, "metro4");
+ InternalMetro* client5 = new InternalMetro(1500, 0.4, 20, 60, "metro5");
+ InternalMetro* client6 = new InternalMetro(1200, 0.4, 20, 84, "metro6");
+ InternalMetro* client7 = new InternalMetro(600, 0.4, 20, 160, "metro7");
+ InternalMetro* client8 = new InternalMetro(1000, 0.4, 20, 113, "metro8");
+ InternalMetro* client9 = new InternalMetro(1200, 0.4, 20, 84, "metro9");
+ InternalMetro* client10 = new InternalMetro(1500, 0.4, 20, 70, "metro10");
+ */
+
+ // install a do-nothing handler because otherwise pthreads
+ // behaviour is undefined when we enter sigwait.
+
+ sigfillset(&allsignals);
+ action.sa_handler = DoNothingHandler;
+ action.sa_mask = allsignals;
+ action.sa_flags = SA_RESTART | SA_RESETHAND;
+
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&signals, i)) {
+ sigaction(i, &action, 0);
+ }
+ }
+
+ waiting = TRUE;
+
+ while (waiting) {
+ sigwait(&signals, &sig);
+
+ fprintf(stderr, "jack main caught signal %d\n", sig);
+
+ switch (sig) {
+ case SIGUSR1:
+ //jack_dump_configuration(engine, 1);
+ break;
+ case SIGUSR2:
+ // driver exit
+ waiting = FALSE;
+ break;
+ default:
+ waiting = FALSE;
+ break;
+ }
+ }
+
+ if (sig != SIGSEGV) {
+ // unblock signals so we can see them during shutdown.
+ // this will help prod developers not to lose sight of
+ // bugs that cause segfaults etc. during shutdown.
+ sigprocmask(SIG_UNBLOCK, &signals, 0);
+ }
+
+ JackStop();
+
+ jack_cleanup_shm();
+ jack_cleanup_files(server_name);
+ jack_unregister_server(server_name);
+
+ return 1;
+}
+
+#else
+
+int main(int argc, char* argv[])
+{
+ char c;
+ long sample_sate = lopt(argv, "-r", 44100);
+ long buffer_size = lopt(argv, "-p", 512);
+ long chan_in = lopt(argv, "-i", 2);
+ long chan_out = lopt(argv, "-o", 2);
+ long audiodevice = lopt(argv, "-I", -1);
+ long sync = lopt(argv, "-s", 0);
+ long timeout = lopt(argv, "-t", 100 * 1000);
+ const char* name = flag(argv, "-n", "Built-in Audio");
+ long rt = lopt(argv, "-R", 0);
+ verbose = lopt(argv, "-v", 0);
+
+ copyright(stdout);
+ usage(stdout);
+
+ FilterSIGPIPE();
+
+ printf("jackdmp: sample_sate = %ld buffer_size = %ld chan_in = %ld chan_out = %ld name = %s sync-mode = %ld\n",
+ sample_sate, buffer_size, chan_in, chan_out, name, sync);
+ assert(buffer_size <= BUFFER_SIZE_MAX);
+
+ int res = JackStart(sample_sate, buffer_size, chan_in, chan_out, name, audiodevice, sync, timeout, rt);
+ if (res < 0) {
+ jack_error("Cannot start server... exit\n");
+ JackDelete();
+ return 0;
+ }
+
+ while (((c = getchar()) != 'q')) {
+
+ switch (c) {
+
+ case 's':
+ fServer->PrintState();
+ break;
+ }
+ }
+
+ JackStop();
+ return 0;
+}
+
+#endif
diff --git a/common/cycles.h b/common/cycles.h
new file mode 100644
index 00000000..96dcbb4d
--- /dev/null
+++ b/common/cycles.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Code derived from various headers from the Linux kernel
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: cycles.h,v 1.4.2.1 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_cycles_h__
+#define __jack_cycles_h__
+
+/*
+ * Standard way to access the cycle counter on i586+ CPUs.
+ * Currently only used on SMP.
+ *
+ * If you really have a SMP machine with i486 chips or older,
+ * compile for that, and this will just always return zero.
+ * That's ok, it just means that the nicer scheduling heuristics
+ * won't work for you.
+ *
+ * We only use the low 32 bits, and we'd simply better make sure
+ * that we reschedule before that wraps. Scheduling at least every
+ * four billion cycles just basically sounds like a good idea,
+ * regardless of how fast the machine is.
+ */
+
+#ifdef __linux__
+
+#ifdef __PPC__
+
+/* PowerPC */
+
+#define CPU_FTR_601 0x00000100
+
+typedef unsigned long cycles_t;
+
+/* For the "cycle" counter we use the timebase lower half. */
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles(void)
+{
+ cycles_t ret = 0;
+
+ __asm__ __volatile__(
+ "98: mftb %0\n"
+ "99:\n"
+ ".section __ftr_fixup,\"a\"\n"
+ " .long %1\n"
+ " .long 0\n"
+ " .long 98b\n"
+ " .long 99b\n"
+ ".previous"
+ : "=r" (ret) : "i" (CPU_FTR_601));
+ return ret;
+}
+
+#endif
+
+#ifdef __i386__
+
+typedef unsigned long long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+#define rdtscll(val) \
+ __asm__ __volatile__("rdtsc" : "=A" (val))
+
+static inline cycles_t get_cycles (void)
+{
+ unsigned long long ret;
+
+ rdtscll(ret);
+ return ret;
+}
+
+#endif
+
+#endif
+
+#endif /* __jack_cycles_h__ */
diff --git a/common/driver_interface.h b/common/driver_interface.h
new file mode 100644
index 00000000..13a642d6
--- /dev/null
+++ b/common/driver_interface.h
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2003 Bob Ham <rah@bash.sh>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __jack_driver_interface_h__
+#define __jack_driver_interface_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <limits.h>
+
+#ifdef WIN32
+#include "types.h"
+#define PATH_MAX 1024
+#else
+#include <inttypes.h>
+#endif
+
+
+#define JACK_DRIVER_NAME_MAX 15
+#define JACK_DRIVER_PARAM_NAME_MAX 15
+#define JACK_DRIVER_PARAM_STRING_MAX 63
+
+ /** Driver parameter types */
+ typedef enum
+ {
+ JackDriverParamInt = 1,
+ JackDriverParamUInt,
+ JackDriverParamChar,
+ JackDriverParamString,
+ JackDriverParamBool
+ } jack_driver_param_type_t;
+
+ /** Driver parameter value */
+ typedef union
+ {
+ uint32_t ui;
+ int32_t i;
+ char c;
+ char str[JACK_DRIVER_PARAM_STRING_MAX + 1];
+ } jack_driver_param_value_t;
+
+
+ /** A driver parameter descriptor */
+ typedef struct {
+ char name[JACK_DRIVER_NAME_MAX + 1]; /**< The parameter's name */
+ char character; /**< The parameter's character (for getopt, etc) */
+ jack_driver_param_type_t type; /**< The parameter's type */
+ jack_driver_param_value_t value; /**< The parameter's (default) value */
+ char short_desc[64]; /**< A short (~30 chars) description for the user */
+ char long_desc[1024]; /**< A longer description for the user */
+ }
+ jack_driver_param_desc_t;
+
+ /** A driver parameter */
+ typedef struct {
+ char character;
+ jack_driver_param_value_t value;
+ }
+ jack_driver_param_t;
+
+
+ /** A struct for describing a jack driver */
+ typedef struct {
+ char name[JACK_DRIVER_NAME_MAX + 1]; /**< The driver's canonical name */
+ char file[PATH_MAX + 1]; /**< The filename of the driver's shared object file */
+ uint32_t nparams; /**< The number of parameters the driver has */
+ jack_driver_param_desc_t * params; /**< An array of parameter descriptors */
+ }
+ jack_driver_desc_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_driver_interface_h__ */
+
+
diff --git a/common/driver_parse.h b/common/driver_parse.h
new file mode 100644
index 00000000..67a20109
--- /dev/null
+++ b/common/driver_parse.h
@@ -0,0 +1,33 @@
+/*
+Copyright (C) 2003 Bob Ham <rah@bash.sh
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __jack_driver_parse_h__
+#define __jack_driver_parse_h__
+
+#include "jslist.h"
+#include "driver_interface.h"
+#include "JackExports.h"
+
+EXPORT int
+jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr);
+
+
+#endif /* __jack_driver_parse_h__ */
+
+
diff --git a/common/intclient.h b/common/intclient.h
new file mode 100644
index 00000000..8e87f6d8
--- /dev/null
+++ b/common/intclient.h
@@ -0,0 +1,132 @@
+/*
+* Copyright (C) 2004 Jack O'Quin
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 of the License, or
+* (at your option) any later version.
+*
+* This program 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* $Id: intclient.h,v 1.2.2.1 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_intclient_h__
+#define __jack_intclient_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ //#include <jack/types.h>
+#include "types.h"
+
+ /**
+ * Get an internal client's name. This is useful when @ref
+ * JackUseExactName was not specified on jack_internal_client_load()
+ * and @ref JackNameNotUnique status was returned. In that case, the
+ * actual name will differ from the @a client_name requested.
+ *
+ * @param client requesting JACK client's handle.
+ *
+ * @param intclient handle returned from jack_internal_client_load()
+ * or jack_internal_client_handle().
+ *
+ * @return NULL if unsuccessful, otherwise pointer to the internal
+ * client name obtained from the heap via malloc(). The caller should
+ * free() this storage when no longer needed.
+ */
+ char *jack_get_internal_client_name (jack_client_t *client,
+ jack_intclient_t intclient);
+
+ /**
+ * Return the @ref jack_intclient_t handle for an internal client
+ * running in the JACK server.
+ *
+ * @param client requesting JACK client's handle.
+ *
+ * @param client_name for the internal client of no more than
+ * jack_client_name_size() characters. The name scope is local to the
+ * current server.
+ *
+ * @param status (if non-NULL) an address for JACK to return
+ * information from this operation. This status word is formed by
+ * OR-ing together the relevant @ref JackStatus bits.
+ *
+ * @return Opaque internal client handle if successful. If 0, the
+ * internal client was not found, and @a *status includes the @ref
+ * JackNoSuchClient and @ref JackFailure bits.
+ */
+ jack_intclient_t jack_internal_client_handle (jack_client_t *client,
+ const char *client_name,
+ jack_status_t *status);
+
+ /**
+ * Load an internal client into the JACK server.
+ *
+ * Internal clients run inside the JACK server process. They can use
+ * most of the same functions as external clients. Each internal
+ * client is built as a shared object module, which must declare
+ * jack_initialize() and jack_finish() entry points called at load and
+ * unload times. See @ref inprocess.c for an example.
+ *
+ * @param client loading JACK client's handle.
+ *
+ * @param client_name of at most jack_client_name_size() characters
+ * for the internal client to load. The name scope is local to the
+ * current server.
+ *
+ * @param options formed by OR-ing together @ref JackOptions bits.
+ * Only the @ref JackLoadOptions bits are valid.
+ *
+ * @param status (if non-NULL) an address for JACK to return
+ * information from the load operation. This status word is formed by
+ * OR-ing together the relevant @ref JackStatus bits.
+ *
+ * <b>Optional parameters:</b> depending on corresponding [@a options
+ * bits] additional parameters may follow @a status (in this order).
+ *
+ * @arg [@ref JackLoadName] <em>(char *) load_name</em> is the shared
+ * object file from which to load the new internal client (otherwise
+ * use the @a client_name).
+ *
+ * @arg [@ref JackLoadInit] <em>(char *) load_init</em> an arbitary
+ * string passed to the internal client's jack_initialize() routine
+ * (otherwise NULL), of no more than @ref JACK_LOAD_INIT_LIMIT bytes.
+ *
+ * @return Opaque internal client handle if successful. If this is 0,
+ * the load operation failed, the internal client was not loaded, and
+ * @a *status includes the @ref JackFailure bit.
+ */
+ jack_intclient_t jack_internal_client_load (jack_client_t *client,
+ const char *client_name,
+ jack_options_t options,
+ jack_status_t *status, ...);
+ /**
+ * Unload an internal client from a JACK server. This calls the
+ * intclient's jack_finish() entry point then removes it. See @ref
+ * inprocess.c for an example.
+ *
+ * @param client unloading JACK client's handle.
+ *
+ * @param intclient handle returned from jack_internal_client_load() or
+ * jack_internal_client_handle().
+ *
+ * @return 0 if successful, otherwise @ref JackStatus bits.
+ */
+ jack_status_t jack_internal_client_unload (jack_client_t *client,
+ jack_intclient_t intclient);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_intclient_h__ */
diff --git a/common/jack.h b/common/jack.h
new file mode 100644
index 00000000..1fb97c8e
--- /dev/null
+++ b/common/jack.h
@@ -0,0 +1,805 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004 Jack O'Quin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: jack.h,v 1.5.2.6 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_h__
+#define __jack_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef WIN32
+ #include <windows.h>
+ typedef HANDLE pthread_t;
+#else
+ #include <pthread.h>
+#endif
+
+ /*
+ #include <jack/types.h>
+ #include <jack/transport.h>
+ */
+
+#include "types.h"
+#include "transport.h"
+
+ /**
+ * Note: More documentation can be found in jack/types.h.
+ */
+
+ /**
+ * Open an external client session with a JACK server. This interface
+ * is more complex but more powerful than jack_client_new(). With it,
+ * clients may choose which of several servers to connect, and control
+ * whether and how to start the server automatically, if it was not
+ * already running. There is also an option for JACK to generate a
+ * unique client name, when necessary.
+ *
+ * @param client_name of at most jack_client_name_size() characters.
+ * The name scope is local to each server. Unless forbidden by the
+ * @ref JackUseExactName option, the server will modify this name to
+ * create a unique variant, if needed.
+ *
+ * @param options formed by OR-ing together @ref JackOptions bits.
+ * Only the @ref JackOpenOptions bits are allowed.
+ *
+ * @param status (if non-NULL) an address for JACK to return
+ * information from the open operation. This status word is formed by
+ * OR-ing together the relevant @ref JackStatus bits.
+ *
+ *
+ * <b>Optional parameters:</b> depending on corresponding [@a options
+ * bits] additional parameters may follow @a status (in this order).
+ *
+ * @arg [@ref JackServerName] <em>(char *) server_name</em> selects
+ * from among several possible concurrent server instances. Server
+ * names are unique to each user. If unspecified, use "default"
+ * unless \$JACK_DEFAULT_SERVER is defined in the process environment.
+ *
+ * @return Opaque client handle if successful. If this is NULL, the
+ * open operation failed, @a *status includes @ref JackFailure and the
+ * caller is not a JACK client.
+ */
+ jack_client_t * jack_client_open (const char *client_name,
+ jack_options_t options,
+ jack_status_t *status, ...);
+
+ /**
+ * Attempt to become an external client of the Jack server.
+ *
+ * JACK is evolving a mechanism for automatically starting the server
+ * when needed. As a transition, jack_client_new() only does this
+ * when \$JACK_START_SERVER is defined in the environment of the
+ * calling process. In the future this will become normal behavior.
+ * For full control of this feature, use jack_client_open(), instead.
+ * In either case, defining \$JACK_NO_START_SERVER disables this
+ * feature.
+ *
+ * @param client_name of at most jack_client_name_size() characters.
+ * If this name is already in use, the request fails.
+ *
+ * @return Opaque client handle if successful, otherwise NULL.
+ *
+ * @note Failure generally means that the JACK server is not running.
+ * If there was some other problem, it will be reported via the @ref
+ * jack_error_callback mechanism. Use jack_client_open() and check
+ * the @a status parameter for more detailed information.
+ */
+ jack_client_t * jack_client_new (const char *client_name);
+
+ /**
+ * Disconnects an external client from a JACK server.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_client_close (jack_client_t *client);
+
+ /**
+ * @return the maximum number of characters in a JACK client name
+ * including the final NULL character. This value is a constant.
+ */
+ int jack_client_name_size (void);
+
+ /**
+ * @return pointer to actual client name. This is useful when @ref
+ * JackUseExactName is not specified on open and @ref
+ * JackNameNotUnique status was returned. In that case, the actual
+ * name will differ from the @a client_name requested.
+ */
+ char * jack_get_client_name (jack_client_t *client);
+
+ /**
+ * Load an internal client into the Jack server.
+ *
+ * Internal clients run inside the JACK server process. They can use
+ * most of the same functions as external clients. Each internal
+ * client must declare jack_initialize() and jack_finish() entry
+ * points, called at load and unload times. See inprocess.c for an
+ * example of how to write an internal client.
+ *
+ * @deprecated Please use jack_internal_client_load().
+ *
+ * @param client_name of at most jack_client_name_size() characters.
+ *
+ * @param load_name of a shared object file containing the code for
+ * the new client.
+ *
+ * @param load_init an arbitary string passed to the jack_initialize()
+ * routine of the new client (may be NULL).
+ *
+ * @return 0 if successful.
+ */
+ int jack_internal_client_new (const char *client_name,
+ const char *load_name,
+ const char *load_init);
+
+ jack_client_t* my_jack_internal_client_new(const char* client_name);
+
+ /**
+ * Remove an internal client from a JACK server.
+ *
+ * @deprecated Please use jack_internal_client_load().
+ */
+ void jack_internal_client_close (const char *client_name);
+
+ void my_jack_internal_client_close (jack_client_t* client);
+
+ /**
+ * @param client pointer to JACK client structure.
+ *
+ * Check if the JACK subsystem is running with -R (--realtime).
+ *
+ * @return 1 if JACK is running realtime, 0 otherwise
+ */
+ int jack_is_realtime (jack_client_t *client);
+
+ /**
+ * @param client pointer to JACK client structure.
+ * @param function The jack_shutdown function pointer.
+ * @param arg The arguments for the jack_shutdown function.
+ *
+ * Register a function (and argument) to be called if and when the
+ * JACK server shuts down the client thread. The function must
+ * be written as if it were an asynchonrous POSIX signal
+ * handler --- use only async-safe functions, and remember that it
+ * is executed from another thread. A typical function might
+ * set a flag or write to a pipe so that the rest of the
+ * application knows that the JACK client thread has shut
+ * down.
+ *
+ * NOTE: clients do not need to call this. It exists only
+ * to help more complex clients understand what is going
+ * on. It should be called before jack_client_activate().
+ */
+ void jack_on_shutdown (jack_client_t *client,
+ void (*function)(void *arg), void *arg);
+
+ /**
+ * Tell the Jack server to call @a process_callback whenever there is
+ * work be done, passing @a arg as the second argument.
+ *
+ * The code in the supplied function must be suitable for real-time
+ * execution. That means that it cannot call functions that might
+ * block for a long time.  This includes malloc, free, printf,
+ * pthread_mutex_lock, sleep, wait, poll, select, pthread_join,
+ * pthread_cond_wait, etc, etc.  See
+ * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000
+ * for more information.
+ *
+ * @return 0 on success, otherwise a non-zero error code, causing JACK
+ * to remove that client from the process() graph.
+ */
+ int jack_set_process_callback (jack_client_t *client,
+ JackProcessCallback process_callback,
+ void *arg);
+
+ /**
+ * Tell JACK to call @a thread_init_callback once just after
+ * the creation of the thread in which all other callbacks
+ * will be handled.
+ *
+ * The code in the supplied function does not need to be
+ * suitable for real-time execution.
+ *
+ * @return 0 on success, otherwise a non-zero error code, causing JACK
+ * to remove that client from the process() graph.
+ */
+ int jack_set_thread_init_callback (jack_client_t *client,
+ JackThreadInitCallback thread_init_callback,
+ void *arg);
+
+ /**
+ * Tell the Jack server to call @a freewheel_callback
+ * whenever we enter or leave "freewheel" mode, passing @a
+ * arg as the second argument. The first argument to the
+ * callback will be non-zero if JACK is entering freewheel
+ * mode, and zero otherwise.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ */
+ int jack_set_freewheel_callback (jack_client_t *client,
+ JackFreewheelCallback freewheel_callback,
+ void *arg);
+
+ /**
+ * Start/Stop JACK's "freewheel" mode.
+ *
+ * When in "freewheel" mode, JACK no longer waits for
+ * any external event to begin the start of the next process
+ * cycle.
+ *
+ * As a result, freewheel mode causes "faster than realtime"
+ * execution of a JACK graph. If possessed, real-time
+ * scheduling is dropped when entering freewheel mode, and
+ * if appropriate it is reacquired when stopping.
+ *
+ * IMPORTANT: on systems using capabilities to provide real-time
+ * scheduling (i.e. Linux kernel 2.4), if onoff is zero, this function
+ * must be called from the thread that originally called jack_activate().
+ * This restriction does not apply to other systems (e.g. Linux kernel 2.6
+ * or OS X).
+ *
+ * @param client pointer to JACK client structure
+ * @param onoff if non-zero, freewheel mode starts. Otherwise
+ * freewheel mode ends.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ */
+ int jack_set_freewheel(jack_client_t* client, int onoff);
+
+ /**
+ * Change the buffer size passed to the @a process_callback.
+ *
+ * This operation stops the JACK engine process cycle, then calls all
+ * registered @a bufsize_callback functions before restarting the
+ * process cycle. This will cause a gap in the audio flow, so it
+ * should only be done at appropriate stopping points.
+ *
+ * @see jack_set_buffer_size_callback()
+ *
+ * @param client pointer to JACK client structure.
+ * @param nframes new buffer size. Must be a power of two.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes);
+
+ /**
+ * Tell JACK to call @a bufsize_callback whenever the size of the the
+ * buffer that will be passed to the @a process_callback is about to
+ * change. Clients that depend on knowing the buffer size must supply
+ * a @a bufsize_callback before activating themselves.
+ *
+ * @param client pointer to JACK client structure.
+ * @param bufsize_callback function to call when the buffer size changes.
+ * @param arg argument for @a bufsize_callback.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_set_buffer_size_callback (jack_client_t *client,
+ JackBufferSizeCallback bufsize_callback,
+ void *arg);
+
+ /**
+ * Tell the Jack server to call @a srate_callback whenever the system
+ * sample rate changes.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_set_sample_rate_callback (jack_client_t *client,
+ JackSampleRateCallback srate_callback,
+ void *arg);
+
+ /**
+ * Tell the JACK server to call @a registration_callback whenever a
+ * port is registered or unregistered, passing @a arg as a parameter.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_set_port_registration_callback (jack_client_t *,
+ JackPortRegistrationCallback
+ registration_callback, void *arg);
+
+ /**
+ * Tell the JACK server to call @a graph_callback whenever the
+ * processing graph is reordered, passing @a arg as a parameter.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_set_graph_order_callback (jack_client_t *,
+ JackGraphOrderCallback graph_callback,
+ void *);
+
+ /**
+ * Tell the JACK server to call @a xrun_callback whenever there is a
+ * xrun, passing @a arg as a parameter.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_set_xrun_callback (jack_client_t *,
+ JackXRunCallback xrun_callback, void *arg);
+
+ /**
+ * Tell the Jack server that the program is ready to start processing
+ * audio.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_activate (jack_client_t *client);
+
+ /**
+ * Tell the Jack server to remove this @a client from the process
+ * graph. Also, disconnect all ports belonging to it, since inactive
+ * clients have no port connections.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_deactivate (jack_client_t *client);
+
+ /**
+ * Create a new port for the client. This is an object used for moving
+ * data of any type in or out of the client. Ports may be connected
+ * in various ways.
+ *
+ * Each port has a short name. The port's full name contains the name
+ * of the client concatenated with a colon (:) followed by its short
+ * name. The jack_port_name_size() is the maximum length of this full
+ * name. Exceeding that will cause the port registration to fail and
+ * return NULL.
+ *
+ * All ports have a type, which may be any non-NULL and non-zero
+ * length string, passed as an argument. Some port types are built
+ * into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE.
+ *
+ * @param client pointer to JACK client structure.
+ * @param port_name non-empty short name for the new port (not
+ * including the leading @a "client_name:").
+ * @param port_type port type name. If longer than
+ * jack_port_type_size(), only that many characters are significant.
+ * @param flags @ref JackPortFlags bit mask.
+ * @param buffer_size must be non-zero if this is not a built-in @a
+ * port_type. Otherwise, it is ignored.
+ *
+ * @return jack_port_t pointer on success, otherwise NULL.
+ */
+ jack_port_t * jack_port_register (jack_client_t *client,
+ const char *port_name,
+ const char *port_type,
+ unsigned long flags,
+ unsigned long buffer_size);
+
+ /**
+ * Remove the port from the client, disconnecting any existing
+ * connections.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_port_unregister (jack_client_t *, jack_port_t *);
+
+ /**
+ * This returns a pointer to the memory area associated with the
+ * specified port. For an output port, it will be a memory area
+ * that can be written to; for an input port, it will be an area
+ * containing the data from the port's connection(s), or
+ * zero-filled. if there are multiple inbound connections, the data
+ * will be mixed appropriately.
+ *
+ * FOR OUTPUT PORTS ONLY
+ * ---------------------
+ * You may cache the value returned, but only between calls to
+ * your "blocksize" callback. For this reason alone, you should
+ * either never cache the return value or ensure you have
+ * a "blocksize" callback and be sure to invalidate the cached
+ * address from there.
+ */
+ void * jack_port_get_buffer (jack_port_t *, jack_nframes_t);
+
+ /**
+ * @return the full name of the jack_port_t (including the @a
+ * "client_name:" prefix).
+ *
+ * @see jack_port_name_size().
+ */
+ const char * jack_port_name (const jack_port_t *port);
+
+ /**
+ * @return the short name of the jack_port_t (not including the @a
+ * "client_name:" prefix).
+ *
+ * @see jack_port_name_size().
+ */
+ const char * jack_port_short_name (const jack_port_t *port);
+
+ /**
+ * @return the @ref JackPortFlags of the jack_port_t.
+ */
+ int jack_port_flags (const jack_port_t *port);
+
+ /**
+ * @return the @a port type, at most jack_port_type_size() characters
+ * including a final NULL.
+ */
+ const char * jack_port_type (const jack_port_t *port);
+
+ /**
+ * @return TRUE if the jack_port_t belongs to the jack_client_t.
+ */
+ int jack_port_is_mine (const jack_client_t *, const jack_port_t *port);
+
+ /**
+ * @return number of connections to or from @a port.
+ *
+ * @pre The calling client must own @a port.
+ */
+ int jack_port_connected (const jack_port_t *port);
+
+ /**
+ * @return TRUE if the locally-owned @a port is @b directly connected
+ * to the @a port_name.
+ *
+ * @see jack_port_name_size()
+ */
+ int jack_port_connected_to (const jack_port_t *port,
+ const char *port_name);
+
+ /**
+ * @return a null-terminated array of full port names to which the @a
+ * port is connected. If none, returns NULL.
+ *
+ * The caller is responsible for calling free(3) on any non-NULL
+ * returned value.
+ *
+ * @param port locally owned jack_port_t pointer.
+ *
+ * @see jack_port_name_size(), jack_port_get_all_connections()
+ */
+ const char ** jack_port_get_connections (const jack_port_t *port);
+
+ /**
+ * @return a null-terminated array of full port names to which the @a
+ * port is connected. If none, returns NULL.
+ *
+ * The caller is responsible for calling free(3) on any non-NULL
+ * returned value.
+ *
+ * This differs from jack_port_get_connections() in two important
+ * respects:
+ *
+ * 1) You may not call this function from code that is
+ * executed in response to a JACK event. For example,
+ * you cannot use it in a GraphReordered handler.
+ *
+ * 2) You need not be the owner of the port to get information
+ * about its connections.
+ *
+ * @see jack_port_name_size()
+ */
+ const char ** jack_port_get_all_connections (const jack_client_t *client,
+ const jack_port_t *port);
+
+ /**
+ * A client may call this on a pair of its own ports to
+ * semi-permanently wire them together. This means that
+ * a client that wants to direct-wire an input port to
+ * an output port can call this and then no longer
+ * have to worry about moving data between them. Any data
+ * arriving at the input port will appear automatically
+ * at the output port.
+ *
+ * The 'destination' port must be an output port. The 'source'
+ * port must be an input port. Both ports must belong to
+ * the same client. You cannot use this to tie ports between
+ * clients. That is what a connection is for.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_port_tie (jack_port_t *src, jack_port_t *dst);
+
+ /**
+ * This undoes the effect of jack_port_tie(). The port
+ * should be same as the 'destination' port passed to
+ * jack_port_tie().
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_port_untie (jack_port_t *port);
+
+ /**
+ * A client may call this function to prevent other objects
+ * from changing the connection status of a port. The port
+ * must be owned by the calling client.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_port_lock (jack_client_t *, jack_port_t *);
+
+ /**
+ * This allows other objects to change the connection status of a port.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_port_unlock (jack_client_t *, jack_port_t *);
+
+ /**
+ * @return the time (in frames) between data being available or
+ * delivered at/to a port, and the time at which it arrived at or is
+ * delivered to the "other side" of the port. E.g. for a physical
+ * audio output port, this is the time between writing to the port and
+ * when the signal will leave the connector. For a physical audio
+ * input port, this is the time between the sound arriving at the
+ * connector and the corresponding frames being readable from the
+ * port.
+ */
+ jack_nframes_t jack_port_get_latency (jack_port_t *port);
+
+ /**
+ * The maximum of the sum of the latencies in every
+ * connection path that can be drawn between the port and other
+ * ports with the @ref JackPortIsTerminal flag set.
+ */
+ jack_nframes_t jack_port_get_total_latency (jack_client_t *,
+ jack_port_t *port);
+
+ /**
+ * The port latency is zero by default. Clients that control
+ * physical hardware with non-zero latency should call this
+ * to set the latency to its correct value. Note that the value
+ * should include any systemic latency present "outside" the
+ * physical hardware controlled by the client. For example,
+ * for a client controlling a digital audio interface connected
+ * to an external digital converter, the latency setting should
+ * include both buffering by the audio interface *and* the converter.
+ */
+ void jack_port_set_latency (jack_port_t *, jack_nframes_t);
+
+ /**
+ *
+ */
+ int jack_recompute_total_latencies (jack_client_t*);
+
+ /**
+ * Modify a port's short name. May be called at any time. If the
+ * resulting full name (including the @a "client_name:" prefix) is
+ * longer than jack_port_name_size(), it will be truncated.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ */
+ int jack_port_set_name (jack_port_t *port, const char *port_name);
+
+ /**
+ * If @ref JackPortCanMonitor is set for this @a port, turn input
+ * monitoring on or off. Otherwise, do nothing.
+ */
+ int jack_port_request_monitor (jack_port_t *port, int onoff);
+
+ /**
+ * If @ref JackPortCanMonitor is set for this @a port_name, turn input
+ * monitoring on or off. Otherwise, do nothing.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ *
+ * @see jack_port_name_size()
+ */
+ int jack_port_request_monitor_by_name (jack_client_t *client,
+ const char *port_name, int onoff);
+
+ /**
+ * If @ref JackPortCanMonitor is set for a port, this function turns
+ * on input monitoring if it was off, and turns it off if only one
+ * request has been made to turn it on. Otherwise it does nothing.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_port_ensure_monitor (jack_port_t *port, int onoff);
+
+ /**
+ * @return TRUE if input monitoring has been requested for @a port.
+ */
+ int jack_port_monitoring_input (jack_port_t *port);
+
+ /**
+ * Establish a connection between two ports.
+ *
+ * When a connection exists, data written to the source port will
+ * be available to be read at the destination port.
+ *
+ * @pre The port types must be identical.
+ *
+ * @pre The @ref JackPortFlags of the @a source_port must include @ref
+ * JackPortIsOutput.
+ *
+ * @pre The @ref JackPortFlags of the @a destination_port must include
+ * @ref JackPortIsInput.
+ *
+ * @return 0 on success, EEXIST if the connection is already made,
+ * otherwise a non-zero error code
+ */
+ int jack_connect (jack_client_t *,
+ const char *source_port,
+ const char *destination_port);
+
+ /**
+ * Remove a connection between two ports.
+ *
+ * @pre The port types must be identical.
+ *
+ * @pre The @ref JackPortFlags of the @a source_port must include @ref
+ * JackPortIsOutput.
+ *
+ * @pre The @ref JackPortFlags of the @a destination_port must include
+ * @ref JackPortIsInput.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+ int jack_disconnect (jack_client_t *,
+ const char *source_port,
+ const char *destination_port);
+
+ /**
+ * Perform the same function as jack_disconnect() using port handles
+ * rather than names. This avoids the name lookup inherent in the
+ * name-based version.
+ *
+ * Clients connecting their own ports are likely to use this function,
+ * while generic connection clients (e.g. patchbays) would use
+ * jack_disconnect().
+ */
+ int jack_port_disconnect (jack_client_t *, jack_port_t *);
+
+ /**
+ * @return the maximum number of characters in a full JACK port name
+ * including the final NULL character. This value is a constant.
+ *
+ * A port's full name contains the owning client name concatenated
+ * with a colon (:) followed by its short name and a NULL
+ * character.
+ */
+ int jack_port_name_size(void);
+
+ /**
+ * @return the maximum number of characters in a JACK port type name
+ * including the final NULL character. This value is a constant.
+ */
+ int jack_port_type_size(void);
+
+ /**
+ * @return the sample rate of the jack system, as set by the user when
+ * jackd was started.
+ */
+ jack_nframes_t jack_get_sample_rate (jack_client_t *);
+
+ /**
+ * @return the current maximum size that will ever be passed to the @a
+ * process_callback. It should only be used *before* the client has
+ * been activated. This size may change, clients that depend on it
+ * must register a @a bufsize_callback so they will be notified if it
+ * does.
+ *
+ * @see jack_set_buffer_size_callback()
+ */
+ jack_nframes_t jack_get_buffer_size (jack_client_t *);
+
+ /**
+ * @param port_name_pattern A regular expression used to select
+ * ports by name. If NULL or of zero length, no selection based
+ * on name will be carried out.
+ * @param type_name_pattern A regular expression used to select
+ * ports by type. If NULL or of zero length, no selection based
+ * on type will be carried out.
+ * @param flags A value used to select ports by their flags.
+ * If zero, no selection based on flags will be carried out.
+ *
+ * @return a NULL-terminated array of ports that match the specified
+ * arguments. The caller is responsible for calling free(3) any
+ * non-NULL returned value.
+ *
+ * @see jack_port_name_size(), jack_port_type_size()
+ */
+ const char ** jack_get_ports (jack_client_t *,
+ const char *port_name_pattern,
+ const char *type_name_pattern,
+ unsigned long flags);
+
+ /**
+ * @return address of the jack_port_t named @a port_name.
+ *
+ * @see jack_port_name_size()
+ */
+ jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name);
+
+ /**
+ * @return address of the jack_port_t of a @a port_id.
+ */
+ jack_port_t * jack_port_by_id (jack_client_t *client,
+ jack_port_id_t port_id);
+
+ /**
+ * Old-style interface to become the timebase for the entire JACK
+ * subsystem.
+ *
+ * @deprecated This function still exists for compatibility with the
+ * earlier transport interface, but it does nothing. Instead, see
+ * transport.h and use jack_set_timebase_callback().
+ *
+ * @return ENOSYS, function not implemented.
+ */
+ int jack_engine_takeover_timebase (jack_client_t *);
+
+ /**
+ * @return the time in frames that has passed since the JACK server
+ * began the current process cycle.
+ */
+ jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *);
+
+ /**
+ * @return an estimate of the current time in frames. This is a
+ * running counter, no significance should be attached to its value,
+ * but it can be compared to a previously returned value.
+ */
+ jack_nframes_t jack_frame_time (const jack_client_t *);
+
+ /**
+ * @return the frame_time after the last processing of the graph
+ * this is only to be used from the process callback.
+ *
+ * This function can be used to put timestamps generated by
+ * jack_frame_time() in correlation to the current process cycle.
+ */
+ jack_nframes_t jack_last_frame_time (const jack_client_t *client);
+
+ /**
+ * @return the current CPU load estimated by JACK. This is a running
+ * average of the time it takes to execute a full process cycle for
+ * all clients as a percentage of the real time available per cycle
+ * determined by the buffer size and sample rate.
+ */
+ float jack_cpu_load (jack_client_t *client);
+
+ /**
+ * @return the pthread ID of the thread running the JACK client side
+ * code.
+ */
+ pthread_t jack_client_thread_id (jack_client_t *);
+
+ /**
+ * Display JACK error message.
+ *
+ * Set via jack_set_error_function(), otherwise a JACK-provided
+ * default will print @a msg (plus a newline) to stderr.
+ *
+ * @param msg error message text (no newline at end).
+ */
+ extern void (*jack_error_callback)(const char *msg);
+
+ /**
+ * Set the @ref jack_error_callback for error message display.
+ *
+ * The JACK library provides two built-in callbacks for this purpose:
+ * default_jack_error_callback() and silent_jack_error_callback().
+ */
+ void jack_set_error_function (void (*func)(const char *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_h__ */
diff --git a/common/jslist.h b/common/jslist.h
new file mode 100644
index 00000000..45e8c266
--- /dev/null
+++ b/common/jslist.h
@@ -0,0 +1,287 @@
+/*
+ Based on gslist.c from glib-1.2.9 (LGPL).
+
+ Adaption to JACK, Copyright (C) 2002 Kai Vehmanen.
+ - replaced use of gtypes with normal ANSI C types
+ - glib's memory allocation routines replaced with
+ malloc/free calls
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef __jack_jslist_h__
+#define __jack_jslist_h__
+
+#include <stdlib.h>
+
+#ifdef WIN32
+#define __inline__ inline
+#endif
+
+typedef struct _JSList JSList;
+
+typedef int (*JCompareFunc) (void* a, void* b);
+struct _JSList
+{
+ void *data;
+ JSList *next;
+};
+
+static __inline__
+JSList*
+jack_slist_alloc (void)
+{
+ JSList *new_list;
+
+ new_list = (JSList*)malloc(sizeof(JSList));
+ new_list->data = NULL;
+ new_list->next = NULL;
+
+ return new_list;
+}
+
+static __inline__
+JSList*
+jack_slist_prepend (JSList* list, void* data)
+{
+ JSList *new_list;
+
+ new_list = (JSList*)malloc(sizeof(JSList));
+ new_list->data = data;
+ new_list->next = list;
+
+ return new_list;
+}
+
+#define jack_slist_next(slist) ((slist) ? (((JSList *)(slist))->next) : NULL)
+static __inline__
+JSList*
+jack_slist_last (JSList *list)
+{
+ if (list) {
+ while (list->next)
+ list = list->next;
+ }
+
+ return list;
+}
+
+static __inline__
+JSList*
+jack_slist_remove_link (JSList *list,
+ JSList *link)
+{
+ JSList *tmp;
+ JSList *prev;
+
+ prev = NULL;
+ tmp = list;
+
+ while (tmp) {
+ if (tmp == link) {
+ if (prev)
+ prev->next = tmp->next;
+ if (list == tmp)
+ list = list->next;
+
+ tmp->next = NULL;
+ break;
+ }
+
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ return list;
+}
+
+static __inline__
+void
+jack_slist_free (JSList *list)
+{
+ while (list) {
+ JSList *next = list->next;
+ free(list);
+ list = next;
+ }
+}
+
+static __inline__
+void
+jack_slist_free_1 (JSList *list)
+{
+ if (list) {
+ free(list);
+ }
+}
+
+static __inline__
+JSList*
+jack_slist_remove (JSList *list,
+ void *data)
+{
+ JSList *tmp;
+ JSList *prev;
+
+ prev = NULL;
+ tmp = list;
+
+ while (tmp) {
+ if (tmp->data == data) {
+ if (prev)
+ prev->next = tmp->next;
+ if (list == tmp)
+ list = list->next;
+
+ tmp->next = NULL;
+ jack_slist_free (tmp);
+
+ break;
+ }
+
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ return list;
+}
+
+static __inline__
+unsigned int
+jack_slist_length (JSList *list)
+{
+ unsigned int length;
+
+ length = 0;
+ while (list) {
+ length++;
+ list = list->next;
+ }
+
+ return length;
+}
+
+static __inline__
+JSList*
+jack_slist_find (JSList *list,
+ void *data)
+{
+ while (list) {
+ if (list->data == data)
+ break;
+ list = list->next;
+ }
+
+ return list;
+}
+
+static __inline__
+JSList*
+jack_slist_copy (JSList *list)
+{
+ JSList *new_list = NULL;
+
+ if (list) {
+ JSList *last;
+
+ new_list = jack_slist_alloc ();
+ new_list->data = list->data;
+ last = new_list;
+ list = list->next;
+ while (list) {
+ last->next = jack_slist_alloc ();
+ last = last->next;
+ last->data = list->data;
+ list = list->next;
+ }
+ }
+
+ return new_list;
+}
+
+static __inline__
+JSList*
+jack_slist_append (JSList *list,
+ void *data)
+{
+ JSList *new_list;
+ JSList *last;
+
+ new_list = jack_slist_alloc ();
+ new_list->data = data;
+
+ if (list) {
+ last = jack_slist_last (list);
+ last->next = new_list;
+
+ return list;
+ } else
+ return new_list;
+}
+
+static __inline__
+JSList*
+jack_slist_sort_merge (JSList *l1,
+ JSList *l2,
+ JCompareFunc compare_func)
+{
+ JSList list, *l;
+
+ l = &list;
+
+ while (l1 && l2) {
+ if (compare_func(l1->data, l2->data) < 0) {
+ l = l->next = l1;
+ l1 = l1->next;
+ } else {
+ l = l->next = l2;
+ l2 = l2->next;
+ }
+ }
+ l->next = l1 ? l1 : l2;
+
+ return list.next;
+}
+
+static __inline__
+JSList*
+jack_slist_sort (JSList *list,
+ JCompareFunc compare_func)
+{
+ JSList *l1, *l2;
+
+ if (!list)
+ return NULL;
+ if (!list->next)
+ return list;
+
+ l1 = list;
+ l2 = list->next;
+
+ while ((l2 = l2->next) != NULL) {
+ if ((l2 = l2->next) == NULL)
+ break;
+ l1 = l1->next;
+ }
+ l2 = l1->next;
+ l1->next = NULL;
+
+ return jack_slist_sort_merge (jack_slist_sort (list, compare_func),
+ jack_slist_sort (l2, compare_func),
+ compare_func);
+}
+
+#endif /* __jack_jslist_h__ */
diff --git a/common/patest_sine.c b/common/patest_sine.c
new file mode 100644
index 00000000..80a9c499
--- /dev/null
+++ b/common/patest_sine.c
@@ -0,0 +1,151 @@
+/** @file patest_sine.c
+ @brief Play a sine wave for several seconds.
+ @author Ross Bencina <rossb@audiomulch.com>
+ @author Phil Burk <philburk@softsynth.com>
+*/
+/*
+ * $Id: patest_sine.c,v 1.1.2.1 2006/06/06 19:37:56 letz Exp $
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (5)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters outputParameters;
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for %d seconds.\n", NUM_SECONDS );
+ Pa_Sleep( NUM_SECONDS * 1000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/common/ringbuffer.c b/common/ringbuffer.c
new file mode 100644
index 00000000..75170411
--- /dev/null
+++ b/common/ringbuffer.c
@@ -0,0 +1,359 @@
+/*
+ Copyright (C) 2000 Paul Davis
+ Copyright (C) 2003 Rohan Drape
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code.
+ This is safe for the case of one read thread and one write thread.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef USE_MLOCK
+#include <sys/mman.h>
+#endif /* USE_MLOCK */
+#include "ringbuffer.h"
+
+/* Create a new ringbuffer to hold at least `sz' bytes of data. The
+ actual buffer size is rounded up to the next power of two. */
+
+jack_ringbuffer_t *
+jack_ringbuffer_create (size_t sz)
+{
+ int power_of_two;
+ jack_ringbuffer_t *rb;
+
+ rb = malloc (sizeof (jack_ringbuffer_t));
+
+ for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
+
+ rb->size = 1 << power_of_two;
+ rb->size_mask = rb->size;
+ rb->size_mask -= 1;
+ rb->write_ptr = 0;
+ rb->read_ptr = 0;
+ rb->buf = malloc (rb->size);
+ memset(rb->buf, 0, rb->size);
+ rb->mlocked = 0;
+
+ return rb;
+}
+
+/* Free all data associated with the ringbuffer `rb'. */
+
+void
+jack_ringbuffer_free (jack_ringbuffer_t * rb)
+{
+#ifdef USE_MLOCK
+ if (rb->mlocked) {
+ munlock (rb->buf, rb->size);
+ }
+#endif /* USE_MLOCK */
+ free (rb->buf);
+}
+
+/* Lock the data block of `rb' using the system call 'mlock'. */
+
+int
+jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
+{
+#ifdef USE_MLOCK
+ if (mlock (rb->buf, rb->size)) {
+ return -1;
+ }
+#endif /* USE_MLOCK */
+ rb->mlocked = 1;
+ return 0;
+}
+
+/* Reset the read and write pointers to zero. This is not thread
+ safe. */
+
+void
+jack_ringbuffer_reset (jack_ringbuffer_t * rb)
+{
+ rb->read_ptr = 0;
+ rb->write_ptr = 0;
+}
+
+/* Return the number of bytes available for reading. This is the
+ number of bytes in front of the read pointer and behind the write
+ pointer. */
+
+size_t
+jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
+{
+ size_t w, r;
+
+ w = rb->write_ptr;
+ r = rb->read_ptr;
+
+ if (w > r) {
+ return w - r;
+ } else {
+ return (w - r + rb->size) & rb->size_mask;
+ }
+}
+
+/* Return the number of bytes available for writing. This is the
+ number of bytes in front of the write pointer and behind the read
+ pointer. */
+
+size_t
+jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
+{
+ size_t w, r;
+
+ w = rb->write_ptr;
+ r = rb->read_ptr;
+
+ if (w > r) {
+ return ((r - w + rb->size) & rb->size_mask) - 1;
+ } else if (w < r) {
+ return (r - w) - 1;
+ } else {
+ return rb->size - 1;
+ }
+}
+
+/* The copying data reader. Copy at most `cnt' bytes from `rb' to
+ `dest'. Returns the actual number of bytes copied. */
+
+size_t
+jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_read;
+ size_t n1, n2;
+
+ if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
+ return 0;
+ }
+
+ to_read = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = rb->read_ptr + to_read;
+
+ if (cnt2 > rb->size) {
+ n1 = rb->size - rb->read_ptr;
+ n2 = cnt2 & rb->size_mask;
+ } else {
+ n1 = to_read;
+ n2 = 0;
+ }
+
+ memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
+ rb->read_ptr += n1;
+ rb->read_ptr &= rb->size_mask;
+
+ if (n2) {
+ memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
+ rb->read_ptr += n2;
+ rb->read_ptr &= rb->size_mask;
+ }
+
+ return to_read;
+}
+
+/* The copying data reader w/o read pointer advance. Copy at most
+ `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
+copied. */
+
+size_t
+jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_read;
+ size_t n1, n2;
+ size_t tmp_read_ptr;
+
+ tmp_read_ptr = rb->read_ptr;
+
+ if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
+ return 0;
+ }
+
+ to_read = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = tmp_read_ptr + to_read;
+
+ if (cnt2 > rb->size) {
+ n1 = rb->size - tmp_read_ptr;
+ n2 = cnt2 & rb->size_mask;
+ } else {
+ n1 = to_read;
+ n2 = 0;
+ }
+
+ memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
+ tmp_read_ptr += n1;
+ tmp_read_ptr &= rb->size_mask;
+
+ if (n2) {
+ memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
+ tmp_read_ptr += n2;
+ tmp_read_ptr &= rb->size_mask;
+ }
+
+ return to_read;
+}
+
+
+/* The copying data writer. Copy at most `cnt' bytes to `rb' from
+ `src'. Returns the actual number of bytes copied. */
+
+size_t
+jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_write;
+ size_t n1, n2;
+
+ if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
+ return 0;
+ }
+
+ to_write = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = rb->write_ptr + to_write;
+
+ if (cnt2 > rb->size) {
+ n1 = rb->size - rb->write_ptr;
+ n2 = cnt2 & rb->size_mask;
+ } else {
+ n1 = to_write;
+ n2 = 0;
+ }
+
+ memcpy (&(rb->buf[rb->write_ptr]), src, n1);
+ rb->write_ptr += n1;
+ rb->write_ptr &= rb->size_mask;
+
+ if (n2) {
+ memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
+ rb->write_ptr += n2;
+ rb->write_ptr &= rb->size_mask;
+ }
+
+ return to_write;
+}
+
+/* Advance the read pointer `cnt' places. */
+
+void
+jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
+{
+ rb->read_ptr += cnt;
+ rb->read_ptr &= rb->size_mask;
+}
+
+/* Advance the write pointer `cnt' places. */
+
+void
+jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
+{
+ rb->write_ptr += cnt;
+ rb->write_ptr &= rb->size_mask;
+}
+
+/* The non-copying data reader. `vec' is an array of two places. Set
+ the values at `vec' to hold the current readable data at `rb'. If
+ the readable data is in one segment the second segment has zero
+ length. */
+
+void
+jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb,
+ jack_ringbuffer_data_t * vec)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = rb->write_ptr;
+ r = rb->read_ptr;
+
+ if (w > r) {
+ free_cnt = w - r;
+ } else {
+ free_cnt = (w - r + rb->size) & rb->size_mask;
+ }
+
+ cnt2 = r + free_cnt;
+
+ if (cnt2 > rb->size) {
+
+ /* Two part vector: the rest of the buffer after the current write
+ ptr, plus some from the start of the buffer. */
+
+ vec[0].buf = &(rb->buf[r]);
+ vec[0].len = rb->size - r;
+ vec[1].buf = rb->buf;
+ vec[1].len = cnt2 & rb->size_mask;
+
+ } else {
+
+ /* Single part vector: just the rest of the buffer */
+
+ vec[0].buf = &(rb->buf[r]);
+ vec[0].len = free_cnt;
+ vec[1].len = 0;
+ }
+}
+
+/* The non-copying data writer. `vec' is an array of two places. Set
+ the values at `vec' to hold the current writeable data at `rb'. If
+ the writeable data is in one segment the second segment has zero
+ length. */
+
+void
+jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
+ jack_ringbuffer_data_t * vec)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = rb->write_ptr;
+ r = rb->read_ptr;
+
+ if (w > r) {
+ free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
+ } else if (w < r) {
+ free_cnt = (r - w) - 1;
+ } else {
+ free_cnt = rb->size - 1;
+ }
+
+ cnt2 = w + free_cnt;
+
+ if (cnt2 > rb->size) {
+
+ /* Two part vector: the rest of the buffer after the current write
+ ptr, plus some from the start of the buffer. */
+
+ vec[0].buf = &(rb->buf[w]);
+ vec[0].len = rb->size - w;
+ vec[1].buf = rb->buf;
+ vec[1].len = cnt2 & rb->size_mask;
+ } else {
+ vec[0].buf = &(rb->buf[w]);
+ vec[0].len = free_cnt;
+ vec[1].len = 0;
+ }
+}
diff --git a/common/ringbuffer.h b/common/ringbuffer.h
new file mode 100644
index 00000000..78bf6536
--- /dev/null
+++ b/common/ringbuffer.h
@@ -0,0 +1,235 @@
+/*
+ Copyright (C) 2000 Paul Davis
+ Copyright (C) 2003 Rohan Drape
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: ringbuffer.h,v 1.2.2.1 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef _RINGBUFFER_H
+#define _RINGBUFFER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <sys/types.h>
+
+ /** @file ringbuffer.h
+ *
+ * A set of library functions to make lock-free ringbuffers available
+ * to JACK clients. The `capture_client.c' (in the example_clients
+ * directory) is a fully functioning user of this API.
+ *
+ * The key attribute of a ringbuffer is that it can be safely accessed
+ * by two threads simultaneously -- one reading from the buffer and
+ * the other writing to it -- without using any synchronization or
+ * mutual exclusion primitives. For this to work correctly, there can
+ * only be a single reader and a single writer thread. Their
+ * identities cannot be interchanged.
+ */
+
+ typedef struct {
+ char *buf;
+ size_t len;
+ }
+ jack_ringbuffer_data_t ;
+
+ typedef struct {
+ char *buf;
+ volatile size_t write_ptr;
+ volatile size_t read_ptr;
+ size_t size;
+ size_t size_mask;
+ int mlocked;
+ }
+ jack_ringbuffer_t ;
+
+ /**
+ * Allocates a ringbuffer data structure of a specified size. The
+ * caller must arrange for a call to jack_ringbuffer_free() to release
+ * the memory associated with the ringbuffer.
+ *
+ * @param sz the ringbuffer size in bytes.
+ *
+ * @return a pointer to a new jack_ringbuffer_t, if successful; NULL
+ * otherwise.
+ */
+ jack_ringbuffer_t *jack_ringbuffer_create(size_t sz);
+
+ /**
+ * Frees the ringbuffer data structure allocated by an earlier call to
+ * jack_ringbuffer_create().
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ */
+ void jack_ringbuffer_free(jack_ringbuffer_t *rb);
+
+ /**
+ * Fill a data structure with a description of the current readable
+ * data held in the ringbuffer. This description is returned in a two
+ * element array of jack_ringbuffer_data_t. Two elements are needed
+ * because the data to be read may be split across the end of the
+ * ringbuffer.
+ *
+ * The first element will always contain a valid @a len field, which
+ * may be zero or greater. If the @a len field is non-zero, then data
+ * can be read in a contiguous fashion using the address given in the
+ * corresponding @a buf field.
+ *
+ * If the second element has a non-zero @a len field, then a second
+ * contiguous stretch of data can be read from the address given in
+ * its corresponding @a buf field.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param vec a pointer to a 2 element array of jack_ringbuffer_data_t.
+ *
+ */
+ void jack_ringbuffer_get_read_vector(const jack_ringbuffer_t *rb,
+ jack_ringbuffer_data_t *vec);
+
+ /**
+ * Fill a data structure with a description of the current writable
+ * space in the ringbuffer. The description is returned in a two
+ * element array of jack_ringbuffer_data_t. Two elements are needed
+ * because the space available for writing may be split across the end
+ * of the ringbuffer.
+ *
+ * The first element will always contain a valid @a len field, which
+ * may be zero or greater. If the @a len field is non-zero, then data
+ * can be written in a contiguous fashion using the address given in
+ * the corresponding @a buf field.
+ *
+ * If the second element has a non-zero @a len field, then a second
+ * contiguous stretch of data can be written to the address given in
+ * the corresponding @a buf field.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param vec a pointer to a 2 element array of jack_ringbuffer_data_t.
+ */
+ void jack_ringbuffer_get_write_vector(const jack_ringbuffer_t *rb,
+ jack_ringbuffer_data_t *vec);
+
+ /**
+ * Read data from the ringbuffer.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param dest a pointer to a buffer where data read from the
+ * ringbuffer will go.
+ * @param cnt the number of bytes to read.
+ *
+ * @return the number of bytes read, which may range from 0 to cnt.
+ */
+ size_t jack_ringbuffer_read(jack_ringbuffer_t *rb, char *dest, size_t cnt);
+
+ /**
+ * Read data from the ringbuffer. Opposed to jack_ringbuffer_read()
+ * this function does not move the read pointer. Thus it's
+ * a convenient way to inspect data in the ringbuffer in a
+ * continous fashion. The price is that the data is copied
+ * into a user provided buffer. For "raw" non-copy inspection
+ * of the data in the ringbuffer use jack_ringbuffer_get_read_vector().
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param dest a pointer to a buffer where data read from the
+ * ringbuffer will go.
+ * @param cnt the number of bytes to read.
+ *
+ * @return the number of bytes read, which may range from 0 to cnt.
+ */
+ size_t jack_ringbuffer_peek(jack_ringbuffer_t *rb, char *dest, size_t cnt);
+
+ /**
+ * Advance the read pointer.
+ *
+ * After data have been read from the ringbuffer using the pointers
+ * returned by jack_ringbuffer_get_read_vector(), use this function to
+ * advance the buffer pointers, making that space available for future
+ * write operations.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param cnt the number of bytes read.
+ */
+ void jack_ringbuffer_read_advance(jack_ringbuffer_t *rb, size_t cnt);
+
+ /**
+ * Return the number of bytes available for reading.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ *
+ * @return the number of bytes available to read.
+ */
+ size_t jack_ringbuffer_read_space(const jack_ringbuffer_t *rb);
+
+ /**
+ * Lock a ringbuffer data block into memory.
+ *
+ * Uses the mlock() system call. This is not a realtime operation.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ */
+ int jack_ringbuffer_mlock(jack_ringbuffer_t *rb);
+
+ /**
+ * Reset the read and write pointers, making an empty buffer.
+ *
+ * This is not thread safe.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ */
+ void jack_ringbuffer_reset(jack_ringbuffer_t *rb);
+
+ /**
+ * Write data into the ringbuffer.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param src a pointer to the data to be written to the ringbuffer.
+ * @param cnt the number of bytes to write.
+ *
+ * @return the number of bytes write, which may range from 0 to cnt
+ */
+ size_t jack_ringbuffer_write(jack_ringbuffer_t *rb, const char *src,
+ size_t cnt);
+
+ /**
+ * Advance the write pointer.
+ *
+ * After data have been written the ringbuffer using the pointers
+ * returned by jack_ringbuffer_get_write_vector(), use this function
+ * to advance the buffer pointer, making the data available for future
+ * read operations.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ * @param cnt the number of bytes written.
+ */
+ void jack_ringbuffer_write_advance(jack_ringbuffer_t *rb, size_t cnt);
+
+ /**
+ * Return the number of bytes available for writing.
+ *
+ * @param rb a pointer to the ringbuffer structure.
+ *
+ * @return the amount of free space (in bytes) available for writing.
+ */
+ size_t jack_ringbuffer_write_space(const jack_ringbuffer_t *rb);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/shm.c b/common/shm.c
new file mode 100644
index 00000000..1c0ad939
--- /dev/null
+++ b/common/shm.c
@@ -0,0 +1,1182 @@
+/* This module provides a set of abstract shared memory interfaces
+ * with support using both System V and POSIX shared memory
+ * implementations. The code is divided into three sections:
+ *
+ * - common (interface-independent) code
+ * - POSIX implementation
+ * - System V implementation
+ *
+ * The implementation used is determined by whether USE_POSIX_SHM was
+ * set in the ./configure step.
+ */
+
+/*
+ * Copyright (C) 2003 Paul Davis
+ * Copyright (C) 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: shm.c,v 1.8.2.16 2006/08/28 10:10:16 letz Exp $
+ */
+
+#ifdef WIN32
+#include <process.h>
+#else
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <limits.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <stdlib.h>
+
+#endif
+
+#include "shm.h"
+#include "JackError.h"
+
+#ifdef USE_POSIX_SHM
+static jack_shmtype_t jack_shmtype = shm_POSIX;
+#elif WIN32
+static jack_shmtype_t jack_shmtype = shm_WIN32;
+#else
+static jack_shmtype_t jack_shmtype = shm_SYSV;
+#endif
+
+/* interface-dependent forward declarations */
+static int jack_access_registry (jack_shm_info_t *ri);
+static int jack_create_registry (jack_shm_info_t *ri);
+static void jack_remove_shm (jack_shm_id_t *id);
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * common interface-independent section
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* The JACK SHM registry is a chunk of memory for keeping track of the
+ * shared memory used by each active JACK server. This allows the
+ * server to clean up shared memory when it exits. To avoid memory
+ * leakage due to kill -9, crashes or debugger-driven exits, this
+ * cleanup is also done when a new instance of that server starts.
+ */
+
+/* per-process global data for the SHM interfaces */
+static jack_shm_id_t registry_id; /* SHM id for the registry */
+
+#ifdef WIN32
+static jack_shm_info_t registry_info = {/* SHM info for the registry */
+ JACK_SHM_NULL_INDEX,
+ NULL
+};
+#else
+static jack_shm_info_t registry_info = { /* SHM info for the registry */
+ .index = JACK_SHM_NULL_INDEX,
+ .attached_at = MAP_FAILED
+};
+
+#endif
+
+/* pointers to registry header and array */
+static jack_shm_header_t *jack_shm_header = NULL;
+static jack_shm_registry_t *jack_shm_registry = NULL;
+static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
+
+/* jack_shm_lock_registry() serializes updates to the shared memory
+ * segment JACK uses to keep track of the SHM segements allocated to
+ * all its processes, including multiple servers.
+ *
+ * This is not a high-contention lock, but it does need to work across
+ * multiple processes. High transaction rates and realtime safety are
+ * not required. Any solution needs to at least be portable to POSIX
+ * and POSIX-like systems.
+ *
+ * We must be particularly careful to ensure that the lock be released
+ * if the owning process terminates abnormally. Otherwise, a segfault
+ * or kill -9 at the wrong moment could prevent JACK from ever running
+ * again on that machine until after a reboot.
+ */
+
+#define JACK_SEMAPHORE_KEY 0x282929
+#ifndef USE_POSIX_SHM
+#define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
+#endif
+
+static int semid = -1;
+
+#ifdef WIN32
+
+// steph TODO
+static void
+semaphore_init () {}
+
+static void
+semaphore_add (int value) {}
+
+#else
+/* all semaphore errors are fatal -- issue message, but do not return */
+static void
+semaphore_error (char *msg)
+{
+ jack_error ("Fatal JACK semaphore error: %s (%s)",
+ msg, strerror (errno));
+ abort ();
+}
+
+static void
+semaphore_init ()
+{
+ key_t semkey = JACK_SEMAPHORE_KEY;
+ struct sembuf sbuf;
+ int create_flags = IPC_CREAT | IPC_EXCL
+ | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+ /* Get semaphore ID associated with this key. */
+ if ((semid = semget(semkey, 0, 0)) == -1) {
+
+ /* Semaphore does not exist - Create. */
+ if ((semid = semget(semkey, 1, create_flags)) != -1) {
+
+ /* Initialize the semaphore, allow one owner. */
+ sbuf.sem_num = 0;
+ sbuf.sem_op = 1;
+ sbuf.sem_flg = 0;
+ if (semop(semid, &sbuf, 1) == -1) {
+ semaphore_error ("semop");
+ }
+
+ } else if (errno == EEXIST) {
+ if ((semid = semget(semkey, 0, 0)) == -1) {
+ semaphore_error ("semget");
+ }
+
+ } else {
+ semaphore_error ("semget creation");
+ }
+ }
+}
+
+static inline void
+semaphore_add (int value)
+{
+ struct sembuf sbuf;
+
+ sbuf.sem_num = 0;
+ sbuf.sem_op = value;
+ sbuf.sem_flg = SEM_UNDO;
+ if (semop(semid, &sbuf, 1) == -1) {
+ semaphore_error ("semop");
+ }
+}
+
+#endif
+
+static void
+jack_shm_lock_registry (void)
+{
+ if (semid == -1)
+ semaphore_init ();
+
+ semaphore_add (-1);
+}
+
+static void
+jack_shm_unlock_registry (void)
+{
+ semaphore_add (1);
+}
+
+static void
+jack_shm_init_registry ()
+{
+ /* registry must be locked */
+ int i;
+
+ memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
+
+ jack_shm_header->magic = JACK_SHM_MAGIC;
+ //jack_shm_header->protocol = jack_protocol_version; // steph
+ jack_shm_header->type = jack_shmtype;
+ jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
+ jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
+ jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
+
+ for (i = 0; i < MAX_SHM_ID; ++i) {
+ jack_shm_registry[i].index = i;
+ }
+}
+
+static int
+jack_shm_validate_registry ()
+{
+ /* registry must be locked */
+
+ if ((jack_shm_header->magic == JACK_SHM_MAGIC)
+ //&& (jack_shm_header->protocol == jack_protocol_version) // steph
+ && (jack_shm_header->type == jack_shmtype)
+ && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
+ && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
+ && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
+
+ return 0; /* registry OK */
+ }
+
+ return -1;
+}
+
+/* set a unique per-user, per-server shm prefix string
+ *
+ * According to the POSIX standard:
+ *
+ * "The name argument conforms to the construction rules for a
+ * pathname. If name begins with the slash character, then processes
+ * calling shm_open() with the same value of name refer to the same
+ * shared memory object, as long as that name has not been
+ * removed. If name does not begin with the slash character, the
+ * effect is implementation-defined. The interpretation of slash
+ * characters other than the leading slash character in name is
+ * implementation-defined."
+ *
+ * Since the Linux implementation does not allow slashes *within* the
+ * name, in the interest of portability we use colons instead.
+ */
+static void
+jack_set_server_prefix (const char *server_name)
+{
+#ifdef WIN32
+ snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
+ "jack-%d:%s:", _getpid (), server_name); // steph TO CHECK
+#else
+ snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
+ "/jack-%d:%s:", getuid (), server_name);
+#endif
+
+}
+
+/* gain server addressability to shared memory registration segment
+ *
+ * returns: 0 if successful
+ */
+static int
+jack_server_initialize_shm (void)
+{
+ int rc;
+
+ if (jack_shm_header)
+ return 0; /* already initialized */
+
+ jack_shm_lock_registry ();
+
+ rc = jack_access_registry (&registry_info);
+
+ switch (rc) {
+ case ENOENT: /* registry does not exist */
+ rc = jack_create_registry (&registry_info);
+ break;
+ case 0: /* existing registry */
+ if (jack_shm_validate_registry () == 0)
+ break;
+ /* else it was invalid, so fall through */
+ case EINVAL: /* bad registry */
+ /* Apparently, this registry was created by an older
+ * JACK version. Delete it so we can try again. */
+ jack_release_shm (&registry_info);
+ jack_remove_shm (&registry_id);
+ if ((rc = jack_create_registry (&registry_info)) != 0) {
+ jack_error ("incompatible shm registry (%s)",
+ strerror (errno));
+#ifndef USE_POSIX_SHM
+ jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
+ JACK_SHM_REGISTRY_KEY);
+#endif
+ }
+ break;
+ default: /* failure return code */
+ break;
+ }
+
+ jack_shm_unlock_registry ();
+ return rc;
+}
+
+/* gain client addressability to shared memory registration segment
+ *
+ * NOTE: this function is no longer used for server initialization,
+ * instead it calls jack_register_server().
+ *
+ * returns: 0 if successful
+ */
+int
+jack_initialize_shm (const char *server_name)
+{
+ int rc;
+
+ if (jack_shm_header)
+ return 0; /* already initialized */
+
+ jack_set_server_prefix (server_name);
+
+ jack_shm_lock_registry ();
+ if ((rc = jack_access_registry (&registry_info)) == 0) {
+ if ((rc = jack_shm_validate_registry ()) != 0) {
+ jack_error ("Incompatible shm registry, "
+ "are jackd and libjack in sync?");
+ }
+ }
+ jack_shm_unlock_registry ();
+
+ return rc;
+}
+
+
+// steph
+
+int jack_initialize_shm_server()
+{
+ return jack_initialize_shm("default");
+}
+
+int jack_initialize_shm_client()
+{
+ return jack_initialize_shm("default");
+}
+
+char* jack_shm_addr (jack_shm_info_t* si)
+{
+ return (char*)si->attached_at;
+}
+
+void
+jack_destroy_shm (jack_shm_info_t* si)
+{
+ /* must NOT have the registry locked */
+ if (si->index == JACK_SHM_NULL_INDEX)
+ return; /* segment not allocated */
+
+ jack_remove_shm (&jack_shm_registry[si->index].id);
+ jack_release_shm_info (si->index);
+}
+
+jack_shm_registry_t *
+jack_get_free_shm_info ()
+{
+ /* registry must be locked */
+ jack_shm_registry_t* si = NULL;
+ int i;
+
+ for (i = 0; i < MAX_SHM_ID; ++i) {
+ if (jack_shm_registry[i].size == 0) {
+ break;
+ }
+ }
+
+ if (i < MAX_SHM_ID) {
+ si = &jack_shm_registry[i];
+ }
+
+ return si;
+}
+
+static void
+jack_release_shm_entry (jack_shm_registry_index_t index)
+{
+ /* the registry must be locked */
+ jack_shm_registry[index].size = 0;
+ jack_shm_registry[index].allocator = 0;
+ memset (&jack_shm_registry[index].id, 0,
+ sizeof (jack_shm_registry[index].id));
+}
+
+void
+jack_release_shm_info (jack_shm_registry_index_t index)
+{
+#ifdef WIN32
+ int my_pid = _getpid();
+#else
+ pid_t my_pid = getpid();
+#endif
+
+ /* must NOT have the registry locked */
+ if (jack_shm_registry[index].allocator == my_pid) {
+ jack_shm_lock_registry ();
+ jack_release_shm_entry (index);
+ jack_shm_unlock_registry ();
+ }
+}
+
+/* Claim server_name for this process.
+ *
+ * returns 0 if successful
+ * EEXIST if server_name was already active for this user
+ * ENOSPC if server registration limit reached
+ * ENOMEM if unable to access shared memory registry
+ */
+EXPORT int
+jack_register_server (const char *server_name)
+{
+ int i;
+
+#ifdef WIN32
+ int my_pid = _getpid();
+#else
+ pid_t my_pid = getpid();
+#endif
+
+ jack_set_server_prefix (server_name);
+
+ if (jack_server_initialize_shm ())
+ return ENOMEM;
+
+ jack_shm_lock_registry ();
+
+ /* See if server_name already registered. Since server names
+ * are per-user, we register the unique server prefix string.
+ */
+ for (i = 0; i < MAX_SERVERS; i++) {
+
+ if (strncmp (jack_shm_header->server[i].name,
+ jack_shm_server_prefix,
+ JACK_SERVER_NAME_SIZE) != 0)
+ continue; /* no match */
+
+ if (jack_shm_header->server[i].pid == my_pid)
+ return 0; /* it's me */
+
+ /* see if server still exists */
+ #ifndef WIN32 // steph TO CHECK
+ if (kill (jack_shm_header->server[i].pid, 0) == 0) {
+ return EEXIST; /* other server running */
+ }
+ #endif
+
+ /* it's gone, reclaim this entry */
+ memset (&jack_shm_header->server[i], 0,
+ sizeof (jack_shm_server_t));
+ }
+
+ /* find a free entry */
+ for (i = 0; i < MAX_SERVERS; i++) {
+ if (jack_shm_header->server[i].pid == 0)
+ break;
+ }
+
+ if (i >= MAX_SERVERS)
+ return ENOSPC; /* out of space */
+
+ /* claim it */
+ jack_shm_header->server[i].pid = my_pid;
+ strncpy (jack_shm_header->server[i].name,
+ jack_shm_server_prefix,
+ JACK_SERVER_NAME_SIZE);
+
+ jack_shm_unlock_registry ();
+ return 0;
+}
+
+/* release server_name registration */
+EXPORT void
+jack_unregister_server (const char *server_name /* unused */)
+{
+ int i;
+
+#ifdef WIN32
+ int my_pid = _getpid();
+#else
+ pid_t my_pid = getpid();
+#endif
+
+ jack_shm_lock_registry ();
+
+ for (i = 0; i < MAX_SERVERS; i++) {
+ if (jack_shm_header->server[i].pid == my_pid) {
+ memset (&jack_shm_header->server[i], 0,
+ sizeof (jack_shm_server_t));
+ }
+ }
+
+ jack_shm_unlock_registry ();
+}
+
+/* called for server startup and termination */
+EXPORT int
+jack_cleanup_shm ()
+{
+ int i;
+ int destroy;
+ jack_shm_info_t copy;
+
+#ifdef WIN32
+ int my_pid = _getpid();
+#else
+ pid_t my_pid = getpid();
+#endif
+
+ jack_shm_lock_registry ();
+
+ for (i = 0; i < MAX_SHM_ID; i++) {
+ jack_shm_registry_t* r;
+
+ r = &jack_shm_registry[i];
+ memcpy (&copy, r, sizeof (jack_shm_info_t));
+ destroy = FALSE;
+
+ /* ignore unused entries */
+ if (r->allocator == 0)
+ continue;
+
+ /* is this my shm segment? */
+ if (r->allocator == my_pid) {
+
+ /* allocated by this process, so unattach
+ and destroy. */
+ jack_release_shm (&copy);
+ destroy = TRUE;
+
+ } else {
+
+ /* see if allocator still exists */
+ #ifdef WIN32 // steph
+ printf("TODO: kill API not available !!\n");
+ #else
+ if (kill (r->allocator, 0)) {
+ if (errno == ESRCH) {
+ /* allocator no longer exists,
+ * so destroy */
+ destroy = TRUE;
+ }
+ }
+ #endif
+ }
+
+ if (destroy) {
+
+ int index = copy.index;
+
+ if ((index >= 0) && (index < MAX_SHM_ID)) {
+ jack_remove_shm (&jack_shm_registry[index].id);
+ jack_release_shm_entry (index);
+ }
+ r->size = 0;
+ r->allocator = 0;
+ }
+ }
+
+ jack_shm_unlock_registry ();
+ return TRUE;
+}
+
+/* resize a shared memory segment
+ *
+ * There is no way to resize a System V shm segment. Resizing is
+ * possible with POSIX shm, but not with the non-conformant Mac OS X
+ * implementation. Since POSIX shm is mainly used on that platform,
+ * it's simpler to treat them both the same.
+ *
+ * So, we always resize by deleting and reallocating. This is
+ * tricky, because the old segment will not disappear until
+ * all the clients have released it. We only do what we can
+ * from here.
+ *
+ * This is not done under a single lock. I don't even want to think
+ * about all the things that could possibly go wrong if multple
+ * processes tried to resize the same segment concurrently. That
+ * probably doesn't happen.
+ */
+int
+jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
+{
+ jack_shm_id_t id;
+
+ /* The underlying type of `id' differs for SYSV and POSIX */
+ memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
+
+ jack_release_shm (si);
+ jack_destroy_shm (si);
+
+ if (jack_shmalloc ((char *) id, size, si)) {
+ return -1;
+ }
+
+ return jack_attach_shm (si);
+}
+
+#ifdef USE_POSIX_SHM
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * POSIX interface-dependent functions
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* gain addressability to existing SHM registry segment
+ *
+ * sets up global registry pointers, if successful
+ *
+ * returns: 0 if existing registry accessed successfully
+ * ENOENT if registry does not exist
+ * EINVAL if registry exists, but has the wrong size
+ */
+static int
+jack_access_registry (jack_shm_info_t *ri)
+{
+ /* registry must be locked */
+ int shm_fd;
+
+ strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
+
+ /* try to open an existing segment */
+ if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
+ int rc = errno;
+ if (errno != ENOENT) {
+ jack_error ("Cannot open existing shm registry segment"
+ " (%s)", strerror (errno));
+ }
+ close (shm_fd);
+ return rc;
+ }
+
+ if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
+ jack_error ("Cannot mmap shm registry segment (%s)",
+ strerror (errno));
+ close (shm_fd);
+ return EINVAL;
+ }
+
+ /* set up global pointers */
+ ri->index = JACK_SHM_REGISTRY_INDEX;
+ jack_shm_header = ri->attached_at;
+ jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
+
+ close (shm_fd); // steph
+ return 0;
+}
+
+/* create a new SHM registry segment
+ *
+ * sets up global registry pointers, if successful
+ *
+ * returns: 0 if registry created successfully
+ * nonzero error code if unable to allocate a new registry
+ */
+static int
+jack_create_registry (jack_shm_info_t *ri)
+{
+ /* registry must be locked */
+ int shm_fd;
+
+ strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
+
+ if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
+ int rc = errno;
+ jack_error ("Cannot create shm registry segment (%s)",
+ strerror (errno));
+ return rc;
+ }
+
+ /* Set the desired segment size. NOTE: the non-conformant Mac
+ * OS X POSIX shm only allows ftruncate() on segment creation.
+ */
+ if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
+ int rc = errno;
+ jack_error ("Cannot set registry size (%s)", strerror (errno));
+ jack_remove_shm (&registry_id);
+ close (shm_fd);
+ return rc;
+ }
+
+ if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
+ jack_error ("Cannot mmap shm registry segment (%s)",
+ strerror (errno));
+ jack_remove_shm (&registry_id);
+ close (shm_fd);
+ return EINVAL;
+ }
+
+ /* set up global pointers */
+ ri->index = JACK_SHM_REGISTRY_INDEX;
+ jack_shm_header = ri->attached_at;
+ jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
+
+ /* initialize registry contents */
+ jack_shm_init_registry ();
+ close (shm_fd); // steph
+ return 0;
+}
+
+static void
+jack_remove_shm (jack_shm_id_t *id)
+{
+ /* registry may or may not be locked */
+ shm_unlink ((char *) id);
+}
+
+void
+jack_release_shm (jack_shm_info_t* si)
+{
+ /* registry may or may not be locked */
+ if (si->attached_at != MAP_FAILED) {
+ munmap (si->attached_at, jack_shm_registry[si->index].size);
+ }
+}
+
+/* allocate a POSIX shared memory segment */
+int
+jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
+{
+ jack_shm_registry_t* registry;
+ int shm_fd;
+ int rc = -1;
+ char name[SHM_NAME_MAX+1];
+
+ jack_shm_lock_registry ();
+
+ if ((registry = jack_get_free_shm_info ()) == NULL) {
+ jack_error ("shm registry full");
+ goto unlock;
+ }
+
+ /* On Mac OS X, the maximum length of a shared memory segment
+ * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
+ * defined by the standard). Unfortunately, Apple sets this
+ * value so small (about 31 bytes) that it is useless for
+ * actual names. So, we construct a short name from the
+ * registry index for uniqueness and ignore the shm_name
+ * parameter. Bah!
+ */
+ snprintf (name, sizeof (name), "/jack-%d", registry->index);
+
+ if (strlen (name) >= sizeof (registry->id)) {
+ jack_error ("shm segment name too long %s", name);
+ goto unlock;
+ }
+
+ if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
+ jack_error ("Cannot create shm segment %s (%s)",
+ name, strerror (errno));
+ goto unlock;
+ }
+
+ if (ftruncate (shm_fd, size) < 0) {
+ jack_error ("Cannot set size of engine shm "
+ "registry 0 (%s)",
+ strerror (errno));
+ close (shm_fd);
+ goto unlock;
+ }
+
+ close (shm_fd);
+ registry->size = size;
+ strncpy (registry->id, name, sizeof (registry->id));
+ registry->allocator = getpid();
+ si->index = registry->index;
+ si->attached_at = MAP_FAILED; /* not attached */
+ rc = 0; /* success */
+
+ unlock:
+ jack_shm_unlock_registry ();
+ return rc;
+}
+
+int
+jack_attach_shm (jack_shm_info_t* si)
+{
+ int shm_fd;
+ jack_shm_registry_t *registry = &jack_shm_registry[si->index];
+
+ if ((shm_fd = shm_open (registry->id,
+ O_RDWR, 0666)) < 0) {
+ jack_error ("Cannot open shm segment %s (%s)", registry->id,
+ strerror (errno));
+ return -1;
+ }
+
+ if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
+ jack_error ("Cannot mmap shm segment %s (%s)",
+ registry->id,
+ strerror (errno));
+ close (shm_fd);
+ return -1;
+ }
+
+ close (shm_fd);
+ return 0;
+}
+
+int
+jack_attach_shm_read (jack_shm_info_t* si)
+{
+ int shm_fd;
+ jack_shm_registry_t *registry = &jack_shm_registry[si->index];
+
+ if ((shm_fd = shm_open (registry->id,
+ O_RDONLY, 0666)) < 0) {
+ jack_error ("Cannot open shm segment %s (%s)", registry->id,
+ strerror (errno));
+ return -1;
+ }
+
+ if ((si->attached_at = mmap (0, registry->size, PROT_READ,
+ MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
+ jack_error ("Cannot mmap shm segment %s (%s)",
+ registry->id,
+ strerror (errno));
+ close (shm_fd);
+ return -1;
+ }
+
+ close (shm_fd);
+ return 0;
+}
+
+#elif WIN32
+
+static int
+jack_access_registry (jack_shm_info_t *ri)
+{
+ /* registry must be locked */
+ HANDLE shm_fd;
+ LPSECURITY_ATTRIBUTES sec = 0;
+
+ strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
+
+ /* try to open an existing segment */
+
+ if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
+ int rc = GetLastError();
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ jack_error ("Cannot open existing shm registry segment (%ld)", rc);
+ }
+ return rc;
+ }
+
+ if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
+ jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
+ jack_remove_shm (&registry_id);
+ CloseHandle (shm_fd);
+ return EINVAL;
+ }
+
+ /* set up global pointers */
+ ri->index = JACK_SHM_REGISTRY_INDEX;
+ jack_shm_header = ri->attached_at;
+ jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
+
+ //CloseHandle(shm_fd); // TO CHECK
+ return 0;
+}
+
+static int
+jack_create_registry (jack_shm_info_t *ri)
+{
+ /* registry must be locked */
+ HANDLE shm_fd;
+
+ strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
+
+ if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
+ 0, PAGE_READWRITE,
+ 0, JACK_SHM_REGISTRY_SIZE,
+ registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
+ int rc = GetLastError();
+ jack_error ("Cannot create shm registry segment (%ld)", rc);
+ return rc;
+ }
+
+ if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
+ jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
+ jack_remove_shm (&registry_id);
+ CloseHandle (shm_fd);
+ return EINVAL;
+ }
+
+ /* set up global pointers */
+ ri->index = JACK_SHM_REGISTRY_INDEX;
+ jack_shm_header = ri->attached_at;
+ jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
+
+ /* initialize registry contents */
+ jack_shm_init_registry ();
+
+ //CloseHandle(shm_fd); // TO CHECK
+ return 0;
+}
+
+static void
+jack_remove_shm (jack_shm_id_t *id)
+{
+ /* nothing to do */
+}
+
+void
+jack_release_shm (jack_shm_info_t* si)
+{
+ /* registry may or may not be locked */
+ if (si->attached_at != NULL) {
+ UnmapViewOfFile (si->attached_at);
+ }
+}
+
+int
+jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
+{
+ jack_shm_registry_t* registry;
+ HANDLE shm_fd;
+ int rc = -1;
+ char name[SHM_NAME_MAX+1];
+
+ jack_shm_lock_registry ();
+
+ if ((registry = jack_get_free_shm_info ()) == NULL) {
+ jack_error ("shm registry full");
+ goto unlock;
+ }
+
+ snprintf (name, sizeof (name), "jack-%d", registry->index);
+
+ if (strlen (name) >= sizeof (registry->id)) {
+ jack_error ("shm segment name too long %s", name);
+ goto unlock;
+ }
+
+ if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
+ 0, PAGE_READWRITE,
+ 0, size,
+ name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
+ int rc = GetLastError();
+ jack_error ("Cannot create shm segment (%ld)",rc);
+ goto unlock;
+ }
+
+ //CloseHandle (shm_fd); // TO CHECK
+
+ registry->size = size;
+ strncpy (registry->id, name, sizeof (registry->id));
+ registry->allocator = _getpid();
+ si->index = registry->index;
+ si->attached_at = NULL; /* not attached */
+ rc = 0; /* success */
+
+ unlock:
+ jack_shm_unlock_registry ();
+ return rc;
+}
+
+int
+jack_attach_shm (jack_shm_info_t* si)
+{
+ HANDLE shm_fd;
+ jack_shm_registry_t *registry = &jack_shm_registry[si->index];
+
+ if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
+ int rc = GetLastError();
+ jack_error ("Cannot open shm segment (%ld)",rc);
+ return -1;
+ }
+
+ if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
+ jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
+ jack_remove_shm (&registry_id);
+ CloseHandle (shm_fd);
+ return -1;
+ }
+
+ //CloseHandle (shm_fd); // TO CHECK
+ return 0;
+}
+
+int
+jack_attach_shm_read (jack_shm_info_t* si)
+{
+ HANDLE shm_fd;
+ jack_shm_registry_t *registry = &jack_shm_registry[si->index];
+
+ if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
+ int rc = GetLastError();
+ jack_error ("Cannot open shm segment (%ld)",rc);
+ return -1;
+ }
+
+ if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
+ jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
+ jack_remove_shm (&registry_id);
+ CloseHandle (shm_fd);
+ return -1;
+ }
+
+ //CloseHandle (shm_fd); // TO CHECK
+ return 0;
+}
+
+#else
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * System V interface-dependent functions
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* gain addressability to existing SHM registry segment
+ *
+ * sets up global registry pointers, if successful
+ *
+ * returns: 0 if existing registry accessed successfully
+ * ENOENT if registry does not exist
+ * EINVAL if registry exists, but has the wrong size
+ * other nonzero error code if unable to access registry
+ */
+static int
+jack_access_registry (jack_shm_info_t *ri)
+{
+ /* registry must be locked */
+
+ /* try without IPC_CREAT to get existing segment */
+ if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
+ JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
+
+ switch (errno) {
+
+ case ENOENT: /* segment does not exist */
+ return ENOENT;
+
+ case EINVAL: /* segment exists, but too small */
+ /* attempt minimum size access */
+ registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
+ return EINVAL;
+
+ default: /* or other error */
+ jack_error ("unable to access shm registry (%s)",
+ strerror (errno));
+ return errno;
+ }
+ }
+
+ if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
+ jack_error ("Cannot attach shm registry segment (%s)",
+ strerror (errno));
+ return EINVAL;
+ }
+
+ /* set up global pointers */
+ ri->index = JACK_SHM_REGISTRY_INDEX;
+ jack_shm_header = ri->attached_at;
+ jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
+ return 0;
+}
+
+/* create a new SHM registry segment
+ *
+ * sets up global registry pointers, if successful
+ *
+ * returns: 0 if registry created successfully
+ * nonzero error code if unable to allocate a new registry
+ */
+static int
+jack_create_registry (jack_shm_info_t *ri)
+{
+ /* registry must be locked */
+ if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
+ JACK_SHM_REGISTRY_SIZE,
+ 0666|IPC_CREAT)) < 0) {
+ jack_error ("Cannot create shm registry segment (%s)",
+ strerror (errno));
+ return errno;
+ }
+
+ if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
+ jack_error ("Cannot attach shm registry segment (%s)",
+ strerror (errno));
+ return EINVAL;
+ }
+
+ /* set up global pointers */
+ ri->index = JACK_SHM_REGISTRY_INDEX;
+ jack_shm_header = ri->attached_at;
+ jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
+
+ /* initialize registry contents */
+ jack_shm_init_registry ();
+ return 0;
+}
+
+static void
+jack_remove_shm (jack_shm_id_t *id)
+{
+ /* registry may or may not be locked */
+ shmctl (*id, IPC_RMID, NULL);
+}
+
+void
+jack_release_shm (jack_shm_info_t* si)
+{
+ /* registry may or may not be locked */
+ if (si->attached_at != MAP_FAILED) {
+ shmdt (si->attached_at);
+ }
+}
+
+int
+jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
+ jack_shm_info_t* si)
+{
+ int shmflags;
+ int shmid;
+ int rc = -1;
+ jack_shm_registry_t* registry;
+
+ jack_shm_lock_registry ();
+
+ if ((registry = jack_get_free_shm_info ())) {
+
+ shmflags = 0666 | IPC_CREAT | IPC_EXCL;
+
+ if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
+
+ registry->size = size;
+ registry->id = shmid;
+ registry->allocator = getpid();
+ si->index = registry->index;
+ si->attached_at = MAP_FAILED; /* not attached */
+ rc = 0;
+
+ } else {
+ jack_error ("Cannot create shm segment %s (%s)",
+ name_not_used, strerror (errno));
+ }
+ }
+
+ jack_shm_unlock_registry ();
+ return rc;
+}
+
+int
+jack_attach_shm (jack_shm_info_t* si)
+{
+ if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
+ jack_error ("Cannot attach shm segment (%s)",
+ strerror (errno));
+ jack_release_shm_info (si->index);
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* !USE_POSIX_SHM */
diff --git a/common/shm.h b/common/shm.h
new file mode 100644
index 00000000..2ef29fc4
--- /dev/null
+++ b/common/shm.h
@@ -0,0 +1,156 @@
+#ifndef __jack_shm_h__
+#define __jack_shm_h__
+
+#include <limits.h>
+#include <sys/types.h>
+#include "types.h"
+#include "JackExports.h"
+
+
+#define TRUE 1
+#define FALSE 0
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define MAX_SERVERS 8 /* maximum concurrent servers */
+#define MAX_SHM_ID 256 /* generally about 16 per server */
+#define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */
+#define JACK_SHM_MAGIC 0x4a41434b /* shm magic number: "JACK" */
+#define JACK_SHM_NULL_INDEX -1 /* NULL SHM index */
+#define JACK_SHM_REGISTRY_INDEX -2 /* pseudo SHM index for registry */
+
+
+ /* On Mac OS X, SHM_NAME_MAX is the maximum length of a shared memory
+ * segment name (instead of NAME_MAX or PATH_MAX as defined by the
+ * standard).
+ */
+#ifdef USE_POSIX_SHM
+
+#ifndef SHM_NAME_MAX
+#define SHM_NAME_MAX NAME_MAX
+#endif
+ typedef char shm_name_t[SHM_NAME_MAX];
+ typedef shm_name_t jack_shm_id_t;
+
+#elif WIN32 // steph TO CHECK
+#define NAME_MAX 255
+#ifndef SHM_NAME_MAX
+#define SHM_NAME_MAX NAME_MAX
+#endif
+ typedef char shm_name_t[SHM_NAME_MAX];
+ typedef shm_name_t jack_shm_id_t;
+
+#else
+ /* System V SHM */
+ typedef int jack_shm_id_t;
+#endif /* SHM type */
+
+ /* shared memory type */
+ typedef enum {
+ shm_POSIX = 1, /* POSIX shared memory */
+ shm_SYSV = 2, /* System V shared memory */
+ shm_WIN32 = 3 /* Windows 32 shared memory */
+ } jack_shmtype_t;
+
+ typedef int16_t jack_shm_registry_index_t;
+
+ /**
+ * A structure holding information about shared memory allocated by
+ * JACK. this persists across invocations of JACK, and can be used by
+ * multiple JACK servers. It contains no pointers and is valid across
+ * address spaces.
+ *
+ * The registry consists of two parts: a header including an array of
+ * server names, followed by an array of segment registry entries.
+ */
+ typedef struct _jack_shm_server {
+#ifdef WIN32
+ int pid; /* process ID */
+#else
+
+ pid_t pid; /* process ID */
+#endif
+
+ char name[JACK_SERVER_NAME_SIZE];
+ }
+ jack_shm_server_t;
+
+ typedef struct _jack_shm_header {
+ uint32_t magic; /* magic number */
+ uint16_t protocol; /* JACK protocol version */
+ jack_shmtype_t type; /* shm type */
+ jack_shmsize_t size; /* total registry segment size */
+ jack_shmsize_t hdr_len; /* size of header */
+ jack_shmsize_t entry_len; /* size of registry entry */
+ jack_shm_server_t server[MAX_SERVERS]; /* current server array */
+ }
+ jack_shm_header_t;
+
+ typedef struct _jack_shm_registry {
+ jack_shm_registry_index_t index; /* offset into the registry */
+
+#ifdef WIN32
+
+ int allocator; /* PID that created shm segment */
+#else
+
+ pid_t allocator; /* PID that created shm segment */
+#endif
+
+ jack_shmsize_t size; /* for POSIX unattach */
+ jack_shm_id_t id; /* API specific, see above */
+ }
+ jack_shm_registry_t;
+
+#define JACK_SHM_REGISTRY_SIZE (sizeof (jack_shm_header_t) \
+ + sizeof (jack_shm_registry_t) * MAX_SHM_ID)
+
+ /**
+ * a structure holding information about shared memory
+ * allocated by JACK. this version is valid only
+ * for a given address space. It contains a pointer
+ * indicating where the shared memory has been
+ * attached to the address space.
+ */
+ typedef struct _jack_shm_info {
+ jack_shm_registry_index_t index; /* offset into the registry */
+ void *attached_at; /* address where attached */
+ }
+ jack_shm_info_t;
+
+ /* utility functions used only within JACK */
+
+ extern void jack_shm_copy_from_registry (jack_shm_info_t*,
+ jack_shm_registry_index_t);
+ extern void jack_shm_copy_to_registry (jack_shm_info_t*,
+ jack_shm_registry_index_t*);
+ extern void jack_release_shm_info (jack_shm_registry_index_t);
+
+ extern char* jack_shm_addr (jack_shm_info_t* si); // steph
+
+ /* here beginneth the API */
+
+ EXPORT extern int jack_register_server (const char *server_name);
+ EXPORT extern void jack_unregister_server (const char *server_name);
+
+ extern int jack_initialize_shm (const char *server_name);
+ extern int jack_initialize_shm_server (void); // steph
+ extern int jack_initialize_shm_client (void); // steph
+ EXPORT extern int jack_cleanup_shm (void);
+
+ extern int jack_shmalloc (const char *shm_name, jack_shmsize_t size,
+ jack_shm_info_t* result);
+ extern void jack_release_shm (jack_shm_info_t*);
+ extern void jack_destroy_shm (jack_shm_info_t*);
+ extern int jack_attach_shm (jack_shm_info_t*);
+ extern int jack_attach_shm_read (jack_shm_info_t*); // steph
+ extern int jack_resize_shm (jack_shm_info_t*, jack_shmsize_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_shm_h__ */
diff --git a/common/statistics.h b/common/statistics.h
new file mode 100644
index 00000000..23ea4b66
--- /dev/null
+++ b/common/statistics.h
@@ -0,0 +1,59 @@
+/*
+* Copyright (C) 2004 Rui Nuno Capela, Lee Revell
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either version 2.1
+* of the License, or (at your option) any later version.
+*
+* This program 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this program; if not, write to the Free
+* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+* 02111-1307, USA.
+*
+* $Id: statistics.h,v 1.2.2.3 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __statistics_h__
+#define __statistics_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ //#include <jack/types.h>
+#include "types.h"
+
+ /**
+ * @return the maximum delay reported by the backend since
+ * startup or reset. When compared to the period size in usecs, this
+ * can be used to estimate the ideal period size for a given setup.
+ */
+ float jack_get_max_delayed_usecs (jack_client_t *client);
+
+ /**
+ * @return the delay in microseconds due to the most recent XRUN
+ * occurrence. This probably only makes sense when called from a @ref
+ * JackXRunCallback defined using jack_set_xrun_callback().
+ */
+ float jack_get_xrun_delayed_usecs (jack_client_t *client);
+
+ /**
+ * Reset the maximum delay counter. This would be useful
+ * to estimate the effect that a change to the configuration of a running
+ * system (e.g. toggling kernel preemption) has on the delay
+ * experienced by JACK, without having to restart the JACK engine.
+ */
+ void jack_reset_max_delayed_usecs (jack_client_t *client);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __statistics_h__ */
diff --git a/common/thread.h b/common/thread.h
new file mode 100644
index 00000000..a7ddd4a7
--- /dev/null
+++ b/common/thread.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2004 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: thread.h,v 1.1.2.2 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_thread_h__
+#define __jack_thread_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef WIN32
+ #include <windows.h>
+ typedef HANDLE pthread_t;
+#else
+ #include <pthread.h>
+#endif
+
+
+ /** @file thread.h
+ *
+ * Library functions to standardize thread creation for JACK and its
+ * clients. These interfaces hide some system variations in the
+ * handling of realtime scheduling and associated privileges.
+ */
+
+ /**
+ * Attempt to enable realtime scheduling for a thread. On some
+ * systems that may require special privileges.
+ *
+ * @param thread POSIX thread ID.
+ * @param priority requested thread priority.
+ *
+ * @returns 0, if successful; EPERM, if the calling process lacks
+ * required realtime privileges; otherwise some other error number.
+ */
+ int jack_acquire_real_time_scheduling (pthread_t thread, int priority);
+
+ /**
+ * Create a thread for JACK or one of its clients. The thread is
+ * created executing @a start_routine with @a arg as its sole
+ * argument.
+ *
+ * @param client the JACK client for whom the thread is being created. May be
+ * NULL if the client is being created within the JACK server.
+ * @param thread place to return POSIX thread ID.
+ * @param priority thread priority, if realtime.
+ * @param realtime true for the thread to use realtime scheduling. On
+ * some systems that may require special privileges.
+ * @param start_routine function the thread calls when it starts.
+ * @param arg parameter passed to the @a start_routine.
+ *
+ * @returns 0, if successful; otherwise some error number.
+ */
+ int jack_client_create_thread (jack_client_t* client,
+ pthread_t *thread,
+ int priority,
+ int realtime, /* boolean */
+ void *(*start_routine)(void*),
+ void *arg);
+
+ /**
+ * Drop realtime scheduling for a thread.
+ *
+ * @param thread POSIX thread ID.
+ *
+ * @returns 0, if successful; otherwise an error number.
+ */
+ int jack_drop_real_time_scheduling (pthread_t thread);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_thread_h__ */
diff --git a/common/transport.h b/common/transport.h
new file mode 100644
index 00000000..877f8a68
--- /dev/null
+++ b/common/transport.h
@@ -0,0 +1,430 @@
+/*
+ Copyright (C) 2002 Paul Davis
+ Copyright (C) 2003 Jack O'Quin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: transport.h,v 1.8.2.5 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_transport_h__
+#define __jack_transport_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ //#include <jack/types.h>
+#include "types.h"
+
+ /**
+ * Transport states.
+ */
+ typedef enum {
+
+ /* the order matters for binary compatibility */
+ JackTransportStopped = 0, /**< Transport halted */
+ JackTransportRolling = 1, /**< Transport playing */
+ JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */
+ JackTransportStarting = 3, /**< Waiting for sync ready */
+ JackTransportSynching = 4 /**< temporary*/
+
+ } jack_transport_state_t;
+
+ typedef uint64_t jack_unique_t; /**< Unique ID (opaque) */
+
+ /**
+ * Optional struct jack_position_t fields.
+ */
+ typedef enum {
+
+ JackPositionBBT = 0x10, /**< Bar, Beat, Tick */
+ JackPositionTimecode = 0x20 /**< External timecode */
+
+ } jack_position_bits_t;
+
+ /** all valid position bits */
+#define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode)
+#define EXTENDED_TIME_INFO
+
+ /**
+ * Struct for transport position information.
+ */
+ typedef struct {
+
+ /* these four cannot be set from clients: the server sets them */
+ jack_unique_t unique_1; /**< unique ID */
+ jack_time_t usecs; /**< monotonic, free-rolling */
+ jack_nframes_t frame_rate; /**< current frame rate (per second) */
+ jack_nframes_t frame; /**< frame number, always present */
+
+ jack_position_bits_t valid; /**< which other fields are valid */
+
+ /* JackPositionBBT fields: */
+ int32_t bar; /**< current bar */
+ int32_t beat; /**< current beat-within-bar */
+ int32_t tick; /**< current tick-within-beat */
+ double bar_start_tick;
+
+ float beats_per_bar; /**< time signature "numerator" */
+ float beat_type; /**< time signature "denominator" */
+ double ticks_per_beat;
+ double beats_per_minute;
+
+ /* JackPositionTimecode fields: (EXPERIMENTAL: could change) */
+ double frame_time; /**< current time in seconds */
+ double next_time; /**< next sequential frame_time
+ (unless repositioned) */
+
+ /* For binary compatibility, new fields should be allocated from
+ * this padding area with new valid bits controlling access, so
+ * the existing structure size and offsets are preserved. */
+ int32_t padding[10];
+
+ /* When (unique_1 == unique_2) the contents are consistent. */
+ jack_unique_t unique_2; /**< unique ID */
+
+ }
+ jack_position_t;
+
+ /**
+ * Called by the timebase master to release itself from that
+ * responsibility.
+ *
+ * If the timebase master releases the timebase or leaves the JACK
+ * graph for any reason, the JACK engine takes over at the start of
+ * the next process cycle. The transport state does not change. If
+ * rolling, it continues to play, with frame numbers as the only
+ * available position information.
+ *
+ * @see jack_set_timebase_callback
+ *
+ * @param client the JACK client structure.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ */
+
+ int jack_release_timebase (jack_client_t *client);
+
+ /**
+ * Prototype for the @a sync_callback defined by slow-sync clients.
+ * When the client is active, this callback is invoked just before
+ * process() in the same thread. This occurs once after registration,
+ * then subsequently whenever some client requests a new position, or
+ * the transport enters the ::JackTransportStarting state. This
+ * realtime function must not wait.
+ *
+ * The transport @a state will be:
+ *
+ * - ::JackTransportStopped when a new position is requested;
+ * - ::JackTransportStarting when the transport is waiting to start;
+ * - ::JackTransportRolling when the timeout has expired, and the
+ * position is now a moving target.
+ *
+ * @param state current transport state.
+ * @param pos new transport position.
+ * @param arg the argument supplied by jack_set_sync_callback().
+ *
+ * @return TRUE (non-zero) when ready to roll.
+ */
+ typedef int (*JackSyncCallback)(jack_transport_state_t state,
+ jack_position_t *pos,
+ void *arg);
+
+ /**
+ * Register (or unregister) as a slow-sync client, one that cannot
+ * respond immediately to transport position changes.
+ *
+ * The @a sync_callback will be invoked at the first available
+ * opportunity after its registration is complete. If the client is
+ * currently active this will be the following process cycle,
+ * otherwise it will be the first cycle after calling jack_activate().
+ * After that, it runs according to the ::JackSyncCallback rules.
+ * Clients that don't set a @a sync_callback are assumed to be ready
+ * immediately any time the transport wants to start.
+ *
+ * @param client the JACK client structure.
+ * @param sync_callback is a realtime function that returns TRUE when
+ * the client is ready. Setting @a sync_callback to NULL declares that
+ * this client no longer requires slow-sync processing.
+ * @param arg an argument for the @a sync_callback function.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ */
+
+ int jack_set_sync_callback (jack_client_t *client,
+ JackSyncCallback sync_callback,
+ void *arg);
+ /**
+ * Set the timeout value for slow-sync clients.
+ *
+ * This timeout prevents unresponsive slow-sync clients from
+ * completely halting the transport mechanism. The default is two
+ * seconds. When the timeout expires, the transport starts rolling,
+ * even if some slow-sync clients are still unready. The @a
+ * sync_callbacks of these clients continue being invoked, giving them
+ * a chance to catch up.
+ *
+ * @see jack_set_sync_callback
+ *
+ * @param client the JACK client structure.
+ * @param timeout is delay (in microseconds) before the timeout expires.
+ *
+ * @return 0 on success, otherwise a non-zero error code.
+ */
+
+ int jack_set_sync_timeout (jack_client_t *client,
+ jack_time_t timeout);
+ /**
+ * Prototype for the @a timebase_callback used to provide extended
+ * position information. Its output affects all of the following
+ * process cycle. This realtime function must not wait.
+ *
+ * This function is called immediately after process() in the same
+ * thread whenever the transport is rolling, or when any client has
+ * requested a new position in the previous cycle. The first cycle
+ * after jack_set_timebase_callback() is also treated as a new
+ * position, or the first cycle after jack_activate() if the client
+ * had been inactive.
+ *
+ * The timebase master may not use its @a pos argument to set @a
+ * pos->frame. To change position, use jack_transport_reposition() or
+ * jack_transport_locate(). These functions are realtime-safe, the @a
+ * timebase_callback can call them directly.
+ *
+ * @param state current transport state.
+ * @param nframes number of frames in current period.
+ * @param pos address of the position structure for the next cycle; @a
+ * pos->frame will be its frame number. If @a new_pos is FALSE, this
+ * structure contains extended position information from the current
+ * cycle. If TRUE, it contains whatever was set by the requester.
+ * The @a timebase_callback's task is to update the extended
+ * information here.
+ * @param new_pos TRUE (non-zero) for a newly requested @a pos, or for
+ * the first cycle after the @a timebase_callback is defined.
+ * @param arg the argument supplied by jack_set_timebase_callback().
+ */
+ typedef void (*JackTimebaseCallback)(jack_transport_state_t state,
+ jack_nframes_t nframes,
+ jack_position_t *pos,
+ int new_pos,
+ void *arg);
+
+ /**
+ * Register as timebase master for the JACK subsystem.
+ *
+ * The timebase master registers a callback that updates extended
+ * position information such as beats or timecode whenever necessary.
+ * Without this extended information, there is no need for this
+ * function.
+ *
+ * There is never more than one master at a time. When a new client
+ * takes over, the former @a timebase_callback is no longer called.
+ * Taking over the timebase may be done conditionally, so it fails if
+ * there was a master already.
+ *
+ * @param client the JACK client structure.
+ * @param conditional non-zero for a conditional request.
+ * @param timebase_callback is a realtime function that returns
+ * position information.
+ * @param arg an argument for the @a timebase_callback function.
+ *
+ * @return
+ * - 0 on success;
+ * - EBUSY if a conditional request fails because there was already a
+ * timebase master;
+ * - other non-zero error code.
+ */
+
+ int jack_set_timebase_callback (jack_client_t *client,
+ int conditional,
+ JackTimebaseCallback timebase_callback,
+ void *arg);
+ /**
+ * Reposition the transport to a new frame number.
+ *
+ * May be called at any time by any client. The new position takes
+ * effect in two process cycles. If there are slow-sync clients and
+ * the transport is already rolling, it will enter the
+ * ::JackTransportStarting state and begin invoking their @a
+ * sync_callbacks until ready. This function is realtime-safe.
+ *
+ * @see jack_transport_reposition, jack_set_sync_callback
+ *
+ * @param client the JACK client structure.
+ * @param frame frame number of new transport position.
+ *
+ * @return 0 if valid request, non-zero otherwise.
+ */
+
+ int jack_transport_locate (jack_client_t *client,
+ jack_nframes_t frame);
+ /**
+ * Query the current transport state and position.
+ *
+ * This function is realtime-safe, and can be called from any thread.
+ * If called from the process thread, @a pos corresponds to the first
+ * frame of the current cycle and the state returned is valid for the
+ * entire cycle.
+ *
+ * @param client the JACK client structure.
+ * @param pos pointer to structure for returning current transport
+ * position; @a pos->valid will show which fields contain valid data.
+ * If @a pos is NULL, do not return position information.
+ *
+ * @return Current transport state.
+ */
+
+ jack_transport_state_t jack_transport_query (const jack_client_t *client,
+ jack_position_t *pos);
+ /**
+ * Return an estimate of the current transport frame,
+ * including any time elapsed since the last transport
+ * positional update.
+ *
+ * @param client the JACK client structure
+ */
+
+ jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client);
+ /**
+ * Request a new transport position.
+ *
+ * May be called at any time by any client. The new position takes
+ * effect in two process cycles. If there are slow-sync clients and
+ * the transport is already rolling, it will enter the
+ * ::JackTransportStarting state and begin invoking their @a
+ * sync_callbacks until ready. This function is realtime-safe.
+ *
+ * @see jack_transport_locate, jack_set_sync_callback
+ *
+ * @param client the JACK client structure.
+ * @param pos requested new transport position.
+ *
+ * @return 0 if valid request, EINVAL if position structure rejected.
+ */
+
+ int jack_transport_reposition (jack_client_t *client,
+ jack_position_t *pos);
+ /**
+ * Start the JACK transport rolling.
+ *
+ * Any client can make this request at any time. It takes effect no
+ * sooner than the next process cycle, perhaps later if there are
+ * slow-sync clients. This function is realtime-safe.
+ *
+ * @see jack_set_sync_callback
+ *
+ * @param client the JACK client structure.
+ */
+
+ void jack_transport_start (jack_client_t *client);
+ /**
+ * Stop the JACK transport.
+ *
+ * Any client can make this request at any time. It takes effect on
+ * the next process cycle. This function is realtime-safe.
+ *
+ * @param client the JACK client structure.
+ */
+
+ void jack_transport_stop (jack_client_t *client);
+
+ /*********************************************************************
+ * The following interfaces are DEPRECATED. They are only provided
+ * for compatibility with the earlier JACK transport implementation.
+ *********************************************************************/
+
+ /**
+ * Optional struct jack_transport_info_t fields.
+ *
+ * @see jack_position_bits_t.
+ */
+ typedef enum {
+
+ JackTransportState = 0x1, /**< Transport state */
+ JackTransportPosition = 0x2, /**< Frame number */
+ JackTransportLoop = 0x4, /**< Loop boundaries (ignored) */
+ JackTransportSMPTE = 0x8, /**< SMPTE (ignored) */
+ JackTransportBBT = 0x10 /**< Bar, Beat, Tick */
+
+ } jack_transport_bits_t;
+
+ /**
+ * Deprecated struct for transport position information.
+ *
+ * @deprecated This is for compatibility with the earlier transport
+ * interface. Use the jack_position_t struct, instead.
+ */
+ typedef struct {
+
+ /* these two cannot be set from clients: the server sets them */
+
+ jack_nframes_t frame_rate; /**< current frame rate (per second) */
+ jack_time_t usecs; /**< monotonic, free-rolling */
+
+ jack_transport_bits_t valid; /**< which fields are legal to read */
+ jack_transport_state_t transport_state;
+ jack_nframes_t frame;
+ jack_nframes_t loop_start;
+ jack_nframes_t loop_end;
+
+ long smpte_offset; /**< SMPTE offset (from frame 0) */
+ float smpte_frame_rate; /**< 29.97, 30, 24 etc. */
+
+ int bar;
+ int beat;
+ int tick;
+ double bar_start_tick;
+
+ float beats_per_bar;
+ float beat_type;
+ double ticks_per_beat;
+ double beats_per_minute;
+
+ }
+ jack_transport_info_t;
+
+ /**
+ * Gets the current transport info structure (deprecated).
+ *
+ * @param client the JACK client structure.
+ * @param tinfo current transport info structure. The "valid" field
+ * describes which fields contain valid data.
+ *
+ * @deprecated This is for compatibility with the earlier transport
+ * interface. Use jack_transport_query(), instead.
+ *
+ * @pre Must be called from the process thread.
+ */
+
+ void jack_get_transport_info (jack_client_t *client,
+ jack_transport_info_t *tinfo);
+ /**
+ * Set the transport info structure (deprecated).
+ *
+ * @deprecated This function still exists for compatibility with the
+ * earlier transport interface, but it does nothing. Instead, define
+ * a ::JackTimebaseCallback.
+ */
+
+ void jack_set_transport_info (jack_client_t *client,
+ jack_transport_info_t *tinfo);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_transport_h__ */
diff --git a/common/transport_types.h b/common/transport_types.h
new file mode 100644
index 00000000..74aa94ec
--- /dev/null
+++ b/common/transport_types.h
@@ -0,0 +1,223 @@
+/*
+ Copyright (C) 2002 Paul Davis
+ Copyright (C) 2003 Jack O'Quin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: transport_types.h,v 1.1.2.2 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_transport_aux_h__
+#define __jack_transport_aux_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ //#include <jack/types.h>
+#include "types.h"
+
+ /**
+ * Transport states.
+ */
+ typedef enum {
+
+ /* the order matters for binary compatibility */
+ JackTransportStopped = 0, /**< Transport halted */
+ JackTransportRolling = 1, /**< Transport playing */
+ JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */
+ JackTransportStarting = 3, /**< Waiting for sync ready */
+ JackTransportSynching = 4 /**< temporary*/
+
+ } jack_transport_state_t;
+
+ typedef uint64_t jack_unique_t; /**< Unique ID (opaque) */
+
+ /**
+ * Optional struct jack_position_t fields.
+ */
+ typedef enum {
+
+ JackPositionBBT = 0x10, /**< Bar, Beat, Tick */
+ JackPositionTimecode = 0x20 /**< External timecode */
+
+ } jack_position_bits_t;
+
+ /** all valid position bits */
+#define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode)
+#define EXTENDED_TIME_INFO
+
+ /**
+ * Struct for transport position information.
+ */
+ typedef struct {
+
+ /* these four cannot be set from clients: the server sets them */
+ jack_unique_t unique_1; /**< unique ID */
+ jack_time_t usecs; /**< monotonic, free-rolling */
+ jack_nframes_t frame_rate; /**< current frame rate (per second) */
+ jack_nframes_t frame; /**< frame number, always present */
+
+ jack_position_bits_t valid; /**< which other fields are valid */
+
+ /* JackPositionBBT fields: */
+ int32_t bar; /**< current bar */
+ int32_t beat; /**< current beat-within-bar */
+ int32_t tick; /**< current tick-within-beat */
+ double bar_start_tick;
+
+ float beats_per_bar; /**< time signature "numerator" */
+ float beat_type; /**< time signature "denominator" */
+ double ticks_per_beat;
+ double beats_per_minute;
+
+ /* JackPositionTimecode fields: (EXPERIMENTAL: could change) */
+ double frame_time; /**< current time in seconds */
+ double next_time; /**< next sequential frame_time
+ (unless repositioned) */
+
+ /* For binary compatibility, new fields should be allocated from
+ * this padding area with new valid bits controlling access, so
+ * the existing structure size and offsets are preserved. */
+ int32_t padding[10];
+
+ /* When (unique_1 == unique_2) the contents are consistent. */
+ jack_unique_t unique_2; /**< unique ID */
+
+ }
+ jack_position_t;
+
+ /**
+ * Prototype for the @a sync_callback defined by slow-sync clients.
+ * When the client is active, this callback is invoked just before
+ * process() in the same thread. This occurs once after registration,
+ * then subsequently whenever some client requests a new position, or
+ * the transport enters the ::JackTransportStarting state. This
+ * realtime function must not wait.
+ *
+ * The transport @a state will be:
+ *
+ * - ::JackTransportStopped when a new position is requested;
+ * - ::JackTransportStarting when the transport is waiting to start;
+ * - ::JackTransportRolling when the timeout has expired, and the
+ * position is now a moving target.
+ *
+ * @param state current transport state.
+ * @param pos new transport position.
+ * @param arg the argument supplied by jack_set_sync_callback().
+ *
+ * @return TRUE (non-zero) when ready to roll.
+ */
+ typedef int (*JackSyncCallback)(jack_transport_state_t state,
+ jack_position_t *pos,
+ void *arg);
+
+
+ /**
+ * Prototype for the @a timebase_callback used to provide extended
+ * position information. Its output affects all of the following
+ * process cycle. This realtime function must not wait.
+ *
+ * This function is called immediately after process() in the same
+ * thread whenever the transport is rolling, or when any client has
+ * requested a new position in the previous cycle. The first cycle
+ * after jack_set_timebase_callback() is also treated as a new
+ * position, or the first cycle after jack_activate() if the client
+ * had been inactive.
+ *
+ * The timebase master may not use its @a pos argument to set @a
+ * pos->frame. To change position, use jack_transport_reposition() or
+ * jack_transport_locate(). These functions are realtime-safe, the @a
+ * timebase_callback can call them directly.
+ *
+ * @param state current transport state.
+ * @param nframes number of frames in current period.
+ * @param pos address of the position structure for the next cycle; @a
+ * pos->frame will be its frame number. If @a new_pos is FALSE, this
+ * structure contains extended position information from the current
+ * cycle. If TRUE, it contains whatever was set by the requester.
+ * The @a timebase_callback's task is to update the extended
+ * information here.
+ * @param new_pos TRUE (non-zero) for a newly requested @a pos, or for
+ * the first cycle after the @a timebase_callback is defined.
+ * @param arg the argument supplied by jack_set_timebase_callback().
+ */
+ typedef void (*JackTimebaseCallback)(jack_transport_state_t state,
+ jack_nframes_t nframes,
+ jack_position_t *pos,
+ int new_pos,
+ void *arg);
+
+ /*********************************************************************
+ * The following interfaces are DEPRECATED. They are only provided
+ * for compatibility with the earlier JACK transport implementation.
+ *********************************************************************/
+
+ /**
+ * Optional struct jack_transport_info_t fields.
+ *
+ * @see jack_position_bits_t.
+ */
+ typedef enum {
+
+ JackTransportState = 0x1, /**< Transport state */
+ JackTransportPosition = 0x2, /**< Frame number */
+ JackTransportLoop = 0x4, /**< Loop boundaries (ignored) */
+ JackTransportSMPTE = 0x8, /**< SMPTE (ignored) */
+ JackTransportBBT = 0x10 /**< Bar, Beat, Tick */
+
+ } jack_transport_bits_t;
+
+ /**
+ * Deprecated struct for transport position information.
+ *
+ * @deprecated This is for compatibility with the earlier transport
+ * interface. Use the jack_position_t struct, instead.
+ */
+ typedef struct {
+
+ /* these two cannot be set from clients: the server sets them */
+
+ jack_nframes_t frame_rate; /**< current frame rate (per second) */
+ jack_time_t usecs; /**< monotonic, free-rolling */
+
+ jack_transport_bits_t valid; /**< which fields are legal to read */
+ jack_transport_state_t transport_state;
+ jack_nframes_t frame;
+ jack_nframes_t loop_start;
+ jack_nframes_t loop_end;
+
+ long smpte_offset; /**< SMPTE offset (from frame 0) */
+ float smpte_frame_rate; /**< 29.97, 30, 24 etc. */
+
+ int bar;
+ int beat;
+ int tick;
+ double bar_start_tick;
+
+ float beats_per_bar;
+ float beat_type;
+ double ticks_per_beat;
+ double beats_per_minute;
+
+ }
+ jack_transport_info_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_transport_aux_h__ */
diff --git a/common/types.h b/common/types.h
new file mode 100644
index 00000000..ec294348
--- /dev/null
+++ b/common/types.h
@@ -0,0 +1,395 @@
+/*
+ Copyright (C) 2001 Paul Davis
+ Copyright (C) 2004 Jack O'Quin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: types.h,v 1.4.2.8 2006/06/20 14:44:00 letz Exp $
+*/
+
+#ifndef __jack_types_h__
+#define __jack_types_h__
+
+#ifdef WIN32
+ #include <windows.h>
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef long int32_t;
+typedef unsigned long uint32_t;
+typedef LONGLONG int64_t;
+typedef ULONGLONG uint64_t;
+#else
+ #include <inttypes.h>
+#endif
+
+typedef int32_t jack_shmsize_t;
+
+/**
+ * Type used to represent sample frame counts.
+ */
+typedef uint32_t jack_nframes_t;
+
+/**
+ * Maximum value that can be stored in jack_nframes_t
+ */
+#define JACK_MAX_FRAMES (4294967295U) /* This should be UINT32_MAX, but C++ has a problem with that. */
+
+/**
+ * Type used to represent the value of free running
+ * monotonic clock with units of microseconds.
+ */
+
+#ifdef WIN32
+typedef int64_t jack_time_t;
+//typedef double jack_time_t;
+//typedef uint64_t jack_time_t;
+
+#else
+typedef uint64_t jack_time_t;
+#endif
+
+/**
+ * Maximum size of @a load_init string passed to an internal client
+ * jack_initialize() function via jack_internal_client_load().
+ */
+#define JACK_LOAD_INIT_LIMIT 1024
+
+/**
+ * jack_intclient_t is an opaque type representing a loaded internal
+ * client. You may only access it using the API provided in @ref
+ * intclient.h "<jack/intclient.h>".
+ */
+typedef uint64_t jack_intclient_t;
+
+/**
+ * jack_port_t is an opaque type. You may only access it using the
+ * API provided.
+ */
+typedef struct _jack_port jack_port_t;
+
+/**
+ * jack_client_t is an opaque type. You may only access it using the
+ * API provided.
+ */
+typedef struct _jack_client jack_client_t;
+
+/**
+ * Ports have unique ids. A port registration callback is the only
+ * place you ever need to know their value.
+ */
+#if defined(__x86_64__)
+typedef uint64_t jack_port_id_t;
+#else
+typedef uint32_t jack_port_id_t;
+#endif
+
+/**
+ * Prototype for the client supplied function that is called
+ * by the engine anytime there is work to be done.
+ *
+ * @pre nframes == jack_get_buffer_size()
+ * @pre nframes == pow(2,x)
+ *
+ * @param nframes number of frames to process
+ * @param arg pointer to a client supplied structure
+ *
+ * @return zero on success, non-zero on error
+ */
+typedef int (*JackProcessCallback)(jack_nframes_t nframes, void *arg);
+
+/**
+ * Prototype for the client supplied function that is called
+ * once after the creation of the thread in which other
+ * callbacks will be made. Special thread characteristics
+ * can be set from this callback, for example. This is a
+ * highly specialized callback and most clients will not
+ * and should not use it.
+ *
+ * @param arg pointer to a client supplied structure
+ *
+ * @return void
+ */
+typedef void (*JackThreadInitCallback)(void *arg);
+
+/**
+ * Prototype for the client supplied function that is called
+ * whenever the processing graph is reordered.
+ *
+ * @param arg pointer to a client supplied structure
+ *
+ * @return zero on success, non-zero on error
+ */
+typedef int (*JackGraphOrderCallback)(void *arg);
+
+/**
+ * Prototype for the client-supplied function that is called whenever
+ * an xrun has occured.
+ *
+ * @see jack_get_xrun_delayed_usecs()
+ *
+ * @param arg pointer to a client supplied structure
+ *
+ * @return zero on success, non-zero on error
+ */
+typedef int (*JackXRunCallback)(void *arg);
+
+/**
+ * Prototype for the @a bufsize_callback that is invoked whenever the
+ * JACK engine buffer size changes. Although this function is called
+ * in the JACK process thread, the normal process cycle is suspended
+ * during its operation, causing a gap in the audio flow. So, the @a
+ * bufsize_callback can allocate storage, touch memory not previously
+ * referenced, and perform other operations that are not realtime
+ * safe.
+ *
+ * @param nframes buffer size
+ * @param arg pointer supplied by jack_set_buffer_size_callback().
+ *
+ * @return zero on success, non-zero on error
+ */
+typedef int (*JackBufferSizeCallback)(jack_nframes_t nframes, void *arg);
+
+/**
+ * Prototype for the client supplied function that is called
+ * when the engine sample rate changes.
+ *
+ * @param nframes new engine sample rate
+ * @param arg pointer to a client supplied structure
+ *
+ * @return zero on success, non-zero on error
+ */
+typedef int (*JackSampleRateCallback)(jack_nframes_t nframes, void *arg);
+
+/**
+ * Prototype for the client supplied function that is called
+ * whenever a port is registered or unregistered.
+ *
+ * @param arg pointer to a client supplied structure
+ */
+typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg);
+
+/**
+ * Prototype for the client supplied function that is called
+ * whenever jackd starts or stops freewheeling.
+ *
+ * @param starting non-zero if we start starting to freewheel, zero otherwise
+ * @param arg pointer to a client supplied structure
+ */
+typedef void (*JackFreewheelCallback)(int starting, void *arg);
+
+/**
+ * Used for the type argument of jack_port_register() for default
+ * audio ports.
+ */
+#define JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio"
+
+/**
+ * For convenience, use this typedef if you want to be able to change
+ * between float and double. You may want to typedef sample_t to
+ * jack_default_audio_sample_t in your application.
+ */
+typedef float jack_default_audio_sample_t;
+
+/**
+ * A port has a set of flags that are formed by AND-ing together the
+ * desired values from the list below. The flags "JackPortIsInput" and
+ * "JackPortIsOutput" are mutually exclusive and it is an error to use
+ * them both.
+ */
+enum JackPortFlags {
+
+ /**
+ * if JackPortIsInput is set, then the port can receive
+ * data.
+ */
+ JackPortIsInput = 0x1,
+
+ /**
+ * if JackPortIsOutput is set, then data can be read from
+ * the port.
+ */
+ JackPortIsOutput = 0x2,
+
+ /**
+ * if JackPortIsPhysical is set, then the port corresponds
+ * to some kind of physical I/O connector.
+ */
+ JackPortIsPhysical = 0x4,
+
+ /**
+ * if JackPortCanMonitor is set, then a call to
+ * jack_port_request_monitor() makes sense.
+ *
+ * Precisely what this means is dependent on the client. A typical
+ * result of it being called with TRUE as the second argument is
+ * that data that would be available from an output port (with
+ * JackPortIsPhysical set) is sent to a physical output connector
+ * as well, so that it can be heard/seen/whatever.
+ *
+ * Clients that do not control physical interfaces
+ * should never create ports with this bit set.
+ */
+ JackPortCanMonitor = 0x8,
+
+ /**
+ * JackPortIsTerminal means:
+ *
+ * for an input port: the data received by the port
+ * will not be passed on or made
+ * available at any other port
+ *
+ * for an output port: the data available at the port
+ * does not originate from any other port
+ *
+ * Audio synthesizers, I/O hardware interface clients, HDR
+ * systems are examples of clients that would set this flag for
+ * their ports.
+ */
+ JackPortIsTerminal = 0x10
+};
+
+/**
+ * @ref jack_options_t bits
+ */
+enum JackOptions {
+
+ /**
+ * Null value to use when no option bits are needed.
+ */
+ JackNullOption = 0x00,
+
+ /**
+ * Do not automatically start the JACK server when it is not
+ * already running. This option is always selected if
+ * \$JACK_NO_START_SERVER is defined in the calling process
+ * environment.
+ */
+ JackNoStartServer = 0x01,
+
+ /**
+ * Use the exact client name requested. Otherwise, JACK
+ * automatically generates a unique one, if needed.
+ */
+ JackUseExactName = 0x02,
+
+ /**
+ * Open with optional <em>(char *) server_name</em> parameter.
+ */
+ JackServerName = 0x04,
+
+ /**
+ * Load internal client from optional <em>(char *)
+ * load_name</em>. Otherwise use the @a client_name.
+ */
+ JackLoadName = 0x08,
+
+ /**
+ * Pass optional <em>(char *) load_init</em> string to the
+ * jack_initialize() entry point of an internal client.
+ */
+ JackLoadInit = 0x10
+};
+
+/** Valid options for opening an external client. */
+#define JackOpenOptions (JackServerName|JackNoStartServer|JackUseExactName)
+
+/** Valid options for loading an internal client. */
+#define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName)
+
+/**
+ * Options for several JACK operations, formed by OR-ing together the
+ * relevant @ref JackOptions bits.
+ */
+typedef enum JackOptions jack_options_t;
+
+/**
+ * @ref jack_status_t bits
+ */
+enum JackStatus {
+
+ /**
+ * Overall operation failed.
+ */
+ JackFailure = 0x01,
+
+ /**
+ * The operation contained an invalid or unsupported option.
+ */
+ JackInvalidOption = 0x02,
+
+ /**
+ * The desired client name was not unique. With the @ref
+ * JackUseExactName option this situation is fatal. Otherwise,
+ * the name was modified by appending a dash and a two-digit
+ * number in the range "-01" to "-99". The
+ * jack_get_client_name() function will return the exact string
+ * that was used. If the specified @a client_name plus these
+ * extra characters would be too long, the open fails instead.
+ */
+ JackNameNotUnique = 0x04,
+
+ /**
+ * The JACK server was started as a result of this operation.
+ * Otherwise, it was running already. In either case the caller
+ * is now connected to jackd, so there is no race condition.
+ * When the server shuts down, the client will find out.
+ */
+ JackServerStarted = 0x08,
+
+ /**
+ * Unable to connect to the JACK server.
+ */
+ JackServerFailed = 0x10,
+
+ /**
+ * Communication error with the JACK server.
+ */
+ JackServerError = 0x20,
+
+ /**
+ * Requested client does not exist.
+ */
+ JackNoSuchClient = 0x40,
+
+ /**
+ * Unable to load internal client
+ */
+ JackLoadFailure = 0x80,
+
+ /**
+ * Unable to initialize client
+ */
+ JackInitFailure = 0x100,
+
+ /**
+ * Unable to access shared memory
+ */
+ JackShmFailure = 0x200,
+
+ /**
+ * Client's protocol version does not match
+ */
+ JackVersionError = 0x400
+};
+
+/**
+ * Status word returned from several JACK operations, formed by
+ * OR-ing together the relevant @ref JackStatus bits.
+ */
+typedef enum JackStatus jack_status_t;
+
+#endif /* __jack_types_h__ */
diff --git a/common/varargs.h b/common/varargs.h
new file mode 100644
index 00000000..238cb3c1
--- /dev/null
+++ b/common/varargs.h
@@ -0,0 +1,71 @@
+/*
+* Copyright (C) 2004 Jack O'Quin
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 of the License, or
+* (at your option) any later version.
+*
+* This program 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* $Id: varargs.h,v 1.3 2005/11/23 11:24:00 letz Exp $
+*/
+
+#ifndef __jack_varargs_h__
+#define __jack_varargs_h__
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /* variable argument structure */
+ typedef struct {
+ char *server_name; /* server name */
+ char *load_name; /* load module name */
+ char *load_init; /* initialization string */
+ }
+ jack_varargs_t;
+
+ static char* jack_default_server_name (void) {
+ char *server_name;
+ if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
+ server_name = "default";
+ return server_name;
+ }
+
+ static inline void jack_varargs_init (jack_varargs_t *va) {
+ memset (va, 0, sizeof(jack_varargs_t));
+ va->server_name = jack_default_server_name();
+ }
+
+ static inline void jack_varargs_parse (jack_options_t options, va_list ap, jack_varargs_t *va) {
+ // initialize default settings
+ jack_varargs_init (va);
+
+ if ((options & JackServerName)) {
+ char *sn = va_arg(ap, char *);
+ if (sn)
+ va->server_name = sn;
+ }
+ if ((options & JackLoadName))
+ va->load_name = va_arg(ap, char *);
+ if ((options & JackLoadInit))
+ va->load_init = va_arg(ap, char *);
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __jack_varargs_h__ */