git-svn-id: svn+ssh://jackaudio.org/trunk/jack@89 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
| @@ -8,7 +8,8 @@ SUBDIRS = jack | |||
| EXTRA_PROGRAMS = jack_fltk_client jackrec | |||
| bin_PROGRAMS = jackd jack_simple_client jack_monitor_client @XTRA@ | |||
| bin_PROGRAMS = jackd jack_simple_client jack_monitor_client \ | |||
| jack_impulse_grabber @XTRA@ | |||
| AM_CFLAGS = $(JACK_CFLAGS) -DADDON_DIR=\"$(ADDON_DIR)\" @GLIB_CFLAGS@ | |||
| @@ -34,6 +35,10 @@ jackrec_SOURCES = capture_client.c | |||
| jackrec_LDFLAGS = -lsndfile -ldl -lpthread | |||
| jackrec_LDADD = libjack.la | |||
| jack_impulse_grabber_SOURCES = impulse_grabber.c | |||
| jack_impulse_grabber_LDFLAGS = -ldl -lpthread -lm | |||
| jack_impulse_grabber_LDADD = libjack.la | |||
| lib_LTLIBRARIES = libjack.la jack_alsa.la | |||
| libjack_la_SOURCES = client.c pool.c driver.c | |||
| @@ -1,7 +1,10 @@ | |||
| TODO | |||
| fix graph sorting to use same approach as in ARDOUR::Session for | |||
| routes | |||
| * silence ports when they are disconnected from for the last time | |||
| * use a VSTTimeInfo-like structure for time info | |||
| * call time client before all others | |||
| * support frames_since_interrupt() | |||
| * fix monitor system to be exactly like audioengine's | |||
| figure out how to have pools of buffers for ports by type | |||
| figure out how to use the same buffer over and over when possible | |||
| @@ -16,5 +19,3 @@ TO THINK ABOUT: | |||
| multiple port buffer shm segments (i.e. dynamically | |||
| increase the total number of ports in the system) | |||
| wingo (apwingo@eos.ncsu.edu) adds: | |||
| - add helper functions to access _jack_port_shared without requiring glib | |||
| @@ -24,9 +24,9 @@ | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <errno.h> | |||
| #include <asm/msr.h> | |||
| #include <glib.h> | |||
| #include <stdarg.h> | |||
| #include <asm/msr.h> | |||
| #include <jack/alsa_driver.h> | |||
| #include <jack/types.h> | |||
| @@ -38,12 +38,6 @@ | |||
| static int config_max_level = 0; | |||
| static int config_min_level = 0; | |||
| static unsigned long long current_cycles () { | |||
| unsigned long long now; | |||
| rdtscll (now); | |||
| return now; | |||
| } | |||
| static void | |||
| alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) | |||
| @@ -62,11 +56,6 @@ alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) | |||
| free (driver->silent); | |||
| driver->silent = 0; | |||
| } | |||
| if (driver->input_monitor_requests) { | |||
| free (driver->input_monitor_requests); | |||
| driver->input_monitor_requests = 0; | |||
| } | |||
| } | |||
| static int | |||
| @@ -118,7 +107,7 @@ alsa_driver_generic_hardware (alsa_driver_t *driver) | |||
| } | |||
| static int | |||
| alsa_driver_hw_specific (alsa_driver_t *driver) | |||
| alsa_driver_hw_specific (alsa_driver_t *driver, int hw_monitoring) | |||
| { | |||
| int err; | |||
| @@ -135,13 +124,12 @@ alsa_driver_hw_specific (alsa_driver_t *driver) | |||
| if (driver->hw->capabilities & Cap_HardwareMonitoring) { | |||
| driver->has_hw_monitoring = TRUE; | |||
| /* XXX need to ensure that this is really FALSE or TRUE or whatever*/ | |||
| driver->hw_monitoring = hw_monitoring; | |||
| } else { | |||
| driver->has_hw_monitoring = FALSE; | |||
| driver->hw_monitoring = FALSE; | |||
| } | |||
| /* XXX need to ensure that this is really FALSE */ | |||
| driver->hw_monitoring = FALSE; | |||
| if (driver->hw->capabilities & Cap_ClockLockReporting) { | |||
| driver->has_clock_sync_reporting = TRUE; | |||
| @@ -460,9 +448,6 @@ alsa_driver_set_parameters (alsa_driver_t *driver, nframes_t frames_per_cycle, n | |||
| driver->silent[chn] = 0; | |||
| } | |||
| driver->input_monitor_requests = (unsigned long *) malloc (sizeof (unsigned long) * driver->max_nchannels); | |||
| memset (driver->input_monitor_requests, 0, sizeof (unsigned long) * driver->max_nchannels); | |||
| driver->clock_sync_data = (ClockSyncStatus *) malloc (sizeof (ClockSyncStatus) * | |||
| driver->capture_nchannels > driver->playback_nchannels ? | |||
| driver->capture_nchannels : driver->playback_nchannels); | |||
| @@ -607,8 +592,10 @@ alsa_driver_audio_start (alsa_driver_t *driver) | |||
| driver->playback_nfds = snd_pcm_poll_descriptors_count (driver->playback_handle); | |||
| driver->capture_nfds = snd_pcm_poll_descriptors_count (driver->capture_handle); | |||
| if (driver->pfd) | |||
| free (driver->pfd); | |||
| driver->pfd = (struct pollfd *) malloc (sizeof (struct pollfd) * | |||
| (driver->playback_nfds + driver->capture_nfds)); | |||
| (driver->playback_nfds + driver->capture_nfds + 1)); | |||
| return 0; | |||
| } | |||
| @@ -675,7 +662,7 @@ alsa_driver_silence_untouched_channels (alsa_driver_t *driver, nframes_t nframes | |||
| for (chn = 0; chn < driver->playback_nchannels; chn++) { | |||
| if ((driver->channels_not_done & (1<<chn))) { | |||
| if (driver->silent[chn] < driver->buffer_frames) { | |||
| alsa_driver_silence_on_channel (driver, chn, nframes); | |||
| alsa_driver_silence_on_channel_no_mark (driver, chn, nframes); | |||
| driver->silent[chn] += nframes; | |||
| } | |||
| } | |||
| @@ -709,7 +696,6 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| int need_capture = 1; | |||
| int need_playback = 1; | |||
| int i; | |||
| unsigned long long before; | |||
| again: | |||
| @@ -731,6 +717,11 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| ci = nfds; | |||
| nfds += driver->capture_nfds; | |||
| } | |||
| if (need_capture != need_playback) { | |||
| fprintf (stderr, "poll needs capture: %s playback: %s\n", need_capture ? "yes":"no", | |||
| need_playback ? "yes":"no"); | |||
| } | |||
| /* ALSA doesn't set POLLERR in some versions of 0.9.X */ | |||
| @@ -738,10 +729,6 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| driver->pfd[nfds].events |= POLLERR; | |||
| } | |||
| // printf ("c? %d p? %d poll on %d fds\n", need_capture, need_playback, nfds); | |||
| before = current_cycles(); | |||
| if (poll (driver->pfd, nfds, 1000) < 0) { | |||
| if (errno == EINTR) { | |||
| printf ("poll interrupt\n"); | |||
| @@ -756,13 +743,13 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| jack_error ("ALSA::Device: poll call failed (%s)", strerror (errno)); | |||
| return -1; | |||
| } | |||
| driver->time_at_interrupt = current_cycles(); | |||
| // printf ("time in poll: %f usecs since last = %f usecs\n", | |||
| // ((float) (driver->time_at_interrupt - before)/450.0f), | |||
| // ((float) (driver->time_at_interrupt - last_time)/450.0f)); | |||
| // last_time = driver->time_at_interrupt; | |||
| if (driver->engine) { | |||
| struct timeval tv; | |||
| gettimeofday (&tv, NULL); | |||
| driver->engine->control->time.microseconds = tv.tv_sec * 1000000 + tv.tv_usec; | |||
| } | |||
| p_timed_out = 0; | |||
| if (need_playback) { | |||
| @@ -827,11 +814,7 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| } | |||
| if (xrun_detected) { | |||
| if (alsa_driver_xrun_recovery (driver)) { | |||
| return -1; | |||
| } else { | |||
| return 0; | |||
| } | |||
| return alsa_driver_xrun_recovery (driver); | |||
| } | |||
| avail = capture_avail < playback_avail ? capture_avail : playback_avail; | |||
| @@ -854,11 +837,8 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| return -1; | |||
| } | |||
| contiguous = capture_avail < playback_avail ? capture_avail : playback_avail; | |||
| // printf ("\tcontiguous = %lu\n", contiguous); | |||
| /* XXX possible race condition here with silence_pending */ | |||
| /* XXX this design is wrong. cf. ardour/audioengine *** FIX ME *** */ | |||
| @@ -871,21 +851,15 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| } | |||
| driver->silence_pending = 0; | |||
| } | |||
| driver->channels_not_done = driver->channel_done_bits; | |||
| if ((driver->hw->input_monitor_mask != driver->input_monitor_mask) && | |||
| driver->hw_monitoring && !driver->all_monitor_in) { | |||
| driver->hw->set_input_monitor_mask (driver->hw, driver->input_monitor_mask); | |||
| } | |||
| /* XXX race condition on engine ptr */ | |||
| if (driver->engine && driver->engine->process (driver->engine, contiguous)) { | |||
| jack_error ("alsa_pcm: engine processing error - stopping."); | |||
| return -1; | |||
| } | |||
| /* now move data from ports to channels */ | |||
| for (chn = 0, node = driver->playback_ports; node; node = g_slist_next (node), chn++) { | |||
| @@ -904,7 +878,16 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| /* Now handle input monitoring */ | |||
| driver->input_monitor_mask = 0; | |||
| for (chn = 0, node = driver->capture_ports; node; node = g_slist_next (node), chn++) { | |||
| if (((jack_port_t *) node->data)->shared->monitor_requests) { | |||
| driver->input_monitor_mask |= (1<<chn); | |||
| } | |||
| } | |||
| if (!driver->hw_monitoring) { | |||
| if (driver->all_monitor_in) { | |||
| for (chn = 0; chn < driver->playback_nchannels; chn++) { | |||
| alsa_driver_copy_channel (driver, chn, chn, contiguous); | |||
| @@ -916,20 +899,26 @@ alsa_driver_wait (alsa_driver_t *driver) | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| if ((driver->hw->input_monitor_mask != driver->input_monitor_mask) && !driver->all_monitor_in) { | |||
| driver->hw->set_input_monitor_mask (driver->hw, driver->input_monitor_mask); | |||
| } | |||
| } | |||
| if (driver->channels_not_done) { | |||
| alsa_driver_silence_untouched_channels (driver, contiguous); | |||
| } | |||
| snd_pcm_mmap_commit (driver->capture_handle, capture_offset, contiguous); | |||
| snd_pcm_mmap_commit (driver->playback_handle, playback_offset, contiguous); | |||
| avail -= contiguous; | |||
| } | |||
| // end = current_cycles(); | |||
| // printf ("entire cycle took %f usecs\n", ((float)(end - driver->time_at_interrupt))/450.0f); | |||
| // rdtscl (now); | |||
| // fprintf (stderr, "engine cycle took %.6f usecs\n", (((float) (now - start))/450.0f)); | |||
| return 0; | |||
| } | |||
| @@ -957,18 +946,6 @@ alsa_driver_process (nframes_t nframes, void *arg) | |||
| return 0; | |||
| } | |||
| static void | |||
| alsa_driver_port_monitor_handler (jack_port_id_t port_id, int onoff, void *arg) | |||
| { | |||
| alsa_driver_t *driver = (alsa_driver_t *) arg; | |||
| jack_port_shared_t *port; | |||
| int channel; | |||
| port = &driver->engine->control->ports[port_id]; | |||
| sscanf (port->name, "%*s%*s%*s%d", &channel); | |||
| driver->request_monitor_input ((jack_driver_t *) driver, channel, onoff); | |||
| } | |||
| static void | |||
| alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||
| @@ -990,7 +967,6 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||
| } | |||
| jack_set_process_callback (driver->client, alsa_driver_process, driver); | |||
| jack_set_port_monitor_callback (driver->client, alsa_driver_port_monitor_handler, driver); | |||
| for (chn = 0; chn < driver->capture_nchannels; chn++) { | |||
| snprintf (buf, sizeof(buf) - 1, "in_%lu", chn+1); | |||
| @@ -1001,6 +977,12 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||
| jack_error ("ALSA: cannot register port for %s", buf); | |||
| break; | |||
| } | |||
| /* XXX fix this so that it can handle: systemic (external) latency | |||
| */ | |||
| jack_port_set_latency (port, driver->frames_per_cycle * driver->nfragments); | |||
| driver->capture_ports = g_slist_append (driver->capture_ports, port); | |||
| } | |||
| @@ -1013,6 +995,12 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) | |||
| jack_error ("ALSA: cannot register port for %s", buf); | |||
| break; | |||
| } | |||
| /* XXX fix this so that it can handle: systemic (external) latency | |||
| */ | |||
| jack_port_set_latency (port, driver->frames_per_cycle * driver->nfragments); | |||
| driver->playback_ports = g_slist_append (driver->playback_ports, port); | |||
| } | |||
| @@ -1061,45 +1049,6 @@ alsa_driver_mark_channel_silent (alsa_driver_t *driver, unsigned long chn) | |||
| driver->silence_pending |= (1<<chn); | |||
| } | |||
| static void | |||
| alsa_driver_request_monitor_input (alsa_driver_t *driver, unsigned long chn, int yn) | |||
| { | |||
| int changed; | |||
| if (chn >= driver->max_nchannels) { | |||
| return; | |||
| } | |||
| changed = FALSE; | |||
| if (yn) { | |||
| if (++driver->input_monitor_requests[chn] == 1) { | |||
| if (!(driver->input_monitor_mask & (1<<chn))) { | |||
| driver->input_monitor_mask |= (1<<chn); | |||
| changed = TRUE; | |||
| } | |||
| } | |||
| } else { | |||
| if (driver->input_monitor_requests[chn] && --driver->input_monitor_requests[chn] == 0) { | |||
| if (driver->input_monitor_mask & (1<<chn)) { | |||
| driver->input_monitor_mask &= ~(1<<chn); | |||
| changed = TRUE; | |||
| } | |||
| } | |||
| } | |||
| if (changed) { | |||
| if (!driver->hw_monitoring && !yn) { | |||
| alsa_driver_mark_channel_silent (driver, chn); | |||
| } | |||
| /* Tell anyone who cares about the state of input monitoring */ | |||
| jack_driver_input_monitor_notify ((jack_driver_t *) driver, chn, yn); | |||
| } | |||
| } | |||
| static void | |||
| alsa_driver_request_all_monitor_input (alsa_driver_t *driver, int yn) | |||
| @@ -1133,12 +1082,6 @@ alsa_driver_set_hw_monitoring (alsa_driver_t *driver, int yn) | |||
| } | |||
| } | |||
| static nframes_t | |||
| alsa_driver_frames_since_cycle_start (alsa_driver_t *driver) | |||
| { | |||
| return (nframes_t) ((driver->frame_rate / 1000000.0) * ((float) (current_cycles() - driver->time_at_interrupt))); | |||
| } | |||
| static ClockSyncStatus | |||
| alsa_driver_clock_sync_status (channel_t chn) | |||
| @@ -1199,13 +1142,16 @@ alsa_driver_delete (alsa_driver_t *driver) | |||
| static jack_driver_t * | |||
| alsa_driver_new (char *name, char *alsa_device, | |||
| nframes_t frames_per_cycle, | |||
| nframes_t rate) | |||
| nframes_t rate, | |||
| int hw_monitoring) | |||
| { | |||
| int err; | |||
| alsa_driver_t *driver; | |||
| printf ("creating alsa driver ... %s|%lu|%lu\n", alsa_device, frames_per_cycle, rate); | |||
| printf ("creating alsa driver ... %s|%lu|%lu|%s\n", | |||
| alsa_device, frames_per_cycle, rate, | |||
| hw_monitoring ? "hwmon":"swmon"); | |||
| driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); | |||
| @@ -1220,9 +1166,7 @@ alsa_driver_new (char *name, char *alsa_device, | |||
| driver->set_hw_monitoring = (JackDriverSetHwMonitoringFunction) alsa_driver_set_hw_monitoring ; | |||
| driver->reset_parameters = (JackDriverResetParametersFunction) alsa_driver_reset_parameters; | |||
| driver->mark_channel_silent = (JackDriverMarkChannelSilentFunction) alsa_driver_mark_channel_silent; | |||
| driver->request_monitor_input = (JackDriverRequestMonitorInputFunction) alsa_driver_request_monitor_input; | |||
| driver->request_all_monitor_input = (JackDriverRequestAllMonitorInputFunction) alsa_driver_request_all_monitor_input; | |||
| driver->frames_since_cycle_start = (JackDriverFramesSinceCycleStartFunction) alsa_driver_frames_since_cycle_start; | |||
| driver->clock_sync_status = (JackDriverClockSyncStatusFunction) alsa_driver_clock_sync_status; | |||
| driver->change_sample_clock = (JackDriverChangeSampleClockFunction) alsa_driver_change_sample_clock; | |||
| @@ -1238,7 +1182,6 @@ alsa_driver_new (char *name, char *alsa_device, | |||
| driver->capture_addr = 0; | |||
| driver->silence_pending = 0; | |||
| driver->silent = 0; | |||
| driver->input_monitor_requests = 0; | |||
| driver->all_monitor_in = FALSE; | |||
| driver->clock_mode = ClockMaster; /* XXX is it? */ | |||
| @@ -1310,7 +1253,7 @@ alsa_driver_new (char *name, char *alsa_device, | |||
| driver->capture_and_playback_not_synced = FALSE; | |||
| } | |||
| alsa_driver_hw_specific (driver); | |||
| alsa_driver_hw_specific (driver, hw_monitoring); | |||
| return (jack_driver_t *) driver; | |||
| } | |||
| @@ -1323,12 +1266,14 @@ driver_initialize (va_list ap) | |||
| nframes_t srate; | |||
| nframes_t frames_per_interrupt; | |||
| char *pcm_name; | |||
| int hw_monitoring; | |||
| pcm_name = va_arg (ap, char *); | |||
| frames_per_interrupt = va_arg (ap, nframes_t); | |||
| srate = va_arg (ap, nframes_t); | |||
| hw_monitoring = va_arg (ap, int); | |||
| return alsa_driver_new ("alsa_pcm", pcm_name, frames_per_interrupt, srate); | |||
| return alsa_driver_new ("alsa_pcm", pcm_name, frames_per_interrupt, srate, hw_monitoring); | |||
| } | |||
| void | |||
| @@ -283,7 +283,7 @@ setup_ports (int sources, char *source_names[], thread_info_t *info) | |||
| } | |||
| for (i = 0; i < nports; i++) { | |||
| if (jack_port_connect (info->client, source_names[i], jack_port_name (ports[i]))) { | |||
| if (jack_connect (info->client, source_names[i], jack_port_name (ports[i]))) { | |||
| fprintf (stderr, "cannot connect input port %s to %s\n", jack_port_name (ports[i]), source_names[i]); | |||
| jack_client_close (info->client); | |||
| exit (1); | |||
| @@ -26,10 +26,13 @@ | |||
| #include <sys/types.h> | |||
| #include <sys/ipc.h> | |||
| #include <sys/shm.h> | |||
| #include <sys/mman.h> | |||
| #include <sys/poll.h> | |||
| #include <stdarg.h> | |||
| #include <stdio.h> | |||
| #include <regex.h> | |||
| #include <math.h> | |||
| #include <asm/msr.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/internal.h> | |||
| @@ -51,6 +54,13 @@ static pthread_mutex_t client_lock; | |||
| static pthread_cond_t client_ready; | |||
| static void *jack_zero_filled_buffer = 0; | |||
| static void jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes); | |||
| jack_port_type_info_t builtin_port_types[] = { | |||
| { JACK_DEFAULT_AUDIO_TYPE, jack_audio_port_mixdown, 1 }, | |||
| { "", NULL } | |||
| }; | |||
| struct _jack_client { | |||
| jack_control_t *engine; | |||
| @@ -131,23 +141,41 @@ jack_port_by_id (jack_client_t *client, jack_port_id_t id) | |||
| return NULL; | |||
| } | |||
| static jack_port_id_t | |||
| jack_port_id_by_name (jack_client_t *client, const char *port_name) | |||
| static jack_port_shared_t * | |||
| jack_shared_port_by_name (jack_client_t *client, const char *port_name) | |||
| { | |||
| jack_port_id_t id, limit; | |||
| unsigned long i, limit; | |||
| jack_port_shared_t *port; | |||
| limit = client->engine->port_max; | |||
| port = &client->engine->ports[0]; | |||
| for (id = 0; id < limit; id++) { | |||
| if (port[id].in_use && strcmp (port[id].name, port_name) == 0) { | |||
| return port[id].id; | |||
| for (i = 0; i < limit; i++) { | |||
| if (port[i].in_use && strcmp (port[i].name, port_name) == 0) { | |||
| return &port[i]; | |||
| } | |||
| } | |||
| return NoPort; | |||
| return NULL; | |||
| } | |||
| jack_port_t * | |||
| jack_port_by_name (jack_client_t *client, const char *port_name) | |||
| { | |||
| unsigned long i, limit; | |||
| jack_port_shared_t *port; | |||
| limit = client->engine->port_max; | |||
| port = &client->engine->ports[0]; | |||
| for (i = 0; i < limit; i++) { | |||
| if (port[i].in_use && strcmp (port[i].name, port_name) == 0) { | |||
| return jack_port_new (client, port[i].id, client->engine); | |||
| } | |||
| } | |||
| return NULL; | |||
| } | |||
| static void | |||
| @@ -167,8 +195,11 @@ jack_client_invalidate_port_buffers (jack_client_t *client) | |||
| port = (jack_port_t *) node->data; | |||
| if (port->shared->flags & JackPortIsInput) { | |||
| /* XXX release buffer */ | |||
| port->client_segment_base = NULL; | |||
| if (port->client_segment_base != 0 && port->shared->offset == 0) { | |||
| jack_pool_release ((void *) port->shared->offset); | |||
| port->client_segment_base = 0; | |||
| port->shared->offset = 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -196,7 +227,6 @@ jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event) | |||
| other = (jack_port_t *) node->data; | |||
| if (other->shared->id == event->y.other_id) { | |||
| printf ("%s DIS-connecting and %s\n", control_port->shared->name, other->shared->name); | |||
| control_port->connections = g_slist_remove_link (control_port->connections, node); | |||
| g_slist_free_1 (node); | |||
| free (other); | |||
| @@ -541,19 +571,6 @@ jack_client_thread (void *arg) | |||
| case NewPortBufferSegment: | |||
| break; | |||
| case PortMonitor: | |||
| if (control->port_monitor) { | |||
| control->port_monitor (event.x.port_id, TRUE, control->port_monitor_arg); | |||
| } | |||
| break; | |||
| case PortUnMonitor: | |||
| if (control->port_monitor) { | |||
| control->port_monitor (event.x.port_id, FALSE, control->port_monitor_arg); | |||
| } | |||
| break; | |||
| } | |||
| if (write (client->event_fd, &status, sizeof (status)) != sizeof (status)) { | |||
| @@ -632,6 +649,11 @@ jack_start_thread (jack_client_t *client) | |||
| jack_error ("Cannot set scheduling priority for RT thread (%s)", strerror (errno)); | |||
| return -1; | |||
| } | |||
| if (mlockall (MCL_CURRENT|MCL_FUTURE)) { | |||
| jack_error ("cannot lock down all memory (%s)", strerror (errno)); | |||
| return -1; | |||
| } | |||
| } | |||
| if (pthread_create (&client->thread, attributes, jack_client_thread, client)) { | |||
| @@ -882,7 +904,7 @@ unsigned long jack_get_buffer_size (jack_client_t *client) | |||
| unsigned long jack_get_sample_rate (jack_client_t *client) | |||
| { | |||
| return client->engine->sample_rate; | |||
| return client->engine->time.frame_rate; | |||
| } | |||
| static jack_port_t * | |||
| @@ -898,7 +920,7 @@ jack_port_new (jack_client_t *client, jack_port_id_t port_id, jack_control_t *co | |||
| port = (jack_port_t *) malloc (sizeof (jack_port_t)); | |||
| port->client_segment_base = NULL; | |||
| port->client_segment_base = 0; | |||
| port->shared = shared; | |||
| port->connections = 0; | |||
| port->tied = NULL; | |||
| @@ -933,16 +955,8 @@ jack_port_register (jack_client_t *client, | |||
| { | |||
| jack_request_t req; | |||
| jack_port_t *port = 0; | |||
| /* before we get started, check a few basics */ | |||
| if (flags & JackPortCanMonitor) { | |||
| if (client->control->port_monitor == NULL) { | |||
| jack_error ("you cannot register ports with PortCanMonitor " | |||
| "without a port monitor callback"); | |||
| return NULL; | |||
| } | |||
| } | |||
| jack_port_type_info_t *type_info; | |||
| int n; | |||
| req.type = RegisterPort; | |||
| @@ -971,6 +985,32 @@ jack_port_register (jack_client_t *client, | |||
| port = jack_port_new (client, req.x.port_info.port_id, client->engine); | |||
| type_info = NULL; | |||
| for (n = 0; builtin_port_types[n].type_name[0]; n++) { | |||
| if (strcmp (req.x.port_info.type, builtin_port_types[n].type_name) == 0) { | |||
| type_info = &builtin_port_types[n]; | |||
| break; | |||
| } | |||
| } | |||
| if (type_info == NULL) { | |||
| /* not a builtin type, so allocate a new type_info structure, | |||
| and fill it appropriately. | |||
| */ | |||
| type_info = (jack_port_type_info_t *) malloc (sizeof (jack_port_type_info_t)); | |||
| snprintf ((char *) type_info->type_name, sizeof (type_info->type_name), req.x.port_info.type); | |||
| type_info->mixdown = NULL; /* we have no idea how to mix this */ | |||
| type_info->buffer_scale_factor = -1; /* use specified port buffer size */ | |||
| } | |||
| memcpy (&port->shared->type_info, type_info, sizeof (jack_port_type_info_t)); | |||
| client->ports = g_slist_prepend (client->ports, port); | |||
| return port; | |||
| @@ -1000,7 +1040,7 @@ jack_port_unregister (jack_client_t *client, jack_port_t *port) | |||
| } | |||
| int | |||
| jack_port_connect (jack_client_t *client, const char *source_port, const char *destination_port) | |||
| jack_connect (jack_client_t *client, const char *source_port, const char *destination_port) | |||
| { | |||
| jack_request_t req; | |||
| @@ -1026,8 +1066,7 @@ jack_port_connect (jack_client_t *client, const char *source_port, const char *d | |||
| } | |||
| int | |||
| jack_port_disconnect (jack_client_t *client, const char *source_port, const char *destination_port) | |||
| jack_disconnect (jack_client_t *client, const char *source_port, const char *destination_port) | |||
| { | |||
| jack_request_t req; | |||
| @@ -1086,6 +1125,18 @@ jack_set_error_function (void (*func) (const char *, ...)) | |||
| jack_error = func; | |||
| } | |||
| nframes_t | |||
| jack_port_get_latency (jack_port_t *port) | |||
| { | |||
| return port->shared->latency; | |||
| } | |||
| void | |||
| jack_port_set_latency (jack_port_t *port, nframes_t nframes) | |||
| { | |||
| port->shared->latency = nframes; | |||
| } | |||
| void * | |||
| jack_port_get_buffer (jack_port_t *port, nframes_t nframes) | |||
| @@ -1128,8 +1179,7 @@ jack_port_get_buffer (jack_port_t *port, nframes_t nframes) | |||
| during the connection process. | |||
| */ | |||
| if (port->client_segment_base == NULL) { | |||
| port->client_segment_base = 0; | |||
| if (port->client_segment_base == 0 && port->shared->offset == 0) { | |||
| port->shared->offset = (size_t) jack_pool_alloc (port->shared->type_info.buffer_scale_factor * sizeof (sample_t) * nframes); | |||
| } | |||
| @@ -1139,7 +1189,7 @@ jack_port_get_buffer (jack_port_t *port, nframes_t nframes) | |||
| } | |||
| int | |||
| jack_port_tie (jack_port_t *dst, jack_port_t *src) | |||
| jack_port_tie (jack_port_t *src, jack_port_t *dst) | |||
| { | |||
| if (dst->shared->client_id != src->shared->client_id) { | |||
| @@ -1209,7 +1259,7 @@ jack_set_sample_rate_callback (jack_client_t *client, JackSampleRateCallback cal | |||
| /* Now invoke it */ | |||
| callback (client->engine->sample_rate, arg); | |||
| callback (client->engine->time.frame_rate, arg); | |||
| return 0; | |||
| } | |||
| @@ -1226,18 +1276,6 @@ jack_set_port_registration_callback(jack_client_t *client, JackPortRegistrationC | |||
| return 0; | |||
| } | |||
| int | |||
| jack_set_port_monitor_callback (jack_client_t *client, JackPortMonitorCallback callback, void *arg) | |||
| { | |||
| if (client->control->active) { | |||
| return -1; | |||
| } | |||
| client->control->port_monitor_arg = arg; | |||
| client->control->port_monitor = callback; | |||
| return 0; | |||
| } | |||
| int | |||
| jack_get_process_start_fd (jack_client_t *client) | |||
| { | |||
| @@ -1257,34 +1295,103 @@ jack_get_process_done_fd (jack_client_t *client) | |||
| } | |||
| int | |||
| jack_port_request_monitor (jack_client_t *client, const char *port_name, int onoff) | |||
| jack_port_request_monitor_by_name (jack_client_t *client, const char *port_name, int onoff) | |||
| { | |||
| jack_request_t req; | |||
| int n; | |||
| jack_port_shared_t *port; | |||
| req.type = (onoff ? RequestPortMonitor : RequestPortUnMonitor); | |||
| req.x.port_info.port_id = jack_port_id_by_name (client, port_name); | |||
| if ((port = jack_shared_port_by_name (client, port_name)) != NULL) { | |||
| if (onoff) { | |||
| port->monitor_requests++; | |||
| } else if (port->monitor_requests) { | |||
| port->monitor_requests--; | |||
| } | |||
| return 0; | |||
| } | |||
| return -1; | |||
| } | |||
| if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { | |||
| jack_error ("cannot send request to jack server (%s)", strerror (errno)); | |||
| return -1; | |||
| int | |||
| jack_port_request_monitor (jack_port_t *port, int onoff) | |||
| { | |||
| if (onoff) { | |||
| port->shared->monitor_requests++; | |||
| } else if (port->shared->monitor_requests) { | |||
| port->shared->monitor_requests--; | |||
| } | |||
| return 0; | |||
| } | |||
| if ((n = read (client->request_fd, &req, sizeof (req))) != sizeof (req)) { | |||
| jack_error ("cannot read response from jack server (%s)", strerror (errno)); | |||
| return -1; | |||
| int | |||
| jack_ensure_port_monitor_input (jack_port_t *port, int yn) | |||
| { | |||
| if (yn) { | |||
| if (port->shared->monitor_requests == 0) { | |||
| port->shared->monitor_requests++; | |||
| } | |||
| } else { | |||
| if (port->shared->monitor_requests == 1) { | |||
| port->shared->monitor_requests--; | |||
| } | |||
| } | |||
| return req.status; | |||
| return 0; | |||
| } | |||
| int | |||
| jack_port_monitoring_input (jack_port_t *port) | |||
| { | |||
| return port->shared->monitor_requests > 0; | |||
| } | |||
| const char * | |||
| jack_port_name (const jack_port_t *port) | |||
| { | |||
| return port->shared->name; | |||
| } | |||
| const char * | |||
| jack_port_short_name (const jack_port_t *port) | |||
| { | |||
| /* we know there is always a colon, because we put | |||
| it there ... | |||
| */ | |||
| return strchr (port->shared->name, ':') + 1; | |||
| } | |||
| int | |||
| jack_port_flags (const jack_port_t *port) | |||
| { | |||
| return port->shared->flags; | |||
| } | |||
| const char * | |||
| jack_port_type (const jack_port_t *port) | |||
| { | |||
| return port->shared->type_info.type_name; | |||
| } | |||
| int | |||
| jack_port_equal (const jack_port_t *a, const jack_port_t *b) | |||
| { | |||
| return a->shared == b->shared; | |||
| } | |||
| int | |||
| jack_port_set_name (jack_port_t *port, const char *new_name) | |||
| { | |||
| char *colon; | |||
| int len; | |||
| colon = strchr (port->shared->name, ':'); | |||
| len = sizeof (port->shared->name) - ((int) (colon - port->shared->name)) - 2; | |||
| snprintf (colon+1, len, "%s", new_name); | |||
| return 0; | |||
| } | |||
| void | |||
| jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg) | |||
| { | |||
| @@ -1309,10 +1416,10 @@ jack_get_ports (jack_client_t *client, | |||
| engine = client->engine; | |||
| if (port_name_pattern) { | |||
| if (port_name_pattern && port_name_pattern[0]) { | |||
| regcomp (&port_regex, port_name_pattern, REG_EXTENDED|REG_NOSUB); | |||
| } | |||
| if (type_name_pattern) { | |||
| if (type_name_pattern && type_name_pattern[0]) { | |||
| regcomp (&type_regex, type_name_pattern, REG_EXTENDED|REG_NOSUB); | |||
| } | |||
| @@ -1334,13 +1441,13 @@ jack_get_ports (jack_client_t *client, | |||
| } | |||
| } | |||
| if (matching && port_name_pattern) { | |||
| if (matching && port_name_pattern && port_name_pattern[0]) { | |||
| if (regexec (&port_regex, psp[i].name, 0, NULL, 0)) { | |||
| matching = 0; | |||
| } | |||
| } | |||
| if (matching && type_name_pattern) { | |||
| if (matching && type_name_pattern && type_name_pattern[0]) { | |||
| if (regexec (&type_regex, psp[i].type_info.type_name, 0, NULL, 0)) { | |||
| matching = 0; | |||
| } | |||
| @@ -1353,5 +1460,75 @@ jack_get_ports (jack_client_t *client, | |||
| matching_ports[match_cnt] = 0; | |||
| if (match_cnt == 0) { | |||
| free (matching_ports); | |||
| matching_ports = 0; | |||
| } | |||
| return matching_ports; | |||
| } | |||
| nframes_t | |||
| jack_frames_since_cycle_start (jack_client_t *client) | |||
| { | |||
| struct timeval now; | |||
| float usecs; | |||
| gettimeofday (&now, NULL); | |||
| usecs = ((now.tv_sec * 1000000) + now.tv_usec) - client->engine->time.microseconds; | |||
| return (nframes_t) floor ((((float) client->engine->time.frame_rate) / 1000000.0f) * usecs); | |||
| } | |||
| int | |||
| jack_port_lock (jack_client_t *client, jack_port_t *port) | |||
| { | |||
| if (port) { | |||
| port->shared->locked = 1; | |||
| return 0; | |||
| } | |||
| return -1; | |||
| } | |||
| int | |||
| jack_port_unlock (jack_client_t *client, jack_port_t *port) | |||
| { | |||
| if (port) { | |||
| port->shared->locked = 0; | |||
| return 0; | |||
| } | |||
| return -1; | |||
| } | |||
| static void | |||
| jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes) | |||
| { | |||
| GSList *node; | |||
| jack_port_t *input; | |||
| nframes_t n; | |||
| sample_t *buffer; | |||
| sample_t *dst, *src; | |||
| /* by the time we've called this, we've already established | |||
| the existence of more than 1 connection to this input port. | |||
| */ | |||
| node = port->connections; | |||
| input = (jack_port_t *) node->data; | |||
| buffer = jack_port_buffer (port); | |||
| memcpy (buffer, jack_port_buffer (input), sizeof (sample_t) * nframes); | |||
| for (node = g_slist_next (node); node; node = g_slist_next (node)) { | |||
| input = (jack_port_t *) node->data; | |||
| n = nframes; | |||
| dst = buffer; | |||
| src = jack_port_buffer (input); | |||
| while (n--) { | |||
| *dst++ += *src++; | |||
| } | |||
| } | |||
| } | |||
| @@ -29,7 +29,6 @@ | |||
| static int dummy_attach (jack_driver_t *drv, jack_engine_t *eng) { return 0; } | |||
| static int dummy_detach (jack_driver_t *drv, jack_engine_t *eng) { return 0; } | |||
| static int dummy_wait (jack_driver_t *drv) { return 0; } | |||
| static nframes_t dummy_frames_since_cycle_start (jack_driver_t *drv) { return 0; } | |||
| static ClockSyncStatus dummy_clock_sync_status (jack_driver_t *drv, channel_t chn) { return ClockMaster; } | |||
| static int dummy_audio_stop (jack_driver_t *drv) { return 0; } | |||
| static int dummy_audio_start (jack_driver_t *drv) { return 0;; } | |||
| @@ -37,15 +36,8 @@ static void dummy_set_hw_monitoring (jack_driver_t *drv, int yn) { return; } | |||
| static int dummy_change_sample_clock (jack_driver_t *drv, SampleClockMode mode) { return 0; } | |||
| static int dummy_reset_parameters (jack_driver_t *drv, nframes_t frames_per_cycle, nframes_t rate) { return 0; } | |||
| static void dummy_mark_channel_silent (jack_driver_t *drv, unsigned long chn) { return; } | |||
| static void dummy_request_monitor_input (jack_driver_t *drv, unsigned long chn, int yn) { return ; } | |||
| static void dummy_request_all_monitor_input (jack_driver_t *drv, int yn) { return; } | |||
| int | |||
| jack_driver_monitoring_input (jack_driver_t *driver, channel_t chn) | |||
| { | |||
| return chn != NoChannel && (driver->all_monitor_in || (driver->input_monitor_mask & (1<<chn))); | |||
| } | |||
| void | |||
| jack_driver_init (jack_driver_t *driver) | |||
| @@ -57,7 +49,6 @@ jack_driver_init (jack_driver_t *driver) | |||
| driver->attach = dummy_attach; | |||
| driver->detach = dummy_detach; | |||
| driver->wait = dummy_wait; | |||
| driver->frames_since_cycle_start = dummy_frames_since_cycle_start; | |||
| driver->clock_sync_status = dummy_clock_sync_status; | |||
| driver->audio_stop = dummy_audio_stop; | |||
| driver->audio_start = dummy_audio_start; | |||
| @@ -65,9 +56,7 @@ jack_driver_init (jack_driver_t *driver) | |||
| driver->change_sample_clock = dummy_change_sample_clock; | |||
| driver->reset_parameters = dummy_reset_parameters; | |||
| driver->mark_channel_silent = dummy_mark_channel_silent; | |||
| driver->request_monitor_input = dummy_request_monitor_input; | |||
| driver->request_all_monitor_input = dummy_request_all_monitor_input; | |||
| driver->monitoring_input = jack_driver_monitoring_input; | |||
| driver->engine = 0; | |||
| pthread_mutex_init (&driver->clock_sync_lock, 0); | |||
| @@ -96,8 +85,8 @@ jack_driver_release (jack_driver_t *driver) | |||
| int | |||
| jack_driver_listen_for_clock_sync_status (jack_driver_t *driver, | |||
| ClockSyncListenerFunction func, | |||
| void *arg) | |||
| ClockSyncListenerFunction func, | |||
| void *arg) | |||
| { | |||
| ClockSyncListener *csl; | |||
| @@ -132,71 +121,19 @@ jack_driver_stop_listening_to_clock_sync_status (jack_driver_t *driver, int whic | |||
| return ret; | |||
| } | |||
| int | |||
| jack_driver_listen_for_input_monitor_status (jack_driver_t *driver, | |||
| InputMonitorListenerFunction func, | |||
| void *arg) | |||
| { | |||
| InputMonitorListener *iml; | |||
| iml = (InputMonitorListener *) malloc (sizeof (InputMonitorListener)); | |||
| iml->function = func; | |||
| iml->arg = arg; | |||
| iml->id = driver->next_input_monitor_listener_id++; | |||
| pthread_mutex_lock (&driver->input_monitor_lock); | |||
| driver->input_monitor_listeners = g_slist_prepend (driver->input_monitor_listeners, iml); | |||
| pthread_mutex_unlock (&driver->input_monitor_lock); | |||
| return iml->id; | |||
| } | |||
| int | |||
| jack_driver_stop_listening_to_input_monitor_status (jack_driver_t *driver, int which) | |||
| { | |||
| GSList *node; | |||
| int ret = -1; | |||
| pthread_mutex_lock (&driver->input_monitor_lock); | |||
| for (node = driver->input_monitor_listeners; node; node = g_slist_next (node)) { | |||
| if (((InputMonitorListener *) node->data)->id == which) { | |||
| driver->input_monitor_listeners = g_slist_remove_link (driver->input_monitor_listeners, node); | |||
| free (node->data); | |||
| g_slist_free_1 (node); | |||
| ret = 0; | |||
| break; | |||
| } | |||
| } | |||
| pthread_mutex_unlock (&driver->input_monitor_lock); | |||
| return ret; | |||
| } | |||
| void jack_driver_clock_sync_notify (jack_driver_t *driver, channel_t chn, ClockSyncStatus status) | |||
| { | |||
| GSList *node; | |||
| pthread_mutex_lock (&driver->input_monitor_lock); | |||
| for (node = driver->input_monitor_listeners; node; node = g_slist_next (node)) { | |||
| pthread_mutex_lock (&driver->clock_sync_lock); | |||
| for (node = driver->clock_sync_listeners; node; node = g_slist_next (node)) { | |||
| ClockSyncListener *csl = (ClockSyncListener *) node->data; | |||
| csl->function (chn, status, csl->arg); | |||
| } | |||
| pthread_mutex_unlock (&driver->input_monitor_lock); | |||
| } | |||
| void jack_driver_input_monitor_notify (jack_driver_t *driver, channel_t chn, int status) | |||
| { | |||
| GSList *node; | |||
| pthread_mutex_unlock (&driver->clock_sync_lock); | |||
| pthread_mutex_lock (&driver->input_monitor_lock); | |||
| for (node = driver->input_monitor_listeners; node; node = g_slist_next (node)) { | |||
| InputMonitorListener *iml = (InputMonitorListener *) node->data; | |||
| iml->function (chn, status, iml->arg); | |||
| } | |||
| pthread_mutex_unlock (&driver->input_monitor_lock); | |||
| } | |||
| jack_driver_t * | |||
| jack_driver_load (const char *path_to_so, ...) | |||
| @@ -95,16 +95,11 @@ 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_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *); | |||
| static void jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes); | |||
| static int jack_get_total_latency (jack_engine_t *engine, const char *portname, nframes_t *latency); | |||
| static int *jack_shm_registry; | |||
| static int jack_shm_id_cnt; | |||
| jack_port_type_info_t builtin_port_types[] = { | |||
| { JACK_DEFAULT_AUDIO_TYPE, jack_audio_port_mixdown, 1 }, | |||
| { 0, NULL } | |||
| }; | |||
| static inline int | |||
| jack_client_is_inprocess (jack_client_internal_t *client) | |||
| { | |||
| @@ -398,7 +393,7 @@ static int | |||
| jack_set_sample_rate (jack_engine_t *engine, nframes_t nframes) | |||
| { | |||
| engine->control->sample_rate = nframes; | |||
| engine->control->time.frame_rate = nframes; | |||
| return 0; | |||
| } | |||
| @@ -412,9 +407,6 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| struct pollfd pollfd[1]; | |||
| char c; | |||
| unsigned long then, now; | |||
| // rdtscl (then); | |||
| if (pthread_mutex_trylock (&engine->graph_lock) != 0) { | |||
| return 0; | |||
| } | |||
| @@ -426,7 +418,7 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| } | |||
| if (engine->timebase_client) { | |||
| engine->control->frame_time = engine->timebase_client->control->frame_time; | |||
| engine->control->time.frame = engine->timebase_client->control->frame_time; | |||
| } | |||
| for (node = engine->clients; err == 0 && node; ) { | |||
| @@ -472,18 +464,14 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| pollfd[0].fd = client->subgraph_wait_fd; | |||
| pollfd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| rdtscl (then); | |||
| if (poll (pollfd, 1, engine->driver->period_interval) < 0) { | |||
| jack_error ("engine cannot poll for graph completion (%s)", strerror (errno)); | |||
| err++; | |||
| break; | |||
| } | |||
| rdtscl (now); | |||
| if (pollfd[0].revents == 0) { | |||
| jack_error ("subgraph starting at %s timed out (state = %d) (time = %f usecs)", | |||
| client->control->name, client->control->state, | |||
| ((float)(now - then))/450.0f); | |||
| jack_error ("subgraph starting at %s timed out (state = %d)", client->control->name, client->control->state); | |||
| err++; | |||
| break; | |||
| } else if (pollfd[0].revents & ~POLLIN) { | |||
| @@ -514,8 +502,6 @@ jack_process (jack_engine_t *engine, nframes_t nframes) | |||
| jack_cleanup_clients (engine); | |||
| } | |||
| // rdtscl (now); | |||
| // printf ("engine cycle time: %.6f usecs\n", ((float) (now - then)) / 450.00f); | |||
| return 0; | |||
| } | |||
| @@ -574,7 +560,7 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||
| { | |||
| GSList *node; | |||
| jack_client_internal_t *client; | |||
| jack_client_internal_t *client = NULL; | |||
| jack_client_connect_request_t req; | |||
| jack_client_connect_result_t res; | |||
| @@ -587,6 +573,7 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||
| for (node = engine->clients; node; node = g_slist_next (node)) { | |||
| client = (jack_client_internal_t *) node->data; | |||
| if (strncmp(req.name, (char*)client->control->name, sizeof(req.name)) == 0) { | |||
| jack_error ("cannot create new client; %s already exists", client->control->name); | |||
| @@ -596,7 +583,7 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||
| if (res.status == 0) { | |||
| if ((client = jack_client_internal_new (engine, client_fd, &req)) == 0) { | |||
| if ((client = jack_client_internal_new (engine, client_fd, &req)) == NULL) { | |||
| jack_error ("cannot create new client object"); | |||
| return -1; | |||
| } | |||
| @@ -617,8 +604,12 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||
| } | |||
| } | |||
| if (client == NULL) { | |||
| return -1; | |||
| } | |||
| if (write (client->request_fd, &res, sizeof (res)) != sizeof (res)) { | |||
| jack_error ("cannot write connection response to client"); | |||
| jack_error ("cannot write connection response to client"); | |||
| jack_client_delete (engine, client); | |||
| return -1; | |||
| } | |||
| @@ -693,23 +684,6 @@ jack_client_drop (jack_engine_t *engine, jack_client_id_t id) | |||
| return 0; | |||
| } | |||
| #if 0 | |||
| static int | |||
| jack_client_has_connections (jack_client_internal_t *client) | |||
| { | |||
| GSList *node; | |||
| for (node = client->ports; node; node = g_slist_next (node)) { | |||
| if (((jack_port_internal_t *) node->data)->connections) { | |||
| return TRUE; | |||
| } | |||
| } | |||
| return FALSE; | |||
| } | |||
| #endif | |||
| static int | |||
| jack_client_activate (jack_engine_t *engine, jack_client_id_t id) | |||
| @@ -803,7 +777,7 @@ jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id, int to_wait) | |||
| if (client == engine->timebase_client) { | |||
| engine->timebase_client = 0; | |||
| engine->control->frame_time = 0; | |||
| engine->control->time.frame = 0; | |||
| } | |||
| for (portnode = client->ports; portnode; portnode = g_slist_next (portnode)) { | |||
| @@ -829,7 +803,7 @@ jack_set_timebase (jack_engine_t *engine, jack_client_id_t client) | |||
| pthread_mutex_lock (&engine->graph_lock); | |||
| if ((engine->timebase_client = jack_client_internal_by_id (engine, client)) != 0) { | |||
| engine->control->frame_time = engine->timebase_client->control->frame_time; | |||
| engine->control->time.frame = engine->timebase_client->control->frame_time; | |||
| ret = 0; | |||
| } | |||
| pthread_mutex_unlock (&engine->graph_lock); | |||
| @@ -863,41 +837,6 @@ handle_client_jack_error (jack_engine_t *engine, int fd) | |||
| return 0; | |||
| } | |||
| static int | |||
| jack_client_port_monitor (jack_engine_t *engine, jack_port_id_t port_id, int onoff) | |||
| { | |||
| jack_port_shared_t *port; | |||
| jack_client_internal_t *client = NULL; | |||
| jack_event_t event; | |||
| if (port_id < 0 || port_id >= engine->port_max) { | |||
| jack_error ("illegal port ID in port monitor request"); | |||
| return -1; | |||
| } | |||
| port = &engine->control->ports[port_id]; | |||
| if (!(port->flags & JackPortCanMonitor)) { | |||
| jack_error ("port monitor request made on a port (%s) that doesn't support monitoring", | |||
| port->name); | |||
| return -1; | |||
| } | |||
| pthread_mutex_lock (&engine->graph_lock); | |||
| if ((client = jack_client_internal_by_id (engine, port->client_id)) == NULL) { | |||
| jack_error ("unknown client owns port %d!!", port_id); | |||
| pthread_mutex_unlock (&engine->graph_lock); | |||
| return -1; | |||
| } | |||
| pthread_mutex_unlock (&engine->graph_lock); | |||
| event.type = (onoff ? PortMonitor : PortUnMonitor); | |||
| event.x.port_id = port_id; | |||
| return jack_deliver_event (engine, client, &event); | |||
| } | |||
| static int | |||
| handle_client_io (jack_engine_t *engine, int fd) | |||
| @@ -965,12 +904,14 @@ handle_client_io (jack_engine_t *engine, int fd) | |||
| req.status = jack_set_timebase (engine, req.x.client_id); | |||
| break; | |||
| case RequestPortMonitor: | |||
| req.status = jack_client_port_monitor (engine, req.x.port_info.port_id, TRUE); | |||
| case GetPortTotalLatency: | |||
| req.status = jack_get_total_latency (engine, req.x.port_info.name, &req.x.nframes); | |||
| break; | |||
| case RequestPortUnMonitor: | |||
| req.status = jack_client_port_monitor (engine, req.x.port_info.port_id, FALSE); | |||
| default: | |||
| /* some requests are handled entirely on the client side, | |||
| by adjusting the shared memory area(s) | |||
| */ | |||
| break; | |||
| } | |||
| @@ -1133,16 +1074,6 @@ jack_engine_new (int realtime, int rtpriority) | |||
| engine->fifo[i] = -1; | |||
| } | |||
| /* Build a linked list of known port types. We use a list so that | |||
| we can easily manage other data types without messing with | |||
| reallocation of arrays, etc. | |||
| */ | |||
| engine->port_types = NULL; | |||
| for (i = 0; builtin_port_types[i].type_name; i++) { | |||
| engine->port_types = g_slist_append (engine->port_types, &builtin_port_types[i]); | |||
| } | |||
| engine->external_client_cnt = 0; | |||
| srandom (time ((time_t *) 0)); | |||
| @@ -1195,9 +1126,9 @@ jack_engine_new (int realtime, int rtpriority) | |||
| engine->control->real_time = realtime; | |||
| engine->control->client_priority = engine->rtpriority - 1; | |||
| engine->control->sample_rate = 0; | |||
| engine->control->buffer_size = 0; | |||
| engine->control->frame_time = 0; | |||
| engine->control->time.frame_rate = 0; | |||
| engine->control->time.frame = 0; | |||
| sprintf (engine->fifo_prefix, "%s/ack_fifo_%d", jack_temp_dir, getpid()); | |||
| @@ -1392,8 +1323,6 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req | |||
| client->control->srate_arg = NULL; | |||
| client->control->port_register = NULL; | |||
| client->control->port_register_arg = NULL; | |||
| client->control->port_monitor = NULL; | |||
| client->control->port_monitor_arg = NULL; | |||
| if (req->type == ClientDynamic) { | |||
| if (jack_load_client (engine, client, req->object_path)) { | |||
| @@ -1439,7 +1368,7 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) | |||
| if (client == engine->timebase_client) { | |||
| engine->timebase_client = 0; | |||
| engine->control->frame_time = 0; | |||
| engine->control->time.frame = 0; | |||
| } | |||
| jack_client_disconnect (engine, client); | |||
| @@ -1563,18 +1492,6 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_ | |||
| } | |||
| break; | |||
| case PortMonitor: | |||
| if (client->control->port_monitor) { | |||
| client->control->port_monitor (event->x.port_id, TRUE, client->control->port_monitor_arg); | |||
| } | |||
| break; | |||
| case PortUnMonitor: | |||
| if (client->control->port_monitor) { | |||
| client->control->port_monitor (event->x.port_id, FALSE, client->control->port_monitor_arg); | |||
| } | |||
| break; | |||
| default: | |||
| /* internal clients don't need to know */ | |||
| break; | |||
| @@ -1901,6 +1818,16 @@ jack_port_do_connect (jack_engine_t *engine, | |||
| return -1; | |||
| } | |||
| if (srcport->shared->locked) { | |||
| jack_error ("source port is locked against connection changes"); | |||
| return -1; | |||
| } | |||
| if (dstport->shared->locked) { | |||
| jack_error ("destination port is locked against connection changes"); | |||
| return -1; | |||
| } | |||
| if (strcmp (srcport->shared->type_info.type_name, | |||
| dstport->shared->type_info.type_name) != 0) { | |||
| jack_error ("ports used in attemped connection are not of the same data type"); | |||
| @@ -1964,6 +1891,16 @@ jack_port_disconnect_internal (jack_engine_t *engine, | |||
| src_id = srcport->shared->id; | |||
| dst_id = dstport->shared->id; | |||
| /* this is a bit harsh, but it basically says that if we actually | |||
| do a disconnect, and its the last one, then make sure that | |||
| any input monitoring is turned off on the srcport. this isn't | |||
| ideal for all situations, but it works better for most of them. | |||
| */ | |||
| if (srcport->connections == NULL) { | |||
| srcport->shared->monitor_requests = 0; | |||
| } | |||
| jack_send_connection_notification (engine, srcport->shared->client_id, src_id, dst_id, FALSE); | |||
| jack_send_connection_notification (engine, dstport->shared->client_id, dst_id, src_id, FALSE); | |||
| @@ -2010,6 +1947,51 @@ jack_port_do_disconnect (jack_engine_t *engine, | |||
| return ret; | |||
| } | |||
| static int | |||
| jack_port_get_total_latency (jack_engine_t *engine, jack_port_internal_t *port, nframes_t *latency) | |||
| { | |||
| GSList *node; | |||
| /* call tree should hold engine->graph_lock. */ | |||
| (*latency) = port->shared->latency; | |||
| for (node = port->connections; node; node = g_slist_next (node)) { | |||
| nframes_t this_latency; | |||
| jack_connection_internal_t *connection; | |||
| connection = (jack_connection_internal_t *) node->data; | |||
| /* if we're a destination in the connection, recurse on the source to | |||
| get its total latency | |||
| */ | |||
| if (connection->destination == port) { | |||
| jack_port_get_total_latency (engine, connection->source, &this_latency); | |||
| if (this_latency > *latency) { | |||
| (*latency) = this_latency; | |||
| } | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| static int | |||
| jack_get_total_latency (jack_engine_t *engine, const char *portname, nframes_t *latency) | |||
| { | |||
| jack_port_internal_t *port; | |||
| if ((port = jack_get_port_by_name (engine, portname)) == NULL) { | |||
| return -1; | |||
| } | |||
| return jack_port_get_total_latency (engine, port, latency); | |||
| } | |||
| static int | |||
| jack_get_fifo_fd (jack_engine_t *engine, int which_fifo) | |||
| @@ -2139,12 +2121,10 @@ int | |||
| jack_port_do_register (jack_engine_t *engine, jack_request_t *req) | |||
| { | |||
| GSList *node; | |||
| jack_port_id_t port_id; | |||
| jack_port_shared_t *shared; | |||
| jack_port_internal_t *port; | |||
| jack_client_internal_t *client; | |||
| jack_port_type_info_t *type_info; | |||
| pthread_mutex_lock (&engine->graph_lock); | |||
| if ((client = jack_client_internal_by_id (engine, req->x.port_info.client_id)) == 0) { | |||
| @@ -2164,42 +2144,16 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req) | |||
| shared->client_id = req->x.port_info.client_id; | |||
| shared->flags = req->x.port_info.flags; | |||
| shared->locked = 0; | |||
| shared->buffer_size = req->x.port_info.buffer_size; | |||
| shared->latency = 0; | |||
| shared->monitor_requests = 0; | |||
| shared->locked = 0; | |||
| port = &engine->internal_ports[port_id]; | |||
| port->shared = shared; | |||
| port->connections = 0; | |||
| type_info = NULL; | |||
| for (node = engine->port_types; node; node = g_slist_next (node)) { | |||
| if (strcmp (req->x.port_info.type, ((jack_port_type_info_t *) node->data)->type_name) == 0) { | |||
| type_info = (jack_port_type_info_t *) node->data; | |||
| break; | |||
| } | |||
| } | |||
| if (type_info == NULL) { | |||
| /* not a builtin type, so allocate a new type_info structure, | |||
| and fill it appropriately. | |||
| */ | |||
| type_info = (jack_port_type_info_t *) malloc (sizeof (jack_port_type_info_t)); | |||
| type_info->type_name = strdup (req->x.port_info.type); | |||
| type_info->mixdown = NULL; /* we have no idea how to mix this */ | |||
| type_info->buffer_scale_factor = -1; /* use specified port buffer size */ | |||
| engine->port_types = g_slist_prepend (engine->port_types, type_info); | |||
| } | |||
| memcpy (&port->shared->type_info, type_info, sizeof (jack_port_type_info_t)); | |||
| if (jack_port_assign_buffer (engine, port)) { | |||
| jack_error ("cannot assign buffer for port"); | |||
| return -1; | |||
| @@ -2288,6 +2242,7 @@ jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) | |||
| port->shared->shm_key = -1; | |||
| if (port->shared->flags & JackPortIsInput) { | |||
| port->shared->offset = 0; | |||
| return 0; | |||
| } | |||
| @@ -2372,35 +2327,3 @@ jack_send_connection_notification (jack_engine_t *engine, jack_client_id_t clien | |||
| return 0; | |||
| } | |||
| static void | |||
| jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes) | |||
| { | |||
| GSList *node; | |||
| jack_port_t *input; | |||
| nframes_t n; | |||
| sample_t *buffer; | |||
| sample_t *dst, *src; | |||
| /* by the time we've called this, we've already established | |||
| the existence of more than 1 connection to this input port. | |||
| */ | |||
| node = port->connections; | |||
| input = (jack_port_t *) node->data; | |||
| buffer = jack_port_buffer (port); | |||
| memcpy (buffer, jack_port_buffer (input), sizeof (sample_t) * nframes); | |||
| for (node = g_slist_next (node); node; node = g_slist_next (node)) { | |||
| input = (jack_port_t *) node->data; | |||
| n = nframes; | |||
| dst = buffer; | |||
| src = jack_port_buffer (input); | |||
| while (n--) { | |||
| *dst++ += *src++; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,4 +1,5 @@ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| @@ -81,11 +82,11 @@ main (int argc, char *argv[]) | |||
| printf ("client activated\n"); | |||
| if (jack_port_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||
| if (jack_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| if (jack_port_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||
| if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||
| @@ -7,5 +7,5 @@ Name: jack | |||
| Description: the Jack Audio Connection Kit: a low-latency synchronous callback-based media server | |||
| Requires: glib >= 1.0.0 | |||
| Version: @JACK_VERSION@ | |||
| Libs: -L${libdir} -ljack | |||
| Libs: -L${libdir} -ljack -lglib -lpthread -ldl | |||
| Cflags: -I${includedir} | |||
| @@ -49,7 +49,6 @@ typedef struct { | |||
| char **capture_addr; | |||
| const snd_pcm_channel_area_t *capture_areas; | |||
| const snd_pcm_channel_area_t *playback_areas; | |||
| unsigned long long time_at_interrupt; | |||
| struct pollfd *pfd; | |||
| unsigned int playback_nfds; | |||
| unsigned int capture_nfds; | |||
| @@ -78,7 +77,6 @@ typedef struct { | |||
| snd_ctl_t *ctl_handle; | |||
| snd_pcm_t *playback_handle; | |||
| snd_pcm_t *capture_handle; | |||
| unsigned long *input_monitor_requests; | |||
| snd_pcm_hw_params_t *playback_hw_params; | |||
| snd_pcm_sw_params_t *playback_sw_params; | |||
| snd_pcm_hw_params_t *capture_hw_params; | |||
| @@ -116,6 +114,18 @@ static __inline__ void alsa_driver_silence_on_channel (alsa_driver_t *driver, ch | |||
| alsa_driver_mark_channel_done (driver,chn); | |||
| } | |||
| static __inline__ void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, nframes_t nframes) { | |||
| if (driver->interleaved) { | |||
| memset_interleave | |||
| (driver->playback_addr[chn], | |||
| 0, nframes * driver->sample_bytes, | |||
| driver->interleave_unit, | |||
| driver->playback_interleave_skip); | |||
| } else { | |||
| memset (driver->playback_addr[chn], 0, nframes * driver->sample_bytes); | |||
| } | |||
| } | |||
| static __inline__ void alsa_driver_read_from_channel (alsa_driver_t *driver, | |||
| channel_t channel, sample_t *buf, | |||
| nframes_t nsamples, | |||
| @@ -24,6 +24,7 @@ | |||
| #include <glib.h> | |||
| #include <pthread.h> | |||
| #include <jack/types.h> | |||
| #include <jack/port.h> | |||
| typedef void (*ClockSyncListenerFunction)(channel_t,ClockSyncStatus,void*); | |||
| @@ -33,14 +34,6 @@ typedef struct { | |||
| void *arg; | |||
| } ClockSyncListener; | |||
| typedef void (*InputMonitorListenerFunction)(channel_t,int,void*); | |||
| typedef struct { | |||
| unsigned long id; | |||
| InputMonitorListenerFunction function; | |||
| void *arg; | |||
| } InputMonitorListener; | |||
| struct _jack_engine; | |||
| struct _jack_driver; | |||
| @@ -55,9 +48,7 @@ typedef void (*JackDriverSetHwMonitoringFunction) (struct _jack_drive | |||
| typedef int (*JackDriverChangeSampleClockFunction) (struct _jack_driver *, SampleClockMode mode); | |||
| typedef int (*JackDriverResetParametersFunction) (struct _jack_driver *, nframes_t frames_per_cycle, nframes_t rate); | |||
| typedef void (*JackDriverMarkChannelSilentFunction) (struct _jack_driver *, unsigned long chn); | |||
| typedef void (*JackDriverRequestMonitorInputFunction) (struct _jack_driver *, unsigned long chn, int yn); | |||
| typedef void (*JackDriverRequestAllMonitorInputFunction) (struct _jack_driver *, int yn); | |||
| typedef int (*JackDriverMonitoringInputFunction)(struct _jack_driver *,channel_t chn); | |||
| #define JACK_DRIVER_DECL \ | |||
| nframes_t frame_rate; \ | |||
| @@ -91,7 +82,6 @@ typedef int (*JackDriverMonitoringInputFunction)(struct _jack_driver | |||
| could/should be provided by a different kind of object. \ | |||
| */ \ | |||
| \ | |||
| JackDriverFramesSinceCycleStartFunction frames_since_cycle_start; \ | |||
| JackDriverClockSyncStatusFunction clock_sync_status; \ | |||
| JackDriverAudioStopFunction audio_stop; \ | |||
| JackDriverAudioStartFunction audio_start; \ | |||
| @@ -99,9 +89,7 @@ typedef int (*JackDriverMonitoringInputFunction)(struct _jack_driver | |||
| JackDriverChangeSampleClockFunction change_sample_clock; \ | |||
| JackDriverResetParametersFunction reset_parameters; \ | |||
| JackDriverMarkChannelSilentFunction mark_channel_silent; \ | |||
| JackDriverRequestMonitorInputFunction request_monitor_input; \ | |||
| JackDriverRequestAllMonitorInputFunction request_all_monitor_input; \ | |||
| JackDriverMonitoringInputFunction monitoring_input; | |||
| typedef struct _jack_driver { | |||
| @@ -118,11 +106,8 @@ void jack_driver_unload (jack_driver_t *); | |||
| int jack_driver_listen_for_clock_sync_status (jack_driver_t *, ClockSyncListenerFunction, void *arg); | |||
| int jack_driver_stop_listen_for_clock_sync_status (jack_driver_t *, int); | |||
| int jack_driver_listen_for_input_monitor_status (jack_driver_t *, InputMonitorListenerFunction, void *arg); | |||
| int jack_driver_stop_listen_for_input_monitor_status (jack_driver_t *, int); | |||
| void jack_driver_clock_sync_notify (jack_driver_t *, channel_t chn, ClockSyncStatus); | |||
| void jack_driver_input_monitor_notify (jack_driver_t *, channel_t chn, int); | |||
| void jack_driver_input_monitor_notify (jack_driver_t *, jack_port_shared_t *, int); | |||
| #endif /* __jack_driver_h__ */ | |||
| @@ -48,11 +48,30 @@ typedef struct { | |||
| char *address; | |||
| } jack_port_segment_info_t; | |||
| typedef struct _time_info | |||
| { | |||
| nframes_t frame; | |||
| nframes_t frame_rate; | |||
| unsigned long microseconds; | |||
| double ppqPos; // 1 ppq | |||
| double tempo; // in bpm | |||
| double barStartPos; // last bar start, in 1 ppq | |||
| double cycleStartPos; // 1 ppq | |||
| double cycleEndPos; // 1 ppq | |||
| float timeSigNumerator; // time signature | |||
| float timeSigDenominator; | |||
| long smpteOffset; | |||
| long smpteFrameRate; // 0:24, 1:25, 2:29.97, 3:30, 4:29.97 df, 5:30 df | |||
| long samplesToNextClock; // midi clock resolution (24 ppq), can be negative | |||
| long flags; // see below | |||
| } time_info; | |||
| typedef struct { | |||
| nframes_t frame_time; | |||
| time_info time; | |||
| pid_t engine_pid; | |||
| unsigned long sample_rate; | |||
| unsigned long buffer_size; | |||
| char real_time; | |||
| int client_priority; | |||
| @@ -70,8 +89,6 @@ typedef enum { | |||
| GraphReordered, | |||
| PortRegistered, | |||
| PortUnregistered, | |||
| PortMonitor, | |||
| PortUnMonitor, | |||
| } AudioEngineEventType; | |||
| typedef struct { | |||
| @@ -118,8 +135,6 @@ typedef volatile struct { | |||
| void *srate_arg; | |||
| JackPortRegistrationCallback port_register; | |||
| void *port_register_arg; | |||
| JackPortMonitorCallback port_monitor; | |||
| void *port_monitor_arg; | |||
| /* for engine use only */ | |||
| @@ -178,8 +193,7 @@ typedef enum { | |||
| DropClient = 6, | |||
| ActivateClient = 7, | |||
| DeactivateClient = 8, | |||
| RequestPortMonitor = 9, | |||
| RequestPortUnMonitor = 10 | |||
| GetPortTotalLatency = 9 | |||
| } AudioEngineRequestType; | |||
| typedef struct { | |||
| @@ -199,6 +213,7 @@ typedef struct { | |||
| char destination_port[JACK_PORT_NAME_SIZE+1]; | |||
| } connect; | |||
| jack_client_id_t client_id; | |||
| nframes_t nframes; | |||
| } x; | |||
| int status; | |||
| } jack_request_t; | |||
| @@ -51,10 +51,6 @@ int jack_set_process_callback (jack_client_t *, JackProcessCallback, void *arg); | |||
| int jack_set_buffer_size_callback (jack_client_t *, JackBufferSizeCallback, void *arg); | |||
| int jack_set_sample_rate_callback (jack_client_t *, JackSampleRateCallback, void *arg); | |||
| int jack_set_port_registration_callback (jack_client_t *, JackPortRegistrationCallback, void *); | |||
| int jack_set_port_monitor_callback (jack_client_t *, JackPortMonitorCallback, void *); | |||
| int jack_get_process_start_fd (jack_client_t *); | |||
| int jack_get_process_done_fd (jack_client_t *); | |||
| int jack_activate (jack_client_t *client); | |||
| int jack_deactivate (jack_client_t *client); | |||
| @@ -123,9 +119,16 @@ jack_port_register (jack_client_t *, | |||
| int jack_port_unregister (jack_client_t *, jack_port_t *); | |||
| /* a port is an opaque type, and its name is not inferable */ | |||
| /* a port is an opaque type. these help with a few things */ | |||
| const char * jack_port_name (const jack_port_t *port); | |||
| const char * jack_port_short_name (const jack_port_t *port); | |||
| int jack_port_flags (const jack_port_t *port); | |||
| const char * jack_port_type (const jack_port_t *port); | |||
| int jack_port_connected (const jack_port_t *port); | |||
| int jack_port_equal (const jack_port_t *a, const jack_port_t *b); | |||
| int jack_port_set_name (jack_port_t *port, const char *name); | |||
| /* This returns a pointer to the memory area associated with the | |||
| specified port. It can only be called from within the client's | |||
| @@ -149,13 +152,27 @@ void *jack_port_get_buffer (jack_port_t *, nframes_t); | |||
| the flags of the destination port must include PortIsInput. | |||
| */ | |||
| int jack_port_connect (jack_client_t *, | |||
| const char *source_port, | |||
| const char *destination_port); | |||
| int jack_connect (jack_client_t *, | |||
| const char *source_port, | |||
| const char *destination_port); | |||
| int jack_disconnect (jack_client_t *, | |||
| const char *source_port, | |||
| const char *destination_port); | |||
| /* these two functions perform the exact same function | |||
| as the jack_connect() and jack_disconnect(), but they | |||
| use port handles rather than names, which avoids | |||
| the name lookup inherent in the name-based versions. | |||
| it is envisaged that clients (dis)connecting their own | |||
| ports will use these two, wherease generic connection | |||
| clients (e.g. patchbays) will use the name-based | |||
| versions | |||
| */ | |||
| int jack_port_disconnect (jack_client_t *, | |||
| const char *source_port, | |||
| const char *destination_port); | |||
| int jack_port_connect (jack_client_t *, jack_port_t *src, jack_port_t *dst); | |||
| int jack_port_disconnect (jack_client_t *, jack_port_t *); | |||
| /* A client may call this on a pair of its own ports to | |||
| semi-permanently wire them together. This means that | |||
| @@ -171,7 +188,7 @@ int jack_port_disconnect (jack_client_t *, | |||
| clients. Thats what a connection is for. | |||
| */ | |||
| int jack_port_tie (jack_port_t *dst, jack_port_t *src); | |||
| 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 | |||
| @@ -181,19 +198,60 @@ int jack_port_tie (jack_port_t *dst, jack_port_t *src); | |||
| int jack_port_untie (jack_port_t *port); | |||
| /* a client may call this function to prevent other objects | |||
| from changing the connection status of the named port. | |||
| from changing the connection status of a port. the port | |||
| must be owned by the calling client. | |||
| */ | |||
| int jack_port_lock (jack_client_t *, jack_port_t *); | |||
| int jack_port_unlock (jack_client_t *, jack_port_t *); | |||
| /* returns 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 audio will be audible. | |||
| for a physical audio input port, this is the time between the sound | |||
| being audible and the corresponding frames being readable from the | |||
| port. | |||
| */ | |||
| nframes_t jack_port_get_latency (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 *, nframes_t); | |||
| /* if JackPortCanMonitor is set for a port, then this function will | |||
| turn on/off input monitoring for the port. if JackPortCanMonitor | |||
| is not set, then this function will do nothing. | |||
| */ | |||
| int jack_port_request_monitor (jack_client_t *, const char *port_name, int onoff); | |||
| int jack_port_request_monitor (jack_port_t *port, int onoff); | |||
| int jack_port_request_monitor_by_name (jack_client_t *client, const char *port_name, int onoff); | |||
| /* if JackPortCanMonitor is set for a port, then this function will | |||
| turn on input monitoring if it was off, and will turn it off it | |||
| only one request has been made to turn it on. if JackPortCanMonitor | |||
| is not set, then this function will do nothing. | |||
| */ | |||
| int jack_port_ensure_monitor (jack_port_t *port, int onoff); | |||
| /* returns a true or false value depending on whether or not | |||
| input monitoring has been requested for `port'. | |||
| */ | |||
| int jack_port_monitoring_input (jack_port_t *port); | |||
| /* this returns the sample rate of the jack */ | |||
| @@ -226,6 +284,8 @@ char * const * jack_get_ports (jack_client_t *, | |||
| const char *type_name_pattern, | |||
| unsigned long flags); | |||
| jack_port_t *jack_port_by_name (jack_client_t *, const char *portname); | |||
| /* If a client is told to become the timebase for the entire system, | |||
| it calls this function. If it returns zero, then the client has | |||
| the responsibility to call jack_update_time() at the end | |||
| @@ -237,6 +297,11 @@ char * const * jack_get_ports (jack_client_t *, | |||
| int jack_engine_takeover_timebase (jack_client_t *); | |||
| void jack_update_time (jack_client_t *, nframes_t); | |||
| /* this estimates the time that has passed since the | |||
| start of the current cycle. | |||
| */ | |||
| nframes_t jack_frames_since_cycle_start (jack_client_t *); | |||
| #ifdef __cplusplus | |||
| } | |||
| @@ -25,7 +25,7 @@ | |||
| #include <jack/types.h> | |||
| typedef struct _jack_port_type_info { | |||
| const char *type_name; /* what do you think ? */ | |||
| const char type_name[32]; /* what do you think ? */ | |||
| void (*mixdown)(jack_port_t *, nframes_t); /* function to mixdown multiple inputs to a buffer. can be | |||
| NULL, indicating that multiple input connections | |||
| @@ -61,9 +61,12 @@ typedef struct _jack_port_shared { | |||
| char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE+2]; | |||
| jack_port_type_info_t type_info; | |||
| jack_client_id_t client_id; | |||
| nframes_t latency; | |||
| unsigned char monitor_requests; | |||
| char in_use : 1; | |||
| char locked : 1; | |||
| char in_use : 1; | |||
| char locked : 1; | |||
| } jack_port_shared_t; | |||
| /* This is the data structure allocated by the client | |||
| @@ -21,6 +21,8 @@ | |||
| #ifndef __jack_engine_types_h__ | |||
| #define __jack_engine_types_h__ | |||
| #include <limits.h> | |||
| typedef float sample_t; | |||
| typedef unsigned long nframes_t; | |||
| typedef long jack_port_id_t; | |||
| @@ -28,11 +30,12 @@ typedef unsigned long jack_client_id_t; | |||
| typedef float gain_t; | |||
| typedef long channel_t; | |||
| static const nframes_t max_frames = ULONG_MAX; | |||
| typedef int (*JackProcessCallback)(nframes_t, void *); | |||
| typedef int (*JackBufferSizeCallback)(nframes_t, void *); | |||
| typedef int (*JackSampleRateCallback)(nframes_t, void *); | |||
| typedef void (*JackPortRegistrationCallback)(jack_port_id_t,int,void*); | |||
| typedef void (*JackPortMonitorCallback)(jack_port_id_t,int,void*); | |||
| #define NoChannel -1 | |||
| #define NoPort -1 | |||
| @@ -40,6 +40,7 @@ static nframes_t srate = 48000; | |||
| static int realtime = 0; | |||
| static int realtime_priority = 10; | |||
| static int with_fork = 1; | |||
| static int hw_monitoring = 0; | |||
| static void | |||
| signal_handler (int sig) | |||
| @@ -123,7 +124,11 @@ jack_engine_waiter_thread (void *arg) | |||
| return 0; | |||
| } | |||
| if ((driver = jack_driver_load (ADDON_DIR "/jack_alsa.so", alsa_pcm_name, frames_per_interrupt, srate)) == 0) { | |||
| if ((driver = jack_driver_load (ADDON_DIR "/jack_alsa.so", | |||
| alsa_pcm_name, | |||
| frames_per_interrupt, | |||
| srate, | |||
| hw_monitoring)) == 0) { | |||
| fprintf (stderr, "cannot load ALSA driver module\n"); | |||
| kill (signal_pid, SIGTERM); | |||
| return 0; | |||
| @@ -203,6 +208,7 @@ static void usage () | |||
| [ --srate OR -r sample-rate ] | |||
| [ --frames-per-interrupt OR -p frames_per_interrupt ] | |||
| [ --realtime OR -R [ --realtime-priority OR -P priority ] ] | |||
| [ --hw-monitor OR -h ] | |||
| [ --spoon OR -F ] (don't fork) | |||
| "); | |||
| } | |||
| @@ -211,7 +217,7 @@ int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| const char *options = "hd:r:p:RP:FD:"; | |||
| const char *options = "hd:r:p:RP:FD:H"; | |||
| struct option long_options[] = | |||
| { | |||
| { "tmpdir", 1, 0, 'D' }, | |||
| @@ -221,6 +227,7 @@ main (int argc, char *argv[]) | |||
| { "help", 0, 0, 'h' }, | |||
| { "realtime", 0, 0, 'R' }, | |||
| { "realtime-priority", 1, 0, 'P' }, | |||
| { "hw-monitor", 0, 0, 'H' }, | |||
| { "spoon", 0, 0, 'F' }, | |||
| { 0, 0, 0, 0 } | |||
| }; | |||
| @@ -258,6 +265,10 @@ main (int argc, char *argv[]) | |||
| realtime = 1; | |||
| break; | |||
| case 'H': | |||
| hw_monitoring = 1; | |||
| break; | |||
| case 'h': | |||
| default: | |||
| fprintf (stderr, "unknown option character %c\n", opt); | |||
| @@ -17,9 +17,13 @@ main (int argc, char *argv[]) | |||
| return 1; | |||
| } | |||
| jack_port_request_monitor (client, "alsa_pcm:in_1", TRUE); | |||
| if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", TRUE)) { | |||
| fprintf (stderr, "could not enable monitoring for in_1\n"); | |||
| } | |||
| sleep (10); | |||
| jack_port_request_monitor (client, "alsa_pcm:in_1", FALSE); | |||
| if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", FALSE)) { | |||
| fprintf (stderr, "could not disable monitoring for in_1\n"); | |||
| } | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||
| @@ -29,3 +29,9 @@ jack_pool_alloc (size_t bytes) | |||
| return malloc (bytes); | |||
| } | |||
| void | |||
| jack_pool_release (void *ptr) | |||
| { | |||
| free (ptr); | |||
| } | |||
| @@ -109,11 +109,11 @@ main (int argc, char *argv[]) | |||
| the client is activated (this may change in the future). | |||
| */ | |||
| if (jack_port_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||
| if (jack_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| if (jack_port_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||
| if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||