git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3591 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.117.0
| @@ -1290,6 +1290,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||
| strerror (errno)); | |||
| *status = -3; | |||
| return 0; | |||
| } | |||
| @@ -1306,9 +1307,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||
| } | |||
| #ifdef DEBUG_WAKEUP | |||
| jack_info ("%" PRIu64 ": checked %d fds, %" PRIu64 | |||
| " usecs since poll entered", poll_ret, nfds, | |||
| poll_ret - poll_enter); | |||
| fprintf (stderr, "%" PRIu64 ": checked %d fds, started at %" PRIu64 " %" PRIu64 " usecs since poll entered\n", | |||
| poll_ret, nfds, poll_enter, poll_ret - poll_enter); | |||
| #endif | |||
| /* check to see if it was the extra FD that caused us | |||
| @@ -1345,8 +1345,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||
| if (revents & POLLOUT) { | |||
| need_playback = 0; | |||
| #ifdef DEBUG_WAKEUP | |||
| jack_info ("%" PRIu64 | |||
| " playback stream ready", | |||
| fprintf (stderr, "%" PRIu64 | |||
| " playback stream ready\n", | |||
| poll_ret); | |||
| #endif | |||
| } | |||
| @@ -1368,8 +1368,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||
| if (revents & POLLIN) { | |||
| need_capture = 0; | |||
| #ifdef DEBUG_WAKEUP | |||
| jack_info ("%" PRIu64 | |||
| " capture stream ready", | |||
| fprintf (stderr, "%" PRIu64 | |||
| " capture stream ready\n", | |||
| poll_ret); | |||
| #endif | |||
| } | |||
| @@ -1426,8 +1426,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||
| avail = capture_avail < playback_avail ? capture_avail : playback_avail; | |||
| #ifdef DEBUG_WAKEUP | |||
| jack_info ("wakeup complete, avail = %lu, pavail = %lu " | |||
| "cavail = %lu", | |||
| fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu " | |||
| "cavail = %lu\n", | |||
| avail, playback_avail, capture_avail); | |||
| #endif | |||
| @@ -1,20 +1,28 @@ | |||
| MAINTAINERCLEANFILES = Makefile.in | |||
| if HAVE_SNDFILE | |||
| JACKREC = jackrec | |||
| dist-check-sndfile: | |||
| else | |||
| JACKREC = | |||
| dist-check-sndfile: | |||
| @echo | |||
| @echo ' ******' You need sndfile installed to make dist.' ******' | |||
| @echo | |||
| @false | |||
| endif | |||
| bin_PROGRAMS = jack_simple_client \ | |||
| jack_transport_client \ | |||
| jack_impulse_grabber \ | |||
| jack_metro \ | |||
| jack_showtime \ | |||
| jack_midisine \ | |||
| jack_midiseq | |||
| jack_midisine \ | |||
| jack_midiseq \ | |||
| $(JACKREC) | |||
| if HAVE_SNDFILE | |||
| # note! jackrec_CFLAGS syntax not supported by automake-1.4 | |||
| sndfile_cflags = @SNDFILE_CFLAGS@ | |||
| endif | |||
| AM_CFLAGS = -I.. $(JACK_CFLAGS) $(sndfile_cflags) | |||
| AM_CXXFLAGS = -I.. $(JACK_CFLAGS) $(sndfile_cflags) | |||
| AM_CFLAGS = -I.. $(JACK_CFLAGS) | |||
| AM_CXXFLAGS = -I.. $(JACK_CFLAGS) | |||
| jack_simple_client_SOURCES = simple_client.c | |||
| jack_simple_client_LDFLAGS = @OS_LDFLAGS@ | |||
| @@ -44,6 +52,12 @@ jack_midisine_SOURCES = midisine.c | |||
| jack_midisine_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la | |||
| if HAVE_SNDFILE | |||
| jackrec_SOURCES = capture_client.c | |||
| jackrec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@ | |||
| jackrec_LDADD = $(top_builddir)/libjack/libjack.la | |||
| endif | |||
| # | |||
| # sample in-process client(s) | |||
| # | |||
| @@ -508,15 +508,7 @@ int jack_port_unregister (jack_client_t *, jack_port_t *); | |||
| * zero-filled. if there are multiple inbound connections, the data | |||
| * will be mixed appropriately. | |||
| * | |||
| * FOR OUTPUT PORTS ONLY : WILL BE DEPRECATED in Jack 2.0 !! | |||
| * --------------------------------------------------------- | |||
| * You may cache the value returned, but only between calls to | |||
| * your "blocksize" callback. For this reason alone, you should | |||
| * either never cache the return value or ensure you have | |||
| * a "blocksize" callback and be sure to invalidate the cached | |||
| * address from there. | |||
| * | |||
| * Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). | |||
| * Do not cache the returned address across process() callbacks. | |||
| * Port buffers have to be retrieved in each callback for proper functionning. | |||
| */ | |||
| void *jack_port_get_buffer (jack_port_t *, jack_nframes_t); | |||
| @@ -865,47 +857,57 @@ jack_port_t *jack_port_by_id (jack_client_t *client, | |||
| /** | |||
| * @defgroup TimeFunctions Handling time | |||
| * @{ | |||
| * | |||
| * JACK time is in units of 'frames', according to the current sample rate. | |||
| * The absolute value of frame times is meaningless, frame times have meaning | |||
| * only relative to each other. | |||
| */ | |||
| /** | |||
| * @return the time in frames that has passed since the JACK server | |||
| * began the current process cycle. | |||
| * @return the estimated time in frames that has passed since the JACK | |||
| * server began the current process cycle. | |||
| */ | |||
| jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | |||
| /** | |||
| * @return an estimate of the current time in frames. This is a | |||
| * running counter, no significance should be attached to its value, | |||
| * but it can be compared to a previously returned value. | |||
| * @return the estimated current time in frames. | |||
| * This function is intended for use in other threads (not the process | |||
| * callback). The return value can be compared with the value of | |||
| * jack_last_frame_time to relate time in other threads to JACK time. | |||
| */ | |||
| jack_nframes_t jack_frame_time (const jack_client_t *); | |||
| /** | |||
| * @return the frame_time after the last processing of the graph | |||
| * this is only to be used from the process callback. | |||
| * | |||
| * This function can be used to put timestamps generated by | |||
| * jack_frame_time() in correlation to the current process cycle. | |||
| * @return the precise time at the start of the current process cycle. | |||
| * This function may only be used from the process callback, and can | |||
| * be used to interpret timestamps generated by jack_frame_time() in | |||
| * other threads with respect to the current process cycle. | |||
| * | |||
| * This is the only jack time function that returns exact time: | |||
| * when used during the process callback it always returns the same | |||
| * value (until the next process callback, where it will return | |||
| * that value + nframes, etc). The return value is guaranteed to be | |||
| * monotonic and linear in this fashion unless an xrun occurs. | |||
| * If an xrun occurs, clients must check this value again, as time | |||
| * may have advanced in a non-linear way (e.g. cycles may have been skipped). | |||
| */ | |||
| jack_nframes_t jack_last_frame_time (const jack_client_t *client); | |||
| /** | |||
| * @return estimated time in microseconds of the specified frame time | |||
| * @return the estimated time in microseconds of the specified frame time | |||
| */ | |||
| jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t); | |||
| /** | |||
| * @return estimated time in frames for the specified system time. | |||
| * @return the estimated time in frames for the specified system time. | |||
| */ | |||
| jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t); | |||
| /** | |||
| * @return return JACK's current system time in microseconds, | |||
| * using JACK clock source. | |||
| * using the JACK clock source. | |||
| * | |||
| * The value returned is guaranteed to be monotonic, but not linear. | |||
| * | |||
| * This function is a client version of jack_get_microseconds(). | |||
| */ | |||
| jack_time_t jack_get_time(); | |||
| @@ -2270,7 +2270,7 @@ jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes, | |||
| timer->current_wakeup = engine->driver->last_wait_ust; | |||
| timer->next_wakeup = engine->driver->last_wait_ust + | |||
| engine->driver->period_usecs; | |||
| timer->reset_pending = 0; | |||
| } else { | |||
| @@ -248,13 +248,14 @@ jack_time_to_frames(const jack_client_t *client, jack_time_t now) | |||
| if (time.initialized) { | |||
| #if 0 | |||
| jack_info ("now = %Lu current wakeup = %Lu next = %Lu frames = %lu + %f => %lu", | |||
| jack_info ("now = %Lu current wakeup = %Lu next = %Lu frames = %lu + %f => %lu FC = %f SOI = %f", | |||
| now, time.current_wakeup, time.next_wakeup, time.frames, | |||
| (double) (now - time.current_wakeup)/ | |||
| (time.next_wakeup - time.current_wakeup), | |||
| (double) (now - time.current_wakeup)/ (time.next_wakeup - time.current_wakeup), | |||
| time.frames + | |||
| (long) rint (((double) (now - time.current_wakeup)/ | |||
| (time.next_wakeup - time.current_wakeup)) * ectl->buffer_size)); | |||
| (long) rint (((double) ((long long) now - time.current_wakeup)/ | |||
| (long long) (time.next_wakeup - time.current_wakeup)) * ectl->buffer_size), | |||
| time.filter_coefficient, | |||
| time.second_order_integrator); | |||
| #endif | |||
| return time.frames + | |||
| @@ -274,9 +275,7 @@ jack_frame_time (const jack_client_t *client) | |||
| jack_nframes_t | |||
| jack_last_frame_time (const jack_client_t *client) | |||
| { | |||
| jack_frame_timer_t current; | |||
| jack_read_frame_time (client, ¤t); | |||
| return current.frames; | |||
| return client->engine->frame_timer.frames; | |||
| } | |||
| jack_time_t | |||
| @@ -1,17 +1,5 @@ | |||
| MAINTAINERCLEANFILES = Makefile.in | |||
| if HAVE_SNDFILE | |||
| JACKREC = jackrec | |||
| dist-check-sndfile: | |||
| else | |||
| JACKREC = | |||
| dist-check-sndfile: | |||
| @echo | |||
| @echo ' ******' You need sndfile installed to make dist.' ******' | |||
| @echo | |||
| @false | |||
| endif | |||
| if HAVE_READLINE | |||
| JACK_TRANSPORT = jack_transport | |||
| dist-check-readline: | |||
| @@ -48,7 +36,6 @@ bin_PROGRAMS = jack_load \ | |||
| jack_freewheel \ | |||
| jack_evmon \ | |||
| jack_alias \ | |||
| $(JACKREC) \ | |||
| $(JACK_TRANSPORT) \ | |||
| $(NETJACK_TOOLS) | |||
| @@ -94,12 +81,6 @@ jack_freewheel_SOURCES = freewheel.c | |||
| jack_freewheel_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_freewheel_LDADD = $(top_builddir)/libjack/libjack.la | |||
| if HAVE_SNDFILE | |||
| jackrec_SOURCES = capture_client.c | |||
| jackrec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@ | |||
| jackrec_LDADD = $(top_builddir)/libjack/libjack.la | |||
| endif | |||
| if HAVE_READLINE | |||
| jack_transport_SOURCES = transport.c | |||
| jack_transport_LDFLAGS = -lreadline @READLINE_DEPS@ @OS_LDFLAGS@ | |||
| @@ -1,344 +0,0 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2003 Jack O'Quin | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| * 2002/08/23 - modify for libsndfile 1.0.0 <andy@alsaplayer.org> | |||
| * 2003/05/26 - use ringbuffers - joq | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <sndfile.h> | |||
| #include <pthread.h> | |||
| #include <getopt.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/ringbuffer.h> | |||
| typedef struct _thread_info { | |||
| pthread_t thread_id; | |||
| SNDFILE *sf; | |||
| jack_nframes_t duration; | |||
| jack_nframes_t rb_size; | |||
| jack_client_t *client; | |||
| unsigned int channels; | |||
| int bitdepth; | |||
| char *path; | |||
| volatile int can_capture; | |||
| volatile int can_process; | |||
| volatile int status; | |||
| } jack_thread_info_t; | |||
| /* JACK data */ | |||
| unsigned int nports; | |||
| jack_port_t **ports; | |||
| jack_default_audio_sample_t **in; | |||
| jack_nframes_t nframes; | |||
| const size_t sample_size = sizeof(jack_default_audio_sample_t); | |||
| /* Synchronization between process thread and disk thread. */ | |||
| #define DEFAULT_RB_SIZE 16384 /* ringbuffer size in frames */ | |||
| jack_ringbuffer_t *rb; | |||
| pthread_mutex_t disk_thread_lock = PTHREAD_MUTEX_INITIALIZER; | |||
| pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; | |||
| long overruns = 0; | |||
| void * | |||
| disk_thread (void *arg) | |||
| { | |||
| jack_thread_info_t *info = (jack_thread_info_t *) arg; | |||
| static jack_nframes_t total_captured = 0; | |||
| jack_nframes_t samples_per_frame = info->channels; | |||
| size_t bytes_per_frame = samples_per_frame * sample_size; | |||
| void *framebuf = malloc (bytes_per_frame); | |||
| pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||
| pthread_mutex_lock (&disk_thread_lock); | |||
| info->status = 0; | |||
| while (1) { | |||
| /* Write the data one frame at a time. This is | |||
| * inefficient, but makes things simpler. */ | |||
| while (info->can_capture && | |||
| (jack_ringbuffer_read_space (rb) >= bytes_per_frame)) { | |||
| jack_ringbuffer_read (rb, framebuf, bytes_per_frame); | |||
| if (sf_writef_float (info->sf, framebuf, 1) != 1) { | |||
| char errstr[256]; | |||
| sf_error_str (0, errstr, sizeof (errstr) - 1); | |||
| fprintf (stderr, | |||
| "cannot write sndfile (%s)\n", | |||
| errstr); | |||
| info->status = EIO; /* write failed */ | |||
| goto done; | |||
| } | |||
| if (++total_captured >= info->duration) { | |||
| printf ("disk thread finished\n"); | |||
| goto done; | |||
| } | |||
| } | |||
| /* wait until process() signals more data */ | |||
| pthread_cond_wait (&data_ready, &disk_thread_lock); | |||
| } | |||
| done: | |||
| pthread_mutex_unlock (&disk_thread_lock); | |||
| free (framebuf); | |||
| return 0; | |||
| } | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| int chn; | |||
| size_t i; | |||
| jack_thread_info_t *info = (jack_thread_info_t *) arg; | |||
| /* Do nothing until we're ready to begin. */ | |||
| if ((!info->can_process) || (!info->can_capture)) | |||
| return 0; | |||
| for (chn = 0; chn < nports; chn++) | |||
| in[chn] = jack_port_get_buffer (ports[chn], nframes); | |||
| /* Sndfile requires interleaved data. It is simpler here to | |||
| * just queue interleaved samples to a single ringbuffer. */ | |||
| for (i = 0; i < nframes; i++) { | |||
| for (chn = 0; chn < nports; chn++) { | |||
| if (jack_ringbuffer_write (rb, (void *) (in[chn]+i), | |||
| sample_size) | |||
| < sample_size) | |||
| overruns++; | |||
| } | |||
| } | |||
| /* Tell the disk thread there is work to do. If it is already | |||
| * running, the lock will not be available. We can't wait | |||
| * here in the process() thread, but we don't need to signal | |||
| * in that case, because the disk thread will read all the | |||
| * data queued before waiting again. */ | |||
| if (pthread_mutex_trylock (&disk_thread_lock) == 0) { | |||
| pthread_cond_signal (&data_ready); | |||
| pthread_mutex_unlock (&disk_thread_lock); | |||
| } | |||
| return 0; | |||
| } | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| fprintf (stderr, "JACK shutdown\n"); | |||
| // exit (0); | |||
| abort(); | |||
| } | |||
| void | |||
| setup_disk_thread (jack_thread_info_t *info) | |||
| { | |||
| SF_INFO sf_info; | |||
| int short_mask; | |||
| sf_info.samplerate = jack_get_sample_rate (info->client); | |||
| sf_info.channels = info->channels; | |||
| switch (info->bitdepth) { | |||
| case 8: short_mask = SF_FORMAT_PCM_U8; | |||
| break; | |||
| case 16: short_mask = SF_FORMAT_PCM_16; | |||
| break; | |||
| case 24: short_mask = SF_FORMAT_PCM_24; | |||
| break; | |||
| case 32: short_mask = SF_FORMAT_PCM_32; | |||
| break; | |||
| default: short_mask = SF_FORMAT_PCM_16; | |||
| break; | |||
| } | |||
| sf_info.format = SF_FORMAT_WAV|short_mask; | |||
| if ((info->sf = sf_open (info->path, SFM_WRITE, &sf_info)) == NULL) { | |||
| char errstr[256]; | |||
| sf_error_str (0, errstr, sizeof (errstr) - 1); | |||
| fprintf (stderr, "cannot open sndfile \"%s\" for output (%s)\n", info->path, errstr); | |||
| jack_client_close (info->client); | |||
| exit (1); | |||
| } | |||
| if (info->duration == 0) { | |||
| info->duration = JACK_MAX_FRAMES; | |||
| } else { | |||
| info->duration *= sf_info.samplerate; | |||
| } | |||
| info->can_capture = 0; | |||
| pthread_create (&info->thread_id, NULL, disk_thread, info); | |||
| } | |||
| void | |||
| run_disk_thread (jack_thread_info_t *info) | |||
| { | |||
| info->can_capture = 1; | |||
| pthread_join (info->thread_id, NULL); | |||
| sf_close (info->sf); | |||
| if (overruns > 0) { | |||
| fprintf (stderr, | |||
| "jackrec failed with %ld overruns.\n", overruns); | |||
| fprintf (stderr, " try a bigger buffer than -B %" | |||
| PRIu32 ".\n", info->rb_size); | |||
| info->status = EPIPE; | |||
| } | |||
| } | |||
| void | |||
| setup_ports (int sources, char *source_names[], jack_thread_info_t *info) | |||
| { | |||
| unsigned int i; | |||
| size_t in_size; | |||
| /* Allocate data structures that depend on the number of ports. */ | |||
| nports = sources; | |||
| ports = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports); | |||
| in_size = nports * sizeof (jack_default_audio_sample_t *); | |||
| in = (jack_default_audio_sample_t **) malloc (in_size); | |||
| rb = jack_ringbuffer_create (nports * sample_size * info->rb_size); | |||
| /* When JACK is running realtime, jack_activate() will have | |||
| * called mlockall() to lock our pages into memory. But, we | |||
| * still need to touch any newly allocated pages before | |||
| * process() starts using them. Otherwise, a page fault could | |||
| * create a delay that would force JACK to shut us down. */ | |||
| memset(in, 0, in_size); | |||
| memset(rb->buf, 0, rb->size); | |||
| for (i = 0; i < nports; i++) { | |||
| char name[64]; | |||
| sprintf (name, "input%d", i+1); | |||
| if ((ports[i] = jack_port_register (info->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) { | |||
| fprintf (stderr, "cannot register input port \"%s\"!\n", name); | |||
| jack_client_close (info->client); | |||
| exit (1); | |||
| } | |||
| } | |||
| for (i = 0; i < nports; 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); | |||
| } | |||
| } | |||
| info->can_process = 1; /* process() can start, now */ | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| jack_client_t *client; | |||
| jack_thread_info_t thread_info; | |||
| int c; | |||
| int longopt_index = 0; | |||
| extern int optind, opterr; | |||
| int show_usage = 0; | |||
| char *optstring = "d:f:b:B:h"; | |||
| struct option long_options[] = { | |||
| { "help", 0, 0, 'h' }, | |||
| { "duration", 1, 0, 'd' }, | |||
| { "file", 1, 0, 'f' }, | |||
| { "bitdepth", 1, 0, 'b' }, | |||
| { "bufsize", 1, 0, 'B' }, | |||
| { 0, 0, 0, 0 } | |||
| }; | |||
| memset (&thread_info, 0, sizeof (thread_info)); | |||
| thread_info.rb_size = DEFAULT_RB_SIZE; | |||
| opterr = 0; | |||
| while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) { | |||
| switch (c) { | |||
| case 1: | |||
| /* getopt signals end of '-' options */ | |||
| break; | |||
| case 'h': | |||
| show_usage++; | |||
| break; | |||
| case 'd': | |||
| thread_info.duration = atoi (optarg); | |||
| break; | |||
| case 'f': | |||
| thread_info.path = optarg; | |||
| break; | |||
| case 'b': | |||
| thread_info.bitdepth = atoi (optarg); | |||
| break; | |||
| case 'B': | |||
| thread_info.rb_size = atoi (optarg); | |||
| break; | |||
| default: | |||
| fprintf (stderr, "error\n"); | |||
| show_usage++; | |||
| break; | |||
| } | |||
| } | |||
| if (show_usage || thread_info.path == NULL || optind == argc) { | |||
| fprintf (stderr, "usage: jackrec -f filename [ -d second ] [ -b bitdepth ] [ -B bufsize ] port1 [ port2 ... ]\n"); | |||
| exit (1); | |||
| } | |||
| if ((client = jack_client_new ("jackrec")) == 0) { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| exit (1); | |||
| } | |||
| thread_info.client = client; | |||
| thread_info.channels = argc - optind; | |||
| thread_info.can_process = 0; | |||
| setup_disk_thread (&thread_info); | |||
| jack_set_process_callback (client, process, &thread_info); | |||
| jack_on_shutdown (client, jack_shutdown, &thread_info); | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| } | |||
| setup_ports (argc - optind, &argv[optind], &thread_info); | |||
| run_disk_thread (&thread_info); | |||
| jack_client_close (client); | |||
| jack_ringbuffer_free (rb); | |||
| exit (0); | |||
| } | |||