summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--config/Makefile.am1
-rw-r--r--config/os/generic/time.h6
-rw-r--r--config/os/gnu-linux/Makefile.am1
-rw-r--r--config/os/gnu-linux/time.h2
-rw-r--r--config/os/macosx/Makefile.am1
-rw-r--r--configure.ac2
-rw-r--r--drivers/alsa/alsa_driver.c4
-rw-r--r--jack/jack.h37
-rw-r--r--libjack/client.c546
-rw-r--r--libjack/pool.c2
-rw-r--r--libjack/port.c2
12 files changed, 329 insertions, 277 deletions
diff --git a/Makefile.am b/Makefile.am
index b96b0bf..39e207d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ dist-check-doxygen:
@false
endif
-SUBDIRS = jack libjack jackd drivers example-clients $(DOC_DIR)
+SUBDIRS = jack libjack jackd drivers example-clients config $(DOC_DIR)
DIST_SUBDIRS = config jack libjack jackd drivers example-clients doc
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/config/Makefile.am b/config/Makefile.am
index 6da81ac..d608932 100644
--- a/config/Makefile.am
+++ b/config/Makefile.am
@@ -2,6 +2,7 @@
# subdirectories.
DIST_SUBDIRS = cpu os sysdeps
+
EXTRA_DIST = depcomp
MAINTAINERCLEANFILES = Makefile.in config.guess config.sub \
install-sh ltmain.sh missing mkinstalldirs
diff --git a/config/os/generic/time.h b/config/os/generic/time.h
index 7118ed8..7ebbc2f 100644
--- a/config/os/generic/time.h
+++ b/config/os/generic/time.h
@@ -22,9 +22,11 @@
#ifndef __jack_time_h__
#define __jack_time_h__
-#include <jack/internal.h>
+#include <jack/types.h>
-inline jack_time_t
+extern jack_time_t jack_get_microseconds_from_system (void);
+
+static inline jack_time_t
jack_get_microseconds (void) {
return jack_get_microseconds_from_system ();
}
diff --git a/config/os/gnu-linux/Makefile.am b/config/os/gnu-linux/Makefile.am
index ae10130..56c5dca 100644
--- a/config/os/gnu-linux/Makefile.am
+++ b/config/os/gnu-linux/Makefile.am
@@ -1,2 +1,3 @@
MAINTAINERCLEANFILES = Makefile.in
noinst_HEADERS = time.c time.h
+
diff --git a/config/os/gnu-linux/time.h b/config/os/gnu-linux/time.h
index e97601c..9d308db 100644
--- a/config/os/gnu-linux/time.h
+++ b/config/os/gnu-linux/time.h
@@ -24,7 +24,7 @@
#ifndef __jack_time_h__
#define __jack_time_h__
-#include <jack/internal.h>
+#include <jack/types.h>
extern jack_time_t (*_jack_get_microseconds)(void);
diff --git a/config/os/macosx/Makefile.am b/config/os/macosx/Makefile.am
index b49bd77..6231480 100644
--- a/config/os/macosx/Makefile.am
+++ b/config/os/macosx/Makefile.am
@@ -1,4 +1,5 @@
MAINTAINERCLEANFILES = Makefile.in
noinst_HEADERS = getopt.h ipc.h JACK_LOCATION.h mach_port.h \
poll.h pThreadUtilities.h time.c time.h
+
EXTRA_DIST = jack.xcode/project.pbxproj
diff --git a/configure.ac b/configure.ac
index 41c7a0d..e69b130 100644
--- a/configure.ac
+++ b/configure.ac
@@ -554,7 +554,7 @@ fi
JACK_DEFAULT_DRIVER=\"dummy\"
AC_ARG_ENABLE(portaudio, [ --disable-portaudio ignore PortAudio driver ],
- TRY_PORTAUDIO=$enableval , TRY_PORTAUDIO=yes )
+ TRY_PORTAUDIO=$enableval , TRY_PORTAUDIO=no )
HAVE_PA="false"
if test "x$TRY_PORTAUDIO" = "xyes"
then
diff --git a/drivers/alsa/alsa_driver.c b/drivers/alsa/alsa_driver.c
index 415545a..91eed3f 100644
--- a/drivers/alsa/alsa_driver.c
+++ b/drivers/alsa/alsa_driver.c
@@ -2220,8 +2220,8 @@ alsa_driver_new (char *name, char *playback_alsa_device,
driver->capture_and_playback_not_synced = FALSE;
if (driver->capture_handle && driver->playback_handle) {
- if (snd_pcm_link (driver->capture_handle,
- driver->playback_handle) != 0) {
+ if (snd_pcm_link (driver->playback_handle,
+ driver->capture_handle) != 0) {
driver->capture_and_playback_not_synced = TRUE;
}
}
diff --git a/jack/jack.h b/jack/jack.h
index 8024c53..dc61ade 100644
--- a/jack/jack.h
+++ b/jack/jack.h
@@ -198,6 +198,43 @@ int jack_set_process_callback (jack_client_t *client,
void *arg);
/**
+ * Block until this JACK client should process data.
+ *
+ * This is an alternative API for clients whose internal
+ * architecture doesn't suit a callback model. They should
+ * instead contain a core loop that looks something like
+ *
+ * \code
+ * jack_nframes_t nframes;
+ *
+ * // wait for the first time we should do something
+ *
+ * nframes = jack_thread_wait (client, 0);
+ *
+ * while (TRUE) {
+ * nframes = jack_thread_wait (client, do_some_processing (nframes));
+ * }
+ * \endcode
+ *
+ * The function do_some_processing() should return zero if
+ * the client should keep interacting with JACK, and non-zero
+ * if it is finished. Note that passing a non-zero status
+ * will terminate the calling thread. Therefore, this loop should
+ * run in its own thread which should probably have
+ * been created with @function jack_client_create_thread().
+ *
+ * Clients using this call should probably not call
+ * @function jack_set_process_callback although it is not
+ * an error for them to do so.
+ *
+ * @param client - pointer to a JACK client structure
+ * @param status - if non-zero, calling thread should exit
+ *
+ * @return the number of frames of data to process
+ */
+jack_nframes_t jack_thread_wait (jack_client_t*, int status);
+
+/**
* Tell JACK to call @a thread_init_callback once just after
* the creation of the thread in which all other callbacks
* will be handled.
diff --git a/libjack/client.c b/libjack/client.c
index d1c4c2d..1146f7f 100644
--- a/libjack/client.c
+++ b/libjack/client.c
@@ -62,10 +62,6 @@
#include <sysdeps/pThreadUtilities.h>
#endif
-#ifdef WITH_TIMESTAMPS
-#include <jack/timestamps.h>
-#endif /* WITH_TIMESTAMPS */
-
static pthread_mutex_t client_lock;
static pthread_cond_t client_ready;
#ifdef ARCH_X86
@@ -1263,89 +1259,185 @@ jack_stop_freewheel (jack_client_t* client)
}
}
-static void *
-jack_client_thread (void *arg)
+static void
+jack_client_thread_suicide (jack_client_t* client)
+{
+ if (client->on_shutdown) {
+ jack_error ("zombified - calling shutdown handler");
+ client->on_shutdown (client->on_shutdown_arg);
+ } else {
+ jack_error ("jack_client_thread zombified - exiting from JACK");
+ jack_client_close (client);
+ /* Need a fix : possibly make client crash if
+ * zombified without shutdown handler
+ */
+ }
+
+ pthread_exit (0);
+ /*NOTREACHED*/
+}
+
+static int
+jack_client_process_events (jack_client_t* client)
{
- jack_client_t *client = (jack_client_t *) arg;
- jack_client_control_t *control = client->control;
jack_event_t event;
char status = 0;
- int err = 0;
-#ifndef JACK_USE_MACH_THREADS
- char c = 0;
-#endif
+ jack_client_control_t *control = client->control;
- pthread_mutex_lock (&client_lock);
- client->thread_ok = TRUE;
- client->thread_id = pthread_self();
- pthread_cond_signal (&client_ready);
- pthread_mutex_unlock (&client_lock);
+ if (client->pollfd[EVENT_POLL_INDEX].revents & POLLIN) {
+
+ DEBUG ("client receives an event, "
+ "now reading on event fd");
+
+ /* server has sent us an event. process the
+ * event and reply */
+
+ if (read (client->event_fd, &event, sizeof (event))
+ != sizeof (event)) {
+ jack_error ("cannot read server event (%s)",
+ strerror (errno));
+ return -1;
+ }
+
+ status = 0;
+
+ switch (event.type) {
+ case PortRegistered:
+ if (control->port_register) {
+ control->port_register
+ (event.x.port_id, TRUE,
+ control->port_register_arg);
+ }
+ break;
+
+ case PortUnregistered:
+ if (control->port_register) {
+ control->port_register
+ (event.x.port_id, FALSE,
+ control->port_register_arg);
+ }
+ break;
+
+ case GraphReordered:
+ status = jack_handle_reorder (client, &event);
+ break;
+
+ case PortConnected:
+ case PortDisconnected:
+ status = jack_client_handle_port_connection
+ (client, &event);
+ break;
+
+ case BufferSizeChange:
+ jack_client_invalidate_port_buffers (client);
+ if (control->bufsize) {
+ status = control->bufsize
+ (control->nframes,
+ control->bufsize_arg);
+ }
+ break;
+
+ case SampleRateChange:
+ if (control->srate) {
+ status = control->srate
+ (control->nframes,
+ control->srate_arg);
+ }
+ break;
+
+ case XRun:
+ if (control->xrun) {
+ status = control->xrun
+ (control->xrun_arg);
+ }
+ break;
+
+ case AttachPortSegment:
+ jack_attach_port_segment (client, event.y.ptid);
+ break;
+
+ case StartFreewheel:
+ jack_start_freewheel (client);
+ break;
+
+ case StopFreewheel:
+ jack_stop_freewheel (client);
+ break;
+ }
+
+ DEBUG ("client has dealt with the event, writing "
+ "response on event fd");
+
+ if (write (client->event_fd, &status, sizeof (status))
+ != sizeof (status)) {
+ jack_error ("cannot send event response to "
+ "engine (%s)", strerror (errno));
+ return -1;
+ }
+ }
- client->control->pid = getpid();
- client->control->pgrp = getpgrp();
+ return 0;
+}
+
+jack_nframes_t
+jack_thread_wait (jack_client_t* client, int status)
+{
+ /* this function waits for either event notifications from the server
+ (all platforms) or process notifications from the server (with
+ non-threaded backends like ALSA and OSS). it will process the
+ event notifications, and return whenever a process notification
+ arrives.
- DEBUG ("client thread is now running");
+ if passed a non-zero status code, it will terminate the thread
+ in which it is called.
+ */
- if (client->control->thread_init) {
- DEBUG ("calling client thread init callback");
- client->control->thread_init (client->control->thread_init_arg);
+ jack_client_control_t *control = client->control;
+
+ if (status || client->engine->engine_ok == 0) {
+ return 0;
}
- while (err == 0) {
+ DEBUG ("client polling on %s", client->pollmax == 2 ?
+ "event_fd and graph_wait_fd..." :
+ "event_fd only");
- if (client->engine->engine_ok == 0) {
- if (client->on_shutdown)
- client->on_shutdown (client->on_shutdown_arg);
- else
- jack_error ("engine unexpectedly shutdown; "
- "thread exiting\n");
- pthread_exit (0);
- }
-
- DEBUG ("client polling on %s", client->pollmax == 2 ?
- "event_fd and graph_wait_fd..." :
- "event_fd only");
-
+ while (1) {
if (poll (client->pollfd, client->pollmax, 1000) < 0) {
if (errno == EINTR) {
continue;
}
jack_error ("poll failed in client (%s)",
strerror (errno));
- status = -1;
- break;
+ return 0;
}
-
+
+ pthread_testcancel();
+
+#ifndef JACK_USE_MACH_THREADS
+
/* get an accurate timestamp on waking from poll for a
* process() cycle.
*/
-
- #ifndef JACK_USE_MACH_THREADS
+
if (client->graph_wait_fd >= 0
&& client->pollfd[WAIT_POLL_INDEX].revents & POLLIN) {
control->awake_at = jack_get_microseconds();
}
-
+
DEBUG ("pfd[EVENT].revents = 0x%x pfd[WAIT].revents = 0x%x",
client->pollfd[EVENT_POLL_INDEX].revents,
client->pollfd[WAIT_POLL_INDEX].revents);
- #endif
-
- pthread_testcancel();
- #ifndef JACK_USE_MACH_THREADS
if (client->graph_wait_fd >= 0 &&
(client->pollfd[WAIT_POLL_INDEX].revents & ~POLLIN)) {
- DEBUG ("\n\n\n\n\n\n\n\nWAITFD ERROR,"
- " ZOMBIE\n\n\n\n\n");
-
/* our upstream "wait" connection
closed, which either means that
an intermediate client exited, or
jackd exited, or jackd zombified
us.
-
+
we can discover the zombification
via client->control->dead, but
the other two possibilities are
@@ -1356,250 +1448,171 @@ jack_client_thread (void *arg)
*/
if (client->upstream_is_jackd) {
- DEBUG ("WE DIE\n");
- goto zombie;
+ DEBUG ("WE DIE\n");
+ return 0;
} else {
- DEBUG ("WE PUNT\n");
+ DEBUG ("WE PUNT\n");
/* don't poll on the wait fd
* again until we get a
* GraphReordered event.
*/
-
+
client->graph_wait_fd = -1;
client->pollmax = 1;
}
}
- #endif
-
- if (client->control->dead) {
- goto zombie;
- }
-
- if (client->pollfd[EVENT_POLL_INDEX].revents & ~POLLIN) {
- /* jackd shutdown */
- goto zombie;
- }
-
- if (client->pollfd[EVENT_POLL_INDEX].revents & POLLIN) {
-
- DEBUG ("client receives an event, "
- "now reading on event fd");
-
- /* server has sent us an event. process the
- * event and reply */
-
- if (read (client->event_fd, &event, sizeof (event))
- != sizeof (event)) {
- jack_error ("cannot read server event (%s)",
- strerror (errno));
- err++;
- break;
- }
-
- status = 0;
-
- switch (event.type) {
- case PortRegistered:
- if (control->port_register) {
- control->port_register
- (event.x.port_id, TRUE,
- control->port_register_arg);
- }
- break;
-
- case PortUnregistered:
- if (control->port_register) {
- control->port_register
- (event.x.port_id, FALSE,
- control->port_register_arg);
- }
- break;
-
- case GraphReordered:
- status = jack_handle_reorder (client, &event);
- break;
-
- case PortConnected:
- case PortDisconnected:
- status = jack_client_handle_port_connection
- (client, &event);
- break;
-
- case BufferSizeChange:
- jack_client_invalidate_port_buffers (client);
- if (control->bufsize) {
- status = control->bufsize
- (control->nframes,
- control->bufsize_arg);
- }
- break;
-
- case SampleRateChange:
- if (control->srate) {
- status = control->srate
- (control->nframes,
- control->srate_arg);
- }
- break;
-
- case XRun:
- if (control->xrun) {
- status = control->xrun
- (control->xrun_arg);
- }
- break;
-
- case AttachPortSegment:
- jack_attach_port_segment (client, event.y.ptid);
- break;
-
- case StartFreewheel:
- jack_start_freewheel (client);
- break;
-
- case StopFreewheel:
- jack_stop_freewheel (client);
- break;
- }
-
- DEBUG ("client has dealt with the event, writing "
- "response on event fd");
-
- if (write (client->event_fd, &status, sizeof (status))
- != sizeof (status)) {
- jack_error ("cannot send event response to "
- "engine (%s)", strerror (errno));
- err++;
- break;
- }
+#endif
+
+ if (jack_client_process_events (client)) {
+ DEBUG ("event processing failed\n");
+ return 0;
}
+ if ((client->pollfd[WAIT_POLL_INDEX].revents & POLLIN)) {
+ DEBUG ("time to run process()\n");
+ break;
+ }
+ }
-#ifndef JACK_USE_MACH_THREADS
- if (client->pollfd[WAIT_POLL_INDEX].revents & POLLIN) {
-
-#ifdef WITH_TIMESTAMPS
- jack_reset_timestamps ();
-#endif
-
- DEBUG ("client %d signalled at %" PRIu64
- ", awake for process at %" PRIu64
- " (delay = %" PRIu64
- " usecs) (wakeup on graph_wait_fd==%d)",
- getpid(),
- control->signalled_at,
- control->awake_at,
- control->awake_at - control->signalled_at,
- client->pollfd[WAIT_POLL_INDEX].fd);
-
- control->state = Running;
-
- /* begin preemption checking */
- CHECK_PREEMPTION (client->engine, TRUE);
-
- if (control->sync_cb)
- jack_call_sync_client (client);
-
- if (control->process) {
- if (control->process (control->nframes,
- control->process_arg)
- == 0) {
- control->state = Finished;
- }
- } else {
- control->state = Finished;
- }
+ if (client->control->dead || client->pollfd[EVENT_POLL_INDEX].revents & ~POLLIN) {
+ DEBUG ("client appears dead or event pollfd has error status\n");
+ return 0;
+ }
- if (control->timebase_cb)
- jack_call_timebase_master (client);
+ DEBUG("thread wait returns %u\n", control->nframes);
+ return control->nframes;
+}
- /* end preemption checking */
- CHECK_PREEMPTION (client->engine, FALSE);
+static int
+jack_wake_next_client (jack_client_t* client)
+{
+ char c = 0;
- control->finished_at = jack_get_microseconds();
+ if (write (client->graph_next_fd, &c, sizeof (c))
+ != sizeof (c)) {
+ jack_error ("cannot continue execution of the "
+ "processing graph (%s)",
+ strerror(errno));
+ return -1;
+ }
+
+ DEBUG ("client sent message to next stage by %" PRIu64
+ ", client reading on graph_wait_fd==%d",
+ jack_get_microseconds(), client->graph_wait_fd);
+
+ DEBUG("reading cleanup byte from pipe %d\n", client->graph_wait_fd);
+
+ if ((read (client->graph_wait_fd, &c, sizeof (c))
+ != sizeof (c))) {
+ jack_error ("cannot complete execution of the "
+ "processing graph (%s)",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
-#ifdef WITH_TIMESTAMPS
- jack_timestamp ("finished");
-#endif
-
-#ifndef JACK_USE_MACH_THREADS
- /* pass the execution token along */
-
- DEBUG ("client finished processing at %" PRIu64
- " (elapsed = %" PRIu64
- " usecs), writing on graph_next_fd==%d",
- control->finished_at,
- control->finished_at - control->awake_at,
- client->graph_next_fd);
-
- if (write (client->graph_next_fd, &c, sizeof (c))
- != sizeof (c)) {
- jack_error ("cannot continue execution of the "
- "processing graph (%s)",
- strerror(errno));
- err++;
- break;
- }
+static int
+jack_client_run_process_callback (jack_client_t* client)
+{
+ jack_client_control_t *control = client->control;
- DEBUG ("client sent message to next stage by %" PRIu64
- ", client reading on graph_wait_fd==%d",
- jack_get_microseconds(), client->graph_wait_fd);
+#ifdef JACK_USE_MACH_THREADS
+ /* this is done in a dedicated thread on OS X */
+ return control->nframes;
#endif
-#ifdef WITH_TIMESTAMPS
- jack_timestamp ("read pending byte from wait");
-#endif
- DEBUG("reading cleanup byte from pipe\n");
+ DEBUG ("client %d signalled at %" PRIu64
+ ", awake for process at %" PRIu64
+ " (delay = %" PRIu64
+ " usecs) (wakeup on graph_wait_fd==%d)",
+ getpid(),
+ control->signalled_at,
+ control->awake_at,
+ control->awake_at - control->signalled_at,
+ client->pollfd[WAIT_POLL_INDEX].fd);
+
+ control->state = Running;
+
+ /* begin preemption checking */
+ CHECK_PREEMPTION (client->engine, TRUE);
+
+ if (control->sync_cb)
+ jack_call_sync_client (client);
+
+ if (control->process) {
+ if (control->process (control->nframes,
+ control->process_arg)
+ == 0) {
+ control->state = Finished;
+ }
+ } else {
+ control->state = Finished;
+ }
+
+ if (control->timebase_cb) {
+ jack_call_timebase_master (client);
+ }
+
+ /* end preemption checking */
+ CHECK_PREEMPTION (client->engine, FALSE);
+
+ control->finished_at = jack_get_microseconds();
+
+ DEBUG ("client finished processing at %" PRIu64
+ " (elapsed = %" PRIu64
+ " usecs), writing on graph_next_fd==%d",
+ control->finished_at,
+ control->finished_at - control->awake_at,
+ client->graph_next_fd);
+
+ /* wake the next client in the chain (could be the server),
+ and check if we were killed during the process
+ cycle.
+ */
+
+ if (jack_wake_next_client (client) || client->control->dead) {
+ DEBUG("client cannot wake next, or is dead\n");
+ return -1;
+ }
-#ifndef JACK_USE_MACH_THREADS
- if ((read (client->graph_wait_fd, &c, sizeof (c))
- != sizeof (c))) {
- DEBUG ("WARNING: READ FAILED!");
-#if 0
- jack_error ("cannot complete execution of the "
- "processing graph (%s)",
- strerror(errno));
- err++;
- break;
-#endif
- }
-#endif
+ DEBUG("process cycle fully complete\n");
+
+ return 0;
+}
- /* check if we were killed during the process
- * cycle (or whatever) */
- if (client->control->dead) {
- goto zombie;
- }
+static void *
+jack_client_thread (void *arg)
+{
+ jack_client_t *client = (jack_client_t *) arg;
+ jack_client_control_t *control = client->control;
- DEBUG("process cycle fully complete\n");
+ pthread_mutex_lock (&client_lock);
+ client->thread_ok = TRUE;
+ client->thread_id = pthread_self();
+ pthread_cond_signal (&client_ready);
+ pthread_mutex_unlock (&client_lock);
-#ifdef WITH_TIMESTAMPS
- jack_timestamp ("read done");
- jack_dump_timestamps (stdout);
-#endif
+ client->control->pid = getpid();
+ client->control->pgrp = getpgrp();
- }
-#endif
+ DEBUG ("client thread is now running");
+ if (client->control->thread_init) {
+ DEBUG ("calling client thread init callback");
+ client->control->thread_init (client->control->thread_init_arg);
}
-
- return (void *) ((intptr_t)err);
- zombie:
- if (client->on_shutdown) {
- jack_error ("zombified - calling shutdown handler");
- client->on_shutdown (client->on_shutdown_arg);
- } else {
- jack_error ("jack_client_thread zombified - exiting from JACK");
- jack_client_close (client);
- /* Need a fix : possibly make client crash if
- * zombified without shutdown handler
- */
+ /* wait for first wakeup from server */
+
+ if (jack_thread_wait (client, 0) == control->nframes) {
+ while (jack_thread_wait (client, jack_client_run_process_callback (client)) == control->nframes);
}
- pthread_exit (0);
+ jack_client_thread_suicide (client);
/*NOTREACHED*/
- return 0;
+ return (void *) 0;
}
#ifdef JACK_USE_MACH_THREADS
@@ -1654,9 +1667,6 @@ jack_client_process_thread (void *arg)
control->finished_at = jack_get_microseconds();
-#ifdef WITH_TIMESTAMPS
- jack_timestamp ("finished");
-#endif
DEBUG ("client finished processing at %Lu (elapsed = %f usecs)",
control->finished_at,
((float)(control->finished_at - control->awake_at)));
diff --git a/libjack/pool.c b/libjack/pool.c
index 1c094d1..43b3adc 100644
--- a/libjack/pool.c
+++ b/libjack/pool.c
@@ -33,7 +33,7 @@ jack_pool_alloc (size_t bytes)
{
#ifdef HAVE_POSIX_MEMALIGN
void* m;
- int err = posix_memalign (&m, 16, bytes);
+ int err = posix_memalign (&m, 64, bytes);
return (!err) ? m : 0;
#else
return malloc (bytes);
diff --git a/libjack/port.c b/libjack/port.c
index ee910d4..f8f323d 100644
--- a/libjack/port.c
+++ b/libjack/port.c
@@ -396,7 +396,7 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id,
port->client_segment_base =
(void **) &client->port_segment[ptid].attached_at;
-
+
return port;
}