git-svn-id: svn+ssh://jackaudio.org/trunk/jack@370 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
@@ -14,7 +14,7 @@ dnl changes are made | |||||
dnl --- | dnl --- | ||||
JACK_MAJOR_VERSION=0 | JACK_MAJOR_VERSION=0 | ||||
JACK_MINOR_VERSION=67 | JACK_MINOR_VERSION=67 | ||||
JACK_MICRO_VERSION=2 | |||||
JACK_MICRO_VERSION=3 | |||||
dnl --- | dnl --- | ||||
dnl HOWTO: updating the jack protocal version | dnl HOWTO: updating the jack protocal version | ||||
@@ -565,7 +565,8 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
(driver->capture_nchannels > driver->playback_nchannels ? | (driver->capture_nchannels > driver->playback_nchannels ? | ||||
driver->capture_nchannels : driver->playback_nchannels)); | driver->capture_nchannels : driver->playback_nchannels)); | ||||
driver->period_usecs = (((float) driver->frames_per_cycle) / driver->frame_rate) * 1000000.0f; | |||||
driver->period_usecs = (jack_time_t) floor ((((float) driver->frames_per_cycle) / driver->frame_rate) * 1000000.0f); | |||||
driver->poll_timeout = (int) floor (1.5f * driver->period_usecs); | |||||
if (driver->engine) { | if (driver->engine) { | ||||
driver->engine->set_buffer_size (driver->engine, driver->frames_per_cycle); | driver->engine->set_buffer_size (driver->engine, driver->frames_per_cycle); | ||||
@@ -821,7 +822,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay | |||||
int need_capture; | int need_capture; | ||||
int need_playback; | int need_playback; | ||||
unsigned int i; | unsigned int i; | ||||
unsigned long long poll_enter, poll_ret; | |||||
jack_time_t poll_enter, poll_ret; | |||||
*status = -1; | *status = -1; | ||||
*delayed_usecs = 0; | *delayed_usecs = 0; | ||||
@@ -869,7 +870,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay | |||||
poll_enter = jack_get_microseconds (); | poll_enter = jack_get_microseconds (); | ||||
if (poll (driver->pfd, nfds, (int) floor ((1.5f * driver->period_usecs) / 1000.0f)) < 0) { | |||||
if (poll (driver->pfd, nfds, driver->poll_timeout) < 0) { | |||||
if (errno == EINTR) { | if (errno == EINTR) { | ||||
printf ("poll interrupt\n"); | printf ("poll interrupt\n"); | ||||
// this happens mostly when run | // this happens mostly when run | ||||
@@ -891,18 +893,18 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay | |||||
if (extra_fd < 0) { | if (extra_fd < 0) { | ||||
if (driver->poll_next && poll_ret > driver->poll_next) { | if (driver->poll_next && poll_ret > driver->poll_next) { | ||||
*delayed_usecs = (float) (poll_ret - driver->poll_next) / driver->cpu_mhz; | |||||
*delayed_usecs = poll_ret - driver->poll_next; | |||||
} | } | ||||
driver->poll_last = poll_ret; | driver->poll_last = poll_ret; | ||||
driver->poll_next = poll_ret + (unsigned long long) floor ((driver->period_usecs * driver->cpu_mhz)); | |||||
driver->poll_next = poll_ret + driver->period_usecs; | |||||
driver->engine->control->current_time.usecs = poll_ret; | driver->engine->control->current_time.usecs = poll_ret; | ||||
} | } | ||||
#ifdef DEBUG_WAKEUP | #ifdef DEBUG_WAKEUP | ||||
fprintf (stderr, "%Lu: checked %d fds, %.9f usecs since poll entered\n", | |||||
poll_ret, | |||||
nfds, | |||||
(float) (poll_ret - poll_enter) / driver->cpu_mhz); | |||||
fprintf (stderr, "%Lu: checked %d fds, %Lu usecs since poll entered\n", | |||||
poll_ret, | |||||
nfds, | |||||
poll_ret - poll_enter); | |||||
#endif | #endif | ||||
/* check to see if it was the extra FD that caused us to return from poll | /* check to see if it was the extra FD that caused us to return from poll | ||||
@@ -973,7 +975,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay | |||||
if ((p_timed_out && (p_timed_out == driver->playback_nfds)) && | if ((p_timed_out && (p_timed_out == driver->playback_nfds)) && | ||||
(c_timed_out && (c_timed_out == driver->capture_nfds))){ | (c_timed_out && (c_timed_out == driver->capture_nfds))){ | ||||
jack_error ("ALSA: poll time out polled for %.6f", ((float) (poll_ret - poll_enter) / driver->cpu_mhz)); | |||||
jack_error ("ALSA: poll time out, polled for %Lu usecs", poll_ret - poll_enter); | |||||
*status = -5; | *status = -5; | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -1010,6 +1012,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay | |||||
} | } | ||||
*status = 0; | *status = 0; | ||||
driver->last_wait_ust = poll_ret; | |||||
avail = capture_avail < playback_avail ? capture_avail : playback_avail; | avail = capture_avail < playback_avail ? capture_avail : playback_avail; | ||||
@@ -1035,10 +1038,7 @@ alsa_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes) | |||||
jack_nframes_t nf; | jack_nframes_t nf; | ||||
snd_pcm_uframes_t offset; | snd_pcm_uframes_t offset; | ||||
snd_pcm_uframes_t contiguous; | snd_pcm_uframes_t contiguous; | ||||
fprintf (stderr, "C: %p area %p P: %p area %p\n", | |||||
driver->capture_handle, driver->capture_areas, | |||||
driver->playback_handle, driver->playback_areas); | |||||
int chn; | |||||
if (driver->capture_handle) { | if (driver->capture_handle) { | ||||
nf = nframes; | nf = nframes; | ||||
@@ -1073,6 +1073,10 @@ alsa_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes) | |||||
return -1; | return -1; | ||||
} | } | ||||
for (chn = 0; chn < driver->playback_nchannels; chn++) { | |||||
alsa_driver_silence_on_channel (driver, chn, contiguous); | |||||
} | |||||
if (snd_pcm_mmap_commit (driver->playback_handle, offset, contiguous) < 0) { | if (snd_pcm_mmap_commit (driver->playback_handle, offset, contiguous) < 0) { | ||||
return -1; | return -1; | ||||
} | } | ||||
@@ -1192,9 +1196,14 @@ alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) | |||||
buf = jack_port_get_buffer (port, contiguous); | buf = jack_port_get_buffer (port, contiguous); | ||||
if (driver->all_monitor_in || (driver->input_monitor_mask & (1<<chn))) { | |||||
if (driver->all_monitor_in || (driver->input_monitor_mask & (1<<chn))) { | |||||
if (!driver->hw_monitoring) { | if (!driver->hw_monitoring) { | ||||
alsa_driver_copy_channel (driver, chn, chn, contiguous); | alsa_driver_copy_channel (driver, chn, chn, contiguous); | ||||
} else { | |||||
/* allow systems with mixdown for monitoring to playback | |||||
the stream even if monitoring is enabled (e.g. ice1712, hdsp) | |||||
*/ | |||||
alsa_driver_write_to_channel (driver, chn, buf + nwritten, contiguous); | |||||
} | } | ||||
} else { | } else { | ||||
alsa_driver_write_to_channel (driver, chn, buf + nwritten, contiguous); | alsa_driver_write_to_channel (driver, chn, buf + nwritten, contiguous); | ||||
@@ -1262,6 +1271,8 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||||
port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal; | port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal; | ||||
for (chn = 0; chn < driver->playback_nchannels; chn++) { | for (chn = 0; chn < driver->playback_nchannels; chn++) { | ||||
jack_port_t *monitor_port; | |||||
snprintf (buf, sizeof(buf) - 1, "playback_%lu", chn+1); | snprintf (buf, sizeof(buf) - 1, "playback_%lu", chn+1); | ||||
if ((port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0)) == NULL) { | if ((port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0)) == NULL) { | ||||
@@ -1280,6 +1291,16 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||||
jack_port_set_latency (port, driver->frames_per_cycle * driver->nfragments); | jack_port_set_latency (port, driver->frames_per_cycle * driver->nfragments); | ||||
driver->playback_ports = jack_slist_append (driver->playback_ports, port); | driver->playback_ports = jack_slist_append (driver->playback_ports, port); | ||||
if (driver->with_monitor_ports) { | |||||
snprintf (buf, sizeof(buf) - 1, "monitor_%lu", chn+1); | |||||
if ((monitor_port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL) { | |||||
jack_error ("ALSA: cannot register monitor port for %s", buf); | |||||
} else { | |||||
jack_port_tie (port, monitor_port); | |||||
} | |||||
} | |||||
} | } | ||||
jack_activate (driver->client); | jack_activate (driver->client); | ||||
@@ -1429,7 +1450,8 @@ alsa_driver_new (char *name, char *alsa_device, | |||||
int capturing, | int capturing, | ||||
int playing, | int playing, | ||||
DitherAlgorithm dither, | DitherAlgorithm dither, | ||||
int soft_mode) | |||||
int soft_mode, | |||||
int monitor) | |||||
{ | { | ||||
int err; | int err; | ||||
@@ -1466,7 +1488,7 @@ alsa_driver_new (char *name, char *alsa_device, | |||||
driver->capture_addr = 0; | driver->capture_addr = 0; | ||||
driver->silent = 0; | driver->silent = 0; | ||||
driver->all_monitor_in = FALSE; | driver->all_monitor_in = FALSE; | ||||
driver->cpu_mhz = jack_get_mhz(); | |||||
driver->with_monitor_ports = monitor; | |||||
driver->clock_mode = ClockMaster; /* XXX is it? */ | driver->clock_mode = ClockMaster; /* XXX is it? */ | ||||
driver->input_monitor_mask = 0; /* XXX is it? */ | driver->input_monitor_mask = 0; /* XXX is it? */ | ||||
@@ -1668,6 +1690,7 @@ alsa_usage () | |||||
" -C,--capture \tcapture input (default: duplex)\n" | " -C,--capture \tcapture input (default: duplex)\n" | ||||
" -P,--playback\tplayback output (default: duplex)\n" | " -P,--playback\tplayback output (default: duplex)\n" | ||||
" -s,--softmode\tsoft-mode, no xrun handling (default: off)\n" | " -s,--softmode\tsoft-mode, no xrun handling (default: off)\n" | ||||
" -m,--monitor \tprovide monitor ports for the output (default: off)\n" | |||||
" -z,--dither \tdithering mode:\n" | " -z,--dither \tdithering mode:\n" | ||||
" -z-,--dither (off, the default)\n" | " -z-,--dither (off, the default)\n" | ||||
" -zr,--dither=rectangular\n" | " -zr,--dither=rectangular\n" | ||||
@@ -1727,6 +1750,7 @@ driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
int capture = FALSE; | int capture = FALSE; | ||||
int playback = FALSE; | int playback = FALSE; | ||||
int soft_mode = FALSE; | int soft_mode = FALSE; | ||||
int monitor = FALSE; | |||||
DitherAlgorithm dither = None; | DitherAlgorithm dither = None; | ||||
int opt; | int opt; | ||||
char *envvar; | char *envvar; | ||||
@@ -1745,6 +1769,7 @@ driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
{ "nperiods", 1, NULL, 'n' }, | { "nperiods", 1, NULL, 'n' }, | ||||
{ "softmode", 1, NULL, 's' }, | { "softmode", 1, NULL, 's' }, | ||||
{ "dither", 2, NULL, 'z' }, | { "dither", 2, NULL, 'z' }, | ||||
{ "monitor", 0, NULL, 'm' }, | |||||
{ 0, 0, 0, 0 } | { 0, 0, 0, 0 } | ||||
}; | }; | ||||
@@ -1790,6 +1815,10 @@ driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
playback = atoi (envvar); | playback = atoi (envvar); | ||||
} | } | ||||
if ((envvar = getenv ("JACK_ALSA_MONITOR")) != NULL) { | |||||
monitor = atoi (envvar); | |||||
} | |||||
/* | /* | ||||
* Setting optind back to zero is a hack to reinitialize a new | * Setting optind back to zero is a hack to reinitialize a new | ||||
* getopts() loop. See declaration in <getopt.h>. | * getopts() loop. See declaration in <getopt.h>. | ||||
@@ -1798,7 +1827,7 @@ driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
optind = 0; | optind = 0; | ||||
opterr = 0; | opterr = 0; | ||||
while ((opt = getopt_long(argc, argv, "-CDd:HMPp:r:n:sz::", | |||||
while ((opt = getopt_long(argc, argv, "-CDd:HMPp:r:n:msz::", | |||||
long_options, NULL)) | long_options, NULL)) | ||||
!= EOF) { | != EOF) { | ||||
switch (opt) { | switch (opt) { | ||||
@@ -1824,6 +1853,10 @@ driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
alsa_usage(); | alsa_usage(); | ||||
return NULL; | return NULL; | ||||
case 'm': | |||||
monitor = TRUE; | |||||
break; | |||||
case 'M': | case 'M': | ||||
hw_metering = TRUE; | hw_metering = TRUE; | ||||
break; | break; | ||||
@@ -1879,7 +1912,7 @@ driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
return alsa_driver_new ("alsa_pcm", pcm_name, client, frames_per_interrupt, | return alsa_driver_new ("alsa_pcm", pcm_name, client, frames_per_interrupt, | ||||
user_nperiods, srate, hw_monitoring, hw_metering, capture, | user_nperiods, srate, hw_monitoring, hw_metering, capture, | ||||
playback, dither, soft_mode); | |||||
playback, dither, soft_mode, monitor); | |||||
} | } | ||||
void | void | ||||
@@ -45,8 +45,9 @@ typedef struct { | |||||
JACK_DRIVER_DECL | JACK_DRIVER_DECL | ||||
unsigned long long poll_last; | |||||
unsigned long long poll_next; | |||||
int poll_timeout; | |||||
jack_time_t poll_last; | |||||
jack_time_t poll_next; | |||||
char **playback_addr; | char **playback_addr; | ||||
char **capture_addr; | char **capture_addr; | ||||
const snd_pcm_channel_area_t *capture_areas; | const snd_pcm_channel_area_t *capture_areas; | ||||
@@ -63,11 +64,10 @@ typedef struct { | |||||
channel_t capture_nchannels; | channel_t capture_nchannels; | ||||
unsigned long sample_bytes; | unsigned long sample_bytes; | ||||
jack_nframes_t frame_rate; | |||||
jack_nframes_t frames_per_cycle; | |||||
float cpu_mhz; | |||||
jack_nframes_t capture_frame_latency; | |||||
jack_nframes_t playback_frame_latency; | |||||
jack_nframes_t frame_rate; | |||||
jack_nframes_t frames_per_cycle; | |||||
jack_nframes_t capture_frame_latency; | |||||
jack_nframes_t playback_frame_latency; | |||||
unsigned long *silent; | unsigned long *silent; | ||||
char *alsa_name; | char *alsa_name; | ||||
@@ -102,6 +102,7 @@ typedef struct { | |||||
char all_monitor_in : 1; | char all_monitor_in : 1; | ||||
char capture_and_playback_not_synced : 1; | char capture_and_playback_not_synced : 1; | ||||
char interleaved : 1; | char interleaved : 1; | ||||
char with_monitor_ports : 1; | |||||
ReadCopyFunction read_via_copy; | ReadCopyFunction read_via_copy; | ||||
WriteCopyFunction write_via_copy; | WriteCopyFunction write_via_copy; | ||||
@@ -80,9 +80,17 @@ typedef jack_nframes_t (*JackDriverWaitFunction)(struct _jack_driver *, int fd, | |||||
#define JACK_DRIVER_DECL | #define JACK_DRIVER_DECL | ||||
/* the driver should set this to be the interval it expects to elapse | /* the driver should set this to be the interval it expects to elapse | ||||
between returning from the `wait' function. | |||||
between returning from the `wait' function. if set to zero, it | |||||
implies that the driver does not expect regular periodic wakeups. | |||||
*/ | */ | ||||
nframes_t period_usecs; | |||||
jack_time_t period_usecs; | |||||
/* the driver should set this within its "wait" function to indicate | |||||
the UST of the most recent determination that the engine cycle | |||||
should run. it should not be set if the "extra_fd" argument of | |||||
the wait function is set to a non-zero value. | |||||
*/ | |||||
jack_time_t last_wait_ust; | |||||
/* this is not used by the driver. it should not be written to or | /* this is not used by the driver. it should not be written to or | ||||
modified in any way | modified in any way | ||||
@@ -180,7 +188,8 @@ typedef jack_nframes_t (*JackDriverWaitFunction)(struct _jack_driver *, int fd, | |||||
#else | #else | ||||
#define JACK_DRIVER_DECL \ | #define JACK_DRIVER_DECL \ | ||||
jack_nframes_t period_usecs; \ | |||||
jack_time_t period_usecs; \ | |||||
jack_time_t last_wait_ust; \ | |||||
void *handle; \ | void *handle; \ | ||||
void (*finish)(struct _jack_driver *);\ | void (*finish)(struct _jack_driver *);\ | ||||
JackDriverAttachFunction attach; \ | JackDriverAttachFunction attach; \ | ||||
@@ -126,9 +126,6 @@ static void jack_port_registration_notify (jack_engine_t *, jack_port_id_t, int) | |||||
static int jack_send_connection_notification (jack_engine_t *, jack_client_id_t, jack_port_id_t, jack_port_id_t, int); | static int jack_send_connection_notification (jack_engine_t *, jack_client_id_t, jack_port_id_t, jack_port_id_t, int); | ||||
static int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *); | static int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *); | ||||
static void jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event); | static void jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event); | ||||
static int jack_engine_process_lock (jack_engine_t *); | |||||
static void jack_engine_process_unlock (jack_engine_t *); | |||||
static int jack_engine_post_process (jack_engine_t *); | static int jack_engine_post_process (jack_engine_t *); | ||||
static int internal_client_request (void*, jack_request_t *); | static int internal_client_request (void*, jack_request_t *); | ||||
@@ -156,15 +153,22 @@ jack_client_is_internal (jack_client_internal_t *client) | |||||
return (client->control->type == ClientInternal) || (client->control->type == ClientDriver); | return (client->control->type == ClientInternal) || (client->control->type == ClientDriver); | ||||
} | } | ||||
#define jack_lock_graph(engine) do { \ | |||||
DEBUG ("acquiring graph lock"); \ | |||||
pthread_mutex_lock (&engine->client_lock); \ | |||||
} while(0) | |||||
static inline void jack_lock_graph (jack_engine_t* engine) { | |||||
DEBUG ("acquiring graph lock"); | |||||
pthread_mutex_lock (&engine->client_lock); | |||||
} | |||||
#define jack_unlock_graph(engine) do { \ | |||||
DEBUG ("releasing graph lock"); \ | |||||
pthread_mutex_unlock (&engine->client_lock); \ | |||||
} while(0) | |||||
static inline int jack_try_lock_graph (jack_engine_t *engine) | |||||
{ | |||||
DEBUG ("TRYING to acquiring graph lock"); | |||||
return pthread_mutex_trylock (&engine->client_lock); | |||||
} | |||||
static inline void jack_unlock_graph (jack_engine_t* engine) | |||||
{ | |||||
DEBUG ("releasing graph lock"); | |||||
pthread_mutex_unlock (&engine->client_lock); | |||||
} | |||||
static inline void | static inline void | ||||
jack_engine_reset_rolling_usecs (jack_engine_t *engine) | jack_engine_reset_rolling_usecs (jack_engine_t *engine) | ||||
@@ -510,18 +514,6 @@ jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes) | |||||
return 0; | return 0; | ||||
} | } | ||||
int | |||||
jack_engine_process_lock (jack_engine_t *engine) | |||||
{ | |||||
return pthread_mutex_trylock (&engine->client_lock); | |||||
} | |||||
void | |||||
jack_engine_process_unlock (jack_engine_t *engine) | |||||
{ | |||||
pthread_mutex_unlock (&engine->client_lock); | |||||
} | |||||
static JSList * | static JSList * | ||||
jack_process_internal(jack_engine_t *engine, JSList *node, jack_nframes_t nframes) | jack_process_internal(jack_engine_t *engine, JSList *node, jack_nframes_t nframes) | ||||
{ | { | ||||
@@ -628,15 +620,16 @@ jack_process_external(jack_engine_t *engine, JSList *node) | |||||
if (status != 0) { | if (status != 0) { | ||||
if (engine->verbose) { | if (engine->verbose) { | ||||
fprintf (stderr, "at %Lu client waiting on %d took %Lu usecs, status = %d sig = %Lu awa = %Lu fin = %Lu dur=%Lu\n", | |||||
now, | |||||
client->subgraph_wait_fd, | |||||
now - then, | |||||
status, | |||||
ctl->signalled_at, | |||||
ctl->awake_at, | |||||
ctl->finished_at, | |||||
ctl->finished_at - ctl->signalled_at); | |||||
fprintf (stderr, "at %Lu client waiting on %d took %Lu usecs, status = %d sig = %Lu " | |||||
"awa = %Lu fin = %Lu dur=%Lu\n", | |||||
now, | |||||
client->subgraph_wait_fd, | |||||
now - then, | |||||
status, | |||||
ctl->signalled_at, | |||||
ctl->awake_at, | |||||
ctl->finished_at, | |||||
ctl->finished_at ? ctl->finished_at - ctl->signalled_at : 0); | |||||
} | } | ||||
/* we can only consider the timeout a client error if it actually woke up. | /* we can only consider the timeout a client error if it actually woke up. | ||||
@@ -750,6 +743,66 @@ jack_calc_cpu_load(jack_engine_t *engine) | |||||
} | } | ||||
static void* | |||||
jack_removal_thread (void *arg) | |||||
{ | |||||
JSList *tmp, *node; | |||||
int need_sort = FALSE; | |||||
jack_engine_t* engine = (jack_engine_t*) arg; | |||||
jack_client_internal_t *client; | |||||
fprintf (stderr, "@_@_@_@_@ REMOVAL THREAD\n"); | |||||
/* remove all dead clients */ | |||||
for (node = engine->clients; node; ) { | |||||
tmp = jack_slist_next (node); | |||||
client = (jack_client_internal_t *) node->data; | |||||
if (client->error) { | |||||
/* if we have a communication problem with the client, | |||||
remove it. otherwise, turn it into a zombie. the client | |||||
will/should realize this and will close it sockets. | |||||
then we'll end up back here again and will finally | |||||
remove the client. | |||||
*/ | |||||
if (client->error >= JACK_ERROR_WITH_SOCKETS) { | |||||
if (engine->verbose) { | |||||
fprintf (stderr, "removing failed client %s state = %s errors = %d\n", | |||||
client->control->name, client_state_names[client->control->state], | |||||
client->error); | |||||
} | |||||
jack_remove_client (engine, (jack_client_internal_t *) node->data); | |||||
} else { | |||||
if (engine->verbose) { | |||||
fprintf (stderr, "zombifying failed client %s state = %s errors = %d\n", | |||||
client->control->name, client_state_names[client->control->state], | |||||
client->error); | |||||
} | |||||
jack_zombify_client (engine, (jack_client_internal_t *) node->data); | |||||
client->error = 0; | |||||
} | |||||
need_sort = TRUE; | |||||
} | |||||
node = tmp; | |||||
} | |||||
if (need_sort) { | |||||
jack_sort_graph (engine); | |||||
} | |||||
jack_engine_reset_rolling_usecs (engine); | |||||
jack_unlock_graph (engine); | |||||
return 0; | |||||
} | |||||
static int | static int | ||||
jack_engine_post_process (jack_engine_t *engine) | jack_engine_post_process (jack_engine_t *engine) | ||||
{ | { | ||||
@@ -757,7 +810,8 @@ jack_engine_post_process (jack_engine_t *engine) | |||||
jack_client_internal_t *client; | jack_client_internal_t *client; | ||||
JSList *node; | JSList *node; | ||||
int need_remove = FALSE; | int need_remove = FALSE; | ||||
int ret; | |||||
/* maintain the current_time.usecs and frame_rate values, since clients | /* maintain the current_time.usecs and frame_rate values, since clients | ||||
are not permitted to set these. | are not permitted to set these. | ||||
*/ | */ | ||||
@@ -792,63 +846,19 @@ jack_engine_post_process (jack_engine_t *engine) | |||||
need_remove = TRUE; | need_remove = TRUE; | ||||
} | } | ||||
} | } | ||||
if (need_remove) { | if (need_remove) { | ||||
JSList *tmp; | |||||
int need_sort = FALSE; | |||||
/* remove all dead clients */ | |||||
for (node = engine->clients; node; ) { | |||||
tmp = jack_slist_next (node); | |||||
client = (jack_client_internal_t *) node->data; | |||||
if (client->error) { | |||||
/* if we have a communication problem with the client, | |||||
remove it. otherwise, turn it into a zombie. the client | |||||
will/should realize this and will close it sockets. | |||||
then we'll end up back here again and will finally | |||||
remove the client. | |||||
*/ | |||||
if (client->error >= JACK_ERROR_WITH_SOCKETS) { | |||||
if (engine->verbose) { | |||||
fprintf (stderr, "removing failed client %s state = %s errors = %d\n", | |||||
client->control->name, client_state_names[client->control->state], | |||||
client->error); | |||||
} | |||||
jack_remove_client (engine, (jack_client_internal_t *) node->data); | |||||
} else { | |||||
if (engine->verbose) { | |||||
fprintf (stderr, "zombifying failed client %s state = %s errors = %d\n", | |||||
client->control->name, client_state_names[client->control->state], | |||||
client->error); | |||||
} | |||||
jack_zombify_client (engine, (jack_client_internal_t *) node->data); | |||||
client->error = 0; | |||||
} | |||||
need_sort = TRUE; | |||||
} | |||||
node = tmp; | |||||
} | |||||
if (need_sort) { | |||||
jack_sort_graph (engine); | |||||
} | |||||
jack_engine_reset_rolling_usecs (engine); | |||||
pthread_t removal_thread; | |||||
pthread_create (&removal_thread, NULL, jack_removal_thread, engine); | |||||
pthread_detach (removal_thread); | |||||
ret = 1; | |||||
} else { | |||||
ret = 0; | |||||
} | } | ||||
jack_calc_cpu_load(engine); | |||||
jack_calc_cpu_load (engine); | |||||
return 0; | |||||
return ret; | |||||
} | } | ||||
static int | static int | ||||
@@ -1997,6 +2007,12 @@ jack_engine_notify_clients_about_delay (jack_engine_t *engine) | |||||
jack_unlock_graph (engine); | jack_unlock_graph (engine); | ||||
} | } | ||||
#if defined(linux) | |||||
static inline jack_time_t jack_get_wait_timestamp (jack_engine_t *engine) { | |||||
return engine->driver->last_wait_ust; | |||||
} | |||||
#endif | |||||
static inline void | static inline void | ||||
jack_inc_frame_time (jack_engine_t *engine, jack_nframes_t amount) | jack_inc_frame_time (jack_engine_t *engine, jack_nframes_t amount) | ||||
{ | { | ||||
@@ -2007,7 +2023,7 @@ jack_inc_frame_time (jack_engine_t *engine, jack_nframes_t amount) | |||||
time->guard1++; | time->guard1++; | ||||
time->frames += amount; | time->frames += amount; | ||||
time->stamp = jack_get_microseconds (); | |||||
time->stamp = jack_get_wait_timestamp (engine); | |||||
// atomic_inc (&time->guard2, 1); | // atomic_inc (&time->guard2, 1); | ||||
// might need a memory barrier here | // might need a memory barrier here | ||||
@@ -2015,26 +2031,19 @@ jack_inc_frame_time (jack_engine_t *engine, jack_nframes_t amount) | |||||
} | } | ||||
static int | static int | ||||
jack_engine_wait (jack_engine_t *engine, jack_nframes_t* nframes) | |||||
jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes, float delayed_usecs) | |||||
{ | { | ||||
jack_driver_t *driver = engine->driver; | |||||
float delayed_usecs; | |||||
int status; | |||||
int restart = 0; | |||||
jack_driver_t* driver = engine->driver; | |||||
int ret = -1; | |||||
static int consecutive_excessive_delays = 0; | static int consecutive_excessive_delays = 0; | ||||
if ((*nframes = driver->wait (driver, -1, &status, &delayed_usecs)) == 0) { | |||||
/* the driver detected an xrun, and restarted */ | |||||
return 1; /* will continue */ | |||||
} | |||||
jack_inc_frame_time (engine, *nframes); | |||||
engine->watchdog_check = 1; | engine->watchdog_check = 1; | ||||
#define WORK_SCALE 1.0f | #define WORK_SCALE 1.0f | ||||
if (engine->control->real_time != 0 && engine->spare_usecs && ((WORK_SCALE * engine->spare_usecs) <= delayed_usecs)) { | |||||
if (engine->control->real_time && engine->spare_usecs && ((WORK_SCALE * engine->spare_usecs) <= delayed_usecs)) { | |||||
fprintf (stderr, "delay of %.3f usecs exceeds estimated spare time of %.3f; restart ...\n", | fprintf (stderr, "delay of %.3f usecs exceeds estimated spare time of %.3f; restart ...\n", | ||||
delayed_usecs, WORK_SCALE * engine->spare_usecs); | delayed_usecs, WORK_SCALE * engine->spare_usecs); | ||||
@@ -2055,29 +2064,23 @@ jack_engine_wait (jack_engine_t *engine, jack_nframes_t* nframes) | |||||
return -1; /* will exit the thread loop */ | return -1; /* will exit the thread loop */ | ||||
} | } | ||||
return 1; /* will continue */ | |||||
return 0; | |||||
} else { | } else { | ||||
consecutive_excessive_delays = 0; | consecutive_excessive_delays = 0; | ||||
} | } | ||||
return status; | |||||
} | |||||
static int | |||||
jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes) | |||||
{ | |||||
int restart = 0; | |||||
jack_driver_t* driver = engine->driver; | |||||
if (jack_engine_process_lock (engine)) { | |||||
jack_inc_frame_time (engine, nframes); | |||||
if (jack_try_lock_graph (engine)) { | |||||
/* engine can't run. just throw away an entire cycle */ | /* engine can't run. just throw away an entire cycle */ | ||||
fprintf (stderr, "#*#*#*#*# NULL CYCLE\n"); | |||||
driver->null_cycle (driver, nframes); | driver->null_cycle (driver, nframes); | ||||
return 0; | return 0; | ||||
} | } | ||||
if (driver->read (driver, nframes)) { | if (driver->read (driver, nframes)) { | ||||
return -1; | |||||
goto unlock; | |||||
} | } | ||||
if (jack_engine_process (engine, nframes)) { | if (jack_engine_process (engine, nframes)) { | ||||
@@ -2086,25 +2089,36 @@ jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes) | |||||
fprintf (stderr, "restart\n"); | fprintf (stderr, "restart\n"); | ||||
} else { | } else { | ||||
if (driver->write (driver, nframes)) { | if (driver->write (driver, nframes)) { | ||||
return -1; | |||||
goto unlock; | |||||
} | } | ||||
} | } | ||||
jack_engine_post_process (engine); | |||||
jack_engine_process_unlock (engine); | |||||
if ((ret = jack_engine_post_process (engine)) > 0) { | |||||
ret = 0; | |||||
goto maybe_restart; /* leave engine locked */ | |||||
} | |||||
ret = 0; | |||||
unlock: | |||||
jack_unlock_graph (engine); | |||||
maybe_restart: | |||||
if (restart) { | if (restart) { | ||||
driver->start (driver); | driver->start (driver); | ||||
} | } | ||||
return 0; | |||||
return ret; | |||||
} | } | ||||
static void * | static void * | ||||
jack_main_thread (void *arg) | jack_main_thread (void *arg) | ||||
{ | { | ||||
jack_engine_t *engine = (jack_engine_t *) arg; | jack_engine_t *engine = (jack_engine_t *) arg; | ||||
jack_driver_t *driver = engine->driver; | |||||
int wait_status; | |||||
jack_nframes_t nframes; | jack_nframes_t nframes; | ||||
float delayed_usecs; | |||||
if (engine->control->real_time) { | if (engine->control->real_time) { | ||||
@@ -2119,28 +2133,24 @@ jack_main_thread (void *arg) | |||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | ||||
engine->watchdog_check = 1; /* really needed here ? */ | |||||
nframes = 0; /* really needed here ? */ | |||||
engine->watchdog_check = 1; | |||||
while (1) { | while (1) { | ||||
int wait_status = jack_engine_wait (engine, &nframes); | |||||
if (wait_status == -1) { | |||||
break; | |||||
} else if (wait_status == 0) { | |||||
if (jack_run_cycle (engine, nframes)) { | |||||
if ((nframes = driver->wait (driver, -1, &wait_status, &delayed_usecs)) == 0) { | |||||
/* the driver detected an xrun, and restarted */ | |||||
continue; | |||||
} | |||||
if (wait_status == 0) { | |||||
if (jack_run_cycle (engine, nframes, delayed_usecs)) { | |||||
jack_error ("cycle execution failure, exiting"); | jack_error ("cycle execution failure, exiting"); | ||||
break; | break; | ||||
} | } | ||||
} else if (wait_status < 0) { | |||||
break; | |||||
} else { | } else { | ||||
/* driver restarted, just continue */ | /* driver restarted, just continue */ | ||||
} | } | ||||
} | } | ||||
@@ -784,7 +784,7 @@ jack_client_thread (void *arg) | |||||
jack_reset_timestamps (); | jack_reset_timestamps (); | ||||
#endif | #endif | ||||
DEBUG ("client %d signalled at %Lu, awake for process at %Lu (delay = %f usecs) (wakeup on graph_wait_fd==%d)", | |||||
DEBUG ("client %d signalled at %Lu, awake for process at %Lu (delay = %Lu usecs) (wakeup on graph_wait_fd==%d)", | |||||
getpid(), | getpid(), | ||||
control->signalled_at, | control->signalled_at, | ||||
control->awake_at, | control->awake_at, | ||||
@@ -808,9 +808,9 @@ jack_client_thread (void *arg) | |||||
#endif | #endif | ||||
/* pass the execution token along */ | /* pass the execution token along */ | ||||
DEBUG ("client finished processing at %Lu (elapsed = %f usecs), writing on graph_next_fd==%d", | |||||
DEBUG ("client finished processing at %Lu (elapsed = %Lu usecs), writing on graph_next_fd==%d", | |||||
control->finished_at, | control->finished_at, | ||||
((float)(control->finished_at - control->awake_at)/client->cpu_mhz), | |||||
control->finished_at - control->awake_at, | |||||
client->graph_next_fd); | client->graph_next_fd); | ||||
if (write (client->graph_next_fd, &c, sizeof (c)) != sizeof (c)) { | if (write (client->graph_next_fd, &c, sizeof (c)) != sizeof (c)) { | ||||