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)) { | ||||