jackd1-0.121.3+20120418git75e3e20b/0000755001605600047420000000000011743611406013577 5ustar adiirajackd1-0.121.3+20120418git75e3e20b/example-clients/0000755001605600047420000000000011743611406016671 5ustar adiirajackd1-0.121.3+20120418git75e3e20b/example-clients/midisine.c0000644001605600047420000000713011714526444020644 0ustar adiira/* Copyright (C) 2004 Ian Esten 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. */ #include #include #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; jack_default_audio_sample_t ramp=0.0; jack_default_audio_sample_t note_on; unsigned char note = 0; jack_default_audio_sample_t note_frqs[128]; void calc_note_frqs(jack_default_audio_sample_t srate) { int i; for(i=0; i<128; i++) { note_frqs[i] = (2.0 * 440.0 / 32.0) * pow(2, (((jack_default_audio_sample_t)i - 9.0) / 12.0)) / srate; } } int process(jack_nframes_t nframes, void *arg) { int i; void* port_buf = jack_port_get_buffer(input_port, nframes); jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); jack_midi_event_t in_event; jack_nframes_t event_index = 0; jack_nframes_t event_count = jack_midi_get_event_count(port_buf); if(event_count > 1) { printf(" midisine: have %d events\n", event_count); for(i=0; i 1.0) ? ramp - 2.0 : ramp; out[i] = note_on*sin(2*M_PI*ramp); } return 0; } int srate(jack_nframes_t nframes, void *arg) { printf("the sample rate is now %" PRIu32 "/sec\n", nframes); calc_note_frqs((jack_default_audio_sample_t)nframes); return 0; } void jack_shutdown(void *arg) { exit(1); } int main(int narg, char **args) { jack_client_t *client; if ((client = jack_client_open ("midisine", JackNullOption, NULL)) == 0) { fprintf(stderr, "jack server not running?\n"); return 1; } calc_note_frqs(jack_get_sample_rate (client)); jack_set_process_callback (client, process, 0); jack_set_sample_rate_callback (client, srate, 0); jack_on_shutdown (client, jack_shutdown, 0); input_port = jack_port_register (client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "audio_out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (jack_activate (client)) { fprintf(stderr, "cannot activate client"); return 1; } /* run until interrupted */ while(1) { sleep(1); } jack_client_close(client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/example-clients/server_control.c0000644001605600047420000001574311714526444022122 0ustar adiira/* Copyright (C) 2008 Grame 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. */ #include #include #include #include #include #include #include #include static jackctl_driver_t * jackctl_server_get_driver(jackctl_server_t *server, const char *driver_name) { const JSList * node_ptr = jackctl_server_get_drivers_list(server); while (node_ptr) { if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) { return (jackctl_driver_t *)node_ptr->data; } node_ptr = jack_slist_next(node_ptr); } return NULL; } static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name) { const JSList * node_ptr = jackctl_server_get_internals_list(server); while (node_ptr) { if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) { return (jackctl_internal_t *)node_ptr->data; } node_ptr = jack_slist_next(node_ptr); } return NULL; } static jackctl_parameter_t * jackctl_get_parameter( const JSList * parameters_list, const char * parameter_name) { while (parameters_list) { if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) { return (jackctl_parameter_t *)parameters_list->data; } parameters_list = jack_slist_next(parameters_list); } return NULL; } static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type) { switch (type) { case JackParamInt: printf("parameter value = %d\n", value.i); break; case JackParamUInt: printf("parameter value = %u\n", value.ui); break; case JackParamChar: printf("parameter value = %c\n", value.c); break; case JackParamString: printf("parameter value = %s\n", value.str); break; case JackParamBool: printf("parameter value = %d\n", value.b); break; } } static void print_parameters(const JSList * node_ptr) { while (node_ptr != NULL) { jackctl_parameter_t * parameter = (jackctl_parameter_t *)node_ptr->data; printf("\nparameter name = %s\n", jackctl_parameter_get_name(parameter)); printf("parameter id = %c\n", jackctl_parameter_get_id(parameter)); printf("parameter short decs = %s\n", jackctl_parameter_get_short_description(parameter)); printf("parameter long decs = %s\n", jackctl_parameter_get_long_description(parameter)); print_value(jackctl_parameter_get_default_value(parameter), jackctl_parameter_get_type(parameter)); node_ptr = jack_slist_next(node_ptr); } } static void print_driver(jackctl_driver_t * driver) { printf("\n--------------------------\n"); printf("driver = %s\n", jackctl_driver_get_name(driver)); printf("-------------------------- \n"); print_parameters(jackctl_driver_get_parameters(driver)); } static void print_internal(jackctl_internal_t * internal) { printf("\n-------------------------- \n"); printf("internal = %s\n", jackctl_internal_get_name(internal)); printf("-------------------------- \n"); print_parameters(jackctl_internal_get_parameters(internal)); } static void usage() { fprintf (stderr, "\n" "usage: jack_server_control \n" " [ --driver OR -d driver_name ]\n" " [ --client OR -c client_name ]\n" ); } int main(int argc, char *argv[]) { jackctl_server_t * server; const JSList * parameters; const JSList * drivers; const JSList * internals; const JSList * node_ptr; sigset_t signals; int opt, option_index; const char* driver_name = "dummy"; const char* client_name = "audioadapter"; const char *options = "d:c:"; struct option long_options[] = { {"driver", 1, 0, 'd'}, {"client", 1, 0, 'c'}, }; while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { case 'd': driver_name = optarg; break; case 'c': client_name = optarg; break; default: usage(); exit(0); } } server = jackctl_server_create(NULL, NULL); parameters = jackctl_server_get_parameters(server); /* jackctl_parameter_t* param; union jackctl_parameter_value value; param = jackctl_get_parameter(parameters, "verbose"); if (param != NULL) { value.b = true; jackctl_parameter_set_value(param, &value); } */ printf("\n========================== \n"); printf("List of server parameters \n"); printf("========================== \n"); print_parameters(parameters); printf("\n========================== \n"); printf("List of drivers \n"); printf("========================== \n"); drivers = jackctl_server_get_drivers_list(server); node_ptr = drivers; while (node_ptr != NULL) { print_driver((jackctl_driver_t *)node_ptr->data); node_ptr = jack_slist_next(node_ptr); } printf("\n========================== \n"); printf("List of internal clients \n"); printf("========================== \n"); internals = jackctl_server_get_internals_list(server); node_ptr = internals; while (node_ptr != NULL) { print_internal((jackctl_internal_t *)node_ptr->data); node_ptr = jack_slist_next(node_ptr); } signals = jackctl_setup_signals(0); jackctl_server_start(server, jackctl_server_get_driver(server, driver_name)); jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name)); /* // Switch master test jackctl_driver_t* master; usleep(5000000); printf("jackctl_server_load_master\n"); master = jackctl_server_get_driver(server, "coreaudio"); jackctl_server_switch_master(server, master); usleep(5000000); printf("jackctl_server_load_master\n"); master = jackctl_server_get_driver(server, "dummy"); jackctl_server_switch_master(server, master); */ jackctl_wait_signals(signals); jackctl_server_destroy(server); return 0; } jackd1-0.121.3+20120418git75e3e20b/example-clients/transport_client.c0000644001605600047420000001134611714526444022441 0ustar adiira/** @file transport_client.c * * @brief This client demonstrates very simple use of the JACK * transport API. Compare it with the simple_client example, * which is even simpler. It also demonstrates taking a client * name and optionally server name from the command line, rather * than hard-coding either of these names. */ #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; /* a simple state machine for this client */ volatile enum { Init, Run, Exit } client_state = Init; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client follows a simple rule: when the JACK transport is * running, copy the input port to the output. When it stops, exit. */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; jack_transport_state_t ts = jack_transport_query(client, NULL); if (ts == JackTransportRolling) { if (client_state == Init) client_state = Run; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); } else if (ts == JackTransportStopped) { if (client_state == Run) client_state = Exit; } return 0; } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; if (argc >= 2) { /* client name specified? */ client_name = argv[1]; if (argc >= 3) { /* server name specified? */ server_name = argv[2]; options |= JackServerName; } } else { /* use basename of argv[0] */ client_name = strrchr(argv[0], '/'); if (client_name == 0) { client_name = argv[0]; } else { client_name++; } } /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); /* keep running until the transport stops */ while (client_state != Exit) { sleep (1); } jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/example-clients/showtime.c0000644001605600047420000000454411714526444020710 0ustar adiira#include #include #include #include #include #include #include jack_client_t *client; void showtime () { jack_position_t current; jack_transport_state_t transport_state; jack_nframes_t frame_time; transport_state = jack_transport_query (client, ¤t); frame_time = jack_frame_time (client); printf ("frame: %7" PRIu32 " @ %" PRIu32 "\t", current.frame, frame_time); switch (transport_state) { case JackTransportStopped: printf ("state: Stopped"); break; case JackTransportRolling: printf ("state: Rolling"); break; case JackTransportStarting: printf ("state: Starting"); break; default: printf ("state: [unknown]"); } if (current.valid & JackPositionBBT) printf ("\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" PRIi32, current.bar, current.beat, current.tick); if (current.valid & JackPositionTimecode) printf ("\tTC: (%.6f, %.6f)", current.frame_time, current.next_time); if (current.valid & JackBBTFrameOffset) printf ("\tBBT offset: (%" PRIi32 ")", current.bbt_offset); if (current.valid & JackAudioVideoRatio) printf ("\taudio/video: (%f)", current.audio_frames_per_video_frame); if (current.valid & JackVideoFrameOffset) { if (current.video_offset) { printf ("\t video@: (%" PRIi32 ")", current.video_offset); } else { printf ("\t no video"); } } printf ("\n"); } void jack_shutdown (void *arg) { exit (1); } void signal_handler (int sig) { jack_client_close (client); fprintf (stderr, "signal received, exiting ...\n"); exit (0); } int main (int argc, char *argv[]) { /* try to become a client of the JACK server */ if ((client = jack_client_open ("showtime", JackNullOption, NULL)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } signal (SIGQUIT, signal_handler); signal (SIGTERM, signal_handler); signal (SIGHUP, signal_handler); signal (SIGINT, signal_handler); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } while (1) { usleep (20); showtime (); } jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/example-clients/impulse_grabber.c0000644001605600047420000001344711714526444022215 0ustar adiira/* * Copyright (C) 2001 Steve Harris * * 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. * */ #include #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; unsigned int impulse_sent = 0; float *response; unsigned long response_duration; unsigned long response_pos; int grab_finished = 0; int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); unsigned int i; if (grab_finished) { return 0; } else if (impulse_sent) { for(i=0; i= response_duration) { grab_finished = 1; } for (i=0; i peak) { peak = fabs(response[i]); peak_sample = i; } } printf("\n};\n"); } else { for (i=0; i peak) { peak = fabs(response[i]); peak_sample = i; } } } fprintf(stderr, "Peak value was %f at sample %lu\n", peak, peak_sample); exit (0); } jackd1-0.121.3+20120418git75e3e20b/example-clients/simple_client.c0000644001605600047420000001002611714526444021670 0ustar adiira/** @file simple_client.c * * @brief This simple client demonstrates the most basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client does nothing more than copy data from its input * port to its output port. It will exit when stopped by * the user (e.g. using Ctrl-C on a unix-ish operating system) */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); return 0; } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name = "simple"; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); /* keep running until stopped by the user */ sleep (-1); /* this is never reached but if the program had some other way to exit besides being killed, they would be important to call. */ jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/example-clients/metro.c0000644001605600047420000001534311714526444020176 0ustar adiira/* Copyright (C) 2002 Anthony Van Groningen 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. */ #include #include #include #include #include #include #include #include #include typedef jack_default_audio_sample_t sample_t; const double PI = 3.14; jack_client_t *client; jack_port_t *output_port; unsigned long sr; int freq = 880; int bpm; jack_nframes_t tone_length, wave_length; sample_t *wave; long offset = 0; int transport_aware = 0; jack_transport_state_t transport_state; void usage () { fprintf (stderr, "\n" "usage: jack_metro \n" " [ --frequency OR -f frequency (in Hz) ]\n" " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n" " [ --duration OR -D duration (in ms) ]\n" " [ --attack OR -a attack (in percent of duration) ]\n" " [ --decay OR -d decay (in percent of duration) ]\n" " [ --name OR -n jack name for metronome client ]\n" " [ --transport OR -t transport aware ]\n" " --bpm OR -b beats per minute\n" ); } void process_silence (jack_nframes_t nframes) { sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes); } void process_audio (jack_nframes_t nframes) { sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); jack_nframes_t frames_left = nframes; while (wave_length - offset < frames_left) { memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset)); frames_left -= wave_length - offset; offset = 0; } if (frames_left > 0) { memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left); offset += frames_left; } } int process (jack_nframes_t nframes, void *arg) { if (transport_aware) { jack_position_t pos; if (jack_transport_query (client, &pos) != JackTransportRolling) { process_silence (nframes); return 0; } offset = pos.frame % wave_length; } process_audio (nframes); return 0; } int sample_rate_change () { printf("Sample rate has changed! Exiting...\n"); exit(-1); } int main (int argc, char *argv[]) { sample_t scale; int i, attack_length, decay_length; double *amp; double max_amp = 0.5; int option_index; int opt; int got_bpm = 0; int attack_percent = 1, decay_percent = 10, dur_arg = 100; char *client_name = 0; char *bpm_string = "bpm"; int verbose = 0; jack_status_t status; const char *options = "f:A:D:a:d:b:n:thv"; struct option long_options[] = { {"frequency", 1, 0, 'f'}, {"amplitude", 1, 0, 'A'}, {"duration", 1, 0, 'D'}, {"attack", 1, 0, 'a'}, {"decay", 1, 0, 'd'}, {"bpm", 1, 0, 'b'}, {"name", 1, 0, 'n'}, {"transport", 0, 0, 't'}, {"help", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, {0, 0, 0, 0} }; while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { case 'f': if ((freq = atoi (optarg)) <= 0) { fprintf (stderr, "invalid frequency\n"); return -1; } break; case 'A': if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) { fprintf (stderr, "invalid amplitude\n"); return -1; } break; case 'D': dur_arg = atoi (optarg); fprintf (stderr, "durarg = %u\n", dur_arg); break; case 'a': if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) { fprintf (stderr, "invalid attack percent\n"); return -1; } break; case 'd': if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) { fprintf (stderr, "invalid decay percent\n"); return -1; } break; case 'b': got_bpm = 1; if ((bpm = atoi (optarg)) < 0) { fprintf (stderr, "invalid bpm\n"); return -1; } bpm_string = (char *) malloc ((strlen (optarg) + 4) * sizeof (char)); strcpy (bpm_string, optarg); strcat (bpm_string, "_bpm"); break; case 'n': client_name = (char *) malloc (strlen (optarg) * sizeof (char)); strcpy (client_name, optarg); break; case 'v': verbose = 1; break; case 't': transport_aware = 1; break; default: fprintf (stderr, "unknown option %c\n", opt); case 'h': usage (); return -1; } } if (!got_bpm) { fprintf (stderr, "bpm not specified\n"); usage (); return -1; } /* Initial Jack setup, get sample rate */ if (!client_name) { client_name = (char *) malloc (9 * sizeof (char)); strcpy (client_name, "metro"); } if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } jack_set_process_callback (client, process, 0); output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); sr = jack_get_sample_rate (client); /* setup wave table parameters */ wave_length = 60 * sr / bpm; tone_length = sr * dur_arg / 1000; attack_length = tone_length * attack_percent / 100; decay_length = tone_length * decay_percent / 100; scale = 2 * PI * freq / sr; if (tone_length >= wave_length) { fprintf (stderr, "invalid duration (tone length = %" PRIu32 ", wave length = %" PRIu32 "\n", tone_length, wave_length); return -1; } if (attack_length + decay_length > (int)tone_length) { fprintf (stderr, "invalid attack/decay\n"); return -1; } /* Build the wave table */ wave = (sample_t *) malloc (wave_length * sizeof(sample_t)); amp = (double *) malloc (tone_length * sizeof(double)); for (i = 0; i < attack_length; i++) { amp[i] = max_amp * i / ((double) attack_length); } for (i = attack_length; i < (int)tone_length - decay_length; i++) { amp[i] = max_amp; } for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) { amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length); } for (i = 0; i < (int)tone_length; i++) { wave[i] = amp[i] * sin (scale * i); } for (i = tone_length; i < (int)wave_length; i++) { wave[i] = 0; } if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } while (1) { sleep(1); }; } jackd1-0.121.3+20120418git75e3e20b/example-clients/Makefile.am0000644001605600047420000000515111714526444020734 0ustar adiiraMAINTAINERCLEANFILES = Makefile.in if HAVE_SNDFILE JACKREC = jack_rec 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_simple_session_client \ jack_transport_client \ jack_impulse_grabber \ jack_metro \ jack_showtime \ jack_midisine \ jack_midiseq \ jack_latent_client \ jack_server_control \ $(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) jack_simple_client_SOURCES = simple_client.c jack_simple_client_LDFLAGS = @OS_LDFLAGS@ jack_simple_client_LDADD = $(top_builddir)/libjack/libjack.la jack_simple_session_client_SOURCES = simple_session_client.c jack_simple_session_client_LDFLAGS = @OS_LDFLAGS@ jack_simple_session_client_LDADD = $(top_builddir)/libjack/libjack.la jack_transport_client_SOURCES = transport_client.c jack_transport_client_LDFLAGS = @OS_LDFLAGS@ jack_transport_client_LDADD = $(top_builddir)/libjack/libjack.la jack_metro_SOURCES = metro.c jack_metro_LDFLAGS = @OS_LDFLAGS@ jack_metro_LDADD = $(top_builddir)/libjack/libjack.la jack_showtime_SOURCES = showtime.c jack_showtime_LDFLAGS = @OS_LDFLAGS@ jack_showtime_LDADD = $(top_builddir)/libjack/libjack.la jack_impulse_grabber_SOURCES = impulse_grabber.c jack_impulse_grabber_LDFLAGS = @OS_LDFLAGS@ jack_impulse_grabber_LDADD = $(top_builddir)/libjack/libjack.la jack_midiseq_SOURCES = midiseq.c jack_midiseq_LDFLAGS = @OS_LDFLAGS@ jack_midiseq_LDADD = $(top_builddir)/libjack/libjack.la jack_midisine_SOURCES = midisine.c jack_midisine_LDFLAGS = @OS_LDFLAGS@ jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la jack_latent_client_SOURCES = latent_client.c jack_latent_client_LDFLAGS = @OS_LDFLAGS@ jack_latent_client_LDADD = $(top_builddir)/libjack/libjack.la jack_server_control_SOURCES = server_control.c jack_server_control_LDFLAGS = @OS_LDFLAGS@ jack_server_control_LDADD = $(top_builddir)/jackd/libjackserver.la if HAVE_SNDFILE jack_rec_SOURCES = capture_client.c jack_rec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@ jack_rec_LDADD = $(top_builddir)/libjack/libjack.la endif # # sample in-process client(s) # ip_clientdir = $(ADDON_DIR) ip_client_LTLIBRARIES = inprocess.la intime.la inprocess_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@ inprocess_la_SOURCES = inprocess.c intime_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@ intime_la_SOURCES = intime.c jackd1-0.121.3+20120418git75e3e20b/example-clients/inprocess.c0000644001605600047420000000601411714526444021050 0ustar adiira/** @file inprocess.c * * @brief This demonstrates the basic concepts for writing a client * that runs within the JACK server process. * * For the sake of example, a port_pair_t is allocated in * jack_initialize(), passed to inprocess() as an argument, then freed * in jack_finish(). */ #include #include #include #include /** * For the sake of example, an instance of this struct is allocated in * jack_initialize(), passed to inprocess() as an argument, then freed * in jack_finish(). */ typedef struct { jack_port_t *input_port; jack_port_t *output_port; } port_pair_t; /** * Called in the realtime thread on every process cycle. The entry * point name was passed to jack_set_process_callback() from * jack_initialize(). Although this is an internal client, its * process() interface is identical to @ref simple_client.c. * * @return 0 if successful; otherwise jack_finish() will be called and * the client terminated immediately. */ int inprocess (jack_nframes_t nframes, void *arg) { port_pair_t *pp = arg; jack_default_audio_sample_t *out = jack_port_get_buffer (pp->output_port, nframes); jack_default_audio_sample_t *in = jack_port_get_buffer (pp->input_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); return 0; /* continue */ } /** * This required entry point is called after the client is loaded by * jack_internal_client_load(). * * @param client pointer to JACK client structure. * @param load_init character string passed to the load operation. * * @return 0 if successful; otherwise jack_finish() will be called and * the client terminated immediately. */ int jack_initialize (jack_client_t *client, const char *load_init) { port_pair_t *pp = malloc (sizeof (port_pair_t)); if (pp == NULL) return 1; /* heap exhausted */ jack_set_process_callback (client, inprocess, pp); /* create a pair of ports */ pp->input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); pp->output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); /* join the process() cycle */ jack_activate (client); /* try to connect to the first physical input & output ports */ if (jack_connect (client, "system:capture_1", jack_port_name (pp->input_port))) { fprintf (stderr, "cannot connect input port\n"); return 1; /* terminate client */ } if (jack_connect (client, jack_port_name (pp->output_port), "system:playback_1")) { fprintf (stderr, "cannot connect output port\n"); return 1; /* terminate client */ } return 0; /* success */ } /** * This required entry point is called immediately before the client * is unloaded, which could happen due to a call to * jack_internal_client_unload(), or a nonzero return from either * jack_initialize() or inprocess(). * * @param arg the same parameter provided to inprocess(). */ void jack_finish (void *arg) { if (arg) free ((port_pair_t *) arg); } jackd1-0.121.3+20120418git75e3e20b/example-clients/midiseq.c0000644001605600047420000000664711714526444020512 0ustar adiira/* Copyright (C) 2004 Ian Esten 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. */ #include #include #include #include #include jack_client_t *client; jack_port_t *output_port; unsigned char* note_frqs; jack_nframes_t* note_starts; jack_nframes_t* note_lengths; jack_nframes_t num_notes; jack_nframes_t loop_nsamp; jack_nframes_t loop_index; void usage() { fprintf(stderr, "usage: jack_midiseq name nsamp [startindex note nsamp] ...... [startindex note nsamp]\n"); fprintf(stderr, "eg: jack_midiseq Sequencer 24000 0 60 8000 12000 63 8000\n"); fprintf(stderr, "will play a 1/2 sec loop (if srate is 48khz) with a c4 note at the start of the loop\n"); fprintf(stderr, "that lasts for 12000 samples, then a d4# that starts at 1/4 sec that lasts for 800 samples\n"); } int process(jack_nframes_t nframes, void *arg) { int i,j; void* port_buf = jack_port_get_buffer(output_port, nframes); unsigned char* buffer; jack_midi_clear_buffer(port_buf); /*memset(buffer, 0, nframes*sizeof(jack_default_audio_sample_t));*/ for(i=0; i= loop_nsamp ? 0 : loop_index+1; } return 0; } int main(int narg, char **args) { int i; jack_nframes_t nframes; if((narg<6) || ((narg-3)%3 !=0)) { usage(); exit(1); } if((client = jack_client_open (args[1], JackNullOption, NULL)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } jack_set_process_callback (client, process, 0); output_port = jack_port_register (client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); nframes = jack_get_buffer_size(client); loop_index = 0; num_notes = (narg - 3)/3; note_frqs = malloc(num_notes*sizeof(unsigned char)); note_starts = malloc(num_notes*sizeof(unsigned char)); note_lengths = malloc(num_notes*sizeof(jack_nframes_t)); loop_nsamp = atoi(args[2]); for(i=0; i #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; int simple_quit = 0; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client does nothing more than copy data from its input * port to its output port. It will exit when stopped by * the user (e.g. using Ctrl-C on a unix-ish operating system) */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); return 0; } void session_callback (jack_session_event_t *event, void *arg) { char retval[100]; printf ("session notification\n"); printf ("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit"); snprintf (retval, 100, "jack_simple_session_client %s", event->client_uuid); event->command_line = strdup (retval); jack_session_reply( client, event ); if (event->type == JackSessionSaveAndQuit) { simple_quit = 1; } jack_session_event_free (event); } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name = "simple"; jack_status_t status; /* open a client connection to the JACK server */ if( argc == 1 ) client = jack_client_open (client_name, JackNullOption, &status ); else if( argc == 2 ) client = jack_client_open (client_name, JackSessionID, &status, argv[1] ); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* tell the JACK server to call `session_callback()' if the session is saved. */ jack_set_session_callback (client, session_callback, NULL); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ /* only do the autoconnect when not reloading from a session. * in case of a session reload, the SM will restore our connections */ if (argc==1) { ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); } /* keep running until until we get a quit event */ while (!simple_quit) sleep(1); jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/example-clients/capture_client.c0000644001605600047420000002153411714526444022050 0ustar adiira/* 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 * 2003/05/26 - use ringbuffers - joq */ #include #include #include #include #include #include #include #include #include #include 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_open ("jackrec", JackNullOption, NULL)) == 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); } jackd1-0.121.3+20120418git75e3e20b/example-clients/intime.c0000644001605600047420000001153111714526444020330 0ustar adiira/* * intime.c -- JACK internal timebase master example client. * * To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'. */ /* 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. */ #include #include #include /* Time and tempo variables, global to the entire transport timeline. * There is no attempt to keep a true tempo map. The default time * signature is "march time": 4/4, 120bpm */ float time_beats_per_bar = 4.0; float time_beat_type = 4.0; double time_ticks_per_beat = 1920.0; double time_beats_per_minute = 120.0; /* BBT timebase callback. * * Runs in the process thread. Realtime, must not wait. */ void timebbt (jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg) { double min; /* minutes since frame 0 */ long abs_tick; /* ticks since frame 0 */ long abs_beat; /* beats since frame 0 */ if (new_pos) { pos->valid = JackPositionBBT; pos->beats_per_bar = time_beats_per_bar; pos->beat_type = time_beat_type; pos->ticks_per_beat = time_ticks_per_beat; pos->beats_per_minute = time_beats_per_minute; /* Compute BBT info from frame number. This is * relatively simple here, but would become complex if * we supported tempo or time signature changes at * specific locations in the transport timeline. I * make no claims for the numerical accuracy or * efficiency of these calculations. */ min = pos->frame / ((double) pos->frame_rate * 60.0); abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; abs_beat = abs_tick / pos->ticks_per_beat; pos->bar = abs_beat / pos->beats_per_bar; pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat); pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat; pos->bar++; /* adjust start to bar 1 */ /* some debug code... */ fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n", pos->frame, pos->bar, pos->beat, pos->tick); } else { /* Compute BBT info based on previous period. */ pos->tick += (nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60)); while (pos->tick >= pos->ticks_per_beat) { pos->tick -= pos->ticks_per_beat; if (++pos->beat > pos->beats_per_bar) { pos->beat = 1; ++pos->bar; pos->bar_start_tick += (pos->beats_per_bar * pos->ticks_per_beat); } } } } /* experimental timecode callback * * Fill in extended timecode fields using the trivial assumption that * we are running at nominal speed, hence with no drift. * * It would probably be faster to compute frame_time without the * conditional expression. But, this demonstrates the invariant: * next_time[i] == frame_time[i+1], unless a reposition occurs. * * Runs in the process thread. Realtime, must not wait. */ void timecode (jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg) { /* nominal transport speed */ double seconds_per_frame = 1.0 / (double) pos->frame_rate; pos->valid = JackPositionTimecode; pos->frame_time = (new_pos? pos->frame * seconds_per_frame: pos->next_time); pos->next_time = (pos->frame + nframes) * seconds_per_frame; } /* after internal client loaded */ int jack_initialize (jack_client_t *client, const char *load_init) { JackTimebaseCallback callback = timebbt; int rc = sscanf(load_init, " %f/%f, %lf bpm ", &time_beats_per_bar, &time_beat_type, &time_beats_per_minute); if (rc > 0) { fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n", time_beats_per_bar, time_beat_type, time_beats_per_minute); } else { int len = strlen(load_init); if ((len > 0) && (strncmp(load_init, "timecode", len) == 0)) callback = timecode; } if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) { fprintf (stderr, "Unable to take over timebase.\n"); return 1; /* terminate */ } fprintf (stderr, "Internal timebase master defined.\n"); jack_activate (client); return 0; /* success */ } /* before unloading */ void jack_finish (void *arg) { fprintf (stderr, "Internal timebase client exiting.\n"); } jackd1-0.121.3+20120418git75e3e20b/example-clients/latent_client.c0000644001605600047420000001216011714526444021667 0ustar adiira/** @file simple_client.c * * @brief This simple client demonstrates the most basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; jack_default_audio_sample_t *delay_line; jack_nframes_t delay_index; jack_nframes_t latency = 1024; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client does nothing more than copy data from its input * port to its output port. It will exit when stopped by * the user (e.g. using Ctrl-C on a unix-ish operating system) */ int process (jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in, *out; int k; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); for (k=0; k * jackd.c: Better error reporting if/when dlopen() fails. 2003-03-05 Taybin Rutkin * jackd.c: added version flag. -V and --version are accepted. 2003-02-21 Paul Davis * jackd.c: modified signal catching design to actually follow sigwait() specifications (ie. install handlers for all blocked signals). also removed some dead code from benchmarking/debugging. 2003-2-10 Taybin Rutkin * Initial Changelog * engine.c (handle_new_client): Returns protocol version for checking. jackd1-0.121.3+20120418git75e3e20b/jackd/engine.c0000644001605600047420000036327511736346233016311 0ustar adiira/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Copyright (C) 2001-2003 Paul Davis Copyright (C) 2004 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. */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #include #include #include #include #include #include #include "internal.h" #include "engine.h" #include "messagebuffer.h" #include "driver.h" #include "shm.h" #include #include #ifdef USE_MLOCK #include #endif /* USE_MLOCK */ #ifdef USE_CAPABILITIES /* capgetp and capsetp are linux only extensions, not posix */ #undef _POSIX_SOURCE #include #endif #include "clientengine.h" #include "transengine.h" #include "libjack/local.h" typedef struct { jack_port_internal_t *source; jack_port_internal_t *destination; signed int dir; /* -1 = feedback, 0 = self, 1 = forward */ jack_client_internal_t *srcclient; jack_client_internal_t *dstclient; } jack_connection_internal_t; typedef struct _jack_driver_info { jack_driver_t *(*initialize)(jack_client_t*, const JSList *); void (*finish); char (*client_name); dlhandle handle; } jack_driver_info_t; jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; static int jack_port_assign_buffer (jack_engine_t *, jack_port_internal_t *); static jack_port_internal_t *jack_get_port_by_name (jack_engine_t *, const char *name); static int jack_rechain_graph (jack_engine_t *engine); static void jack_clear_fifos (jack_engine_t *engine); static int jack_port_do_connect (jack_engine_t *engine, const char *source_port, const char *destination_port); static int jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, const char *destination_port); static int jack_port_do_disconnect_all (jack_engine_t *engine, jack_port_id_t); static int jack_port_do_unregister (jack_engine_t *engine, jack_request_t *); static int jack_port_do_register (jack_engine_t *engine, jack_request_t *, int); static int jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int reply_fd); static int jack_port_disconnect_internal (jack_engine_t *engine, jack_port_internal_t *src, jack_port_internal_t *dst); static int jack_send_connection_notification (jack_engine_t *, jack_client_id_t, jack_port_id_t, jack_port_id_t, int); static void jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event); static void jack_notify_all_port_interested_clients (jack_engine_t *engine, jack_client_id_t exclude_src_id, jack_client_id_t exclude_dst_id, jack_port_id_t a, jack_port_id_t b, int connect); static void jack_engine_post_process (jack_engine_t *); static int jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes, float delayed_usecs); static int jack_run_one_cycle (jack_engine_t *engine, jack_nframes_t nframes, float delayed_usecs); static void jack_engine_delay (jack_engine_t *engine, float delayed_usecs); static void jack_engine_driver_exit (jack_engine_t* engine); static int jack_start_freewheeling (jack_engine_t* engine, jack_client_id_t); static int jack_client_feeds_transitive (jack_client_internal_t *source, jack_client_internal_t *dest); static int jack_client_sort (jack_client_internal_t *a, jack_client_internal_t *b); static void jack_check_acyclic (jack_engine_t* engine); static void jack_compute_all_port_total_latencies (jack_engine_t *engine); static void jack_compute_port_total_latency (jack_engine_t *engine, jack_port_shared_t*); static int jack_check_client_status (jack_engine_t* engine); static int jack_do_session_notify (jack_engine_t *engine, jack_request_t *req, int reply_fd ); static void jack_do_get_client_by_uuid ( jack_engine_t *engine, jack_request_t *req); static void jack_do_reserve_name ( jack_engine_t *engine, jack_request_t *req); static void jack_do_session_reply (jack_engine_t *engine, jack_request_t *req ); static void jack_compute_new_latency (jack_engine_t *engine); static int jack_do_has_session_cb (jack_engine_t *engine, jack_request_t *req); static inline int jack_rolling_interval (jack_time_t period_usecs) { return floor ((JACK_ENGINE_ROLLING_INTERVAL * 1000.0f) / period_usecs); } void jack_engine_reset_rolling_usecs (jack_engine_t *engine) { memset (engine->rolling_client_usecs, 0, sizeof (engine->rolling_client_usecs)); engine->rolling_client_usecs_index = 0; engine->rolling_client_usecs_cnt = 0; if (engine->driver) { engine->rolling_interval = jack_rolling_interval (engine->driver->period_usecs); } else { engine->rolling_interval = JACK_ENGINE_ROLLING_INTERVAL; } engine->spare_usecs = 0; } static inline jack_port_type_info_t * jack_port_type_info (jack_engine_t *engine, jack_port_internal_t *port) { /* Returns a pointer to the port type information in the engine's shared control structure. */ return &engine->control->port_types[port->shared->ptype_id]; } static inline jack_port_buffer_list_t * jack_port_buffer_list (jack_engine_t *engine, jack_port_internal_t *port) { /* Points to the engine's private port buffer list struct. */ return &engine->port_buffers[port->shared->ptype_id]; } static int make_directory (const char *path) { struct stat statbuf; if (stat (path, &statbuf)) { if (errno == ENOENT) { int mode; if (getenv ("JACK_PROMISCUOUS_SERVER")) { mode = 0777; } else { mode = 0700; } if (mkdir (path, mode) < 0){ jack_error ("cannot create %s directory (%s)\n", path, strerror (errno)); return -1; } } else { jack_error ("cannot stat() %s\n", path); return -1; } } else { if (!S_ISDIR (statbuf.st_mode)) { jack_error ("%s already exists, but is not" " a directory!\n", path); return -1; } } return 0; } static int make_socket_subdirectories (const char *server_name) { struct stat statbuf; char server_dir[PATH_MAX+1] = ""; /* check tmpdir directory */ if (stat (jack_tmpdir, &statbuf)) { jack_error ("cannot stat() %s (%s)\n", jack_tmpdir, strerror (errno)); return -1; } else { if (!S_ISDIR(statbuf.st_mode)) { jack_error ("%s exists, but is not a directory!\n", jack_tmpdir); return -1; } } /* create user subdirectory */ if (make_directory (jack_user_dir ()) < 0) { return -1; } /* create server_name subdirectory */ if (make_directory (jack_server_dir (server_name, server_dir)) < 0) { return -1; } return 0; } static int make_sockets (const char *server_name, int fd[2]) { struct sockaddr_un addr; int i; char server_dir[PATH_MAX+1] = ""; if (make_socket_subdirectories (server_name) < 0) { return -1; } /* First, the master server socket */ if ((fd[0] = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { jack_error ("cannot create server socket (%s)", strerror (errno)); return -1; } addr.sun_family = AF_UNIX; for (i = 0; i < 999; i++) { snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_%d", jack_server_dir (server_name, server_dir), i); if (access (addr.sun_path, F_OK) != 0) { break; } } if (i == 999) { jack_error ("all possible server socket names in use!!!"); close (fd[0]); return -1; } if (bind (fd[0], (struct sockaddr *) &addr, sizeof (addr)) < 0) { jack_error ("cannot bind server to socket (%s)", strerror (errno)); close (fd[0]); return -1; } if (listen (fd[0], 1) < 0) { jack_error ("cannot enable listen on server socket (%s)", strerror (errno)); close (fd[0]); return -1; } /* Now the client/server event ack server socket */ if ((fd[1] = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { jack_error ("cannot create event ACK socket (%s)", strerror (errno)); close (fd[0]); return -1; } addr.sun_family = AF_UNIX; for (i = 0; i < 999; i++) { snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_ack_%d", jack_server_dir (server_name, server_dir), i); if (access (addr.sun_path, F_OK) != 0) { break; } } if (i == 999) { jack_error ("all possible server ACK socket names in use!!!"); close (fd[0]); close (fd[1]); return -1; } if (bind (fd[1], (struct sockaddr *) &addr, sizeof (addr)) < 0) { jack_error ("cannot bind server to socket (%s)", strerror (errno)); close (fd[0]); close (fd[1]); return -1; } if (listen (fd[1], 1) < 0) { jack_error ("cannot enable listen on server socket (%s)", strerror (errno)); close (fd[0]); close (fd[1]); return -1; } return 0; } void jack_engine_place_port_buffers (jack_engine_t* engine, jack_port_type_id_t ptid, jack_shmsize_t one_buffer, jack_shmsize_t size, unsigned long nports, jack_nframes_t nframes) { jack_shmsize_t offset; /* shared memory offset */ jack_port_buffer_info_t *bi; jack_port_buffer_list_t* pti = &engine->port_buffers[ptid]; jack_port_functions_t *pfuncs = jack_get_port_functions(ptid); pthread_mutex_lock (&pti->lock); offset = 0; if (pti->info) { /* Buffer info array already allocated for this port * type. This must be a resize operation, so * recompute the buffer offsets, but leave the free * list alone. */ int i; bi = pti->info; while (offset < size) { bi->offset = offset; offset += one_buffer; ++bi; } /* update any existing output port offsets */ for (i = 0; i < engine->port_max; i++) { jack_port_shared_t *port = &engine->control->ports[i]; if (port->in_use && (port->flags & JackPortIsOutput) && port->ptype_id == ptid) { bi = engine->internal_ports[i].buffer_info; if (bi) { port->offset = bi->offset; } } } } else { jack_port_type_info_t* port_type = &engine->control->port_types[ptid]; /* Allocate an array of buffer info structures for all * the buffers in the segment. Chain them to the free * list in memory address order, offset zero must come * first. */ bi = pti->info = (jack_port_buffer_info_t *) malloc (nports * sizeof (jack_port_buffer_info_t)); while (offset < size) { bi->offset = offset; pti->freelist = jack_slist_append (pti->freelist, bi); offset += one_buffer; ++bi; } /* Allocate the first buffer of the port segment * for an empy buffer area. * NOTE: audio buffer is zeroed in its buffer_init function. */ bi = (jack_port_buffer_info_t *) pti->freelist->data; pti->freelist = jack_slist_remove_link (pti->freelist, pti->freelist); port_type->zero_buffer_offset = bi->offset; if (ptid == JACK_AUDIO_PORT_TYPE) engine->silent_buffer = bi; } /* initialize buffers */ { int i; jack_shm_info_t *shm_info = &engine->port_segment[ptid]; char* shm_segment = (char *) jack_shm_addr(shm_info); bi = pti->info; for (i=0; ibuffer_init(shm_segment + bi->offset, one_buffer, nframes); } pthread_mutex_unlock (&pti->lock); } static int jack_resize_port_segment (jack_engine_t *engine, jack_port_type_id_t ptid, unsigned long nports) { jack_event_t event; jack_shmsize_t one_buffer; /* size of one buffer */ jack_shmsize_t size; /* segment size */ jack_port_type_info_t* port_type = &engine->control->port_types[ptid]; jack_shm_info_t* shm_info = &engine->port_segment[ptid]; one_buffer = jack_port_type_buffer_size (port_type, engine->control->buffer_size); VERBOSE (engine, "resizing port buffer segment for type %d, one buffer = %u bytes", ptid, one_buffer); size = nports * one_buffer; if (shm_info->attached_at == 0) { if (jack_shmalloc (size, shm_info)) { jack_error ("cannot create new port segment of %d" " bytes (%s)", size, strerror (errno)); return -1; } if (jack_attach_shm (shm_info)) { jack_error ("cannot attach to new port segment " "(%s)", strerror (errno)); return -1; } engine->control->port_types[ptid].shm_registry_index = shm_info->index; } else { /* resize existing buffer segment */ if (jack_resize_shm (shm_info, size)) { jack_error ("cannot resize port segment to %d bytes," " (%s)", size, strerror (errno)); return -1; } } jack_engine_place_port_buffers (engine, ptid, one_buffer, size, nports, engine->control->buffer_size); #ifdef USE_MLOCK if (engine->control->real_time) { /* Although we've called mlockall(CURRENT|FUTURE), the * Linux VM manager still allows newly allocated pages * to fault on first reference. This mlock() ensures * that any new pages are present before restarting * the process cycle. Since memory locks do not * stack, they can still be unlocked with a single * munlockall(). */ int rc = mlock (jack_shm_addr (shm_info), size); if (rc < 0) { jack_error("JACK: unable to mlock() port buffers: " "%s", strerror(errno)); } } #endif /* USE_MLOCK */ /* Tell everybody about this segment. */ event.type = AttachPortSegment; event.y.ptid = ptid; jack_deliver_event_to_all (engine, &event); /* XXX need to clean up in the evnt of failures */ return 0; } /* The driver invokes this callback both initially and whenever its * buffer size changes. */ static int jack_driver_buffer_size (jack_engine_t *engine, jack_nframes_t nframes) { int i; jack_event_t event; VERBOSE (engine, "new buffer size %" PRIu32, nframes); engine->control->buffer_size = nframes; if (engine->driver) engine->rolling_interval = jack_rolling_interval (engine->driver->period_usecs); for (i = 0; i < engine->control->n_port_types; ++i) { if (jack_resize_port_segment (engine, i, engine->control->port_max)) { return -1; } } event.type = BufferSizeChange; jack_deliver_event_to_all (engine, &event); return 0; } /* handle client SetBufferSize request */ int jack_set_buffer_size_request (jack_engine_t *engine, jack_nframes_t nframes) { /* precondition: caller holds the request_lock */ int rc; jack_driver_t* driver = engine->driver; if (driver == NULL) return ENXIO; /* no such device */ if (!jack_power_of_two(nframes)) { jack_error("buffer size %" PRIu32 " not a power of 2", nframes); return EINVAL; } rc = driver->bufsize(driver, nframes); if (rc != 0) jack_error("driver does not support %" PRIu32 "-frame buffers", nframes); return rc; } static JSList * jack_process_internal(jack_engine_t *engine, JSList *node, jack_nframes_t nframes) { jack_client_internal_t *client; jack_client_control_t *ctl; client = (jack_client_internal_t *) node->data; ctl = client->control; /* internal client */ DEBUG ("invoking an internal client's (%s) callbacks", ctl->name); ctl->state = Running; engine->current_client = client; /* XXX how to time out an internal client? */ if (ctl->sync_cb_cbset) jack_call_sync_client (client->private_client); if (ctl->process_cbset) if (client->private_client->process (nframes, client->private_client->process_arg)) { jack_error ("internal client %s failed", ctl->name); engine->process_errors++; } if (ctl->timebase_cb_cbset) jack_call_timebase_master (client->private_client); ctl->state = Finished; if (engine->process_errors) return NULL; /* will stop the loop */ else return jack_slist_next (node); } #ifdef __linux /* Linux kernels somewhere between 2.6.18 and 2.6.24 had a bug in poll(2) that led poll to return early. To fix it, we need to know that that jack_get_microseconds() is monotonic. */ #ifdef HAVE_CLOCK_GETTIME static const int system_clock_monotonic = 1; #else static const int system_clock_monotonic = 0; #endif static int linux_poll_bug_encountered (jack_engine_t* engine, jack_time_t then, jack_time_t *required) { if (engine->control->clock_source != JACK_TIMER_SYSTEM_CLOCK || system_clock_monotonic) { jack_time_t now = jack_get_microseconds (); if ((now - then) < *required) { /* So, adjust poll timeout to account for time already spent waiting. */ VERBOSE (engine, "FALSE WAKEUP (%lldusecs vs. %lld usec)", (now - then), *required); *required -= (now - then); /* allow 0.25msec slop */ return 1; } } return 0; } #endif #ifdef JACK_USE_MACH_THREADS static JSList * jack_process_external(jack_engine_t *engine, JSList *node) { jack_client_internal_t * client = (jack_client_internal_t *) node->data; jack_client_control_t *ctl; client = (jack_client_internal_t *) node->data; ctl = client->control; engine->current_client = client; // a race exists if we do this after the write(2) ctl->state = Triggered; ctl->signalled_at = jack_get_microseconds(); if (jack_client_resume(client) < 0) { jack_error("Client will be removed\n"); ctl->state = Finished; } return jack_slist_next (node); } #else /* !JACK_USE_MACH_THREADS */ static JSList * jack_process_external(jack_engine_t *engine, JSList *node) { int status = 0; char c = 0; struct pollfd pfd[1]; int poll_timeout; jack_time_t poll_timeout_usecs; jack_client_internal_t *client; jack_client_control_t *ctl; jack_time_t now, then; int pollret; client = (jack_client_internal_t *) node->data; ctl = client->control; /* external subgraph */ /* a race exists if we do this after the write(2) */ ctl->state = Triggered; ctl->signalled_at = jack_get_microseconds(); engine->current_client = client; DEBUG ("calling process() on an external subgraph, fd==%d", client->subgraph_start_fd); if (write (client->subgraph_start_fd, &c, sizeof (c)) != sizeof (c)) { jack_error ("cannot initiate graph processing (%s)", strerror (errno)); engine->process_errors++; jack_engine_signal_problems (engine); return NULL; /* will stop the loop */ } then = jack_get_microseconds (); if (engine->freewheeling) { poll_timeout_usecs = 250000; /* 0.25 seconds */ } else { poll_timeout_usecs = (engine->client_timeout_msecs > 0 ? engine->client_timeout_msecs * 1000 : engine->driver->period_usecs); } again: poll_timeout = 1 + poll_timeout_usecs / 1000; pfd[0].fd = client->subgraph_wait_fd; pfd[0].events = POLLERR|POLLIN|POLLHUP|POLLNVAL; DEBUG ("waiting on fd==%d for process() subgraph to finish (timeout = %d, period_usecs = %d)", client->subgraph_wait_fd, poll_timeout, engine->driver->period_usecs); if ((pollret = poll (pfd, 1, poll_timeout)) < 0) { jack_error ("poll on subgraph processing failed (%s)", strerror (errno)); status = -1; } DEBUG ("\n\n\n\n\n back from subgraph poll, revents = 0x%x\n\n\n", pfd[0].revents); if (pfd[0].revents & ~POLLIN) { jack_error ("subgraph starting at %s lost client", client->control->name); status = -2; } if (pfd[0].revents & POLLIN) { status = 0; } else if (status == 0) { /* no events, no errors, we woke up because poll() decided that time was up ... */ if (engine->freewheeling) { if (jack_check_client_status (engine)) { return NULL; } else { /* all clients are fine - we're just not done yet. since we're freewheeling, that is fine. */ goto again; } } #ifdef __linux if (linux_poll_bug_encountered (engine, then, &poll_timeout_usecs)) { goto again; } if (poll_timeout_usecs < 200) { VERBOSE (engine, "FALSE WAKEUP skipped, remaining = %lld usec", poll_timeout_usecs); } else { #endif jack_error ("subgraph starting at %s timed out " "(subgraph_wait_fd=%d, status = %d, state = %s, pollret = %d revents = 0x%x)", client->control->name, client->subgraph_wait_fd, status, jack_client_state_name (client), pollret, pfd[0].revents); status = 1; #ifdef __linux } #endif } now = jack_get_microseconds (); if (status != 0) { VERBOSE (engine, "at %" PRIu64 " waiting on %d for %" PRIu64 " usecs, status = %d sig = %" PRIu64 " awa = %" PRIu64 " fin = %" PRIu64 " dur=%" PRIu64, now, client->subgraph_wait_fd, now - then, status, ctl->signalled_at, ctl->awake_at, ctl->finished_at, ctl->finished_at? (ctl->finished_at - ctl->signalled_at): 0); if (jack_check_clients (engine, 1)) { engine->process_errors++; return NULL; /* will stop the loop */ } } else { engine->timeout_count = 0; } DEBUG ("reading byte from subgraph_wait_fd==%d", client->subgraph_wait_fd); if (read (client->subgraph_wait_fd, &c, sizeof(c)) != sizeof (c)) { jack_error ("pp: cannot clean up byte from graph wait " "fd (%s)", strerror (errno)); client->error++; return NULL; /* will stop the loop */ } /* Move to next internal client (or end of client list) */ while (node) { if (jack_client_is_internal ((jack_client_internal_t *) node->data)) { break; } node = jack_slist_next (node); } return node; } #endif /* JACK_USE_MACH_THREADS */ static int jack_engine_process (jack_engine_t *engine, jack_nframes_t nframes) { /* precondition: caller has graph_lock */ jack_client_internal_t *client; JSList *node; engine->process_errors = 0; engine->watchdog_check = 1; for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_control_t *ctl = ((jack_client_internal_t *) node->data)->control; ctl->state = NotTriggered; ctl->timed_out = 0; ctl->awake_at = 0; ctl->finished_at = 0; } for (node = engine->clients; engine->process_errors == 0 && node; ) { client = (jack_client_internal_t *) node->data; DEBUG ("considering client %s for processing", client->control->name); if (!client->control->active || (!client->control->process_cbset && !client->control->thread_cb_cbset) || client->control->dead) { node = jack_slist_next (node); } else if (jack_client_is_internal (client)) { node = jack_process_internal (engine, node, nframes); } else { node = jack_process_external (engine, node); } } return engine->process_errors > 0; } static void jack_calc_cpu_load(jack_engine_t *engine) { jack_time_t cycle_end = jack_get_microseconds (); /* store the execution time for later averaging */ engine->rolling_client_usecs[engine->rolling_client_usecs_index++] = cycle_end - engine->control->current_time.usecs; //jack_info ("cycle_end - engine->control->current_time.usecs %ld", // (long) (cycle_end - engine->control->current_time.usecs)); if (engine->rolling_client_usecs_index >= JACK_ENGINE_ROLLING_COUNT) { engine->rolling_client_usecs_index = 0; } /* every so often, recompute the current maximum use over the last JACK_ENGINE_ROLLING_COUNT client iterations. */ if (++engine->rolling_client_usecs_cnt % engine->rolling_interval == 0) { float max_usecs = 0.0f; int i; for (i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) { if (engine->rolling_client_usecs[i] > max_usecs) { max_usecs = engine->rolling_client_usecs[i]; } } if (max_usecs > engine->max_usecs) { engine->max_usecs = max_usecs; } if (max_usecs < engine->driver->period_usecs) { engine->spare_usecs = engine->driver->period_usecs - max_usecs; } else { engine->spare_usecs = 0; } engine->control->cpu_load = (1.0f - (engine->spare_usecs / engine->driver->period_usecs)) * 50.0f + (engine->control->cpu_load * 0.5f); VERBOSE (engine, "load = %.4f max usecs: %.3f, " "spare = %.3f", engine->control->cpu_load, max_usecs, engine->spare_usecs); } } static void jack_engine_post_process (jack_engine_t *engine) { /* precondition: caller holds the graph lock. */ jack_transport_cycle_end (engine); jack_calc_cpu_load (engine); jack_check_clients (engine, 0); } #ifdef JACK_USE_MACH_THREADS static int jack_start_watchdog (jack_engine_t *engine) { /* Stephane Letz : letz@grame.fr Watch dog thread is * not needed on MacOSX since CoreAudio drivers * already contains a similar mechanism. */ return 0; } void jack_stop_watchdog (jack_engine_t *engine) { /* Stephane Letz : letz@grame.fr Watch dog thread is * not needed on MacOSX since CoreAudio drivers * already contains a similar mechanism. */ return; } #else static void * jack_watchdog_thread (void *arg) { jack_engine_t *engine = (jack_engine_t *) arg; struct timespec timo; timo.tv_sec = JACKD_WATCHDOG_TIMEOUT / 1000; timo.tv_nsec = (JACKD_WATCHDOG_TIMEOUT - (timo.tv_sec * 1000)) * 1000; engine->watchdog_check = 0; while (1) { nanosleep (&timo, NULL); if (!engine->freewheeling && engine->watchdog_check == 0) { jack_error ("jackd watchdog: timeout - killing jackd"); /* Kill the current client (guilt by association). */ if (engine->current_client) { kill (engine->current_client-> control->pid, SIGKILL); } /* kill our process group, try to get a dump */ kill (-getpgrp(), SIGABRT); /*NOTREACHED*/ exit (1); } engine->watchdog_check = 0; } } static int jack_start_watchdog (jack_engine_t *engine) { int watchdog_priority = engine->rtpriority + 10; #ifndef __OpenBSD__ int max_priority = sched_get_priority_max (SCHED_FIFO); #else int max_priority = -1; #endif if ((max_priority != -1) && (max_priority < watchdog_priority)) watchdog_priority = max_priority; if (jack_client_create_thread (NULL, &engine->watchdog_thread, watchdog_priority, TRUE, jack_watchdog_thread, engine)) { jack_error ("cannot start watchdog thread"); return -1; } return 0; } void jack_stop_watchdog (jack_engine_t *engine) { /* Cancel the watchdog thread and wait for it to terminate. * * The watchdog thread is not used on MacOSX since CoreAudio * drivers already contain a similar mechanism. */ if (engine->control->real_time && engine->watchdog_thread) { VERBOSE (engine, "stopping watchdog thread"); pthread_cancel (engine->watchdog_thread); pthread_join (engine->watchdog_thread, NULL); } return; } #endif /* !JACK_USE_MACH_THREADS */ static jack_driver_info_t * jack_load_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc) { const char *errstr; jack_driver_info_t *info; info = (jack_driver_info_t *) calloc (1, sizeof (*info)); info->handle = dlopen (driver_desc->file, RTLD_NOW|RTLD_GLOBAL); if (info->handle == NULL) { if ((errstr = dlerror ()) != 0) { jack_error ("can't load \"%s\": %s", driver_desc->file, errstr); } else { jack_error ("bizarre error loading driver shared " "object %s", driver_desc->file); } goto fail; } info->initialize = dlsym (info->handle, "driver_initialize"); if ((errstr = dlerror ()) != 0) { jack_error ("no initialize function in shared object %s\n", driver_desc->file); goto fail; } info->finish = dlsym (info->handle, "driver_finish"); if ((errstr = dlerror ()) != 0) { jack_error ("no finish function in in shared driver object %s", driver_desc->file); goto fail; } info->client_name = (char *) dlsym (info->handle, "driver_client_name"); if ((errstr = dlerror ()) != 0) { jack_error ("no client name in in shared driver object %s", driver_desc->file); goto fail; } return info; fail: if (info->handle) { dlclose (info->handle); } free (info); return NULL; } void jack_driver_unload (jack_driver_t *driver) { void* handle = driver->handle; driver->finish (driver); dlclose (handle); } int jack_engine_load_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc, JSList * driver_params) { jack_client_internal_t *client; jack_driver_t *driver; jack_driver_info_t *info; if ((info = jack_load_driver (engine, driver_desc)) == NULL) { return -1; } if ((client = jack_create_driver_client (engine, info->client_name) ) == NULL) { return -1; } if ((driver = info->initialize (client->private_client, driver_params)) == NULL) { free (info); return -1; } driver->handle = info->handle; driver->finish = info->finish; driver->internal_client = client; free (info); if (jack_use_driver (engine, driver) < 0) { jack_remove_client (engine, client); return -1; } engine->driver_desc = driver_desc; engine->driver_params = driver_params; if (engine->control->real_time) { if (jack_start_watchdog (engine)) { return -1; } engine->watchdog_check = 1; } return 0; } int jack_engine_load_slave_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc, JSList * driver_params) { jack_client_internal_t *client; jack_driver_t *driver; jack_driver_info_t *info; if ((info = jack_load_driver (engine, driver_desc)) == NULL) { return -1; } if ((client = jack_create_driver_client (engine, info->client_name) ) == NULL) { return -1; } if ((driver = info->initialize (client->private_client, driver_params)) == NULL) { free (info); return -1; } driver->handle = info->handle; driver->finish = info->finish; driver->internal_client = client; free (info); if (jack_add_slave_driver (engine, driver) < 0) { jack_client_delete (engine, client); return -1; } //engine->driver_desc = driver_desc; //engine->driver_params = driver_params; return 0; } #ifdef USE_CAPABILITIES static int check_capabilities (jack_engine_t *engine) { cap_t caps = cap_init(); cap_flag_value_t cap; pid_t pid; int have_all_caps = 1; if (caps == NULL) { VERBOSE (engine, "check: could not allocate capability" " working storage"); return 0; } pid = getpid (); cap_clear (caps); if (capgetp (pid, caps)) { VERBOSE (engine, "check: could not get capabilities " "for process %d", pid); return 0; } /* check that we are able to give capabilites to other processes */ cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } /* check that we have the capabilities we want to transfer */ cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } cap_get_flag(caps, CAP_SYS_RESOURCE, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } cap_get_flag(caps, CAP_IPC_LOCK, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } done: cap_free (caps); return have_all_caps; } static int give_capabilities (jack_engine_t *engine, pid_t pid) { cap_t caps = cap_init(); const unsigned caps_size = 3; cap_value_t cap_list[] = {CAP_SYS_NICE, CAP_SYS_RESOURCE, CAP_IPC_LOCK}; if (caps == NULL) { VERBOSE (engine, "give: could not allocate capability" " working storage"); return -1; } cap_clear(caps); if (capgetp (pid, caps)) { VERBOSE (engine, "give: could not get current " "capabilities for process %d", pid); cap_clear(caps); } cap_set_flag(caps, CAP_EFFECTIVE, caps_size, cap_list , CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, caps_size, cap_list , CAP_SET); cap_set_flag(caps, CAP_PERMITTED, caps_size, cap_list , CAP_SET); if (capsetp (pid, caps)) { cap_free (caps); return -1; } cap_free (caps); return 0; } static int jack_set_client_capabilities (jack_engine_t *engine, pid_t cap_pid) { int ret = -1; /* before sending this request the client has already checked that the engine has realtime capabilities, that it is running realtime and that the pid is defined */ if ((ret = give_capabilities (engine, cap_pid)) != 0) { jack_error ("could not give capabilities to " "process %d", cap_pid); } else { VERBOSE (engine, "gave capabilities to" " process %d", cap_pid); } return ret; } #endif /* USE_CAPABILITIES */ /* perform internal or external client request * * reply_fd is NULL for internal requests */ static void do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) { /* The request_lock serializes internal requests (from any * thread in the server) with external requests (always from "the" * server thread). */ pthread_mutex_lock (&engine->request_lock); DEBUG ("got a request of type %d", req->type); switch (req->type) { case RegisterPort: req->status = jack_port_do_register (engine, req, reply_fd ? FALSE : TRUE); break; case UnRegisterPort: req->status = jack_port_do_unregister (engine, req); break; case ConnectPorts: req->status = jack_port_do_connect (engine, req->x.connect.source_port, req->x.connect.destination_port); break; case DisconnectPort: req->status = jack_port_do_disconnect_all (engine, req->x.port_info.port_id); break; case DisconnectPorts: req->status = jack_port_do_disconnect (engine, req->x.connect.source_port, req->x.connect.destination_port); break; case ActivateClient: req->status = jack_client_activate (engine, req->x.client_id); break; case DeactivateClient: req->status = jack_client_deactivate (engine, req->x.client_id); break; case SetTimeBaseClient: req->status = jack_timebase_set (engine, req->x.timebase.client_id, req->x.timebase.conditional); break; case ResetTimeBaseClient: req->status = jack_timebase_reset (engine, req->x.client_id); break; case SetSyncClient: req->status = jack_transport_client_set_sync (engine, req->x.client_id); break; case ResetSyncClient: req->status = jack_transport_client_reset_sync (engine, req->x.client_id); break; case SetSyncTimeout: req->status = jack_transport_set_sync_timeout (engine, req->x.timeout); break; #ifdef USE_CAPABILITIES case SetClientCapabilities: req->status = jack_set_client_capabilities (engine, req->x.cap_pid); break; #endif /* USE_CAPABILITIES */ case GetPortConnections: case GetPortNConnections: //JOQ bug: reply_fd may be NULL if internal request if ((req->status = jack_do_get_port_connections (engine, req, *reply_fd)) == 0) { /* we have already replied, don't do it again */ *reply_fd = -1; } break; case FreeWheel: req->status = jack_start_freewheeling (engine, req->x.client_id); break; case StopFreeWheel: req->status = jack_stop_freewheeling (engine, 0); break; case SetBufferSize: req->status = jack_set_buffer_size_request (engine, req->x.nframes); break; case IntClientHandle: jack_intclient_handle_request (engine, req); break; case IntClientLoad: jack_intclient_load_request (engine, req); break; case IntClientName: jack_intclient_name_request (engine, req); break; case IntClientUnload: jack_intclient_unload_request (engine, req); break; case RecomputeTotalLatencies: jack_lock_graph (engine); jack_compute_all_port_total_latencies (engine); jack_compute_new_latency (engine); jack_unlock_graph (engine); req->status = 0; break; case RecomputeTotalLatency: jack_lock_graph (engine); jack_compute_port_total_latency (engine, &engine->control->ports[req->x.port_info.port_id]); jack_unlock_graph (engine); req->status = 0; break; case GetClientByUUID: jack_rdlock_graph (engine); jack_do_get_client_by_uuid (engine, req); jack_unlock_graph (engine); break; case ReserveName: jack_rdlock_graph (engine); jack_do_reserve_name (engine, req); jack_unlock_graph (engine); break; case SessionReply: jack_rdlock_graph (engine); jack_do_session_reply (engine, req); jack_unlock_graph (engine); break; case SessionNotify: jack_rdlock_graph (engine); if ((req->status = jack_do_session_notify (engine, req, *reply_fd)) >= 0) { /* we have already replied, don't do it again */ *reply_fd = -1; } jack_unlock_graph (engine); break; case SessionHasCallback: jack_rdlock_graph (engine); req->status = jack_do_has_session_cb (engine, req); jack_unlock_graph (engine); default: /* some requests are handled entirely on the client * side, by adjusting the shared memory area(s) */ break; } pthread_mutex_unlock (&engine->request_lock); DEBUG ("status of request: %d", req->status); } int internal_client_request (void* ptr, jack_request_t *request) { do_request ((jack_engine_t*) ptr, request, NULL); return request->status; } static int handle_external_client_request (jack_engine_t *engine, int fd) { /* CALLER holds read lock on graph */ jack_request_t req; jack_client_internal_t *client = 0; int reply_fd; JSList *node; ssize_t r; for (node = engine->clients; node; node = jack_slist_next (node)) { if (((jack_client_internal_t *) node->data)->request_fd == fd) { client = (jack_client_internal_t *) node->data; break; } } if (client == NULL) { jack_error ("client input on unknown fd %d!", fd); return -1; } if ((r = read (client->request_fd, &req, sizeof (req))) < (ssize_t) sizeof (req)) { if (r == 0) { #ifdef JACK_USE_MACH_THREADS /* poll is implemented using select (see the macosx/fakepoll code). When the socket is closed select does not return any error, POLLIN is true and the next read will return 0 bytes. This behaviour is diffrent from the Linux poll behaviour. Thus we use this condition as a socket error and remove the client. */ jack_mark_client_socket_error (engine, fd); #endif /* JACK_USE_MACH_THREADS */ return 1; } else { jack_error ("cannot read request from client (%d/%d/%s)", r, sizeof(req), strerror (errno)); // XXX: shouldnt we mark this client as error now ? return -1; } } reply_fd = client->request_fd; jack_unlock_graph (engine); do_request (engine, &req, &reply_fd); jack_lock_graph (engine); if (reply_fd >= 0) { DEBUG ("replying to client"); if (write (reply_fd, &req, sizeof (req)) < (ssize_t) sizeof (req)) { jack_error ("cannot write request result to client"); return -1; } } else { DEBUG ("*not* replying to client"); } return 0; } static int handle_client_ack_connection (jack_engine_t *engine, int client_fd) { jack_client_internal_t *client; jack_client_connect_ack_request_t req; jack_client_connect_ack_result_t res; if (read (client_fd, &req, sizeof (req)) != sizeof (req)) { jack_error ("cannot read ACK connection request from client"); return -1; } if ((client = jack_client_internal_by_id (engine, req.client_id)) == NULL) { jack_error ("unknown client ID in ACK connection request"); return -1; } client->event_fd = client_fd; VERBOSE (engine, "new client %s using %d for events", client->control->name, client->event_fd); res.status = 0; if (write (client->event_fd, &res, sizeof (res)) != sizeof (res)) { jack_error ("cannot write ACK connection response to client"); return -1; } return 0; } static void * jack_server_thread (void *arg) { jack_engine_t *engine = (jack_engine_t *) arg; struct sockaddr_un client_addr; socklen_t client_addrlen; int problemsProblemsPROBLEMS = 0; int client_socket; int done = 0; int i; const int fixed_fd_cnt = 3; int stop_freewheeling; while (!done) { JSList* node; int clients; jack_rdlock_graph (engine); clients = jack_slist_length (engine->clients); if (engine->pfd_size < fixed_fd_cnt + clients) { if (engine->pfd) { free (engine->pfd); } engine->pfd = (struct pollfd *) malloc (sizeof(struct pollfd) * (fixed_fd_cnt + clients)); } engine->pfd[0].fd = engine->fds[0]; engine->pfd[0].events = POLLIN|POLLERR; engine->pfd[1].fd = engine->fds[1]; engine->pfd[1].events = POLLIN|POLLERR; engine->pfd[2].fd = engine->cleanup_fifo[0]; engine->pfd[2].events = POLLIN|POLLERR; engine->pfd_max = fixed_fd_cnt; for (node = engine->clients; node; node = node->next) { jack_client_internal_t* client = (jack_client_internal_t*)(node->data); if (client->request_fd < 0 || client->error >= JACK_ERROR_WITH_SOCKETS) { continue; } if( client->control->dead ) { engine->pfd[engine->pfd_max].fd = client->request_fd; engine->pfd[engine->pfd_max].events = POLLHUP|POLLNVAL; engine->pfd_max++; continue; } engine->pfd[engine->pfd_max].fd = client->request_fd; engine->pfd[engine->pfd_max].events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL; engine->pfd_max++; } jack_unlock_graph (engine); VERBOSE (engine, "start poll on %d fd's", engine->pfd_max); /* go to sleep for a long, long time, or until a request arrives, or until a communication channel is broken */ if (poll (engine->pfd, engine->pfd_max, -1) < 0) { if (errno == EINTR) { continue; } jack_error ("poll failed (%s)", strerror (errno)); break; } VERBOSE(engine, "server thread back from poll"); /* Stephane Letz: letz@grame.fr : has to be added * otherwise pthread_cancel() does not work on MacOSX */ pthread_testcancel(); /* empty cleanup FIFO if necessary */ if (engine->pfd[2].revents & ~POLLIN) { /* time to die */ break; } if (engine->pfd[2].revents & POLLIN) { char c; while (read (engine->cleanup_fifo[0], &c, 1) == 1); } /* check each client socket before handling other request*/ jack_rdlock_graph (engine); for (i = fixed_fd_cnt; i < engine->pfd_max; i++) { if (engine->pfd[i].fd < 0) { continue; } if (engine->pfd[i].revents & ~POLLIN) { jack_mark_client_socket_error (engine, engine->pfd[i].fd); jack_engine_signal_problems (engine); } else if (engine->pfd[i].revents & POLLIN) { if (handle_external_client_request (engine, engine->pfd[i].fd)) { jack_error ("could not handle external" " client request"); jack_engine_signal_problems (engine); } } } problemsProblemsPROBLEMS = engine->problems; jack_unlock_graph (engine); /* need to take write lock since we may/will rip out some clients, and reset engine->problems */ stop_freewheeling = 0; while (problemsProblemsPROBLEMS) { VERBOSE (engine, "trying to lock graph to remove %d problems", problemsProblemsPROBLEMS); jack_lock_graph (engine); VERBOSE (engine, "we have problem clients (problems = %d", problemsProblemsPROBLEMS); jack_remove_clients (engine, &stop_freewheeling); if (stop_freewheeling) { VERBOSE (engine, "need to stop freewheeling once problems are cleared"); } jack_unlock_graph (engine); jack_lock_problems (engine); engine->problems -= problemsProblemsPROBLEMS; problemsProblemsPROBLEMS = engine->problems; jack_unlock_problems (engine); VERBOSE (engine, "after removing clients, problems = %d", problemsProblemsPROBLEMS); } if (engine->freewheeling && stop_freewheeling) { jack_stop_freewheeling (engine, 0); } /* check the master server socket */ if (engine->pfd[0].revents & POLLERR) { jack_error ("error on server socket"); break; } if (engine->control->engine_ok && engine->pfd[0].revents & POLLIN) { DEBUG ("pfd[0].revents & POLLIN"); memset (&client_addr, 0, sizeof (client_addr)); client_addrlen = sizeof (client_addr); if ((client_socket = accept (engine->fds[0], (struct sockaddr *) &client_addr, &client_addrlen)) < 0) { jack_error ("cannot accept new connection (%s)", strerror (errno)); } else if (!engine->new_clients_allowed || jack_client_create (engine, client_socket) < 0) { jack_error ("cannot complete client " "connection process"); close (client_socket); } } /* check the ACK server socket */ if (engine->pfd[1].revents & POLLERR) { jack_error ("error on server ACK socket"); break; } if (engine->control->engine_ok && engine->pfd[1].revents & POLLIN) { DEBUG ("pfd[1].revents & POLLIN"); memset (&client_addr, 0, sizeof (client_addr)); client_addrlen = sizeof (client_addr); if ((client_socket = accept (engine->fds[1], (struct sockaddr *) &client_addr, &client_addrlen)) < 0) { jack_error ("cannot accept new ACK connection" " (%s)", strerror (errno)); } else if (handle_client_ack_connection (engine, client_socket)) { jack_error ("cannot complete client ACK " "connection process"); close (client_socket); } } } return 0; } jack_engine_t * jack_engine_new (int realtime, int rtpriority, int do_mlock, int do_unlock, const char *server_name, int temporary, int verbose, int client_timeout, unsigned int port_max, pid_t wait_pid, jack_nframes_t frame_time_offset, int nozombies, int timeout_count_threshold, JSList *drivers) { jack_engine_t *engine; unsigned int i; char server_dir[PATH_MAX+1] = ""; #ifdef USE_CAPABILITIES uid_t uid = getuid (); uid_t euid = geteuid (); #endif /* USE_CAPABILITIES */ /* before we start allocating resources, make sure that if realtime was requested that we can actually do it. */ if (realtime) { if (jack_acquire_real_time_scheduling (pthread_self(), 10) != 0) { /* can't run realtime - time to bomb */ return NULL; } jack_drop_real_time_scheduling (pthread_self()); #ifdef USE_MLOCK if (do_mlock && (mlockall (MCL_CURRENT | MCL_FUTURE) != 0)) { jack_error ("cannot lock down memory for jackd (%s)", strerror (errno)); #ifdef ENSURE_MLOCK return NULL; #endif /* ENSURE_MLOCK */ } #endif /* USE_MLOCK */ } /* start a thread to display messages from realtime threads */ jack_messagebuffer_init(); jack_init_time (); /* allocate the engine, zero the structure to ease debugging */ engine = (jack_engine_t *) calloc (1, sizeof (jack_engine_t)); engine->drivers = drivers; engine->driver = NULL; engine->driver_desc = NULL; engine->driver_params = NULL; engine->slave_drivers = NULL; engine->set_sample_rate = jack_set_sample_rate; engine->set_buffer_size = jack_driver_buffer_size; engine->run_cycle = jack_run_cycle; engine->delay = jack_engine_delay; engine->driver_exit = jack_engine_driver_exit; engine->transport_cycle_start = jack_transport_cycle_start; engine->client_timeout_msecs = client_timeout; engine->timeout_count = 0; engine->problems = 0; engine->next_client_id = 1; /* 0 is a NULL client ID */ engine->port_max = port_max; engine->server_thread = 0; engine->watchdog_thread = 0; engine->rtpriority = rtpriority; engine->silent_buffer = 0; engine->verbose = verbose; engine->server_name = server_name; engine->temporary = temporary; engine->freewheeling = 0; engine->stop_freewheeling = 0; engine->fwclient = 0; engine->feedbackcount = 0; engine->wait_pid = wait_pid; engine->nozombies = nozombies; engine->timeout_count_threshold = timeout_count_threshold; engine->removing_clients = 0; engine->new_clients_allowed = 1; engine->session_reply_fd = -1; engine->session_pending_replies = 0; engine->audio_out_cnt = 0; engine->audio_in_cnt = 0; engine->midi_out_cnt = 0; engine->midi_in_cnt = 0; jack_engine_reset_rolling_usecs (engine); engine->max_usecs = 0.0f; pthread_rwlock_init (&engine->client_lock, 0); pthread_mutex_init (&engine->port_lock, 0); pthread_mutex_init (&engine->request_lock, 0); pthread_mutex_init (&engine->problem_lock, 0); engine->clients = 0; engine->reserved_client_names = 0; engine->pfd_size = 0; engine->pfd_max = 0; engine->pfd = 0; engine->fifo_size = 16; engine->fifo = (int *) malloc (sizeof (int) * engine->fifo_size); for (i = 0; i < engine->fifo_size; i++) { engine->fifo[i] = -1; } if (pipe (engine->cleanup_fifo)) { jack_error ("cannot create cleanup FIFOs (%s)", strerror (errno)); return NULL; } if (fcntl (engine->cleanup_fifo[0], F_SETFL, O_NONBLOCK)) { jack_error ("cannot set O_NONBLOCK on cleanup read FIFO (%s)", strerror (errno)); return NULL; } if (fcntl (engine->cleanup_fifo[1], F_SETFL, O_NONBLOCK)) { jack_error ("cannot set O_NONBLOCK on cleanup write FIFO (%s)", strerror (errno)); return NULL; } engine->external_client_cnt = 0; srandom (time ((time_t *) 0)); if (jack_shmalloc (sizeof (jack_control_t) + ((sizeof (jack_port_shared_t) * engine->port_max)), &engine->control_shm)) { jack_error ("cannot create engine control shared memory " "segment (%s)", strerror (errno)); return NULL; } if (jack_attach_shm (&engine->control_shm)) { jack_error ("cannot attach to engine control shared memory" " (%s)", strerror (errno)); jack_destroy_shm (&engine->control_shm); return NULL; } engine->control = (jack_control_t *) jack_shm_addr (&engine->control_shm); /* Setup port type information from builtins. buffer space is * allocated when the driver calls jack_driver_buffer_size(). */ for (i = 0; jack_builtin_port_types[i].type_name[0]; ++i) { memcpy (&engine->control->port_types[i], &jack_builtin_port_types[i], sizeof (jack_port_type_info_t)); VERBOSE (engine, "registered builtin port type %s", engine->control->port_types[i].type_name); /* the port type id is index into port_types array */ engine->control->port_types[i].ptype_id = i; /* be sure to initialize mutex correctly */ pthread_mutex_init (&engine->port_buffers[i].lock, NULL); /* set buffer list info correctly */ engine->port_buffers[i].freelist = NULL; engine->port_buffers[i].info = NULL; /* mark each port segment as not allocated */ engine->port_segment[i].index = -1; engine->port_segment[i].attached_at = 0; } engine->control->n_port_types = i; /* Mark all ports as available */ for (i = 0; i < engine->port_max; i++) { engine->control->ports[i].in_use = 0; engine->control->ports[i].id = i; engine->control->ports[i].alias1[0] = '\0'; engine->control->ports[i].alias2[0] = '\0'; } /* allocate internal port structures so that we can keep track * of port connections. */ engine->internal_ports = (jack_port_internal_t *) malloc (sizeof (jack_port_internal_t) * engine->port_max); for (i = 0; i < engine->port_max; i++) { engine->internal_ports[i].connections = 0; } if (make_sockets (engine->server_name, engine->fds) < 0) { jack_error ("cannot create server sockets"); return NULL; } engine->control->port_max = engine->port_max; engine->control->real_time = realtime; /* leave some headroom for other client threads to run with priority higher than the regular client threads but less than the server. see thread.h for jack_client_real_time_priority() and jack_client_max_real_time_priority() which are affected by this. */ engine->control->client_priority = (realtime ? engine->rtpriority - 5 : 0); engine->control->max_client_priority = (realtime ? engine->rtpriority - 1 : 0); engine->control->do_mlock = do_mlock; engine->control->do_munlock = do_unlock; engine->control->cpu_load = 0; engine->control->xrun_delayed_usecs = 0; engine->control->max_delayed_usecs = 0; jack_set_clock_source (clock_source); engine->control->clock_source = clock_source; engine->get_microseconds = jack_get_microseconds_pointer(); VERBOSE (engine, "clock source = %s", jack_clock_source_name (clock_source)); engine->control->frame_timer.frames = frame_time_offset; engine->control->frame_timer.reset_pending = 0; engine->control->frame_timer.current_wakeup = 0; engine->control->frame_timer.next_wakeup = 0; engine->control->frame_timer.initialized = 0; engine->control->frame_timer.filter_omega = 0; /* Initialised later */ engine->control->frame_timer.period_usecs = 0; engine->first_wakeup = 1; engine->control->buffer_size = 0; jack_transport_init (engine); jack_set_sample_rate (engine, 0); engine->control->internal = 0; engine->control->has_capabilities = 0; #ifdef JACK_USE_MACH_THREADS /* specific resources for server/client real-time thread * communication */ engine->servertask = mach_task_self(); if (task_get_bootstrap_port(engine->servertask, &engine->bp)){ jack_error("Jackd: Can't find bootstrap mach port"); return NULL; } engine->portnum = 0; #endif /* JACK_USE_MACH_THREADS */ #ifdef USE_CAPABILITIES if (uid == 0 || euid == 0) { VERBOSE (engine, "running with uid=%d and euid=%d, " "will not try to use capabilites", uid, euid); } else { /* only try to use capabilities if not running as root */ engine->control->has_capabilities = check_capabilities (engine); if (engine->control->has_capabilities == 0) { VERBOSE (engine, "required capabilities not " "available"); } if (engine->verbose) { size_t size; cap_t cap = cap_init(); capgetp(0, cap); VERBOSE (engine, "capabilities: %s", cap_to_text(cap, &size)); } } #endif /* USE_CAPABILITIES */ engine->control->engine_ok = 1; snprintf (engine->fifo_prefix, sizeof (engine->fifo_prefix), "%s/jack-ack-fifo-%d", jack_server_dir (engine->server_name, server_dir), getpid ()); (void) jack_get_fifo_fd (engine, 0); jack_client_create_thread (NULL, &engine->server_thread, 0, FALSE, &jack_server_thread, engine); return engine; } static void jack_engine_delay (jack_engine_t *engine, float delayed_usecs) { jack_event_t event; engine->control->frame_timer.reset_pending = 1; engine->control->xrun_delayed_usecs = delayed_usecs; if (delayed_usecs > engine->control->max_delayed_usecs) engine->control->max_delayed_usecs = delayed_usecs; event.type = XRun; jack_deliver_event_to_all (engine, &event); } static inline void jack_inc_frame_time (jack_engine_t *engine, jack_nframes_t nframes) { jack_frame_timer_t *timer = &engine->control->frame_timer; jack_time_t now = engine->driver->last_wait_ust; // effective time float delta; // really need a memory barrier here timer->guard1++; /* Modified implementation (the actual result is the same). 'second_order_integrator' is renamed to 'period_usecs' and now represents the DLL's best estimate of the period time in microseconds (before it was a scaled version of the difference w.r.t. the nominal value). This allows this value to be made available to clients that are interested in it (see libjack/transclient.c). This change also means that 'period_usecs' must be initialised to the nominal period time instead of zero. This is done in the first cycle in jack_run_cycle(). 'filter_coefficient' is renamed to 'filter_omega'. It is now equal to the 'omega' value as defined in the 'Using a DLL to filter time' paper (before it was a scaled version of this value). It is computed once in jack_run_cycle() rather than set to a fixed value. This makes the DLL bandwidth independent of the period time. FA 13/02/2012 */ delta = (float)((int64_t) now - (int64_t) timer->next_wakeup); delta *= timer->filter_omega; timer->current_wakeup = timer->next_wakeup; timer->frames += nframes; timer->period_usecs += timer->filter_omega * delta; timer->next_wakeup += (int64_t) floorf (timer->period_usecs + 1.41f * delta + 0.5f); timer->initialized = 1; // might need a memory barrier here timer->guard2++; } static void* jack_engine_freewheel (void *arg) { jack_engine_t* engine = (jack_engine_t *) arg; jack_client_internal_t* client; VERBOSE (engine, "freewheel thread starting ..."); /* we should not be running SCHED_FIFO, so we don't have to do anything about scheduling. */ client = jack_client_internal_by_id (engine, engine->fwclient); while (!engine->stop_freewheeling) { jack_run_one_cycle (engine, engine->control->buffer_size, 0.0f); if (client && client->error) { /* run one cycle() will already have told the server thread about issues, and the server thread will clean up. however, its time for us to depart this world ... */ break; } } VERBOSE (engine, "freewheel came to an end, naturally"); return 0; } static void jack_slave_driver_remove(jack_engine_t *engine, jack_driver_t *sdriver) { sdriver->detach (sdriver, engine); engine->slave_drivers = jack_slist_remove(engine->slave_drivers, sdriver); jack_driver_unload(sdriver); } int jack_drivers_start (jack_engine_t *engine) { JSList *node; JSList *failed_drivers = NULL; /* first start the slave drivers */ for (node=engine->slave_drivers; node; node=jack_slist_next(node)) { jack_driver_t *sdriver = node->data; if (sdriver->start( sdriver )) failed_drivers = jack_slist_append(failed_drivers, sdriver); } // Clean up drivers which failed to start. for (node=failed_drivers; node; node=jack_slist_next(node)) { jack_driver_t *sdriver = node->data; jack_error( "slave driver %s failed to start, removing it", sdriver->internal_client->control->name ); jack_slave_driver_remove(engine, sdriver); } /* now the master driver is started */ return engine->driver->start(engine->driver); } static int jack_drivers_stop (jack_engine_t *engine) { JSList *node; /* first stop the master driver */ int retval = engine->driver->stop(engine->driver); /* now the slave drivers are stopped */ for (node=engine->slave_drivers; node; node=jack_slist_next(node)) { jack_driver_t *sdriver = node->data; sdriver->stop( sdriver ); } return retval; } static int jack_drivers_read (jack_engine_t *engine, jack_nframes_t nframes) { JSList *node; /* first read the slave drivers */ for (node=engine->slave_drivers; node; node=jack_slist_next(node)) { jack_driver_t *sdriver = node->data; sdriver->read (sdriver, nframes); } /* now the master driver is read */ return engine->driver->read(engine->driver, nframes); } static int jack_drivers_write (jack_engine_t *engine, jack_nframes_t nframes) { JSList *node; /* first start the slave drivers */ for (node=engine->slave_drivers; node; node=jack_slist_next(node)) { jack_driver_t *sdriver = node->data; sdriver->write (sdriver, nframes); } /* now the master driver is written */ return engine->driver->write(engine->driver, nframes); } static int jack_start_freewheeling (jack_engine_t* engine, jack_client_id_t client_id) { jack_event_t event; jack_client_internal_t *client; if (engine->freewheeling) { return 0; } if (engine->driver == NULL) { jack_error ("cannot start freewheeling without a driver!"); return -1; } /* stop driver before telling anyone about it so there are no more process() calls being handled. */ if (jack_drivers_stop (engine)) { jack_error ("could not stop driver for freewheeling"); return -1; } client = jack_client_internal_by_id (engine, client_id); if (client->control->process_cbset || client->control->thread_cb_cbset) { engine->fwclient = client_id; } engine->freewheeling = 1; engine->stop_freewheeling = 0; event.type = StartFreewheel; jack_deliver_event_to_all (engine, &event); if (jack_client_create_thread (NULL, &engine->freewheel_thread, 0, FALSE, jack_engine_freewheel, engine)) { jack_error ("could not start create freewheel thread"); return -1; } return 0; } int jack_stop_freewheeling (jack_engine_t* engine, int engine_exiting) { jack_event_t event; void *ftstatus; if (!engine->freewheeling) { return 0; } if (engine->driver == NULL) { jack_error ("cannot start freewheeling without a driver!"); return -1; } if (!engine->freewheeling) { VERBOSE (engine, "stop freewheel when not freewheeling"); return 0; } /* tell the freewheel thread to stop, and wait for it to exit. */ engine->stop_freewheeling = 1; VERBOSE (engine, "freewheeling stopped, waiting for thread"); pthread_join (engine->freewheel_thread, &ftstatus); VERBOSE (engine, "freewheel thread has returned"); engine->fwclient = 0; engine->freewheeling = 0; engine->first_wakeup = 1; if (!engine_exiting) { /* tell everyone we've stopped */ event.type = StopFreewheel; jack_deliver_event_to_all (engine, &event); /* restart the driver */ if (jack_drivers_start (engine)) { jack_error ("could not restart driver after freewheeling"); return -1; } } return 0; } static int jack_check_client_status (jack_engine_t* engine) { JSList *node; int err = 0; /* we are already late, or something else went wrong, so it can't hurt to check the existence of all clients. */ for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t *client = (jack_client_internal_t *) node->data; if (client->control->type == ClientExternal) { if (kill (client->control->pid, 0)) { VERBOSE(engine, "client %s has died/exited", client->control->name); client->error++; err++; } if(client->control->last_status != 0) { VERBOSE(engine, "client %s has nonzero process callback status (%d)\n", client->control->name, client->control->last_status); client->error++; err++; } } DEBUG ("client %s errors = %d", client->control->name, client->error); } return err; } static int jack_run_one_cycle (jack_engine_t *engine, jack_nframes_t nframes, float delayed_usecs) { jack_driver_t* driver = engine->driver; int ret = -1; static int consecutive_excessive_delays = 0; #define WORK_SCALE 1.0f if (!engine->freewheeling && engine->control->real_time && engine->spare_usecs && ((WORK_SCALE * engine->spare_usecs) <= delayed_usecs)) { MESSAGE("delay of %.3f usecs exceeds estimated spare" " time of %.3f; restart ...\n", delayed_usecs, WORK_SCALE * engine->spare_usecs); if (++consecutive_excessive_delays > 10) { jack_error ("too many consecutive interrupt delays " "... engine pausing"); return -1; /* will exit the thread loop */ } jack_engine_delay (engine, delayed_usecs); return 0; } else { consecutive_excessive_delays = 0; } DEBUG ("trying to acquire read lock (FW = %d)", engine->freewheeling); if (jack_try_rdlock_graph (engine)) { VERBOSE (engine, "lock-driven null cycle"); if (!engine->freewheeling) { driver->null_cycle (driver, nframes); } else { /* don't return too fast */ usleep (1000); } return 0; } if (jack_trylock_problems (engine)) { VERBOSE (engine, "problem-lock-driven null cycle"); jack_unlock_graph (engine); if (!engine->freewheeling) { driver->null_cycle (driver, nframes); } else { /* don't return too fast */ usleep (1000); } return 0; } if (engine->problems || (engine->timeout_count_threshold && (engine->timeout_count > (1 + engine->timeout_count_threshold*1000/engine->driver->period_usecs) ))) { VERBOSE (engine, "problem-driven null cycle problems=%d", engine->problems); jack_unlock_problems (engine); jack_unlock_graph (engine); if (!engine->freewheeling) { driver->null_cycle (driver, nframes); } else { /* don't return too fast */ usleep (1000); } return 0; } jack_unlock_problems (engine); if (!engine->freewheeling) { DEBUG("waiting for driver read\n"); if (jack_drivers_read (engine, nframes)) { goto unlock; } } DEBUG("run process\n"); if (jack_engine_process (engine, nframes) != 0) { DEBUG ("engine process cycle failed"); jack_check_client_status (engine); } if (!engine->freewheeling) { if (jack_drivers_write (engine, nframes)) { goto unlock; } } jack_engine_post_process (engine); if (delayed_usecs > engine->control->max_delayed_usecs) engine->control->max_delayed_usecs = delayed_usecs; ret = 0; unlock: jack_unlock_graph (engine); DEBUG("cycle finished, status = %d", ret); return ret; } static void jack_engine_driver_exit (jack_engine_t* engine) { jack_driver_t* driver = engine->driver; VERBOSE (engine, "stopping driver"); driver->stop (driver); VERBOSE (engine, "detaching driver"); driver->detach (driver, engine); /* tell anyone waiting that the driver exited. */ kill (engine->wait_pid, SIGUSR2); engine->driver = NULL; } static int jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes, float delayed_usecs) { jack_nframes_t left; jack_nframes_t b_size = engine->control->buffer_size; jack_frame_timer_t* timer = &engine->control->frame_timer; if (engine->first_wakeup || timer->reset_pending) { /* the first wakeup or post-freewheeling or post-xrun */ /* There seems to be no significant difference between the two conditions OR-ed above. Incrementing the frame_time after an xrun shouldn't harm, as there will be a discontinuity anyway. So the two are combined in this version. FA 16/03/2012 */ /* Since the DLL *will* be run, next_wakeup should be the current wakeup time *without* adding the period time, as if it were computed in the previous period. FA 16/03/2012 */ /* Added initialisation of timer->period_usecs, required due to the modified implementation of the DLL itself. OTOH, this should maybe not be repeated after e.g. freewheeling or an xrun, as the current value would be more accurate than the nominal one. But it doesn't really harm either. Implementing this would require a new flag in the engine structure, to be used after freewheeling or an xrun instead of first_wakeup. I don't know if this can be done without breaking compatibility, so I did not add this FA 13/02/2012 */ /* Added initialisation of timer->filter_omega. This makes the DLL bandwidth independent of the actual period time. The bandwidth is now 1/8 Hz in all cases. The value of timer->filter_omega is 2 * pi * BW * Tperiod. FA 13/02/2012 */ timer->next_wakeup = engine->driver->last_wait_ust; timer->period_usecs = (float) engine->driver->period_usecs; timer->filter_omega = timer->period_usecs * 7.854e-7f; engine->first_wakeup = 0; timer->reset_pending = 0; } jack_inc_frame_time (engine, nframes); if (engine->verbose) { if (nframes != b_size) { VERBOSE (engine, "late driver wakeup: nframes to process = %" PRIu32 ".", nframes); } } /* run as many cycles as it takes to consume nframes */ /* This should run the DLL as many times as well, to ensure that timing info (including basic frame_time !) is valid in each cycle. So maybe the call to jack_inc_frame_time() should be within this loop. In that case, if there is more than one iteration, the DLL should probably ignore the loop error. This would require a new argument to jack_inc_frame_time(). OTOH, does this actually happen ? FA 16/02/2012 */ for (left = nframes; left >= b_size; left -= b_size) { if (jack_run_one_cycle (engine, b_size, delayed_usecs)) { jack_error ("cycle execution failure, exiting"); return EIO; } } return 0; } void jack_engine_delete (jack_engine_t *engine) { int i; if (engine == NULL) return; VERBOSE (engine, "starting server engine shutdown"); jack_stop_freewheeling (engine, 1); engine->control->engine_ok = 0; /* tell clients we're going away */ /* this will wake the server thread and cause it to exit */ close (engine->cleanup_fifo[0]); close (engine->cleanup_fifo[1]); /* shutdown master socket to prevent new clients arriving */ shutdown (engine->fds[0], SHUT_RDWR); // close (engine->fds[0]); /* now really tell them we're going away */ for (i = 0; i < engine->pfd_max; ++i) { shutdown (engine->pfd[i].fd, SHUT_RDWR); } if (engine->driver) { jack_driver_t* driver = engine->driver; VERBOSE (engine, "stopping driver"); driver->stop (driver); // VERBOSE (engine, "detaching driver"); // driver->detach (driver, engine); VERBOSE (engine, "unloading driver"); jack_driver_unload (driver); engine->driver = NULL; } VERBOSE (engine, "freeing shared port segments"); for (i = 0; i < engine->control->n_port_types; ++i) { jack_release_shm (&engine->port_segment[i]); jack_destroy_shm (&engine->port_segment[i]); } /* stop the other engine threads */ VERBOSE (engine, "stopping server thread"); #if JACK_USE_MACH_THREADS // MacOSX pthread_cancel still not implemented correctly in Darwin mach_port_t machThread = pthread_mach_thread_np (engine->server_thread); thread_terminate (machThread); #else pthread_cancel (engine->server_thread); pthread_join (engine->server_thread, NULL); #endif jack_stop_watchdog (engine); VERBOSE (engine, "last xrun delay: %.3f usecs", engine->control->xrun_delayed_usecs); VERBOSE (engine, "max delay reported by backend: %.3f usecs", engine->control->max_delayed_usecs); /* free engine control shm segment */ engine->control = NULL; VERBOSE (engine, "freeing engine shared memory"); jack_release_shm (&engine->control_shm); jack_destroy_shm (&engine->control_shm); VERBOSE (engine, "max usecs: %.3f, engine deleted", engine->max_usecs); free (engine); jack_messagebuffer_exit(); } void jack_port_clear_connections (jack_engine_t *engine, jack_port_internal_t *port) { JSList *node, *next; for (node = port->connections; node; ) { next = jack_slist_next (node); jack_port_disconnect_internal ( engine, ((jack_connection_internal_t *) node->data)->source, ((jack_connection_internal_t *) node->data)->destination); node = next; } jack_slist_free (port->connections); port->connections = 0; } static void jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event) { JSList *node; jack_rdlock_graph (engine); for (node = engine->clients; node; node = jack_slist_next (node)) { jack_deliver_event (engine, (jack_client_internal_t *) node->data, event); } jack_unlock_graph (engine); } static jack_client_id_t jack_engine_get_max_uuid( jack_engine_t *engine ) { JSList *node; jack_client_id_t retval = 0; for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t* client = (jack_client_internal_t*) node->data; if( client->control->uid > retval ) retval = client->control->uid; } return retval; } static void jack_do_get_client_by_uuid ( jack_engine_t *engine, jack_request_t *req) { JSList *node; req->status = -1; for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t* client = (jack_client_internal_t*) node->data; if( client->control->uid == req->x.client_id ) { snprintf( req->x.port_info.name, sizeof(req->x.port_info.name), "%s", client->control->name ); req->status = 0; return; } } } static void jack_do_reserve_name ( jack_engine_t *engine, jack_request_t *req) { jack_reserved_name_t *reservation; JSList *node; // check is name is free... for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t* client = (jack_client_internal_t*) node->data; if( !strcmp( (char *)client->control->name, req->x.reservename.name )) { req->status = -1; return; } } reservation = malloc( sizeof( jack_reserved_name_t ) ); if( reservation == NULL ) { req->status = -1; return; } snprintf( reservation->name, sizeof( reservation->name ), "%s", req->x.reservename.name ); reservation->uuid = req->x.reservename.uuid; engine->reserved_client_names = jack_slist_append( engine->reserved_client_names, reservation ); req->status = 0; } static int jack_send_session_reply ( jack_engine_t *engine, jack_client_internal_t *client ) { if (write (engine->session_reply_fd, (const void *) &client->control->uid, sizeof (client->control->uid)) < (ssize_t) sizeof (client->control->uid)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", engine->session_reply_fd, strerror (errno)); return -1; } if (write (engine->session_reply_fd, (const void *) client->control->name, sizeof (client->control->name)) < (ssize_t) sizeof (client->control->name)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", engine->session_reply_fd, strerror (errno)); return -1; } if (write (engine->session_reply_fd, (const void *) client->control->session_command, sizeof (client->control->session_command)) < (ssize_t) sizeof (client->control->session_command)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", engine->session_reply_fd, strerror (errno)); return -1; } if (write (engine->session_reply_fd, (const void *) ( & client->control->session_flags ), sizeof (client->control->session_flags)) < (ssize_t) sizeof (client->control->session_flags)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", engine->session_reply_fd, strerror (errno)); return -1; } return 0; } static int jack_do_session_notify (jack_engine_t *engine, jack_request_t *req, int reply_fd ) { JSList *node; jack_event_t event; int reply; jack_client_id_t finalizer=0; struct stat sbuf; if (engine->session_reply_fd != -1) { // we should have a notion of busy or somthing. // just sending empty reply now. goto send_final; } engine->session_reply_fd = reply_fd; engine->session_pending_replies = 0; event.type = SaveSession; event.y.n = req->x.session.type; /* GRAPH MUST BE LOCKED : see callers of jack_send_connection_notification() */ // make sure all uuids are set. for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t* client = (jack_client_internal_t*) node->data; if( client->control->uid == 0 ) { client->control->uid=jack_engine_get_max_uuid( engine ) + 1; } } if (stat (req->x.session.path, &sbuf) != 0 || !S_ISDIR (sbuf.st_mode)) { jack_error ("session parent directory (%s) does not exist", req->x.session.path); goto send_final; } for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t* client = (jack_client_internal_t*) node->data; if (client->control->session_cbset) { // in case we only want to send to a special client. // uuid assign is still complete. not sure if thats necessary. if( (req->x.session.target[0] != 0) && strcmp(req->x.session.target, (char *)client->control->name) ) continue; /* the caller of jack_session_notify() is required to have created the session dir */ if (req->x.session.path[strlen(req->x.session.path)-1] == '/') { snprintf (event.x.name, sizeof (event.x.name), "%s%s/", req->x.session.path, client->control->name ); } else { snprintf (event.x.name, sizeof (event.x.name), "%s/%s/", req->x.session.path, client->control->name ); } if (mkdir (event.x.name, 0777) != 0) { jack_error ("cannot create session directory (%s) for client %s: %s", event.x.name, client->control->name, strerror (errno)); break; } reply = jack_deliver_event (engine, client, &event); if (reply == 1) { // delayed reply engine->session_pending_replies += 1; client->session_reply_pending = TRUE; } else if (reply == 2) { // immediate reply if (jack_send_session_reply (engine, client)) goto error_out; } } } if (engine->session_pending_replies != 0) return 0; send_final: if (write (reply_fd, &finalizer, sizeof (finalizer)) < (ssize_t) sizeof (finalizer)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", reply_fd, strerror (errno)); goto error_out; } engine->session_reply_fd = -1; return 0; error_out: return -3; } static int jack_do_has_session_cb (jack_engine_t *engine, jack_request_t *req) { jack_client_internal_t *client; int retval = -1; client = jack_client_by_name (engine, req->x.name); if (client == NULL) goto out; retval = client->control->session_cbset ? 1 : 0; out: return retval; } static void jack_do_session_reply (jack_engine_t *engine, jack_request_t *req ) { jack_client_id_t client_id = req->x.client_id; jack_client_internal_t *client = jack_client_internal_by_id (engine, client_id); jack_client_id_t finalizer=0; req->status = 0; client->session_reply_pending = 0; if (engine->session_reply_fd == -1) { jack_error ("spurious Session Reply"); return; } engine->session_pending_replies -= 1; if (jack_send_session_reply (engine, client)) { // maybe need to fix all client pendings. // but we will just get a set of spurious replies now. engine->session_reply_fd = -1; return; } if (engine->session_pending_replies == 0) { if (write (engine->session_reply_fd, &finalizer, sizeof (finalizer)) < (ssize_t) sizeof (finalizer)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", engine->session_reply_fd, strerror (errno)); req->status = -1; } engine->session_reply_fd = -1; } } static void jack_notify_all_port_interested_clients (jack_engine_t *engine, jack_client_id_t src, jack_client_id_t dst, jack_port_id_t a, jack_port_id_t b, int connected) { JSList *node; jack_event_t event; event.type = (connected ? PortConnected : PortDisconnected); event.x.self_id = a; event.y.other_id = b; /* GRAPH MUST BE LOCKED : see callers of jack_send_connection_notification() */ jack_client_internal_t* src_client = jack_client_internal_by_id (engine, src); jack_client_internal_t* dst_client = jack_client_internal_by_id (engine, dst); for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t* client = (jack_client_internal_t*) node->data; if (src_client != client && dst_client != client && client->control->port_connect_cbset != FALSE) { /* one of the ports belong to this client or it has a port connect callback */ jack_deliver_event (engine, client, &event); } } } int jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event) { char status=0; /* caller must hold the graph lock */ DEBUG ("delivering event (type %d)", event->type); /* we are not RT-constrained here, so use kill(2) to beef up our check on a client's continued well-being */ if (client->control->dead || client->error >= JACK_ERROR_WITH_SOCKETS || (client->control->type == ClientExternal && kill (client->control->pid, 0))) { DEBUG ("client %s is dead - no event sent", client->control->name); return 0; } DEBUG ("client %s is still alive", client->control->name); if (jack_client_is_internal (client)) { switch (event->type) { case PortConnected: case PortDisconnected: jack_client_handle_port_connection (client->private_client, event); break; case BufferSizeChange: jack_client_fix_port_buffers (client->private_client); if (client->control->bufsize_cbset) { client->private_client->bufsize (event->x.n, client->private_client->bufsize_arg); } break; case SampleRateChange: if (client->control->srate_cbset) { client->private_client->srate (event->x.n, client->private_client->srate_arg); } break; case GraphReordered: if (client->control->graph_order_cbset) { client->private_client->graph_order (client->private_client->graph_order_arg); } break; case XRun: if (client->control->xrun_cbset) { client->private_client->xrun (client->private_client->xrun_arg); } break; case LatencyCallback: jack_client_handle_latency_callback (client->private_client, event, (client->control->type == ClientDriver)); break; default: /* internal clients don't need to know */ break; } } else { if (client->control->active) { /* there's a thread waiting for events, so * it's worth telling the client */ DEBUG ("engine writing on event fd"); if (write (client->event_fd, event, sizeof (*event)) != sizeof (*event)) { jack_error ("cannot send event to client [%s]" " (%s)", client->control->name, strerror (errno)); client->error += JACK_ERROR_WITH_SOCKETS; jack_engine_signal_problems (engine); } if (client->error) { status = -1; } else { // then we check whether there really is an error.... :) struct pollfd pfd[1]; pfd[0].fd = client->event_fd; pfd[0].events = POLLERR|POLLIN|POLLHUP|POLLNVAL; jack_time_t poll_timeout = JACKD_CLIENT_EVENT_TIMEOUT; int poll_ret; jack_time_t then = jack_get_microseconds (); jack_time_t now; #ifdef __linux again: #endif VERBOSE(engine,"client event poll on %d for %s starts at %lld", client->event_fd, client->control->name, then); if ((poll_ret = poll (pfd, 1, poll_timeout)) < 0) { DEBUG ("client event poll not ok! (-1) poll returned an error"); jack_error ("poll on subgraph processing failed (%s)", strerror (errno)); status = -1; } else { DEBUG ("\n\n\n\n\n back from client event poll, revents = 0x%x\n\n\n", pfd[0].revents); now = jack_get_microseconds(); VERBOSE(engine,"back from client event poll after %lld usecs", now - then); if (pfd[0].revents & ~POLLIN) { /* some kind of OOB socket event */ DEBUG ("client event poll not ok! (-2), revents = %d\n", pfd[0].revents); jack_error ("subgraph starting at %s lost client", client->control->name); status = -2; } else if (pfd[0].revents & POLLIN) { /* client responded normally */ DEBUG ("client event poll ok!"); status = 0; } else if (poll_ret == 0) { /* no events, no errors, we woke up because poll() decided that time was up ... */ #ifdef __linux if (linux_poll_bug_encountered (engine, then, &poll_timeout)) { goto again; } if (poll_timeout < 200) { VERBOSE (engine, "FALSE WAKEUP skipped, remaining = %lld usec", poll_timeout); status = 0; } else { #endif DEBUG ("client event poll not ok! (1 = poll timed out, revents = 0x%04x, poll_ret = %d)", pfd[0].revents, poll_ret); VERBOSE (engine,"client %s did not respond to event type %d in time" "(fd=%d, revents = 0x%04x, timeout was %lld)", client->control->name, event->type, client->event_fd, pfd[0].revents, poll_timeout); status = -2; #ifdef __linux } #endif } } } if (status == 0) { if (read (client->event_fd, &status, sizeof (status)) != sizeof (status)) { jack_error ("cannot read event response from " "client [%s] (%s)", client->control->name, strerror (errno)); status = -1; } } else { jack_error ("bad status (%d) for client %s " "handling event (type = %d)", status, client->control->name, event->type); } if (status<0) { client->error += JACK_ERROR_WITH_SOCKETS; jack_engine_signal_problems (engine); } } } DEBUG ("event delivered"); return status; } int jack_rechain_graph (jack_engine_t *engine) { JSList *node, *next; unsigned long n; int err = 0; jack_client_internal_t *subgraph_client, *next_client; jack_event_t event; int upstream_is_jackd; jack_clear_fifos (engine); subgraph_client = 0; VERBOSE(engine, "++ jack_rechain_graph():"); event.type = GraphReordered; for (n = 0, node = engine->clients, next = NULL; node; node = next) { jack_client_internal_t* client = (jack_client_internal_t *) node->data; next = jack_slist_next (node); if (!client->control->process_cbset && !client->control->thread_cb_cbset) { continue; } VERBOSE(engine, "+++ client is now %s active ? %d", client->control->name, client->control->active); if (client->control->active) { /* find the next active client. its ok for * this to be NULL */ while (next) { if (client->control->active && (client->control->process_cbset || client->control->thread_cb_cbset)) { break; } next = jack_slist_next (next); }; if (next == NULL) { next_client = NULL; } else { next_client = (jack_client_internal_t *) next->data; } client->execution_order = n; client->next_client = next_client; if (jack_client_is_internal (client)) { /* break the chain for the current * subgraph. the server will wait for * chain on the nth FIFO, and will * then execute this internal * client. */ if (subgraph_client) { subgraph_client->subgraph_wait_fd = jack_get_fifo_fd (engine, n); VERBOSE (engine, "client %s: wait_fd=" "%d, execution_order=" "%lu.", subgraph_client-> control->name, subgraph_client-> subgraph_wait_fd, n); n++; } VERBOSE (engine, "client %s: internal " "client, execution_order=" "%lu.", client->control->name, n); /* this does the right thing for * internal clients too */ jack_deliver_event (engine, client, &event); subgraph_client = 0; } else { if (subgraph_client == NULL) { /* start a new subgraph. the * engine will start the chain * by writing to the nth * FIFO. */ subgraph_client = client; subgraph_client->subgraph_start_fd = jack_get_fifo_fd (engine, n); VERBOSE (engine, "client %s: " "start_fd=%d, execution" "_order=%lu.", subgraph_client-> control->name, subgraph_client-> subgraph_start_fd, n); /* this external client after this will have jackd as its upstream connection. */ upstream_is_jackd = 1; } else { VERBOSE (engine, "client %s: in" " subgraph after %s, " "execution_order=" "%lu.", client->control->name, subgraph_client-> control->name, n); subgraph_client->subgraph_wait_fd = -1; /* this external client after this will have another client as its upstream connection. */ upstream_is_jackd = 0; } /* make sure fifo for 'n + 1' exists * before issuing client reorder */ (void) jack_get_fifo_fd( engine, client->execution_order + 1); event.x.n = client->execution_order; event.y.n = upstream_is_jackd; jack_deliver_event (engine, client, &event); n++; } } } if (subgraph_client) { subgraph_client->subgraph_wait_fd = jack_get_fifo_fd (engine, n); VERBOSE (engine, "client %s: wait_fd=%d, " "execution_order=%lu (last client).", subgraph_client->control->name, subgraph_client->subgraph_wait_fd, n); } VERBOSE (engine, "-- jack_rechain_graph()"); return err; } static jack_nframes_t jack_get_port_total_latency (jack_engine_t *engine, jack_port_internal_t *port, int hop_count, int toward_port) { JSList *node; jack_nframes_t latency; jack_nframes_t max_latency = 0; #ifdef DEBUG_TOTAL_LATENCY_COMPUTATION char prefix[32]; int i; for (i = 0; i < hop_count; ++i) { prefix[i] = '\t'; } prefix[i] = '\0'; #endif /* call tree must hold engine->client_lock. */ latency = port->shared->latency; /* we don't prevent cyclic graphs, so we have to do something to bottom out in the event that they are created. */ if (hop_count > 8) { return latency; } #ifdef DEBUG_TOTAL_LATENCY_COMPUTATION jack_info ("%sFor port %s (%s)", prefix, port->shared->name, (toward_port ? "toward" : "away")); #endif for (node = port->connections; node; node = jack_slist_next (node)) { jack_nframes_t this_latency; jack_connection_internal_t *connection; connection = (jack_connection_internal_t *) node->data; if ((toward_port && (connection->source->shared == port->shared)) || (!toward_port && (connection->destination->shared == port->shared))) { #ifdef DEBUG_TOTAL_LATENCY_COMPUTATION jack_info ("%s\tskip connection %s->%s", prefix, connection->source->shared->name, connection->destination->shared->name); #endif continue; } #ifdef DEBUG_TOTAL_LATENCY_COMPUTATION jack_info ("%s\tconnection %s->%s ... ", prefix, connection->source->shared->name, connection->destination->shared->name); #endif /* if we're a destination in the connection, recurse on the source to get its total latency */ if (connection->destination == port) { if (connection->source->shared->flags & JackPortIsTerminal) { this_latency = connection->source-> shared->latency; } else { this_latency = jack_get_port_total_latency ( engine, connection->source, hop_count + 1, toward_port); } } else { /* "port" is the source, so get the latency of * the destination */ if (connection->destination->shared->flags & JackPortIsTerminal) { this_latency = connection->destination-> shared->latency; } else { this_latency = jack_get_port_total_latency ( engine, connection->destination, hop_count + 1, toward_port); } } if (this_latency > max_latency) { max_latency = this_latency; } } #ifdef DEBUG_TOTAL_LATENCY_COMPUTATION jack_info ("%s\treturn %lu + %lu = %lu", prefix, latency, max_latency, latency + max_latency); #endif return latency + max_latency; } static void jack_compute_port_total_latency (jack_engine_t* engine, jack_port_shared_t* port) { if (port->in_use) { port->total_latency = jack_get_port_total_latency ( engine, &engine->internal_ports[port->id], 0, !(port->flags & JackPortIsOutput)); } } static void jack_compute_all_port_total_latencies (jack_engine_t *engine) { jack_port_shared_t *shared = engine->control->ports; unsigned int i; int toward_port; for (i = 0; i < engine->control->port_max; i++) { if (shared[i].in_use) { if (shared[i].flags & JackPortIsOutput) { toward_port = FALSE; } else { toward_port = TRUE; } shared[i].total_latency = jack_get_port_total_latency ( engine, &engine->internal_ports[i], 0, toward_port); } } } static void jack_compute_new_latency (jack_engine_t *engine) { JSList *node; JSList *reverse_list = NULL; jack_event_t event; event.type = LatencyCallback; event.x.n = 0; /* iterate over all clients in graph order, and emit * capture latency callback. * also builds up list in reverse graph order. */ for (node = engine->clients; node; node = jack_slist_next(node)) { jack_client_internal_t* client = (jack_client_internal_t *) node->data; reverse_list = jack_slist_prepend (reverse_list, client); jack_deliver_event (engine, client, &event); } if (engine->driver) { jack_deliver_event (engine, engine->driver->internal_client, &event); } /* now issue playback latency callbacks in reverse graphorder */ event.x.n = 1; for (node = reverse_list; node; node = jack_slist_next(node)) { jack_client_internal_t* client = (jack_client_internal_t *) node->data; jack_deliver_event (engine, client, &event); } if (engine->driver) { jack_deliver_event (engine, engine->driver->internal_client, &event); } jack_slist_free (reverse_list); } /* How the sort works: * * Each client has a "sortfeeds" list of clients indicating which clients * it should be considered as feeding for the purposes of sorting the * graph. This list differs from the clients it /actually/ feeds in the * following ways: * * 1. Connections from a client to itself are disregarded * * 2. Connections to a driver client are disregarded * * 3. If a connection from A to B is a feedback connection (ie there was * already a path from B to A when the connection was made) then instead * of B appearing on A's sortfeeds list, A will appear on B's sortfeeds * list. * * If client A is on client B's sortfeeds list, client A must come after * client B in the execution order. The above 3 rules ensure that the * sortfeeds relation is always acyclic so that all ordering constraints * can actually be met. * * Each client also has a "truefeeds" list which is the same as sortfeeds * except that feedback connections appear normally instead of reversed. * This is used to detect whether the graph has become acyclic. * */ void jack_sort_graph (jack_engine_t *engine) { /* called, obviously, must hold engine->client_lock */ VERBOSE (engine, "++ jack_sort_graph"); engine->clients = jack_slist_sort (engine->clients, (JCompareFunc) jack_client_sort); jack_compute_all_port_total_latencies (engine); jack_rechain_graph (engine); jack_compute_new_latency (engine); engine->timeout_count = 0; VERBOSE (engine, "-- jack_sort_graph"); } static int jack_client_sort (jack_client_internal_t *a, jack_client_internal_t *b) { /* drivers are forced to the front, ie considered as sources rather than sinks for purposes of the sort */ if (jack_client_feeds_transitive (a, b) || (a->control->type == ClientDriver && b->control->type != ClientDriver)) { return -1; } else if (jack_client_feeds_transitive (b, a) || (b->control->type == ClientDriver && a->control->type != ClientDriver)) { return 1; } else { return 0; } } /* transitive closure of the relation expressed by the sortfeeds lists. */ static int jack_client_feeds_transitive (jack_client_internal_t *source, jack_client_internal_t *dest ) { jack_client_internal_t *med; JSList *node; if (jack_slist_find (source->sortfeeds, dest)) { return 1; } for (node = source->sortfeeds; node; node = jack_slist_next (node)) { med = (jack_client_internal_t *) node->data; if (jack_client_feeds_transitive (med, dest)) { return 1; } } return 0; } /** * Checks whether the graph has become acyclic and if so modifies client * sortfeeds lists to turn leftover feedback connections into normal ones. * This lowers latency, but at the expense of some data corruption. */ static void jack_check_acyclic (jack_engine_t *engine) { JSList *srcnode, *dstnode, *portnode, *connnode; jack_client_internal_t *src, *dst; jack_port_internal_t *port; jack_connection_internal_t *conn; int stuck; int unsortedclients = 0; VERBOSE (engine, "checking for graph become acyclic"); for (srcnode = engine->clients; srcnode; srcnode = jack_slist_next (srcnode)) { src = (jack_client_internal_t *) srcnode->data; src->tfedcount = src->fedcount; unsortedclients++; } stuck = FALSE; /* find out whether a normal sort would have been possible */ while (unsortedclients && !stuck) { stuck = TRUE; for (srcnode = engine->clients; srcnode; srcnode = jack_slist_next (srcnode)) { src = (jack_client_internal_t *) srcnode->data; if (!src->tfedcount) { stuck = FALSE; unsortedclients--; src->tfedcount = -1; for (dstnode = src->truefeeds; dstnode; dstnode = jack_slist_next (dstnode)) { dst = (jack_client_internal_t *) dstnode->data; dst->tfedcount--; } } } } if (stuck) { VERBOSE (engine, "graph is still cyclic" ); } else { VERBOSE (engine, "graph has become acyclic"); /* turn feedback connections around in sortfeeds */ for (srcnode = engine->clients; srcnode; srcnode = jack_slist_next (srcnode)) { src = (jack_client_internal_t *) srcnode->data; for (portnode = src->ports; portnode; portnode = jack_slist_next (portnode)) { port = (jack_port_internal_t *) portnode->data; for (connnode = port->connections; connnode; connnode = jack_slist_next (connnode)) { conn = (jack_connection_internal_t*) connnode->data; if (conn->dir == -1 ) /*&& conn->srcclient == src) */{ VERBOSE (engine, "reversing connection from " "%s to %s", conn->srcclient->control->name, conn->dstclient->control->name); conn->dir = 1; conn->dstclient->sortfeeds = jack_slist_remove (conn->dstclient->sortfeeds, conn->srcclient); conn->srcclient->sortfeeds = jack_slist_prepend (conn->srcclient->sortfeeds, conn->dstclient ); } } } } engine->feedbackcount = 0; } } /** * Dumps current engine configuration. */ void jack_dump_configuration(jack_engine_t *engine, int take_lock) { JSList *clientnode, *portnode, *connectionnode; jack_client_internal_t *client; jack_client_control_t *ctl; jack_port_internal_t *port; jack_connection_internal_t* connection; int n, m, o; jack_info ("engine.c: <-- dump begins -->"); if (take_lock) { jack_rdlock_graph (engine); } for (n = 0, clientnode = engine->clients; clientnode; clientnode = jack_slist_next (clientnode)) { client = (jack_client_internal_t *) clientnode->data; ctl = client->control; jack_info ("client #%d: %s (type: %d, process? %s, thread ? %s" " start=%d wait=%d", ++n, ctl->name, ctl->type, ctl->process_cbset ? "yes" : "no", ctl->thread_cb_cbset ? "yes" : "no", client->subgraph_start_fd, client->subgraph_wait_fd); for(m = 0, portnode = client->ports; portnode; portnode = jack_slist_next (portnode)) { port = (jack_port_internal_t *) portnode->data; jack_info("\t port #%d: %s", ++m, port->shared->name); for(o = 0, connectionnode = port->connections; connectionnode; connectionnode = jack_slist_next (connectionnode)) { connection = (jack_connection_internal_t *) connectionnode->data; jack_info("\t\t connection #%d: %s %s", ++o, (port->shared->flags & JackPortIsInput)? "<-": "->", (port->shared->flags & JackPortIsInput)? connection->source->shared->name: connection->destination->shared->name); } } } if (take_lock) { jack_unlock_graph (engine); } jack_info("engine.c: <-- dump ends -->"); } static int jack_port_do_connect (jack_engine_t *engine, const char *source_port, const char *destination_port) { jack_connection_internal_t *connection; jack_port_internal_t *srcport, *dstport; jack_port_id_t src_id, dst_id; jack_client_internal_t *srcclient, *dstclient; JSList *it; if ((srcport = jack_get_port_by_name (engine, source_port)) == NULL) { jack_error ("unknown source port in attempted connection [%s]", source_port); return -1; } if ((dstport = jack_get_port_by_name (engine, destination_port)) == NULL) { jack_error ("unknown destination port in attempted connection" " [%s]", destination_port); return -1; } if ((dstport->shared->flags & JackPortIsInput) == 0) { jack_error ("destination port in attempted connection of" " %s and %s is not an input port", source_port, destination_port); return -1; } if ((srcport->shared->flags & JackPortIsOutput) == 0) { jack_error ("source port in attempted connection of %s and" " %s is not an output port", source_port, destination_port); return -1; } if (srcport->shared->ptype_id != dstport->shared->ptype_id) { jack_error ("ports used in attemped connection are not of " "the same data type"); return -1; } if ((srcclient = jack_client_internal_by_id (engine, srcport->shared->client_id)) == 0) { jack_error ("unknown client set as owner of port - " "cannot connect"); return -1; } if (!srcclient->control->active) { jack_error ("cannot connect ports owned by inactive clients;" " \"%s\" is not active", srcclient->control->name); return -1; } if ((dstclient = jack_client_internal_by_id (engine, dstport->shared->client_id)) == 0) { jack_error ("unknown client set as owner of port - cannot " "connect"); return -1; } if (!dstclient->control->active) { jack_error ("cannot connect ports owned by inactive clients;" " \"%s\" is not active", dstclient->control->name); return -1; } for (it = srcport->connections; it; it = it->next) { if (((jack_connection_internal_t *)it->data)->destination == dstport) { return EEXIST; } } connection = (jack_connection_internal_t *) malloc (sizeof (jack_connection_internal_t)); connection->source = srcport; connection->destination = dstport; connection->srcclient = srcclient; connection->dstclient = dstclient; src_id = srcport->shared->id; dst_id = dstport->shared->id; jack_lock_graph (engine); if (dstport->connections && !dstport->shared->has_mixdown) { jack_port_type_info_t *port_type = jack_port_type_info (engine, dstport); jack_error ("cannot make multiple connections to a port of" " type [%s]", port_type->type_name); free (connection); jack_unlock_graph (engine); return -1; } else { if (dstclient->control->type == ClientDriver) { /* Ignore output connections to drivers for purposes of sorting. Drivers are executed first in the sort order anyway, and we don't want to treat graphs such as driver -> client -> driver as containing feedback */ VERBOSE (engine, "connect %s and %s (output)", srcport->shared->name, dstport->shared->name); connection->dir = 1; } else if (srcclient != dstclient) { srcclient->truefeeds = jack_slist_prepend (srcclient->truefeeds, dstclient); dstclient->fedcount++; if (jack_client_feeds_transitive (dstclient, srcclient ) || (dstclient->control->type == ClientDriver && srcclient->control->type != ClientDriver)) { /* dest is running before source so this is a feedback connection */ VERBOSE (engine, "connect %s and %s (feedback)", srcport->shared->name, dstport->shared->name); dstclient->sortfeeds = jack_slist_prepend (dstclient->sortfeeds, srcclient); connection->dir = -1; engine->feedbackcount++; VERBOSE (engine, "feedback count up to %d", engine->feedbackcount); } else { /* this is not a feedback connection */ VERBOSE (engine, "connect %s and %s (forward)", srcport->shared->name, dstport->shared->name); srcclient->sortfeeds = jack_slist_prepend (srcclient->sortfeeds, dstclient); connection->dir = 1; } } else { /* this is a connection to self */ VERBOSE (engine, "connect %s and %s (self)", srcport->shared->name, dstport->shared->name); connection->dir = 0; } dstport->connections = jack_slist_prepend (dstport->connections, connection); srcport->connections = jack_slist_prepend (srcport->connections, connection); DEBUG ("actually sorted the graph..."); jack_send_connection_notification (engine, srcport->shared->client_id, src_id, dst_id, TRUE); jack_send_connection_notification (engine, dstport->shared->client_id, dst_id, src_id, TRUE); /* send a port connection notification just once to everyone who cares excluding clients involved in the connection */ jack_notify_all_port_interested_clients (engine, srcport->shared->client_id, dstport->shared->client_id, src_id, dst_id, 1); jack_sort_graph (engine); } jack_unlock_graph (engine); return 0; } int jack_port_disconnect_internal (jack_engine_t *engine, jack_port_internal_t *srcport, jack_port_internal_t *dstport ) { JSList *node; jack_connection_internal_t *connect; int ret = -1; jack_port_id_t src_id, dst_id; int check_acyclic = engine->feedbackcount; /* call tree **** MUST HOLD **** engine->client_lock. */ for (node = srcport->connections; node; node = jack_slist_next (node)) { connect = (jack_connection_internal_t *) node->data; if (connect->source == srcport && connect->destination == dstport) { VERBOSE (engine, "DIS-connect %s and %s", srcport->shared->name, dstport->shared->name); srcport->connections = jack_slist_remove (srcport->connections, connect); dstport->connections = jack_slist_remove (dstport->connections, connect); 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); /* send a port connection notification just once to everyone who cares excluding clients involved in the connection */ jack_notify_all_port_interested_clients (engine, srcport->shared->client_id, dstport->shared->client_id, src_id, dst_id, 0); if (connect->dir) { jack_client_internal_t *src; jack_client_internal_t *dst; src = jack_client_internal_by_id (engine, srcport->shared->client_id); dst = jack_client_internal_by_id (engine, dstport->shared->client_id); src->truefeeds = jack_slist_remove (src->truefeeds, dst); dst->fedcount--; if (connect->dir == 1) { /* normal connection: remove dest from source's sortfeeds list */ src->sortfeeds = jack_slist_remove (src->sortfeeds, dst); } else { /* feedback connection: remove source from dest's sortfeeds list */ dst->sortfeeds = jack_slist_remove (dst->sortfeeds, src); engine->feedbackcount--; VERBOSE (engine, "feedback count down to %d", engine->feedbackcount); } } /* else self-connection: do nothing */ free (connect); ret = 0; break; } } if (check_acyclic) { jack_check_acyclic (engine); } jack_sort_graph (engine); return ret; } static int jack_port_do_disconnect_all (jack_engine_t *engine, jack_port_id_t port_id) { if (port_id >= engine->control->port_max) { jack_error ("illegal port ID in attempted disconnection [%" PRIu32 "]", port_id); return -1; } VERBOSE (engine, "clear connections for %s", engine->internal_ports[port_id].shared->name); jack_lock_graph (engine); jack_port_clear_connections (engine, &engine->internal_ports[port_id]); jack_sort_graph (engine); jack_unlock_graph (engine); return 0; } static int jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, const char *destination_port) { jack_port_internal_t *srcport, *dstport; int ret = -1; if ((srcport = jack_get_port_by_name (engine, source_port)) == NULL) { jack_error ("unknown source port in attempted disconnection" " [%s]", source_port); return -1; } if ((dstport = jack_get_port_by_name (engine, destination_port)) == NULL) { jack_error ("unknown destination port in attempted" " disconnection [%s]", destination_port); return -1; } jack_lock_graph (engine); ret = jack_port_disconnect_internal (engine, srcport, dstport); jack_unlock_graph (engine); return ret; } int jack_get_fifo_fd (jack_engine_t *engine, unsigned int which_fifo) { /* caller must hold client_lock */ char path[PATH_MAX+1]; struct stat statbuf; snprintf (path, sizeof (path), "%s-%d", engine->fifo_prefix, which_fifo); DEBUG ("%s", path); if (stat (path, &statbuf)) { if (errno == ENOENT) { if (mkfifo(path, 0666) < 0){ jack_error ("cannot create inter-client FIFO" " [%s] (%s)\n", path, strerror (errno)); return -1; } } else { jack_error ("cannot check on FIFO %d\n", which_fifo); return -1; } } else { if (!S_ISFIFO(statbuf.st_mode)) { jack_error ("FIFO %d (%s) already exists, but is not" " a FIFO!\n", which_fifo, path); return -1; } } if (which_fifo >= engine->fifo_size) { unsigned int i; engine->fifo = (int *) realloc (engine->fifo, sizeof (int) * (engine->fifo_size + 16)); for (i = engine->fifo_size; i < engine->fifo_size + 16; i++) { engine->fifo[i] = -1; } engine->fifo_size += 16; } if (engine->fifo[which_fifo] < 0) { if ((engine->fifo[which_fifo] = open (path, O_RDWR|O_CREAT|O_NONBLOCK, 0666)) < 0) { jack_error ("cannot open fifo [%s] (%s)", path, strerror (errno)); return -1; } DEBUG ("opened engine->fifo[%d] == %d (%s)", which_fifo, engine->fifo[which_fifo], path); } return engine->fifo[which_fifo]; } static void jack_clear_fifos (jack_engine_t *engine) { /* caller must hold client_lock */ unsigned int i; char buf[16]; /* this just drains the existing FIFO's of any data left in them by aborted clients, etc. there is only ever going to be 0, 1 or 2 bytes in them, but we'll allow for up to 16. */ for (i = 0; i < engine->fifo_size; i++) { if (engine->fifo[i] >= 0) { int nread = read (engine->fifo[i], buf, sizeof (buf)); if (nread < 0 && errno != EAGAIN) { jack_error ("clear fifo[%d] error: %s", i, strerror (errno)); } } } } int jack_use_driver (jack_engine_t *engine, jack_driver_t *driver) { if (engine->driver) { engine->driver->detach (engine->driver, engine); engine->driver = 0; } if (driver) { engine->driver = driver; if (driver->attach (driver, engine)) { engine->driver = 0; return -1; } engine->rolling_interval = jack_rolling_interval (driver->period_usecs); } return 0; } int jack_add_slave_driver (jack_engine_t *engine, jack_driver_t *driver) { if (driver) { if (driver->attach (driver, engine)) { return -1; } engine->slave_drivers = jack_slist_append (engine->slave_drivers, driver); } return 0; } /* PORT RELATED FUNCTIONS */ static jack_port_id_t jack_get_free_port (jack_engine_t *engine) { jack_port_id_t i; pthread_mutex_lock (&engine->port_lock); for (i = 0; i < engine->port_max; i++) { if (engine->control->ports[i].in_use == 0) { engine->control->ports[i].in_use = 1; break; } } pthread_mutex_unlock (&engine->port_lock); if (i == engine->port_max) { return (jack_port_id_t) -1; } return i; } void jack_port_release (jack_engine_t *engine, jack_port_internal_t *port) { pthread_mutex_lock (&engine->port_lock); port->shared->in_use = 0; port->shared->alias1[0] = '\0'; port->shared->alias2[0] = '\0'; if (port->buffer_info) { jack_port_buffer_list_t *blist = jack_port_buffer_list (engine, port); pthread_mutex_lock (&blist->lock); blist->freelist = jack_slist_prepend (blist->freelist, port->buffer_info); port->buffer_info = NULL; pthread_mutex_unlock (&blist->lock); } pthread_mutex_unlock (&engine->port_lock); } jack_port_internal_t * jack_get_port_internal_by_name (jack_engine_t *engine, const char *name) { jack_port_id_t id; pthread_mutex_lock (&engine->port_lock); for (id = 0; id < engine->port_max; id++) { if (jack_port_name_equals (&engine->control->ports[id], name)) { break; } } pthread_mutex_unlock (&engine->port_lock); if (id != engine->port_max) { return &engine->internal_ports[id]; } else { return NULL; } } int jack_port_do_register (jack_engine_t *engine, jack_request_t *req, int internal) { jack_port_id_t port_id; jack_port_shared_t *shared; jack_port_internal_t *port; jack_client_internal_t *client; unsigned long i; char *backend_client_name; size_t len; for (i = 0; i < engine->control->n_port_types; ++i) { if (strcmp (req->x.port_info.type, engine->control->port_types[i].type_name) == 0) { break; } } if (i == engine->control->n_port_types) { jack_error ("cannot register a port of type \"%s\"", req->x.port_info.type); return -1; } jack_lock_graph (engine); if ((client = jack_client_internal_by_id (engine, req->x.port_info.client_id)) == NULL) { jack_error ("unknown client id in port registration request"); jack_unlock_graph (engine); return -1; } if ((port = jack_get_port_by_name(engine, req->x.port_info.name)) != NULL) { jack_error ("duplicate port name (%s) in port registration request", req->x.port_info.name); jack_unlock_graph (engine); return -1; } if ((port_id = jack_get_free_port (engine)) == (jack_port_id_t) -1) { jack_error ("no ports available!"); jack_unlock_graph (engine); return -1; } shared = &engine->control->ports[port_id]; if (!internal || !engine->driver) { goto fallback; } /* if the port belongs to the backend client, do some magic with names */ backend_client_name = (char *) engine->driver->internal_client->control->name; len = strlen (backend_client_name); if (strncmp (req->x.port_info.name, backend_client_name, len) != 0) { goto fallback; } /* use backend's original as an alias, use predefined names */ if (strcmp(req->x.port_info.type, JACK_DEFAULT_AUDIO_TYPE) == 0) { if ((req->x.port_info.flags & (JackPortIsPhysical|JackPortIsInput)) == (JackPortIsPhysical|JackPortIsInput)) { snprintf (shared->name, sizeof (shared->name), JACK_BACKEND_ALIAS ":playback_%d", ++engine->audio_out_cnt); strcpy (shared->alias1, req->x.port_info.name); goto next; } else if ((req->x.port_info.flags & (JackPortIsPhysical|JackPortIsOutput)) == (JackPortIsPhysical|JackPortIsOutput)) { snprintf (shared->name, sizeof (shared->name), JACK_BACKEND_ALIAS ":capture_%d", ++engine->audio_in_cnt); strcpy (shared->alias1, req->x.port_info.name); goto next; } } #if 0 // do not do this for MIDI else if (strcmp(req->x.port_info.type, JACK_DEFAULT_MIDI_TYPE) == 0) { if ((req->x.port_info.flags & (JackPortIsPhysical|JackPortIsInput)) == (JackPortIsPhysical|JackPortIsInput)) { snprintf (shared->name, sizeof (shared->name), JACK_BACKEND_ALIAS ":midi_playback_%d", ++engine->midi_out_cnt); strcpy (shared->alias1, req->x.port_info.name); goto next; } else if ((req->x.port_info.flags & (JackPortIsPhysical|JackPortIsOutput)) == (JackPortIsPhysical|JackPortIsOutput)) { snprintf (shared->name, sizeof (shared->name), JACK_BACKEND_ALIAS ":midi_capture_%d", ++engine->midi_in_cnt); strcpy (shared->alias1, req->x.port_info.name); goto next; } } #endif fallback: strcpy (shared->name, req->x.port_info.name); next: shared->ptype_id = engine->control->port_types[i].ptype_id; shared->client_id = req->x.port_info.client_id; shared->flags = req->x.port_info.flags; shared->latency = 0; shared->capture_latency.min = shared->capture_latency.max = 0; shared->playback_latency.min = shared->playback_latency.max = 0; shared->monitor_requests = 0; port = &engine->internal_ports[port_id]; port->shared = shared; port->connections = 0; port->buffer_info = NULL; if (jack_port_assign_buffer (engine, port)) { jack_error ("cannot assign buffer for port"); jack_port_release (engine, &engine->internal_ports[port_id]); jack_unlock_graph (engine); return -1; } client->ports = jack_slist_prepend (client->ports, port); if( client->control->active ) jack_port_registration_notify (engine, port_id, TRUE); jack_unlock_graph (engine); VERBOSE (engine, "registered port %s, offset = %u", shared->name, (unsigned int)shared->offset); req->x.port_info.port_id = port_id; return 0; } int jack_port_do_unregister (jack_engine_t *engine, jack_request_t *req) { jack_client_internal_t *client; jack_port_shared_t *shared; jack_port_internal_t *port; if (req->x.port_info.port_id < 0 || req->x.port_info.port_id > engine->port_max) { jack_error ("invalid port ID %" PRIu32 " in unregister request", req->x.port_info.port_id); return -1; } shared = &engine->control->ports[req->x.port_info.port_id]; if (shared->client_id != req->x.port_info.client_id) { jack_error ("Client %" PRIu32 " is not allowed to remove port %s", req->x.port_info.client_id, shared->name); return -1; } jack_lock_graph (engine); if ((client = jack_client_internal_by_id (engine, shared->client_id)) == NULL) { jack_error ("unknown client id in port registration request"); jack_unlock_graph (engine); return -1; } port = &engine->internal_ports[req->x.port_info.port_id]; jack_port_clear_connections (engine, port); jack_port_release (engine, &engine->internal_ports[req->x.port_info.port_id]); client->ports = jack_slist_remove (client->ports, port); jack_port_registration_notify (engine, req->x.port_info.port_id, FALSE); jack_unlock_graph (engine); return 0; } int jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int reply_fd) { jack_port_internal_t *port; JSList *node; unsigned int i; int ret = -1; int internal = FALSE; jack_rdlock_graph (engine); port = &engine->internal_ports[req->x.port_info.port_id]; DEBUG ("Getting connections for port '%s'.", port->shared->name); req->x.port_connections.nports = jack_slist_length (port->connections); req->status = 0; /* figure out if this is an internal or external client */ for (node = engine->clients; node; node = jack_slist_next (node)) { if (((jack_client_internal_t *) node->data)->request_fd == reply_fd) { internal = jack_client_is_internal( (jack_client_internal_t *) node->data); break; } } if (!internal) { if (write (reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (req)) { jack_error ("cannot write GetPortConnections result " "to client via fd = %d (%s)", reply_fd, strerror (errno)); goto out; } } else { req->x.port_connections.ports = (const char**) malloc (sizeof (char *) * req->x.port_connections.nports); } if (req->type == GetPortConnections) { for (i = 0, node = port->connections; node; node = jack_slist_next (node), ++i) { jack_port_id_t port_id; if (((jack_connection_internal_t *) node->data)->source == port) { port_id = ((jack_connection_internal_t *) node->data)->destination->shared->id; } else { port_id = ((jack_connection_internal_t *) node->data)->source->shared->id; } if (internal) { /* internal client asking for * names. store in malloc'ed space, * client frees */ char **ports = (char **) req->x.port_connections.ports; ports[i] = engine->control->ports[port_id].name; } else { /* external client asking for * names. we write the port id's to * the reply fd. */ if (write (reply_fd, &port_id, sizeof (port_id)) < (ssize_t) sizeof (port_id)) { jack_error ("cannot write port id " "to client"); goto out; } } } } ret = 0; out: req->status = ret; jack_unlock_graph (engine); return ret; } void jack_port_registration_notify (jack_engine_t *engine, jack_port_id_t port_id, int yn) { jack_event_t event; jack_client_internal_t *client; JSList *node; event.type = (yn ? PortRegistered : PortUnregistered); event.x.port_id = port_id; for (node = engine->clients; node; node = jack_slist_next (node)) { client = (jack_client_internal_t *) node->data; if (!client->control->active) { continue; } if (client->control->port_register_cbset) { if (jack_deliver_event (engine, client, &event)) { jack_error ("cannot send port registration" " notification to %s (%s)", client->control->name, strerror (errno)); } } } } void jack_client_registration_notify (jack_engine_t *engine, const char* name, int yn) { jack_event_t event; jack_client_internal_t *client; JSList *node; event.type = (yn ? ClientRegistered : ClientUnregistered); snprintf (event.x.name, sizeof (event.x.name), "%s", name); for (node = engine->clients; node; node = jack_slist_next (node)) { client = (jack_client_internal_t *) node->data; if (!client->control->active) { continue; } if (strcmp ((char*) client->control->name, (char*) name) == 0) { /* do not notify client of its own registration */ continue; } if (client->control->client_register_cbset) { if (jack_deliver_event (engine, client, &event)) { jack_error ("cannot send client registration" " notification to %s (%s)", client->control->name, strerror (errno)); } } } } int jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) { jack_port_buffer_list_t *blist = jack_port_buffer_list (engine, port); jack_port_buffer_info_t *bi; if (port->shared->flags & JackPortIsInput) { port->shared->offset = 0; return 0; } pthread_mutex_lock (&blist->lock); if (blist->freelist == NULL) { jack_port_type_info_t *port_type = jack_port_type_info (engine, port); jack_error ("all %s port buffers in use!", port_type->type_name); pthread_mutex_unlock (&blist->lock); return -1; } bi = (jack_port_buffer_info_t *) blist->freelist->data; blist->freelist = jack_slist_remove (blist->freelist, bi); port->shared->offset = bi->offset; port->buffer_info = bi; pthread_mutex_unlock (&blist->lock); return 0; } static jack_port_internal_t * jack_get_port_by_name (jack_engine_t *engine, const char *name) { jack_port_id_t id; /* Note the potential race on "in_use". Other design elements prevent this from being a problem. */ for (id = 0; id < engine->port_max; id++) { if (engine->control->ports[id].in_use && jack_port_name_equals (&engine->control->ports[id], name)) { return &engine->internal_ports[id]; } } return NULL; } static int jack_send_connection_notification (jack_engine_t *engine, jack_client_id_t client_id, jack_port_id_t self_id, jack_port_id_t other_id, int connected) { jack_client_internal_t *client; jack_event_t event; if ((client = jack_client_internal_by_id (engine, client_id)) == NULL) { jack_error ("no such client %" PRIu32 " during connection notification", client_id); return -1; } if (client->control->active) { event.type = (connected ? PortConnected : PortDisconnected); event.x.self_id = self_id; event.y.other_id = other_id; if (jack_deliver_event (engine, client, &event)) { jack_error ("cannot send port connection notification" " to client %s (%s)", client->control->name, strerror (errno)); return -1; } } return 0; } static void jack_wake_server_thread (jack_engine_t* engine) { char c = 0; /* we don't actually care if this fails */ VERBOSE (engine, "waking server thread"); write (engine->cleanup_fifo[1], &c, 1); } void jack_engine_signal_problems (jack_engine_t* engine) { jack_lock_problems (engine); engine->problems++; jack_unlock_problems (engine); jack_wake_server_thread (engine); } jackd1-0.121.3+20120418git75e3e20b/jackd/controlapi.c0000644001605600047420000012172311736346233017204 0ustar adiira// u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */ /* JACK control API implementation Copyright (C) 2008 Nedko Arnaudov Copyright (C) 2008 Grame 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; version 2 of the License. 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. */ #ifndef WIN32 #include #include #include #endif #include "config.h" #include "internal.h" #include #include #include #include #include #include "jack/jslist.h" #include "jack/control.h" #include "driver_interface.h" #include "driver.h" #include "engine.h" #include "clientengine.h" //#include "JackError.h" //#include "JackServer.h" //#include "shm.h" //#include "JackTools.h" //#include "JackControlAPI.h" //#include "JackLockedEngine.h" //#include "JackConstants.h" //#include "JackDriverLoader.h" //#include "JackServerGlobals.h" /* * XXX: dont like statics here. */ static JSList *drivers = NULL; struct jackctl_server { JSList * drivers; JSList * internals; JSList * parameters; jack_engine_t * engine; /* string, server name */ union jackctl_parameter_value name; union jackctl_parameter_value default_name; /* bool, whether to be "realtime" */ union jackctl_parameter_value realtime; union jackctl_parameter_value default_realtime; /* int32_t */ union jackctl_parameter_value realtime_priority; union jackctl_parameter_value default_realtime_priority; /* bool, whether to exit once all clients have closed their connections */ union jackctl_parameter_value temporary; union jackctl_parameter_value default_temporary; /* bool, whether to be verbose */ union jackctl_parameter_value verbose; union jackctl_parameter_value default_verbose; /* int32_t, msecs; if zero, use period size. */ union jackctl_parameter_value client_timeout; union jackctl_parameter_value default_client_timeout; /* uint32_t, clock source type */ union jackctl_parameter_value clock_source; union jackctl_parameter_value default_clock_source; /* uint32_t, max port number */ union jackctl_parameter_value port_max; union jackctl_parameter_value default_port_max; /* bool */ union jackctl_parameter_value replace_registry; union jackctl_parameter_value default_replace_registry; /* bool, use mlock */ union jackctl_parameter_value do_mlock; union jackctl_parameter_value default_do_mlock; /* bool, munlock gui libraries */ union jackctl_parameter_value do_unlock; union jackctl_parameter_value default_do_unlock; /* bool, dont zombify... */ union jackctl_parameter_value nozombies; union jackctl_parameter_value default_nozombies; /* int, timeout thres... */ union jackctl_parameter_value timothres; union jackctl_parameter_value default_timothres; }; struct jackctl_driver { jack_driver_desc_t * desc_ptr; JSList * parameters; JSList * set_parameters; }; struct jackctl_internal { jack_driver_desc_t * desc_ptr; JSList * parameters; JSList * set_parameters; int refnum; }; struct jackctl_parameter { const char * name; const char * short_description; const char * long_description; jackctl_param_type_t type; bool is_set; union jackctl_parameter_value * value_ptr; union jackctl_parameter_value * default_value_ptr; union jackctl_parameter_value value; union jackctl_parameter_value default_value; struct jackctl_driver * driver_ptr; char id; jack_driver_param_t * driver_parameter_ptr; jack_driver_param_constraint_desc_t * constraint_ptr; }; static struct jackctl_parameter * jackctl_add_parameter( JSList ** parameters_list_ptr_ptr, char id, const char * name, const char * short_description, const char * long_description, jackctl_param_type_t type, union jackctl_parameter_value * value_ptr, union jackctl_parameter_value * default_value_ptr, union jackctl_parameter_value value, jack_driver_param_constraint_desc_t * constraint_ptr) { struct jackctl_parameter * parameter_ptr; parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter)); if (parameter_ptr == NULL) { jack_error("Cannot allocate memory for jackctl_parameter structure."); goto fail; } parameter_ptr->name = name; parameter_ptr->short_description = short_description; parameter_ptr->long_description = long_description; parameter_ptr->type = type; parameter_ptr->is_set = false; if (value_ptr == NULL) { value_ptr = ¶meter_ptr->value; } if (default_value_ptr == NULL) { default_value_ptr = ¶meter_ptr->default_value; } parameter_ptr->value_ptr = value_ptr; parameter_ptr->default_value_ptr = default_value_ptr; *value_ptr = *default_value_ptr = value; parameter_ptr->driver_ptr = NULL; parameter_ptr->driver_parameter_ptr = NULL; parameter_ptr->id = id; parameter_ptr->constraint_ptr = constraint_ptr; *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr); return parameter_ptr; fail: return NULL; } static void jackctl_free_driver_parameters( struct jackctl_driver * driver_ptr) { JSList * next_node_ptr; while (driver_ptr->parameters) { next_node_ptr = driver_ptr->parameters->next; free(driver_ptr->parameters->data); free(driver_ptr->parameters); driver_ptr->parameters = next_node_ptr; } while (driver_ptr->set_parameters) { next_node_ptr = driver_ptr->set_parameters->next; free(driver_ptr->set_parameters->data); free(driver_ptr->set_parameters); driver_ptr->set_parameters = next_node_ptr; } } static bool jackctl_add_driver_parameters( struct jackctl_driver * driver_ptr) { uint32_t i; union jackctl_parameter_value jackctl_value; jackctl_param_type_t jackctl_type; struct jackctl_parameter * parameter_ptr; jack_driver_param_desc_t * descriptor_ptr; for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++) { descriptor_ptr = driver_ptr->desc_ptr->params + i; switch (descriptor_ptr->type) { case JackDriverParamInt: jackctl_type = JackParamInt; jackctl_value.i = descriptor_ptr->value.i; break; case JackDriverParamUInt: jackctl_type = JackParamUInt; jackctl_value.ui = descriptor_ptr->value.ui; break; case JackDriverParamChar: jackctl_type = JackParamChar; jackctl_value.c = descriptor_ptr->value.c; break; case JackDriverParamString: jackctl_type = JackParamString; strcpy(jackctl_value.str, descriptor_ptr->value.str); break; case JackDriverParamBool: jackctl_type = JackParamBool; jackctl_value.b = descriptor_ptr->value.i; break; default: jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type); assert(0); goto fail; } parameter_ptr = jackctl_add_parameter( &driver_ptr->parameters, descriptor_ptr->character, descriptor_ptr->name, descriptor_ptr->short_desc, descriptor_ptr->long_desc, jackctl_type, NULL, NULL, jackctl_value, descriptor_ptr->constraint); if (parameter_ptr == NULL) { goto fail; } parameter_ptr->driver_ptr = driver_ptr; } return true; fail: jackctl_free_driver_parameters(driver_ptr); return false; } static jack_driver_desc_t * jack_drivers_get_descriptor (JSList * drivers, const char * sofile) { jack_driver_desc_t * descriptor, * other_descriptor; JackDriverDescFunction so_get_descriptor; JSList * node; void * dlhandle; char * filename; const char * dlerr; int err; char* driver_dir; if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { driver_dir = ADDON_DIR; } filename = malloc (strlen (driver_dir) + 1 + strlen (sofile) + 1); sprintf (filename, "%s/%s", driver_dir, sofile); // if (verbose) { // jack_info ("getting driver descriptor from %s", filename); // } if ((dlhandle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL)) == NULL) { jack_error ("could not open driver .so '%s': %s\n", filename, dlerror ()); free (filename); return NULL; } so_get_descriptor = (JackDriverDescFunction) dlsym (dlhandle, "driver_get_descriptor"); if ((dlerr = dlerror ()) != NULL) { jack_error("%s", dlerr); dlclose (dlhandle); free (filename); return NULL; } if ((descriptor = so_get_descriptor ()) == NULL) { jack_error ("driver from '%s' returned NULL descriptor\n", filename); dlclose (dlhandle); free (filename); return NULL; } if ((err = dlclose (dlhandle)) != 0) { jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ()); } /* check it doesn't exist already */ for (node = drivers; node; node = jack_slist_next (node)) { other_descriptor = (jack_driver_desc_t *) node->data; if (strcmp (descriptor->name, other_descriptor->name) == 0) { jack_error ("the drivers in '%s' and '%s' both have the name '%s'; using the first\n", other_descriptor->file, filename, other_descriptor->name); /* FIXME: delete the descriptor */ free (filename); return NULL; } } snprintf (descriptor->file, sizeof(descriptor->file), "%s", filename); free (filename); return descriptor; } static JSList * jack_drivers_load () { struct dirent * dir_entry; DIR * dir_stream; const char * ptr; int err; JSList * driver_list = NULL; jack_driver_desc_t * desc; char* driver_dir; if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { driver_dir = ADDON_DIR; } /* search through the driver_dir and add get descriptors from the .so files in it */ dir_stream = opendir (driver_dir); if (!dir_stream) { jack_error ("could not open driver directory %s: %s\n", driver_dir, strerror (errno)); return NULL; } while ( (dir_entry = readdir (dir_stream)) ) { /* check the filename is of the right format */ if (strncmp ("jack_", dir_entry->d_name, 5) != 0) { continue; } ptr = strrchr (dir_entry->d_name, '.'); if (!ptr) { continue; } ptr++; if (strncmp ("so", ptr, 2) != 0) { continue; } desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name); if (desc) { driver_list = jack_slist_append (driver_list, desc); } } err = closedir (dir_stream); if (err) { jack_error ("error closing driver directory %s: %s\n", driver_dir, strerror (errno)); } if (!driver_list) { jack_error ("could not find any drivers in %s!\n", driver_dir); return NULL; } return driver_list; } static void jack_cleanup_files (const char *server_name) { DIR *dir; struct dirent *dirent; char dir_name[PATH_MAX+1] = ""; jack_server_dir (server_name, dir_name); /* On termination, we remove all files that jackd creates so * subsequent attempts to start jackd will not believe that an * instance is already running. If the server crashes or is * terminated with SIGKILL, this is not possible. So, cleanup * is also attempted when jackd starts. * * There are several tricky issues. First, the previous JACK * server may have run for a different user ID, so its files * may be inaccessible. This is handled by using a separate * JACK_TMP_DIR subdirectory for each user. Second, there may * be other servers running with different names. Each gets * its own subdirectory within the per-user directory. The * current process has already registered as `server_name', so * we know there is no other server actively using that name. */ /* nothing to do if the server directory does not exist */ if ((dir = opendir (dir_name)) == NULL) { return; } /* unlink all the files in this directory, they are mine */ while ((dirent = readdir (dir)) != NULL) { char fullpath[PATH_MAX+1]; if ((strcmp (dirent->d_name, ".") == 0) || (strcmp (dirent->d_name, "..") == 0)) { continue; } snprintf (fullpath, sizeof (fullpath), "%s/%s", dir_name, dirent->d_name); if (unlink (fullpath)) { jack_error ("cannot unlink `%s' (%s)", fullpath, strerror (errno)); } } closedir (dir); /* now, delete the per-server subdirectory, itself */ if (rmdir (dir_name)) { jack_error ("cannot remove `%s' (%s)", dir_name, strerror (errno)); } /* finally, delete the per-user subdirectory, if empty */ if (rmdir (jack_user_dir ())) { if (errno != ENOTEMPTY) { jack_error ("cannot remove `%s' (%s)", jack_user_dir (), strerror (errno)); } } } static int jackctl_drivers_load( struct jackctl_server * server_ptr) { struct jackctl_driver * driver_ptr; JSList *node_ptr; JSList *descriptor_node_ptr; descriptor_node_ptr = jack_drivers_load(); if (descriptor_node_ptr == NULL) { jack_error("could not find any drivers in driver directory!"); return false; } while (descriptor_node_ptr != NULL) { driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver)); if (driver_ptr == NULL) { jack_error("memory allocation of jackctl_driver structure failed."); goto next; } driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; driver_ptr->parameters = NULL; driver_ptr->set_parameters = NULL; if (!jackctl_add_driver_parameters(driver_ptr)) { assert(driver_ptr->parameters == NULL); free(driver_ptr); goto next; } server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr); next: node_ptr = descriptor_node_ptr; descriptor_node_ptr = descriptor_node_ptr->next; free(node_ptr); } return true; } static void jackctl_server_free_drivers( struct jackctl_server * server_ptr) { JSList * next_node_ptr; struct jackctl_driver * driver_ptr; while (server_ptr->drivers) { next_node_ptr = server_ptr->drivers->next; driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data; jackctl_free_driver_parameters(driver_ptr); free(driver_ptr->desc_ptr->params); free(driver_ptr->desc_ptr); free(driver_ptr); free(server_ptr->drivers); server_ptr->drivers = next_node_ptr; } } static int jackctl_internals_load( struct jackctl_server * server_ptr) { struct jackctl_internal * internal_ptr; JSList *node_ptr; JSList *descriptor_node_ptr = NULL; //XXX: jack1 doesnt support internals enumeration. //descriptor_node_ptr = jack_internals_load(NULL); if (descriptor_node_ptr == NULL) { return false; } while (descriptor_node_ptr != NULL) { internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal)); if (internal_ptr == NULL) { jack_error("memory allocation of jackctl_driver structure failed."); goto next; } internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; internal_ptr->parameters = NULL; internal_ptr->set_parameters = NULL; if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr)) { assert(internal_ptr->parameters == NULL); free(internal_ptr); goto next; } server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr); next: node_ptr = descriptor_node_ptr; descriptor_node_ptr = descriptor_node_ptr->next; free(node_ptr); } return true; } static void jackctl_server_free_internals( struct jackctl_server * server_ptr) { JSList * next_node_ptr; struct jackctl_internal * internal_ptr; while (server_ptr->internals) { next_node_ptr = server_ptr->internals->next; internal_ptr = (struct jackctl_internal *)server_ptr->internals->data; jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr); free(internal_ptr->desc_ptr->params); free(internal_ptr->desc_ptr); free(internal_ptr); free(server_ptr->internals); server_ptr->internals = next_node_ptr; } } static void jackctl_server_free_parameters( struct jackctl_server * server_ptr) { JSList * next_node_ptr; while (server_ptr->parameters) { next_node_ptr = server_ptr->parameters->next; free(server_ptr->parameters->data); free(server_ptr->parameters); server_ptr->parameters = next_node_ptr; } } #ifdef WIN32 static HANDLE waitEvent; static void do_nothing_handler(int signum) { printf("jack main caught signal %d\n", signum); (void) signal(SIGINT, SIG_DFL); SetEvent(waitEvent); } sigset_t jackctl_setup_signals( unsigned int flags) { if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { jack_error("CreateEvent fails err = %ld", GetLastError()); return 0; } (void) signal(SIGINT, do_nothing_handler); (void) signal(SIGABRT, do_nothing_handler); (void) signal(SIGTERM, do_nothing_handler); return (sigset_t)waitEvent; } void jackctl_wait_signals(sigset_t signals) { if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { jack_error("WaitForSingleObject fails err = %ld", GetLastError()); } } #else static void do_nothing_handler(int sig) { /* this is used by the child (active) process, but it never gets called unless we are already shutting down after another signal. */ char buf[64]; snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig); } sigset_t jackctl_setup_signals( unsigned int flags) { sigset_t signals; sigset_t allsignals; struct sigaction action; int i; /* ensure that we are in our own process group so that kill (SIG, -pgrp) does the right thing. */ setsid(); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* what's this for? POSIX says that signals are delivered like this: * if a thread has blocked that signal, it is not a candidate to receive the signal. * of all threads not blocking the signal, pick one at random, and deliver the signal. this means that a simple-minded multi-threaded program can expect to get POSIX signals delivered randomly to any one of its threads, here, we block all signals that we think we might receive and want to catch. all "child" threads will inherit this setting. if we create a thread that calls sigwait() on the same set of signals, implicitly unblocking all those signals. any of those signals that are delivered to the process will be delivered to that thread, and that thread alone. this makes cleanup for a signal-driven exit much easier, since we know which thread is doing it and more importantly, we are free to call async-unsafe functions, because the code is executing in normal thread context after a return from sigwait(). */ sigemptyset(&signals); sigaddset(&signals, SIGHUP); sigaddset(&signals, SIGINT); sigaddset(&signals, SIGQUIT); sigaddset(&signals, SIGPIPE); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGUSR1); sigaddset(&signals, SIGUSR2); /* all child threads will inherit this mask unless they * explicitly reset it */ pthread_sigmask(SIG_BLOCK, &signals, 0); /* install a do-nothing handler because otherwise pthreads behaviour is undefined when we enter sigwait. */ sigfillset(&allsignals); action.sa_handler = do_nothing_handler; action.sa_mask = allsignals; action.sa_flags = SA_RESTART|SA_RESETHAND; for (i = 1; i < NSIG; i++) { if (sigismember (&signals, i)) { sigaction(i, &action, 0); } } return signals; } void jackctl_wait_signals(sigset_t signals) { int sig; bool waiting = true; while (waiting) { #if defined(sun) && !defined(__sun__) // SUN compiler only, to check sigwait(&signals); #else sigwait(&signals, &sig); #endif fprintf(stderr, "jack main caught signal %d\n", sig); switch (sig) { case SIGUSR1: //jack_dump_configuration(engine, 1); break; case SIGUSR2: // driver exit waiting = false; break; case SIGTTOU: break; default: waiting = false; break; } } if (sig != SIGSEGV) { // unblock signals so we can see them during shutdown. // this will help prod developers not to lose sight of // bugs that cause segfaults etc. during shutdown. sigprocmask(SIG_UNBLOCK, &signals, 0); } } #endif static sigset_t jackctl_block_signals() { sigset_t signals; sigset_t oldsignals; sigemptyset(&signals); sigaddset(&signals, SIGHUP); sigaddset(&signals, SIGINT); sigaddset(&signals, SIGQUIT); sigaddset(&signals, SIGPIPE); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGUSR1); sigaddset(&signals, SIGUSR2); pthread_sigmask(SIG_BLOCK, &signals, &oldsignals); return oldsignals; } static void jackctl_unblock_signals(sigset_t oldsignals) { pthread_sigmask(SIG_SETMASK, &oldsignals, 0); } static jack_driver_param_constraint_desc_t * get_realtime_priority_constraint() { #ifndef __OpenBSD__ jack_driver_param_constraint_desc_t * constraint_ptr; int max = sched_get_priority_max (SCHED_FIFO); int min = sched_get_priority_min (SCHED_FIFO); //jack_info("realtime priority range is (%d,%d)", min, max); constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t)); if (constraint_ptr == NULL) { jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure."); return NULL; } constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE; constraint_ptr->constraint.range.min.i = min; constraint_ptr->constraint.range.max.i = max; return constraint_ptr; #else return NULL #endif } jackctl_server_t * jackctl_server_create( bool (* on_device_acquire)(const char * device_name), void (* on_device_release)(const char * device_name)) { struct jackctl_server * server_ptr; union jackctl_parameter_value value; server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server)); if (server_ptr == NULL) { jack_error("Cannot allocate memory for jackctl_server structure."); goto fail; } server_ptr->drivers = NULL; server_ptr->internals = NULL; server_ptr->parameters = NULL; server_ptr->engine = NULL; strcpy(value.str, jack_default_server_name() ); if (jackctl_add_parameter( &server_ptr->parameters, 'n', "name", "Server name to use.", "", JackParamString, &server_ptr->name, &server_ptr->default_name, value, NULL) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, 'R', "realtime", "Whether to use realtime mode.", "Use realtime scheduling. This is needed for reliable low-latency performance. On most systems, it requires JACK to run with special scheduler and memory allocation privileges, which may be obtained in several ways. On Linux you should use PAM.", JackParamBool, &server_ptr->realtime, &server_ptr->default_realtime, value, NULL) == NULL) { goto fail_free_parameters; } value.i = 10; if (jackctl_add_parameter( &server_ptr->parameters, 'P', "realtime-priority", "Scheduler priority when running in realtime mode.", "", JackParamInt, &server_ptr->realtime_priority, &server_ptr->default_realtime_priority, value, get_realtime_priority_constraint() ) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, 'T', "temporary", "Exit once all clients have closed their connections.", "", JackParamBool, &server_ptr->temporary, &server_ptr->default_temporary, value, NULL) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, 'v', "verbose", "Verbose mode.", "", JackParamBool, &server_ptr->verbose, &server_ptr->default_verbose, value, NULL) == NULL) { goto fail_free_parameters; } value.i = 0; if (jackctl_add_parameter( &server_ptr->parameters, 't', "client-timeout", "Client timeout limit in milliseconds.", "", JackParamInt, &server_ptr->client_timeout, &server_ptr->default_client_timeout, value, NULL) == NULL) { goto fail_free_parameters; } value.ui = 0; if (jackctl_add_parameter( &server_ptr->parameters, 'c', "clock-source", "Clocksource type : c(ycle) | h(pet) | s(ystem).", "", JackParamUInt, &server_ptr->clock_source, &server_ptr->default_clock_source, value, NULL) == NULL) { goto fail_free_parameters; } value.ui = 128; if (jackctl_add_parameter( &server_ptr->parameters, 'p', "port-max", "Maximum number of ports.", "", JackParamUInt, &server_ptr->port_max, &server_ptr->default_port_max, value, NULL) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, '\0', "replace-registry", "Replace shared memory registry.", "", JackParamBool, &server_ptr->replace_registry, &server_ptr->default_replace_registry, value, NULL) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, 'm', "mlock", "Use mlock.", "", JackParamBool, &server_ptr->do_mlock, &server_ptr->default_do_mlock, value, NULL) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, 'u', "unlock", "munlock memory for big libraries", "", JackParamBool, &server_ptr->do_unlock, &server_ptr->default_do_unlock, value, NULL) == NULL) { goto fail_free_parameters; } value.b = false; if (jackctl_add_parameter( &server_ptr->parameters, 'Z', "nozombies", "dont zombifiy offending clients", "", JackParamBool, &server_ptr->nozombies, &server_ptr->default_nozombies, value, NULL) == NULL) { goto fail_free_parameters; } value.ui = 0; if (jackctl_add_parameter( &server_ptr->parameters, 'C', "timeout-threshold", "threshold for suspending processing", "", JackParamUInt, &server_ptr->timothres, &server_ptr->default_timothres, value, NULL) == NULL) { goto fail_free_parameters; } //TODO: need //JackServerGlobals::on_device_acquire = on_device_acquire; //JackServerGlobals::on_device_release = on_device_release; if (!jackctl_drivers_load(server_ptr)) { goto fail_free_parameters; } /* Allowed to fail */ jackctl_internals_load(server_ptr); return server_ptr; fail_free_parameters: jackctl_server_free_parameters(server_ptr); free(server_ptr); fail: return NULL; } void jackctl_server_destroy(jackctl_server_t *server_ptr) { jackctl_server_free_drivers(server_ptr); jackctl_server_free_internals(server_ptr); jackctl_server_free_parameters(server_ptr); free(server_ptr); } const JSList * jackctl_server_get_drivers_list(jackctl_server_t *server_ptr) { return server_ptr->drivers; } bool jackctl_server_stop(jackctl_server_t *server_ptr) { //jack_engine_driver_exit (server_ptr->engine); jack_engine_delete (server_ptr->engine); /* clean up shared memory and files from this server instance */ //jack_log("cleaning up shared memory"); jack_cleanup_shm(); //jack_log("cleaning up files"); jack_cleanup_files (server_ptr->name.str); //jack_log("unregistering server `%s'", server_ptr->name.str); jack_unregister_server(server_ptr->name.str); server_ptr->engine = NULL; return true; } const JSList * jackctl_server_get_parameters(jackctl_server_t *server_ptr) { return server_ptr->parameters; } bool jackctl_server_start( jackctl_server_t *server_ptr, jackctl_driver_t *driver_ptr) { int rc; sigset_t oldsignals; // TODO: int frame_time_offset = 0; rc = jack_register_server (server_ptr->name.str, server_ptr->replace_registry.b); switch (rc) { case EEXIST: jack_error("`%s' server already active", server_ptr->name.str); goto fail; case ENOSPC: jack_error("too many servers already active"); goto fail; case ENOMEM: jack_error("no access to shm registry"); goto fail; } //jack_log("server `%s' registered", server_ptr->name.str); /* clean up shared memory and files from any previous * instance of this server name */ jack_cleanup_shm (); jack_cleanup_files (server_ptr->name.str); if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ oldsignals = jackctl_block_signals(); if ((server_ptr->engine = jack_engine_new (server_ptr->realtime.b, server_ptr->realtime_priority.i, server_ptr->do_mlock.b, server_ptr->do_unlock.b, server_ptr->name.str, server_ptr->temporary.b, server_ptr->verbose.b, server_ptr->client_timeout.i, server_ptr->port_max.i, getpid(), frame_time_offset, server_ptr->nozombies.b, server_ptr->timothres.ui, drivers)) == 0) { jack_error ("cannot create engine"); goto fail_unregister; } if (jack_engine_load_driver (server_ptr->engine, driver_ptr->desc_ptr, driver_ptr->set_parameters)) { jack_error ("cannot load driver module %s", driver_ptr->desc_ptr->name); goto fail_delete; } if (server_ptr->engine->driver->start (server_ptr->engine->driver) != 0) { jack_error ("cannot start driver"); goto fail_close; } jackctl_unblock_signals( oldsignals ); return true; fail_close: fail_delete: jack_engine_delete (server_ptr->engine); server_ptr->engine = NULL; fail_unregister: //jack_log("cleaning up shared memory"); jack_cleanup_shm(); //jack_log("cleaning up files"); jack_cleanup_files(server_ptr->name.str); //jack_log("unregistering server `%s'", server_ptr->name.str); jack_unregister_server(server_ptr->name.str); jackctl_unblock_signals( oldsignals ); fail: return false; } const char * jackctl_driver_get_name(jackctl_driver_t *driver_ptr) { return driver_ptr->desc_ptr->name; } const JSList * jackctl_driver_get_parameters(jackctl_driver_t *driver_ptr) { return driver_ptr->parameters; } jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver_t *driver_ptr) { return driver_ptr->desc_ptr; } const char * jackctl_parameter_get_name(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->name; } const char * jackctl_parameter_get_short_description(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->short_description; } const char * jackctl_parameter_get_long_description(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->long_description; } bool jackctl_parameter_has_range_constraint(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0; } bool jackctl_parameter_has_enum_constraint(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0; } uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter_t *parameter_ptr) { if (!jackctl_parameter_has_enum_constraint(parameter_ptr)) { return 0; } return parameter_ptr->constraint_ptr->constraint.enumeration.count; } union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter_t *parameter_ptr, uint32_t index) { jack_driver_param_value_t * value_ptr; union jackctl_parameter_value jackctl_value; value_ptr = ¶meter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value; switch (parameter_ptr->type) { case JackParamInt: jackctl_value.i = value_ptr->i; break; case JackParamUInt: jackctl_value.ui = value_ptr->ui; break; case JackParamChar: jackctl_value.c = value_ptr->c; break; case JackParamString: strcpy(jackctl_value.str, value_ptr->str); break; default: jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type); assert(0); } return jackctl_value; } const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter_t *parameter_ptr, uint32_t index) { return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc; } void jackctl_parameter_get_range_constraint(jackctl_parameter_t *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr) { switch (parameter_ptr->type) { case JackParamInt: min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i; max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i; return; case JackParamUInt: min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui; max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui; return; default: jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type); assert(0); } } bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr) { return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0; } bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr) { return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0; } jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->type; } char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr) { return parameter_ptr->id; } bool jackctl_parameter_is_set(jackctl_parameter_t *parameter_ptr) { return parameter_ptr->is_set; } union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter_t *parameter_ptr) { return *(parameter_ptr->value_ptr); } bool jackctl_parameter_reset(jackctl_parameter_t *parameter_ptr) { if (!parameter_ptr->is_set) { return true; } parameter_ptr->is_set = false; *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr; return true; } bool jackctl_parameter_set_value(jackctl_parameter_t *parameter_ptr, const union jackctl_parameter_value * value_ptr) { bool new_driver_parameter; /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */ if (parameter_ptr->driver_ptr != NULL) { /* jack_info("setting driver parameter %p ...", parameter_ptr); */ new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL; if (new_driver_parameter) { /* jack_info("new driver parameter..."); */ parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t)); if (parameter_ptr->driver_parameter_ptr == NULL) { jack_error ("Allocation of jack_driver_param_t structure failed"); return false; } parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id; parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); } switch (parameter_ptr->type) { case JackParamInt: parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i; break; case JackParamUInt: parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui; break; case JackParamChar: parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c; break; case JackParamString: strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str); break; case JackParamBool: parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b; break; default: jack_error("unknown parameter type %i", (int)parameter_ptr->type); assert(0); if (new_driver_parameter) { parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); } return false; } } parameter_ptr->is_set = true; *parameter_ptr->value_ptr = *value_ptr; return true; } union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter_t *parameter_ptr) { return *(parameter_ptr->default_value_ptr); } // Internals clients const JSList * jackctl_server_get_internals_list(jackctl_server_t *server_ptr) { return server_ptr->internals; } const char * jackctl_internal_get_name(jackctl_internal_t *internal_ptr) { return internal_ptr->desc_ptr->name; } const JSList * jackctl_internal_get_parameters(jackctl_internal_t *internal_ptr) { return internal_ptr->parameters; } bool jackctl_server_load_internal( jackctl_server_t * server_ptr, jackctl_internal_t * internal) { return false; } bool jackctl_server_unload_internal( jackctl_server_t * server_ptr, jackctl_internal_t * internal) { return false; } bool jackctl_server_add_slave(jackctl_server_t * server_ptr, jackctl_driver_t * driver_ptr) { return false; } bool jackctl_server_remove_slave(jackctl_server_t * server_ptr, jackctl_driver_t * driver_ptr) { return false; } bool jackctl_server_switch_master(jackctl_server_t * server_ptr, jackctl_driver_t * driver_ptr) { jack_driver_t *old_driver; if (server_ptr->engine == NULL) goto fail_nostart; old_driver = server_ptr->engine->driver; if (old_driver) { old_driver->stop (old_driver ); old_driver->detach (old_driver, server_ptr->engine); pthread_mutex_lock (&server_ptr->engine->request_lock); jack_lock_graph (server_ptr->engine); jack_remove_client (server_ptr->engine, old_driver->internal_client); jack_unlock_graph (server_ptr->engine); pthread_mutex_unlock (&server_ptr->engine->request_lock); jack_stop_watchdog (server_ptr->engine); server_ptr->engine->driver = NULL; jack_driver_unload (old_driver); } if (jack_engine_load_driver (server_ptr->engine, driver_ptr->desc_ptr, driver_ptr->set_parameters)) { jack_error ("cannot load driver module %s", driver_ptr->desc_ptr->name); goto fail_nodriver; } if (server_ptr->engine->driver->start (server_ptr->engine->driver) != 0) { jack_error ("cannot start driver"); jack_use_driver(server_ptr->engine, NULL); goto fail_nodriver; } return true; fail_nodriver: jack_error ("could not initialise new driver, leaving without driver"); fail_nostart: return false; } jackd1-0.121.3+20120418git75e3e20b/jackd/transengine.h0000644001605600047420000000335011736346233017347 0ustar adiira/* Internal interfaces for JACK transport engine. 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. */ int jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes); int jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id); int jack_timebase_set (jack_engine_t *engine, jack_client_id_t client_id, int conditional); void jack_transport_activate (jack_engine_t *engine, jack_client_internal_t *client); void jack_transport_init (jack_engine_t *engine); void jack_transport_client_exit (jack_engine_t *engine, jack_client_internal_t *client); void jack_transport_client_new (jack_client_internal_t *client); int jack_transport_client_reset_sync (jack_engine_t *engine, jack_client_id_t client_id); int jack_transport_client_set_sync (jack_engine_t *engine, jack_client_id_t client_id); void jack_transport_cycle_end (jack_engine_t *engine); void jack_transport_cycle_start(jack_engine_t *engine, jack_time_t time); int jack_transport_set_sync_timeout (jack_engine_t *engine, jack_time_t usecs); jackd1-0.121.3+20120418git75e3e20b/jackd/jackd.1.in0000644001605600047420000004766111736346233016441 0ustar adiira.TH "JACKD" "1" "@VERSION@" "April 2006" "" .SH "NAME" jackd \- JACK Audio Connection Kit sound server .SH "SYNOPSIS" \fBjackd\fR [\fIoptions\fR] \fB\-d\fI backend \fR [\fIbackend\-parameters\fR] .br \fBjackd \-\-help\fR .SH "DESCRIPTION" \fBjackd\fR is the JACK audio server daemon, a low\-latency audio server. Originally written for the GNU/Linux operating system, it also supports Mac OS X and various Unix platforms. JACK can connect a number of different client applications to an audio device and also to each other. Most clients are external, running in their own processes as normal applications. JACK also supports internal clients, which run within the \fBjackd\fR process using a loadable "plugin" interface. JACK differs from other audio servers in being designed from the ground up for professional audio work. It focuses on two key areas: synchronous execution of all clients, and low latency operation. For the latest JACK information, please consult the web site, <\fBhttp://www.jackaudio.org\fR>. .SH "OPTIONS" .TP \fB\-d, \-\-driver \fIbackend\fR [\fIbackend\-parameters\fR ] .br Select the audio interface backend. The current list of supported backends is: \fBalsa\fR, \fBcoreaudio\fR, \fBdummy\fR, \fBfreebob\fR, \fBoss\fR \fBsun\fR and \fBportaudio\fR. They are not all available on all platforms. All \fIbackend\-parameters\fR are optional. .TP \fB\-h, \-\-help\fR .br Print a brief usage message describing the main \fBjackd\fR options. These do not include \fIbackend\-parameters\fR, which are listed using the \fB\-\-help\fR option for each specific backend. Examples below show how to list them. .TP \fB\-m, \-\-no\-mlock\fR Do not attempt to lock memory, even if \fB\-\-realtime\fR. .TP \fB\-M, \-\-midi\-bufsize\fR [ \fIevent-count\fR ] Specify the size of the buffer used for MIDI ports. Units are "MIDI events per process() cycle", where an event occupies up to 4 bytes (as most common MIDI events do). The default buffer size is same as the one used for audio data, which will store about 2 MIDI events per sample. Typical values for \fIevent-count\fR will range from 10 to about 500. Be aware that using very high values along with a large number of ports may cause JACK to fail to start because of the amount of memory that would be required. .TP \fB\-n, \-\-name\fR \fIserver\-name\fR Name this \fBjackd\fR instance \fIserver\-name\fR. If unspecified, this name comes from the \fB$JACK_DEFAULT_SERVER\fR environment variable. It will be "default" if that is not defined. .TP \fB\-p, \-\-port\-max \fI n\fR Set the maximum number of ports the JACK server can manage. The default value is 256. .TP \fB\-\-replace-registry\fR .br Remove the shared memory registry used by all JACK server instances before startup. This should rarely be used, and is intended only for occasions when the structure of this registry changes in ways that are incompatible across JACK versions (which is rare). .TP \fB\-R, \-\-realtime\fR .br Use realtime scheduling (default = true). This is needed for reliable low\-latency performance. On many systems, it requires \fBjackd\fR to run with special scheduler and memory allocation privileges, which may be obtained in several ways. .TP \fB\-r, \-\-no-realtime\fR .br Do not use realtime scheduling. .TP \fB\-P, \-\-realtime\-priority \fIint\fR When running \fB\-\-realtime\fR, set the scheduler priority to \fIint\fR. .TP \fB\-\-silent\fR Silence any output during operation. .TP \fB\-S, \-\-sync\fR .br This option does nothing in this implementation of JACK, but exists for command-line compatibility with JACK2 and possibly other versions. .TP \fB\-T, \-\-temporary\fR Exit once all clients have closed their connections. .TP \fB\-t, \-\-timeout \fIint\fR .br Set client timeout limit in milliseconds. The default is 500 msec. In realtime mode the client timeout must be smaller than the watchdog timeout (5000 msec). .TP \fB\-Z, \-\-nozombies\fR .br Prevent JACK from ever kicking out clients because they were too slow. This cancels the effect any specified timeout value, but JACK and its clients are still subject to the supervision of the watchdog thread or its equivalent. .TP \fB\-C, \-\-timeout-thres \fItime\fR .br Stop processing clients if JACK cannot complete the process cycle in time (typically caused by CPU overloading or misbehaved clients). The optional \fItime\fR argument specifies the number of miliseconds, during which consectutive process cycles must fail before JACK gives up (if the argument is not given, it defaults to 250). Processing will resume on the next change to the port graph (i.e. a port is added, removed, connected or disconnected) .TP \fB\-u, \-\-unlock\fR .br Unlock libraries GTK+, QT, FLTK, Wine. .TP \fB\-v, \-\-verbose\fR Give verbose output. .TP \fB\-c, \-\-clocksource\fR (\fI c(ycle)\fR | \fI h(pet) \fR | \fI s(ystem) \fR) Select a specific wall clock (Cycle Counter, HPET timer, System timer). .TP \fB\-V, \-\-version\fR Print the current JACK version number and exit. .SS ALSA BACKEND OPTIONS .TP \fB\-C, \-\-capture\fR [ \fIname\fR ] Provide only capture ports, unless combined with \-D or \-P. Parameterally set capture device name. .TP \fB\-d, \-\-device \fIname\fR .br The ALSA pcm device \fIname\fR to use. If none is specified, JACK will use "hw:0", the first hardware card defined in \fB/etc/modules.conf\fR. .TP \fB\-z, \-\-dither [rectangular,triangular,shaped,none] Set dithering mode. If \fBnone\fR or unspecified, dithering is off. Only the first letter of the mode name is required. .TP \fB\-D, \-\-duplex\fR Provide both capture and playback ports. Defaults to on unless only one of \-P or \-C is specified. .TP \fB\-h, \-\-help\fR Print a brief usage message describing only the \fBalsa\fR backend parameters. .TP \fB\-M, \-\-hwmeter\fR .br Enable hardware metering for devices that support it. Otherwise, use software metering. .TP \fB\-H, \-\-hwmon\fR .br Enable hardware monitoring of capture ports. This is a method for obtaining "zero latency" monitoring of audio input. It requires support in hardware and from the underlying ALSA device driver. When enabled, requests to monitor capture ports will be satisfied by creating a direct signal path between audio interface input and output connectors, with no processing by the host computer at all. This offers the lowest possible latency for the monitored signal. Presently (March 2003), only the RME Hammerfall series and cards based on the ICE1712 chipset (M\-Audio Delta series, Terratec, and others) support \fB\-\-hwmon\fR. In the future, some consumer cards may also be supported by modifying their mixer settings. Without \fB\-\-hwmon\fR, port monitoring requires JACK to read audio into system memory, then copy it back out to the hardware again, imposing the basic JACK system latency determined by the \fB\-\-period\fR and \fB\-\-nperiods\fR parameters. .TP \fB\-i, \-\-inchannels \fIint\fR .br Number of capture channels. Default is maximum supported by hardware. .TP \fB\-n, \-\-nperiods \fIint\fR .br Specify the number of periods of playback latency. In seconds, this corresponds to \fB\-\-nperiods\fR times \fB\-\-period\fR divided by \fB\-\-rate\fR. The default is 2, the minimum allowable. For most devices, there is no need for any other value with the \fB\-\-realtime\fR option. Without realtime privileges or with boards providing unreliable interrupts (like ymfpci), a larger value may yield fewer xruns. This can also help if the system is not tuned for reliable realtime scheduling. For most ALSA devices, the hardware buffer has exactly \fB\-\-period\fR times \fB\-\-nperiods\fR frames. Some devices demand a larger buffer. If so, JACK will use the smallest possible buffer containing at least \fB\-\-nperiods\fR, but the playback latency does not increase. For USB audio devices it is recommended to use \fB\-n 3\fR. Firewire devices supported by FFADO (formerly Freebob) are configured with \fB\-n 3\fR by default. .TP \fB\-o, \-\-outchannels \fIint\fR .br Number of playback channels. Default is maximum supported by hardware. .TP \fB\-P, \-\-playback\fR [ \fIname\fR ] Provide only playback ports, unless combined with \-D or \-C. Optionally set playback device name. .TP \fB\-p, \-\-period \fIint\fR .br Specify the number of frames between JACK \fBprocess()\fR calls. This value must be a power of 2, and the default is 1024. If you need low latency, set \fB\-p\fR as low as you can go without seeing xruns. A larger period size yields higher latency, but makes xruns less likely. The JACK capture latency in seconds is \fB\-\-period\fR divided by \fB\-\-rate\fR. .TP \fB\-r, \-\-rate \fIint\fR Specify the sample rate. The default is 48000. .TP \fB\-S, \-\-shorts .br Try to configure card for 16\-bit samples first, only trying 32\-bits if unsuccessful. Default is to prefer 32\-bit samples. .TP \fB\-s, \-\-softmode\fR .br Ignore xruns reported by the ALSA driver. This makes JACK less likely to disconnect unresponsive ports when running without \fB\-\-realtime\fR. .TP \fB\-X, \-\-midi \fR[\fIseq\fR|\fIraw\fR] .br Specify which ALSA MIDI system to provide access to. Using \fBraw\fR will provide a set of JACK MIDI ports that correspond to each raw ALSA device on the machine. Using \fBseq\fR will provide a set of JACK MIDI ports that correspond to each ALSA "sequencer" client (which includes each hardware MIDI port on the machine). \fBraw\fR provides slightly better performance but does not permit JACK MIDI communication with software written to use the ALSA "sequencer" API. .SS COREAUDIO BACKEND PARAMETERS .TP \fB\-c \-\-channel\fR Maximum number of channels (default: 2) .TP \fB\-i \-\-channelin\fR Maximum number of input channels (default: 2) .TP \fB\-o \-\-channelout\fR Maximum number of output channels (default: 2) .TP \fB\-C \-\-capture\fR Whether or not to capture (default: true) .TP \fB\-P \-\-playback\fR Whether or not to playback (default: true) .TP \fB\-D \-\-duplex\fR Capture and playback (default: true) .TP \fB\-r \-\-rate\fR Sample rate (default: 44100) .TP \fB\-p \-\-period\fR Frames per period (default: 128). Must be a power of 2. .TP \fB\-n \-\-name\fR Driver name (default: none) .TP \fB\-I \-\-id\fR Audio Device ID (default: 0) .SS DUMMY BACKEND PARAMETERS .TP \fB\-C, \-\-capture \fIint\fR Specify number of capture ports. The default value is 2. .TP \fB\-P, \-\-playback \fIint\fR Specify number of playback ports. The default value is 2. .TP \fB\-r, \-\-rate \fIint\fR Specify sample rate. The default value is 48000. .TP \fB\-p, \-\-period \fIint\fR Specify the number of frames between JACK \fBprocess()\fR calls. This value must be a power of 2, and the default is 1024. If you need low latency, set \fB\-p\fR as low as you can go without seeing xruns. A larger period size yields higher latency, but makes xruns less likely. The JACK capture latency in seconds is \fB\-\-period\fR divided by \fB\-\-rate\fR. .TP \fB\-w, \-\-wait \fIint\fR Specify number of usecs to wait between engine processes. The default value is 21333. .SS NET BACKEND PARAMETERS .TP \fB\-i, \-\-audio\-ins \fIint\fR Number of capture channels (default: 2) .TP \fB\-o, \-\-audio\-outs \fIint\fR Number of playback channels (default: 2) .TP \fB\-I, \-\-midi\-ins \fIint\fR Number of midi capture channels (default: 1) .TP \fB\-O, \-\-midi\-outs \fIint\fR Number of midi playback channels (default: 1) .TP \fB\-r, \-\-rate \fIint\fR Sample rate (default: 48000) .TP \fB\-p, \-\-period \fIint\fR Frames per period (default: 1024) .TP \fB\-n, \-\-num\-periods \fIint\fR Network latency setting in no. of periods (default: 5) .TP \fB\-l, \-\-listen\-port \fIint\fR The socket port we are listening on for sync packets (default: 3000) .TP \fB\-f, \-\-factor \fIint\fR Factor for sample rate reduction (default: 1) .TP \fB\-u, \-\-upstream\-factor \fIint\fR Factor for sample rate reduction on the upstream (default: 0) .TP \fB\-c, \-\-celt \fIint\fR sets celt encoding and number of kbits per channel (default: 0) .TP \fB\-b, \-\-bit\-depth \fIint\fR Sample bit\-depth (0 for float, 8 for 8bit and 16 for 16bit) (default: 0) .TP \fB\-t, \-\-transport\-sync \fIint\fR Whether to slave the transport to the master transport (default: true) .TP \fB\-a, \-\-autoconf \fIint\fR Whether to use Autoconfig, or just start. (default: true) .TP \fB\-R, \-\-redundancy \fIint\fR Send packets N times (default: 1) .TP \fB\-e, \-\-native\-endian \fIint\fR Dont convert samples to network byte order. (default: false) .TP \fB\-J, \-\-jitterval \fIint\fR attempted jitterbuffer microseconds on master (default: 0) .TP \fB\-D, \-\-always\-deadline \fIint\fR always use deadline (default: false) .SS OSS BACKEND PARAMETERS .TP \fB\-r, \-\-rate \fIint\fR Specify the sample rate. The default is 48000. .TP \fB\-p, \-\-period \fIint\fR Specify the number of frames between JACK \fBprocess()\fR calls. This value must be a power of 2, and the default is 1024. If you need low latency, set \fB\-p\fR as low as you can go without seeing xruns. A larger period size yields higher latency, but makes xruns less likely. The JACK capture latency in seconds is \fB\-\-period\fR divided by \fB\-\-rate\fR. .TP \fB\-n, \-\-nperiods \fIint\fR Specify the number of periods in the hardware buffer. The default is 2. The period size (\fB\-p\fR) times \fB\-\-nperiods\fR times four is the JACK buffer size in bytes. The JACK output latency in seconds is \fB\-\-nperiods\fR times \fB\-\-period\fR divided by \fB\-\-rate\fR. .TP \fB\-w, \-\-wordlength \fIint\fR Specify the sample size in bits. The default is 16. .TP \fB\-i, \-\-inchannels \fIint\fR Specify how many channels to capture (default: 2) .TP \fB\-o, \-\-outchannels \fIint\fR Specify number of playback channels (default: 2) .TP \fB\-C, \-\-capture \fIdevice_file\fR Specify input device for capture (default: /dev/dsp) .TP \fB\-P, \-\-playback \fIdevice_file\fR Specify output device for playback (default: /dev/dsp) .TP \fB\-b, \-\-ignorehwbuf \fIboolean\fR Specify, whether to ignore hardware period size (default: false) .SS SUN BACKEND PARAMETERS .TP \fB\-r, \-\-rate \fIint\fR Specify the sample rate. The default is 48000. .TP \fB\-p, \-\-period \fIint\fR Specify the number of frames between JACK \fBprocess()\fR calls. This value must be a power of 2, and the default is 1024. If you need low latency, set \fB\-p\fR as low as you can go without seeing xruns. A larger period size yields higher latency, but makes xruns less likely. The JACK capture latency in seconds is \fB\-\-period\fR divided by \fB\-\-rate\fR. .TP \fB\-n, \-\-nperiods \fIint\fR Specify the number of periods in the hardware buffer. The default is 2. The period size (\fB\-p\fR) times \fB\-\-nperiods\fR times four (assuming 2 channels 16-bit samples) is the JACK buffer size in bytes. The JACK output latency in seconds is \fB\-\-nperiods\fR times \fB\-\-period\fR divided by \fB\-\-rate\fR. .TP \fB\-w, \-\-wordlength \fIint\fR Specify the sample size in bits. The default is 16. .TP \fB\-i, \-\-inchannels \fIint\fR Specify how many channels to capture (default: 2) .TP \fB\-o, \-\-outchannels \fIint\fR Specify number of playback channels (default: 2) .TP \fB\-C, \-\-capture \fIdevice_file\fR Specify input device for capture (default: /dev/audio) .TP \fB\-P, \-\-playback \fIdevice_file\fR Specify output device for playback (default: /dev/audio) .TP \fB\-b, \-\-ignorehwbuf \fIboolean\fR Specify, whether to ignore hardware period size (default: false) .SS PORTAUDIO BACKEND PARAMETERS .TP \fB\-c \-\-channel\fR Maximum number of channels (default: all available hardware channels) .TP \fB\-i \-\-channelin\fR Maximum number of input channels (default: all available hardware channels) .TP \fB\-o \-\-channelout\fR Maximum number of output channels (default: all available hardware channels) .TP \fB\-C \-\-capture\fR Whether or not to capture (default: true) .TP \fB\-P \-\-playback\fR Whether or not to playback (default: true) .TP \fB\-D \-\-duplex\fR Capture and playback (default: true) .TP \fB\-r \-\-rate\fR Sample rate (default: 48000) .TP \fB\-p \-\-period\fR Frames per period (default: 1024). Must be a power of 2. .TP \fB\-n \-\-name\fR Driver name (default: none) .TP \fB\-z \-\-dither\fR Dithering mode (default: none) .SH "EXAMPLES" .PP Print usage message for the parameters specific to each backend. .IP \fBjackd \-d alsa \-\-help\fR .br \fBjackd \-d coreaudio \-\-help\fR .br \fBjackd \-d net \-\-help\fR .br \fBjackd \-d dummy \-\-help\fR .br \fBjackd \-d firewire \-\-help\fR .br \fBjackd \-d freebob \-\-help\fR .br \fBjackd \-d oss \-\-help\fR .br \fBjackd \-d sun \-\-help\fR .br \fBjackd \-d portaudio \-\-help\fR .PP Run the JACK daemon with realtime priority using the first ALSA hardware card defined in \fB/etc/modules.conf\fR. .IP \fBjackstart \-\-realtime \-\-driver=alsa\fR .PP Run the JACK daemon with low latency giving verbose output, which can be helpful for trouble\-shooting system latency problems. A reasonably well\-tuned system with a good sound card and a low\-latency kernel can handle these values reliably. Some can do better. If you get xrun messages, try a larger buffer. Tuning a system for low latency can be challenging. The JACK FAQ, .I http://jackit.sourceforge.net/docs/faq.php\fR has some useful suggestions. .IP \fBjackstart \-Rv \-d alsa \-p 128 \-n 2 \-r 44100\fR .PP Run \fBjackd\fR with realtime priority using the "sblive" ALSA device defined in ~/.asoundrc. Apply shaped dithering to playback audio. .IP \fBjackd \-R \-d alsa \-d sblive \-\-dither=shaped\fR .PP Run \fBjackd\fR with no special privileges using the second ALSA hardware card defined in \fB/etc/modules.conf\fR. Any xruns reported by the ALSA backend will be ignored. The larger buffer helps reduce data loss. Rectangular dithering will be used for playback. .IP \fBjackd \-d alsa \-d hw:1 \-p2048 \-n3 \-\-softmode \-zr\fR .PP Run \fBjackd\fR in full\-duplex mode using the ALSA hw:0,0 device for playback and the hw:0,2 device for capture. .IP \fBjackd \-d alsa \-P hw:0,0 \-C hw:0,2\fR .PP Run \fBjackd\fR in playback\-only mode using the ALSA hw:0,0 device. .IP \fBjackd \-d alsa \-P hw:0,0\fR .SH "ENVIRONMENT" .br JACK is evolving a mechanism for automatically starting the server when needed. Any client started without a running JACK server will attempt to start one itself using the command line found in the first line of \fB$HOME/.jackdrc\fR if it exists, or \fB/etc/jackdrc\fR if it does not. If neither file exists, a built\-in default command will be used, including the \fB\-T\fR flag, which causes the server to shut down when all clients have exited. As a transition, this only happens when \fB$JACK_START_SERVER\fR is defined in the environment of the calling process. In the future this will become normal behavior. In either case, defining \fB$JACK_NO_START_SERVER\fR disables this feature. To change where JACK looks for the backend drivers, set \fB$JACK_DRIVER_DIR\fR. \fB$JACK_DEFAULT_SERVER\fR specifies the default server name. If not defined, the string "default" is used. If set in their respective environments, this affects \fBjackd\fR unless its \fB\-\-name\fR parameter is set, and all JACK clients unless they pass an explicit name to \fBjack_client_open()\fR. .SH "SEE ALSO:" .PP .I http://www.jackaudio.org .br The official JACK website with news, docs and a list of JACK clients. .PP .I http://jackaudio.org/email .br The JACK developers' mailing list. Subscribe, to take part in development of JACK or JACK clients. User questions are also welcome, there is no user-specific mailing list. .PP .I http://www.jackosx.com/ .br Tools specific to the Mac OS X version of JACK. .PP .I http://www.alsa\-project.org .br The Advanced Linux Sound Architecture. .SH "BUGS" Please report bugs to .br .I http://trac.jackaudio.org/ .SH "AUTHORS" Architect and original implementor: Paul Davis .PP Original design Group: Paul Davis, David Olofson, Kai Vehmanen, Benno Sennoner, Richard Guenther, and other members of the Linux Audio Developers group. .PP Programming: Paul Davis, Jack O'Quin, Taybin Rutkin, Stephane Letz, Fernando Pablo Lopez-Lezcano, Steve Harris, Jeremy Hall, Andy Wingo, Kai Vehmanen, Melanie Thielker, Jussi Laako, Tilman Linneweh, Johnny Petrantoni, Torben Hohn. .PP Manpage written by Stefan Schwandter, Jack O'Quin and Alexandre Prokoudine. jackd1-0.121.3+20120418git75e3e20b/jackd/jackd.c0000644001605600047420000005006611736346233016107 0ustar adiira/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Copyright (C) 2001-2005 Paul Davis 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "engine.h" #include "internal.h" #include "driver.h" #include "shm.h" #include "driver_parse.h" #include "messagebuffer.h" #ifdef USE_CAPABILITIES #include /* capgetp and capsetp are linux only extensions, not posix */ #undef _POSIX_SOURCE #include #include "start.h" static struct stat pipe_stat; #endif /* USE_CAPABILITIES */ static JSList *drivers = NULL; static sigset_t signals; static jack_engine_t *engine = NULL; static char *server_name = NULL; static int realtime = 1; static int realtime_priority = 10; static int do_mlock = 1; static int temporary = 0; static int verbose = 0; static int client_timeout = 0; /* msecs; if zero, use period size. */ static unsigned int port_max = 256; static int do_unlock = 0; static jack_nframes_t frame_time_offset = 0; static int nozombies = 0; static int timeout_count_threshold = 0; extern int sanitycheck (int, int); static jack_driver_desc_t * jack_find_driver_descriptor (const char * name); static void do_nothing_handler (int sig) { /* this is used by the child (active) process, but it never gets called unless we are already shutting down after another signal. */ char buf[64]; snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig); write (1, buf, strlen (buf)); } static int jack_main (jack_driver_desc_t * driver_desc, JSList * driver_params, JSList * slave_names) { int sig; int i; sigset_t allsignals; struct sigaction action; int waiting; JSList * node; /* ensure that we are in our own process group so that kill (SIG, -pgrp) does the right thing. */ setsid (); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* what's this for? POSIX says that signals are delivered like this: * if a thread has blocked that signal, it is not a candidate to receive the signal. * of all threads not blocking the signal, pick one at random, and deliver the signal. this means that a simple-minded multi-threaded program can expect to get POSIX signals delivered randomly to any one of its threads, here, we block all signals that we think we might receive and want to catch. all "child" threads will inherit this setting. if we create a thread that calls sigwait() on the same set of signals, implicitly unblocking all those signals. any of those signals that are delivered to the process will be delivered to that thread, and that thread alone. this makes cleanup for a signal-driven exit much easier, since we know which thread is doing it and more importantly, we are free to call async-unsafe functions, because the code is executing in normal thread context after a return from sigwait(). */ sigemptyset (&signals); sigaddset(&signals, SIGHUP); sigaddset(&signals, SIGINT); sigaddset(&signals, SIGQUIT); sigaddset(&signals, SIGPIPE); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGUSR1); sigaddset(&signals, SIGUSR2); /* all child threads will inherit this mask unless they * explicitly reset it */ pthread_sigmask (SIG_BLOCK, &signals, 0); if (!realtime && client_timeout == 0) client_timeout = 500; /* 0.5 sec; usable when non realtime. */ /* get the engine/driver started */ if ((engine = jack_engine_new (realtime, realtime_priority, do_mlock, do_unlock, server_name, temporary, verbose, client_timeout, port_max, getpid(), frame_time_offset, nozombies, timeout_count_threshold, drivers)) == 0) { jack_error ("cannot create engine"); return -1; } jack_info ("loading driver .."); if (jack_engine_load_driver (engine, driver_desc, driver_params)) { jack_error ("cannot load driver module %s", driver_desc->name); goto error; } for (node=slave_names; node; node=jack_slist_next(node)) { char *sl_name = node->data; jack_driver_desc_t *sl_desc = jack_find_driver_descriptor(sl_name); if (sl_desc) { jack_engine_load_slave_driver(engine, sl_desc, NULL); } } if (jack_drivers_start (engine) != 0) { jack_error ("cannot start driver"); goto error; } /* install a do-nothing handler because otherwise pthreads behaviour is undefined when we enter sigwait. */ sigfillset (&allsignals); action.sa_handler = do_nothing_handler; action.sa_mask = allsignals; action.sa_flags = SA_RESTART|SA_RESETHAND; for (i = 1; i < NSIG; i++) { if (sigismember (&signals, i)) { sigaction (i, &action, 0); } } if (verbose) { jack_info ("%d waiting for signals", getpid()); } waiting = TRUE; while (waiting) { sigwait (&signals, &sig); jack_info ("jack main caught signal %d", sig); switch (sig) { case SIGUSR1: jack_dump_configuration(engine, 1); break; case SIGUSR2: /* driver exit */ waiting = FALSE; break; default: waiting = FALSE; break; } } if (sig != SIGSEGV) { /* unblock signals so we can see them during shutdown. this will help prod developers not to lose sight of bugs that cause segfaults etc. during shutdown. */ sigprocmask (SIG_UNBLOCK, &signals, 0); } jack_engine_delete (engine); return 1; error: jack_engine_delete (engine); return -1; } static jack_driver_desc_t * jack_drivers_get_descriptor (JSList * drivers, const char * sofile) { jack_driver_desc_t * descriptor, * other_descriptor; JackDriverDescFunction so_get_descriptor; JSList * node; void * dlhandle; char * filename; const char * dlerr; int err; char* driver_dir; if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { driver_dir = ADDON_DIR; } filename = malloc (strlen (driver_dir) + 1 + strlen (sofile) + 1); sprintf (filename, "%s/%s", driver_dir, sofile); if (verbose) { jack_info ("getting driver descriptor from %s", filename); } if ((dlhandle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL)) == NULL) { jack_error ("could not open driver .so '%s': %s\n", filename, dlerror ()); free (filename); return NULL; } so_get_descriptor = (JackDriverDescFunction) dlsym (dlhandle, "driver_get_descriptor"); if ((dlerr = dlerror ()) != NULL) { jack_error("%s", dlerr); dlclose (dlhandle); free (filename); return NULL; } if ((descriptor = so_get_descriptor ()) == NULL) { jack_error ("driver from '%s' returned NULL descriptor\n", filename); dlclose (dlhandle); free (filename); return NULL; } if ((err = dlclose (dlhandle)) != 0) { jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ()); } /* check it doesn't exist already */ for (node = drivers; node; node = jack_slist_next (node)) { other_descriptor = (jack_driver_desc_t *) node->data; if (strcmp (descriptor->name, other_descriptor->name) == 0) { jack_error ("the drivers in '%s' and '%s' both have the name '%s'; using the first\n", other_descriptor->file, filename, other_descriptor->name); /* FIXME: delete the descriptor */ free (filename); return NULL; } } snprintf (descriptor->file, sizeof(descriptor->file), "%s", filename); free (filename); return descriptor; } static JSList * jack_drivers_load () { struct dirent * dir_entry; DIR * dir_stream; const char * ptr; int err; JSList * driver_list = NULL; jack_driver_desc_t * desc; char* driver_dir; if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { driver_dir = ADDON_DIR; } /* search through the driver_dir and add get descriptors from the .so files in it */ dir_stream = opendir (driver_dir); if (!dir_stream) { jack_error ("could not open driver directory %s: %s\n", driver_dir, strerror (errno)); return NULL; } while ( (dir_entry = readdir (dir_stream)) ) { /* check the filename is of the right format */ if (strncmp ("jack_", dir_entry->d_name, 5) != 0) { continue; } ptr = strrchr (dir_entry->d_name, '.'); if (!ptr) { continue; } ptr++; if (strncmp ("so", ptr, 2) != 0) { continue; } desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name); if (desc) { driver_list = jack_slist_append (driver_list, desc); } } err = closedir (dir_stream); if (err) { jack_error ("error closing driver directory %s: %s\n", driver_dir, strerror (errno)); } if (!driver_list) { jack_error ("could not find any drivers in %s!\n", driver_dir); return NULL; } return driver_list; } static void copyright (FILE* file) { fprintf (file, "jackd " VERSION "\n" "Copyright 2001-2009 Paul Davis, Stephane Letz, Jack O'Quinn, Torben Hohn and others.\n" "jackd comes with ABSOLUTELY NO WARRANTY\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions; see the file COPYING for details\n\n"); } static void usage (FILE *file) { copyright (file); fprintf (file, "\n" "usage: jackd [ --no-realtime OR -r ]\n" " [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n" " (the two previous arguments are mutually exclusive. The default is --realtime)\n" " [ --name OR -n server-name ]\n" " [ --no-mlock OR -m ]\n" " [ --unlock OR -u ]\n" " [ --timeout OR -t client-timeout-in-msecs ]\n" " [ --port-max OR -p maximum-number-of-ports]\n" " [ --debug-timer OR -D ]\n" " [ --no-sanity-checks OR -N ]\n" " [ --verbose OR -v ]\n" " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" " [ --replace-registry ]\n" " [ --silent OR -s ]\n" " [ --version OR -V ]\n" " [ --nozombies OR -Z ]\n" " -d backend [ ... backend args ... ]\n" #ifdef __APPLE__ " Available backends may include: coreaudio, dummy, net, portaudio.\n\n" #else " Available backends may include: alsa, dummy, freebob, firewire, net, oss, sun, or portaudio.\n\n" #endif " jackd -d backend --help\n" " to display options for each backend\n\n"); } static jack_driver_desc_t * jack_find_driver_descriptor (const char * name) { jack_driver_desc_t * desc = 0; JSList * node; for (node = drivers; node; node = jack_slist_next (node)) { desc = (jack_driver_desc_t *) node->data; if (strcmp (desc->name, name) != 0) { desc = NULL; } else { break; } } return desc; } static void jack_cleanup_files (const char *server_name) { DIR *dir; struct dirent *dirent; char dir_name[PATH_MAX+1] = ""; jack_server_dir (server_name, dir_name); /* On termination, we remove all files that jackd creates so * subsequent attempts to start jackd will not believe that an * instance is already running. If the server crashes or is * terminated with SIGKILL, this is not possible. So, cleanup * is also attempted when jackd starts. * * There are several tricky issues. First, the previous JACK * server may have run for a different user ID, so its files * may be inaccessible. This is handled by using a separate * JACK_TMP_DIR subdirectory for each user. Second, there may * be other servers running with different names. Each gets * its own subdirectory within the per-user directory. The * current process has already registered as `server_name', so * we know there is no other server actively using that name. */ /* nothing to do if the server directory does not exist */ if ((dir = opendir (dir_name)) == NULL) { return; } /* unlink all the files in this directory, they are mine */ while ((dirent = readdir (dir)) != NULL) { char fullpath[PATH_MAX+1]; if ((strcmp (dirent->d_name, ".") == 0) || (strcmp (dirent->d_name, "..") == 0)) { continue; } snprintf (fullpath, sizeof (fullpath), "%s/%s", dir_name, dirent->d_name); if (unlink (fullpath)) { jack_error ("cannot unlink `%s' (%s)", fullpath, strerror (errno)); } } closedir (dir); /* now, delete the per-server subdirectory, itself */ if (rmdir (dir_name)) { jack_error ("cannot remove `%s' (%s)", dir_name, strerror (errno)); } /* finally, delete the per-user subdirectory, if empty */ if (rmdir (jack_user_dir ())) { if (errno != ENOTEMPTY) { jack_error ("cannot remove `%s' (%s)", jack_user_dir (), strerror (errno)); } } } static void maybe_use_capabilities () { #ifdef USE_CAPABILITIES int status; /* check to see if there is a pipe in the right descriptor */ if ((status = fstat (PIPE_WRITE_FD, &pipe_stat)) == 0 && S_ISFIFO(pipe_stat.st_mode)) { /* tell jackstart we are up and running */ char c = 1; if (write (PIPE_WRITE_FD, &c, 1) != 1) { jack_error ("cannot write to jackstart sync " "pipe %d (%s)", PIPE_WRITE_FD, strerror (errno)); } if (close(PIPE_WRITE_FD) != 0) { jack_error("jackd: error on startup pipe close: %s", strerror (errno)); } else { /* wait for jackstart process to set our capabilities */ if (wait (&status) == -1) { jack_error ("jackd: wait for startup " "process exit failed"); } if (!WIFEXITED (status) || WEXITSTATUS (status)) { jack_error ("jackd: jackstart did not " "exit cleanly"); exit (1); } } } #endif /* USE_CAPABILITIES */ } int main (int argc, char *argv[]) { jack_driver_desc_t * desc; int replace_registry = 0; int do_sanity_checks = 1; int show_version = 0; const char *options = "-d:P:uvshVrRZTFlt:mM:n:Np:c:X:C:"; struct option long_options[] = { /* keep ordered by single-letter option code */ { "clock-source", 1, 0, 'c' }, { "driver", 1, 0, 'd' }, { "help", 0, 0, 'h' }, { "tmpdir-location", 0, 0, 'l' }, { "no-mlock", 0, 0, 'm' }, { "midi-bufsize", 1, 0, 'M' }, { "name", 1, 0, 'n' }, { "no-sanity-checks", 0, 0, 'N' }, { "port-max", 1, 0, 'p' }, { "realtime-priority", 1, 0, 'P' }, { "no-realtime", 0, 0, 'r' }, { "realtime", 0, 0, 'R' }, { "replace-registry", 0, &replace_registry, 0 }, { "silent", 0, 0, 's' }, { "sync", 0, 0, 'S' }, { "timeout", 1, 0, 't' }, { "temporary", 0, 0, 'T' }, { "unlock", 0, 0, 'u' }, { "version", 0, 0, 'V' }, { "verbose", 0, 0, 'v' }, { "slave-driver", 1, 0, 'X' }, { "nozombies", 0, 0, 'Z' }, { "timeout-thres", 2, 0, 'C' }, { 0, 0, 0, 0 } }; int opt = 0; int option_index = 0; int seen_driver = 0; char *driver_name = NULL; char **driver_args = NULL; JSList * driver_params; JSList * slave_drivers = NULL; size_t midi_buffer_size = 0; int driver_nargs = 1; int i; int rc; setvbuf (stdout, NULL, _IOLBF, 0); maybe_use_capabilities (); opterr = 0; while (!seen_driver && (opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { case 'c': if (tolower (optarg[0]) == 'h') { clock_source = JACK_TIMER_HPET; } else if (tolower (optarg[0]) == 'c') { clock_source = JACK_TIMER_CYCLE_COUNTER; } else if (tolower (optarg[0]) == 's') { clock_source = JACK_TIMER_SYSTEM_CLOCK; } else { usage (stderr); return -1; } break; case 'C': if (optarg) timeout_count_threshold = atoi (optarg); else timeout_count_threshold = 250; break; case 'd': seen_driver = 1; driver_name = optarg; break; case 'D': frame_time_offset = JACK_MAX_FRAMES - atoi(optarg); break; case 'l': /* special flag to allow libjack to determine jackd's idea of where tmpdir is */ printf ("%s\n", jack_tmpdir); exit (0); case 'm': do_mlock = 0; break; case 'M': midi_buffer_size = (unsigned int) atol (optarg); break; case 'n': server_name = optarg; break; case 'N': do_sanity_checks = 0; break; case 'p': port_max = (unsigned int) atol (optarg); break; case 'P': realtime_priority = atoi (optarg); break; case 'r': realtime = 0; break; case 'R': /* this is now the default */ realtime = 1; break; case 's': jack_set_error_function (silent_jack_error_callback); break; case 'S': /* this option is for jack2 only (synchronous mode) */ break; case 'T': temporary = 1; break; case 't': client_timeout = atoi (optarg); break; case 'u': do_unlock = 1; break; case 'v': verbose = 1; break; case 'V': show_version = 1; break; case 'X': slave_drivers = jack_slist_append(slave_drivers, optarg); break; case 'Z': nozombies = 1; break; default: jack_error ("Unknown option character %c", optopt); /*fallthru*/ case 'h': usage (stdout); return -1; } } if (show_version) { printf ( "jackd version " VERSION " tmpdir " DEFAULT_TMP_DIR " protocol " PROTOCOL_VERSION "\n"); return 0; } copyright (stdout); if (do_sanity_checks && (0 < sanitycheck (realtime, (clock_source == JACK_TIMER_CYCLE_COUNTER)))) { return -1; } if (realtime && (client_timeout >= JACKD_WATCHDOG_TIMEOUT)) { usage (stderr); fprintf (stderr, "In realtime mode (-R) the client timeout must be smaller than the watchdog timeout (%ims).\n", JACKD_WATCHDOG_TIMEOUT); exit (1); } if (!seen_driver) { usage (stderr); exit (1); } drivers = jack_drivers_load (); if (!drivers) { fprintf (stderr, "jackd: no drivers found; exiting\n"); exit (1); } if (midi_buffer_size != 0) { jack_port_type_info_t* port_type = &jack_builtin_port_types[JACK_MIDI_PORT_TYPE]; port_type->buffer_size = midi_buffer_size * jack_midi_internal_event_size (); port_type->buffer_scale_factor = -1; if (verbose) { fprintf (stderr, "Set MIDI buffer size to %u bytes\n", port_type->buffer_size); } } desc = jack_find_driver_descriptor (driver_name); if (!desc) { fprintf (stderr, "jackd: unknown driver '%s'\n", driver_name); exit (1); } if (optind < argc) { driver_nargs = 1 + argc - optind; } else { driver_nargs = 1; } if (driver_nargs == 0) { fprintf (stderr, "No driver specified ... hmm. JACK won't do" " anything when run like this.\n"); return -1; } driver_args = (char **) malloc (sizeof (char *) * driver_nargs); driver_args[0] = driver_name; for (i = 1; i < driver_nargs; i++) { driver_args[i] = argv[optind++]; } if (jack_parse_driver_params (desc, driver_nargs, driver_args, &driver_params)) { exit (0); } if (server_name == NULL) server_name = jack_default_server_name (); rc = jack_register_server (server_name, replace_registry); switch (rc) { case EEXIST: fprintf (stderr, "`%s' server already active\n", server_name); exit (1); case ENOSPC: fprintf (stderr, "too many servers already active\n"); exit (2); case ENOMEM: fprintf (stderr, "no access to shm registry\n"); exit (3); default: if (verbose) fprintf (stderr, "server `%s' registered\n", server_name); } /* clean up shared memory and files from any previous * instance of this server name */ jack_cleanup_shm (); jack_cleanup_files (server_name); /* run the server engine until it terminates */ jack_main (desc, driver_params, slave_drivers); /* clean up shared memory and files from this server instance */ if (verbose) fprintf (stderr, "cleaning up shared memory\n"); jack_cleanup_shm (); if (verbose) fprintf (stderr, "cleaning up files\n"); jack_cleanup_files (server_name); if (verbose) fprintf (stderr, "unregistering server `%s'\n", server_name); jack_unregister_server (server_name); exit (0); } jackd1-0.121.3+20120418git75e3e20b/jackd/jackstart.c0000644001605600047420000002107411736346233017016 0ustar adiira/* Copyright (C) 2002 Fernando Lopez-Lezcano 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. Jackstart is based on code and concepts found in sucap.c, written by Finn Arne Gangstad and givertcap.c, written by Tommi Ilmonen, Tommi.Ilmonen@hut.fi */ #include #include #include #include #include #include #include #include #include #include #include #include #undef _POSIX_SOURCE #include #include "jack/start.h" #include "md5.h" #include "jack_md5.h" #define READ_BLOCKSIZE 4096 /* JACK_LOCATION must be passed on the gcc command line */ static char *jackd_bin_path = JACK_LOCATION "/jackd"; static char *jackd_md5_sum = JACKD_MD5_SUM; static int check_capabilities (void) { cap_t caps = cap_init(); cap_flag_value_t cap; pid_t pid; int have_all_caps = 1; if (caps == NULL) { fprintf (stderr, "jackstart: could not allocate capability working storage\n"); return 0; } pid = getpid (); cap_clear (caps); if (capgetp (pid, caps)) { fprintf (stderr, "jackstart: could not get capabilities for process %d\n", pid); return 0; } /* check that we are able to give capabilites to other processes */ cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } /* check that we have the capabilities we want to transfer */ cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } cap_get_flag(caps, CAP_SYS_RESOURCE, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } cap_get_flag(caps, CAP_IPC_LOCK, CAP_EFFECTIVE, &cap); if (cap == CAP_CLEAR) { have_all_caps = 0; goto done; } done: cap_free (caps); return have_all_caps; } static int give_capabilities (pid_t pid) { cap_t caps = cap_init(); const unsigned caps_size = 4; cap_value_t cap_list[] = { CAP_SETPCAP, CAP_SYS_NICE, CAP_SYS_RESOURCE, CAP_IPC_LOCK} ; if (caps == NULL) { fprintf (stderr, "jackstart: could not allocate capability working storage\n"); return -1; } cap_clear(caps); if (capgetp (pid, caps)) { fprintf (stderr, "jackstart: could not get capabilities for process %d\n", pid); cap_clear(caps); } cap_set_flag(caps, CAP_EFFECTIVE, caps_size, cap_list , CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, caps_size, cap_list , CAP_SET); cap_set_flag(caps, CAP_PERMITTED, caps_size, cap_list , CAP_SET); if (capsetp (pid, caps)) { fprintf (stderr, "jackstart: could not give capabilities: %s\n", strerror (errno)); cap_free (caps); return -1; } cap_free (caps); return 0; } static int check_binary (const char *binpath) { struct stat status; FILE *binstream; if (lstat(jackd_bin_path, &status)) { fprintf (stderr, "jackstart: could not stat %s: %s\n", binpath, strerror(errno)); return -1; } if (!(S_ISREG(status.st_mode))) { fprintf (stderr, "jackstart: %s is not a regular file\n", binpath); return -1; } if (status.st_uid != 0) { fprintf (stderr, "jackstart: %s is not owned by root\n", binpath); return -1; } if ((status.st_mode & 022) != 0) { fprintf (stderr, "jackstart: %s mode %o writeable by non-root users\n", binpath, status.st_mode & 07777); return -1; } if ((binstream = fopen (binpath, "r")) == NULL) { fprintf (stderr, "jackstart: can't open %s for reading: %s\n", binpath, strerror(errno)); return -1; } else { /* md5sum the executable file, check man evp for more details */ size_t sum; md5_t ctx; char buffer[READ_BLOCKSIZE + 72]; unsigned char md_value[MD5_SIZE]; char md_string[3]; int i, j; md5_init(&ctx); while (1) { size_t n; sum = 0; do { n = fread (buffer + sum, 1, READ_BLOCKSIZE - sum, binstream); sum += n; } while (sum < READ_BLOCKSIZE && n != 0); if (n == 0 && ferror (binstream)) { fprintf (stderr, "jackstart: error while reading %s: %s\n", binpath, strerror(errno)); return -1; } if (n == 0) { break; } md5_process(&ctx, buffer, READ_BLOCKSIZE); } if (sum > 0) md5_process(&ctx, buffer, sum); if (fclose (binstream)) { fprintf (stderr, "jackstart: could not close %s after reading: %s\n", binpath, strerror(errno)); } md5_finish(&ctx, md_value); for(i = 0, j = 0; i < sizeof(md_value); i++, j+=2) { sprintf(md_string, "%02x", md_value[i]); if (md_string[0] != jackd_md5_sum[j] || md_string[1] != jackd_md5_sum[j+1]) { fprintf (stderr, "jackstart: md5 checksum for %s does not match\n", binpath); return -1; } } } return 0; } int main(int argc, char **argv) { uid_t uid, euid; pid_t pid, parent_pid; gid_t gid; int pipe_fds[2]; int err; parent_pid = getpid (); /* get real user and group ids, effective user id */ uid = getuid (); gid = getgid (); euid = geteuid (); /* are we running suid root? */ if (uid != 0) { if (euid != 0) { fprintf (stderr, "jackstart: not running suid root, can't use capabilities\n"); fprintf (stderr, " (currently running with uid=%d and euid=%d),\n", uid, euid); fprintf (stderr, " make jackstart suid root or start jackd directly\n\n"); } } /* see if we can get the required capabilities */ if (check_capabilities () == 0) { size_t size; cap_t cap = cap_init(); capgetp(0, cap); fprintf (stderr, "jackstart: cannot get realtime capabilities, current capabilities are:\n"); fprintf (stderr, " %s\n", cap_to_text(cap, &size)); fprintf (stderr, " probably running under a kernel with capabilities disabled,\n"); fprintf (stderr, " a suitable kernel would have printed something like \"=eip\"\n\n"); } /* check the executable, owner, permissions, md5 checksum */ if (check_binary(jackd_bin_path)) { exit(1); } /* set process group to current pid */ if (setpgid (0, getpid())) { fprintf (stderr, "jackstart: failed to set process group: %s\n", strerror(errno)); exit (1); } /* create pipe to synchronize with jackd */ if (pipe (pipe_fds)) { fprintf (stderr, "jackstart: could not create pipe: %s\n", strerror(errno)); exit (1); } /* make sure the file descriptors are the right ones, otherwise dup them, this is to make sure that both jackstart and jackd use the same fds */ if (pipe_fds[0] != PIPE_READ_FD) { if (dup2 (pipe_fds[0], PIPE_READ_FD) != PIPE_READ_FD) { fprintf (stderr, "jackstart: could not dup pipe read file descriptor: %s\n", strerror(errno)); exit (1); } } if (pipe_fds[1] != PIPE_WRITE_FD) { if (dup2(pipe_fds[1], PIPE_WRITE_FD)!=PIPE_WRITE_FD) { fprintf (stderr, "jackstart: could not dup pipe write file descriptor: %s\n", strerror(errno)); exit (1); } } /* fork off a child to wait for jackd to start */ fflush(NULL); pid = fork(); if (pid == -1) { fprintf (stderr, "jackstart: fork failed\n"); exit (1); } if (pid) { /* mother process: drops privileges, execs jackd */ close(PIPE_READ_FD); /* get rid of any supplemental groups */ if (!getuid () && setgroups (0, 0)) { fprintf (stderr, "jackstart: setgroups failed: %s\n", strerror(errno)); exit (1); } /* set gid and uid */ setregid(gid, gid); setreuid(uid, uid); execvp(jackd_bin_path, argv); /* we could not start jackd, clean up and exit */ fprintf(stderr, "jackstart: unable to execute %s: %s\n", jackd_bin_path, strerror(errno)); close (PIPE_WRITE_FD); wait (&err); exit (1); } else { /* child process: grants privileges to jackd */ close(PIPE_WRITE_FD); /* wait for jackd to start */ while (1) { int ret; char c; /* picking up pipe closure is a tricky business. this seems to work as well as anything else. */ ret = read(PIPE_READ_FD, &c, 1); fprintf (stderr, "back from read, ret = %d errno == %s\n", ret, strerror (errno)); if (ret == 1) { break; } else if (errno != EINTR) { break; } } /* set privileges on jackd process */ give_capabilities (parent_pid); } exit (0); } jackd1-0.121.3+20120418git75e3e20b/jackd/.cvsignore0000644001605600047420000000010411736346233016653 0ustar adiira.deps .libs Makefile Makefile.in jack_md5.h jackd jackd.1 jackstart jackd1-0.121.3+20120418git75e3e20b/jackd/transengine.c0000644001605600047420000003462711736346233017355 0ustar adiira/* JACK transport engine -- runs in the server process. Copyright (C) 2001-2003 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 Lesser 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. */ #include #include #include #include #include #include "internal.h" #include "engine.h" #include "messagebuffer.h" #include "transengine.h" /********************** internal functions **********************/ /* initiate polling a new slow-sync client * * precondition: caller holds the graph lock. */ static inline void jack_sync_poll_new (jack_engine_t *engine, jack_client_internal_t *client) { /* force sync_cb callback to run in its first cycle */ engine->control->sync_time_left = engine->control->sync_timeout; client->control->sync_new = 1; if (!client->control->sync_poll) { client->control->sync_poll = 1; engine->control->sync_remain++; } // JOQ: I don't like doing this here... if (engine->control->transport_state == JackTransportRolling) { engine->control->transport_state = JackTransportStarting; VERBOSE (engine, "force transport state to Starting"); } VERBOSE (engine, "polling sync client %" PRIu32, client->control->id); } /* stop polling a specific slow-sync client * * precondition: caller holds the graph lock. */ static inline void jack_sync_poll_deactivate (jack_engine_t *engine, jack_client_internal_t *client) { if (client->control->sync_poll) { client->control->sync_poll = 0; client->control->sync_new = 0; engine->control->sync_remain--; VERBOSE (engine, "sync poll interrupted for client %" PRIu32, client->control->id); } client->control->active_slowsync = 0; engine->control->sync_clients--; assert(engine->control->sync_clients >= 0); } /* stop polling all the slow-sync clients * * precondition: caller holds the graph lock. */ static void jack_sync_poll_stop (jack_engine_t *engine) { JSList *node; long poll_count = 0; /* count sync_poll clients */ for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t *client = (jack_client_internal_t *) node->data; if (client->control->active_slowsync && client->control->sync_poll) { client->control->sync_poll = 0; poll_count++; } } //JOQ: check invariant for debugging... assert (poll_count == engine->control->sync_remain); VERBOSE (engine, "sync poll halted with %" PRIu32 " clients and %8.6f secs remaining", engine->control->sync_remain, (double) (engine->control->sync_time_left / 1000000.0)); engine->control->sync_remain = 0; engine->control->sync_time_left = 0; } /* start polling all the slow-sync clients * * precondition: caller holds the graph lock. */ static void jack_sync_poll_start (jack_engine_t *engine) { JSList *node; long sync_count = 0; /* count slow-sync clients */ for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t *client = (jack_client_internal_t *) node->data; if (client->control->active_slowsync) { client->control->sync_poll = 1; sync_count++; } } //JOQ: check invariant for debugging... assert (sync_count == engine->control->sync_clients); engine->control->sync_remain = sync_count; engine->control->sync_time_left = engine->control->sync_timeout; VERBOSE (engine, "transport Starting, sync poll of %" PRIu32 " clients for %8.6f secs", engine->control->sync_remain, (double) (engine->control->sync_time_left / 1000000.0)); } /* check for sync timeout */ static inline int jack_sync_timeout (jack_engine_t *engine) { jack_control_t *ectl = engine->control; jack_time_t buf_usecs = ((ectl->buffer_size * (jack_time_t) 1000000) / ectl->current_time.frame_rate); /* compare carefully, jack_time_t is unsigned */ if (ectl->sync_time_left > buf_usecs) { ectl->sync_time_left -= buf_usecs; return FALSE; } /* timed out */ VERBOSE (engine, "transport sync timeout"); ectl->sync_time_left = 0; return TRUE; } /**************** subroutines used by engine.c ****************/ /* driver callback */ int jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes) { jack_control_t *ectl = engine->control; ectl->current_time.frame_rate = nframes; ectl->pending_time.frame_rate = nframes; return 0; } /* on ResetTimeBaseClient request */ int jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id) { int ret; struct _jack_client_internal *client; jack_control_t *ectl = engine->control; jack_lock_graph (engine); client = jack_client_internal_by_id (engine, client_id); if (client && (client == engine->timebase_client)) { client->control->is_timebase = 0; client->control->timebase_new = 0; engine->timebase_client = NULL; ectl->pending_time.valid = 0; VERBOSE (engine, "%s resigned as timebase master", client->control->name); ret = 0; } else ret = EINVAL; jack_unlock_graph (engine); return ret; } /* on SetTimeBaseClient request */ int jack_timebase_set (jack_engine_t *engine, jack_client_id_t client_id, int conditional) { int ret = 0; struct _jack_client_internal *client; jack_lock_graph (engine); client = jack_client_internal_by_id (engine, client_id); if (client == NULL) { VERBOSE (engine, " %" PRIu32 " no longer exists", client_id); jack_unlock_graph (engine); return EINVAL; } if (conditional && engine->timebase_client) { /* see if timebase master is someone else */ if (client != engine->timebase_client) { VERBOSE (engine, "conditional timebase for %s failed", client->control->name); VERBOSE (engine, " %s is already the master", engine->timebase_client->control->name); ret = EBUSY; } else VERBOSE (engine, " %s was already timebase master:", client->control->name); } else { if (engine->timebase_client) { engine->timebase_client->control->is_timebase = 0; engine->timebase_client->control->timebase_new = 0; } engine->timebase_client = client; client->control->is_timebase = 1; if (client->control->active) client->control->timebase_new = 1; VERBOSE (engine, "new timebase master: %s", client->control->name); } jack_unlock_graph (engine); return ret; } /* for client activation * * precondition: caller holds the graph lock. */ void jack_transport_activate (jack_engine_t *engine, jack_client_internal_t *client) { if (client->control->is_slowsync) { assert(!client->control->active_slowsync); client->control->active_slowsync = 1; engine->control->sync_clients++; jack_sync_poll_new (engine, client); } if (client->control->is_timebase) { client->control->timebase_new = 1; } } /* for engine initialization */ void jack_transport_init (jack_engine_t *engine) { jack_control_t *ectl = engine->control; engine->timebase_client = NULL; ectl->transport_state = JackTransportStopped; ectl->transport_cmd = TransportCommandStop; ectl->previous_cmd = TransportCommandStop; memset (&ectl->current_time, 0, sizeof(ectl->current_time)); memset (&ectl->pending_time, 0, sizeof(ectl->pending_time)); memset (&ectl->request_time, 0, sizeof(ectl->request_time)); ectl->prev_request = 0; ectl->seq_number = 1; /* can't start at 0 */ ectl->new_pos = 0; ectl->pending_pos = 0; ectl->pending_frame = 0; ectl->sync_clients = 0; ectl->sync_remain = 0; ectl->sync_timeout = 2000000; /* 2 second default */ ectl->sync_time_left = 0; } /* when any client exits the graph (either dead or not active) * * precondition: caller holds the graph lock */ void jack_transport_client_exit (jack_engine_t *engine, jack_client_internal_t *client) { if (client == engine->timebase_client) { if (client->control->dead) { engine->timebase_client->control->is_timebase = 0; engine->timebase_client->control->timebase_new = 0; engine->timebase_client = NULL; VERBOSE (engine, "timebase master exit"); } engine->control->current_time.valid = 0; engine->control->pending_time.valid = 0; } if (client->control->is_slowsync) { if (client->control->active_slowsync) jack_sync_poll_deactivate (engine, client); if (client->control->dead) client->control->is_slowsync = 0; } } /* when a new client is being created */ void jack_transport_client_new (jack_client_internal_t *client) { client->control->is_timebase = 0; client->control->timebase_new = 0; client->control->is_slowsync = 0; client->control->active_slowsync = 0; client->control->sync_poll = 0; client->control->sync_new = 0; client->control->sync_cb_cbset = FALSE; client->control->timebase_cb_cbset = FALSE; #if 0 if (client->control->type != ClientExternal) { client->sync_cb = NULL; client->sync_arg = NULL; client->timebase_cb = NULL; client->timebase_arg = NULL; } #endif } /* on ResetSyncClient request */ int jack_transport_client_reset_sync (jack_engine_t *engine, jack_client_id_t client_id) { int ret; jack_client_internal_t *client; jack_lock_graph (engine); client = jack_client_internal_by_id (engine, client_id); if (client && (client->control->is_slowsync)) { if (client->control->active_slowsync) jack_sync_poll_deactivate (engine, client); client->control->is_slowsync = 0; ret = 0; } else ret = EINVAL; jack_unlock_graph (engine); return ret; } /* on SetSyncClient request */ int jack_transport_client_set_sync (jack_engine_t *engine, jack_client_id_t client_id) { int ret; jack_client_internal_t *client; DEBUG ("set sync client"); /* The process cycle runs with this lock. */ jack_lock_graph (engine); DEBUG ("got write lock"); client = jack_client_internal_by_id (engine, client_id); DEBUG ("client was %p"); if (client) { if (!client->control->is_slowsync) { client->control->is_slowsync = 1; if (client->control->active) { client->control->active_slowsync = 1; engine->control->sync_clients++; } } /* force poll of the new slow-sync client, if active */ if (client->control->active_slowsync) { DEBUG ("sync poll new"); jack_sync_poll_new (engine, client); } ret = 0; } else ret = EINVAL; DEBUG ("unlocking write lock for set_sync"); jack_unlock_graph (engine); return ret; } /* at process cycle end, set transport parameters for the next cycle * * precondition: caller holds the graph lock. */ void jack_transport_cycle_end (jack_engine_t *engine) { jack_control_t *ectl = engine->control; transport_command_t cmd; /* latest transport command */ /* Promote pending_time to current_time. Maintain the usecs, * frame_rate and frame values, clients may not set them. */ ectl->pending_time.usecs = ectl->current_time.usecs; ectl->pending_time.frame_rate = ectl->current_time.frame_rate; ectl->pending_time.frame = ectl->pending_frame; ectl->current_time = ectl->pending_time; ectl->new_pos = ectl->pending_pos; /* check sync results from previous cycle */ if (ectl->transport_state == JackTransportStarting) { if ((ectl->sync_remain == 0) || (jack_sync_timeout(engine))) { ectl->transport_state = JackTransportRolling; VERBOSE (engine, "transport Rolling, %8.6f sec" " left for poll", (double) (ectl->sync_time_left / 1000000.0)); } } /* Handle any new transport command from the last cycle. */ cmd = ectl->transport_cmd; if (cmd != ectl->previous_cmd) { ectl->previous_cmd = cmd; VERBOSE (engine, "transport command: %s", (cmd == TransportCommandStart? "START": "STOP")); } else cmd = TransportCommandNone; /* state transition switch */ switch (ectl->transport_state) { case JackTransportStopped: if (cmd == TransportCommandStart) { if (ectl->sync_clients) { ectl->transport_state = JackTransportStarting; jack_sync_poll_start(engine); } else { ectl->transport_state = JackTransportRolling; VERBOSE (engine, "transport Rolling"); } } break; case JackTransportStarting: if (cmd == TransportCommandStop) { ectl->transport_state = JackTransportStopped; VERBOSE (engine, "transport Stopped"); if (ectl->sync_remain) jack_sync_poll_stop(engine); } else if (ectl->new_pos) { if (ectl->sync_clients) { ectl->transport_state = JackTransportStarting; jack_sync_poll_start(engine); } else { ectl->transport_state = JackTransportRolling; VERBOSE (engine, "transport Rolling"); } } break; case JackTransportRolling: if (cmd == TransportCommandStop) { ectl->transport_state = JackTransportStopped; VERBOSE (engine, "transport Stopped"); if (ectl->sync_remain) jack_sync_poll_stop(engine); } else if (ectl->new_pos) { if (ectl->sync_clients) { ectl->transport_state = JackTransportStarting; jack_sync_poll_start(engine); } } break; default: jack_error ("invalid JACK transport state: %d", ectl->transport_state); } /* Update timebase, if needed. */ if (ectl->transport_state == JackTransportRolling) { ectl->pending_time.frame = ectl->current_time.frame + ectl->buffer_size; } /* See if an asynchronous position request arrived during the * last cycle. The request_time could change during the * guarded copy. If so, we use the newest request. */ ectl->pending_pos = 0; if (ectl->request_time.unique_1 != ectl->prev_request) { jack_transport_copy_position(&ectl->request_time, &ectl->pending_time); VERBOSE (engine, "new transport position: %" PRIu32 ", id=0x%" PRIx64, ectl->pending_time.frame, ectl->pending_time.unique_1); ectl->prev_request = ectl->pending_time.unique_1; ectl->pending_pos = 1; } /* clients can't set pending frame number, so save it here */ ectl->pending_frame = ectl->pending_time.frame; } /* driver callback at start of cycle */ void jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time) { engine->control->current_time.usecs = time; } /* on SetSyncTimeout request */ int jack_transport_set_sync_timeout (jack_engine_t *engine, jack_time_t usecs) { engine->control->sync_timeout = usecs; VERBOSE (engine, "new sync timeout: %8.6f secs", (double) (usecs / 1000000.0)); return 0; } jackd1-0.121.3+20120418git75e3e20b/jackd/md5.h0000644001605600047420000001276211736346233015526 0ustar adiira/* * Declaration of functions and data types used for MD5 sum computing * library functions. Copyright (C) 1995, 1996 Free Software * Foundation, Inc. NOTE: The canonical source of this file is * maintained with the GNU C Library. Bugs can be reported to * bug-glibc@prep.ai.mit.edu. * * 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, 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * */ /* * NOTE: during quick performance tests on a sun ultra and an alpha * 255 300, the md5 libraries performed upwards of 3mb/sec. That * included disk i/o on bobcat and panther. */ #ifndef __MD5_H__ #define __MD5_H__ /* * Size of a standard MD5 signature in bytes. This definition is for * external programs only. The MD5 routines themselves reference the * signature as 4 unsigned 32-bit integers. */ #define MD5_SIZE 16 /* * NOTE: the following is assumed to generate a 32-bit unsigned data * type. */ typedef unsigned int md5_uint32; #define MAX_MD5_UINT32 ((md5_uint32)4294967295U) /* * The MD5 algorithm works on blocks of characters of 64 bytes. This * is an internal value only and is not necessary for external use. */ #define MD5_BLOCK_SIZE 64 /* * Structure to save state of computation between the single steps. */ typedef struct { md5_uint32 md_A; /* accumulater 1 */ md5_uint32 md_B; /* accumulater 2 */ md5_uint32 md_C; /* accumulater 3 */ md5_uint32 md_D; /* accumulater 4 */ md5_uint32 md_total[2]; /* totaling storage */ md5_uint32 md_buf_len; /* length of the storage buffer */ char md_buffer[MD5_BLOCK_SIZE * 2]; /* character storage buffer */ } md5_t; /*<<<<<<<<<< The below prototypes are auto-generated by fillproto */ /* * md5_init * * DESCRIPTION: * * Initialize structure containing state of MD5 computation. (RFC 1321, * 3.3: Step 3). This is for progressive MD5 calculations only. If * you have the complete string available, md5_buffer should be used. * md5_process should be called for each bunch of bytes and after the * last process call, md5_finish should be called to get the * signature. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to md5 structure that we are initializing. */ extern void md5_init(md5_t *md5_p); /* * md5_process * * DESCRIPTION: * * This function is used to progressively calculate a MD5 signature some * number of bytes at a time. If you have the complete string * available, md5_buffer should be used. The MD5 structure should * have been initialized with md5_init and after the last process * call, md5_finish should be called to get the results. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to MD5 structure which we are progressively updating. * * buffer - A buffer of bytes whose MD5 signature we are calculating. * * buf_len - The length of the buffer. */ extern void md5_process(md5_t *md5_p, const void *buffer, const unsigned int buf_len); /* * md5_finish * * DESCRIPTION: * * Finish a progressing MD5 calculation and copy the resulting MD5 * signature into the result buffer which should be 16 bytes * (MD5_SIZE). After this call, the MD5 structure is invalid. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to MD5 structure which we are finishing. * * signature - A 16 byte buffer that will contain the MD5 signature. */ extern void md5_finish(md5_t *md5_p, void *signature); /* * md5_buffer * * DESCRIPTION: * * This function is used to calculate a MD5 signature for a buffer of * bytes. If you only have part of a buffer that you want to process * then md5_init, md5_process, and md5_finish should be used. * * RETURNS: * * None. * * ARGUMENTS: * * buffer - A buffer of bytes whose MD5 signature we are calculating. * * buf_len - The length of the buffer. * * signature - A 16 byte buffer that will contain the MD5 signature. */ extern void md5_buffer(const char *buffer, const unsigned int buf_len, void *signature); /* * md5_sig_to_string * * DESCRIPTION: * * Convert a MD5 signature in a 16 byte buffer into a hexadecimal string * representation. * * RETURNS: * * None. * * ARGUMENTS: * * signature - a 16 byte buffer that contains the MD5 signature. * * str - a string of charactes which should be at least 33 bytes long (2 * characters per MD5 byte and 1 for the \0). * * str_len - the length of the string. */ extern void md5_sig_to_string(void *signature, char *str, const int str_len); /* * md5_sig_from_string * * DESCRIPTION: * * Convert a MD5 signature from a hexadecimal string representation into * a 16 byte buffer. * * RETURNS: * * None. * * ARGUMENTS: * * signature - A 16 byte buffer that will contain the MD5 signature. * * str - A string of charactes which _must_ be at least 32 bytes long (2 * characters per MD5 byte). */ extern void md5_sig_from_string(void *signature, const char *str); /*<<<<<<<<<< This is end of the auto-generated output from fillproto. */ #endif /* ! __MD5_H__ */ jackd1-0.121.3+20120418git75e3e20b/jackd/Makefile.am0000644001605600047420000000376511736346233016727 0ustar adiiraMAINTAINERCLEANFILES = Makefile.in jackd.1 jack_md5.h if USE_CAPABILITIES CAP_PROGS = jackstart CAP_LIBS = -lcap install-exec-hook: if [ "`id -u`" = "0" ]; \ then chown root.root $(DESTDIR)$(bindir)/jackd; \ chmod 555 $(DESTDIR)$(bindir)/jackd; \ chown root.root $(DESTDIR)$(bindir)/jackstart; \ chmod 4555 $(DESTDIR)$(bindir)/jackstart; \ else echo "You must be root to set ownership and permissions"; \ echo " for jackd and jackstart."; \ fi else CAP_PROGS = CAP_LIBS = install-exec-hook: @echo "Nothing to make for $@." endif bin_PROGRAMS = jackd $(CAP_PROGS) AM_CFLAGS = $(JACK_CFLAGS) -DJACK_LOCATION=\"$(bindir)\" jackd_SOURCES = jackd.c jackd_LDADD = libjackserver.la $(CAP_LIBS) @OS_LDFLAGS@ noinst_HEADERS = jack_md5.h md5.h md5_loc.h \ clientengine.h transengine.h BUILT_SOURCES = jack_md5.h jack_md5.h: jackd if STRIPPED_JACKD strip -R .note -R .comment .libs/jackd endif echo "#define JACKD_MD5_SUM \"`md5sum .libs/jackd | awk '{print $$1}'`\"" > jack_md5.h jackstart_SOURCES = jackstart.c md5.c jackstart_LDFLAGS = -lcap lib_LTLIBRARIES = libjackserver.la libjackserver_la_CFLAGS = $(AM_CFLAGS) libjackserver_la_SOURCES = engine.c clientengine.c transengine.c controlapi.c \ ../libjack/systemtest.c ../libjack/sanitycheck.c \ ../libjack/client.c ../libjack/driver.c ../libjack/intclient.c \ ../libjack/messagebuffer.c ../libjack/pool.c ../libjack/port.c \ ../libjack/midiport.c ../libjack/ringbuffer.c ../libjack/shm.c \ ../libjack/thread.c ../libjack/time.c ../libjack/transclient.c \ ../libjack/unlock.c libjackserver_la_LIBADD = simd.lo @OS_LDFLAGS@ libjackserver_la_LDFLAGS = -export-dynamic -version-info @JACK_SO_VERSION@ simd.lo: $(srcdir)/../libjack/simd.c $(LIBTOOL) --mode=compile $(CC) -I$(top_builddir) $(JACK_CORE_CFLAGS) $(SIMD_CFLAGS) -c -o simd.lo $(srcdir)/../libjack/simd.c man_MANS = jackd.1 jackstart.1 EXTRA_DIST = $(man_MANS) dist-hook: rm -f $(distdir)/jack_md5.h distclean-local: rm -f $(top_builddir)/jackd/jack_md5.h jackd1-0.121.3+20120418git75e3e20b/jackd/jackstart.10000644001605600047420000000002111736346233016721 0ustar adiira.so man1/jackd.1 jackd1-0.121.3+20120418git75e3e20b/jackd/clientengine.h0000644001605600047420000000463111736346233017501 0ustar adiira/* * Client creation and destruction interfaces for JACK engine. * * Copyright (C) 2001-2003 Paul Davis * Copyright (C) 2004 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. * */ static inline int jack_client_is_internal (jack_client_internal_t *client) { return (client->control->type == ClientInternal) || (client->control->type == ClientDriver); } static inline char * jack_client_state_name (jack_client_internal_t *client) { static char *client_state_names[] = { "Not triggered", "Triggered", "Running", "Finished" }; return client_state_names[client->control->state]; } #define JACK_ERROR_WITH_SOCKETS 10000000 int jack_client_activate (jack_engine_t *engine, jack_client_id_t id); int jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id); int jack_client_create (jack_engine_t *engine, int client_fd); void jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client); int jack_mark_client_socket_error (jack_engine_t *engine, int fd); jack_client_internal_t * jack_create_driver_client (jack_engine_t *engine, char *name); void jack_intclient_handle_request (jack_engine_t *engine, jack_request_t *req); void jack_intclient_load_request (jack_engine_t *engine, jack_request_t *req); void jack_intclient_name_request (jack_engine_t *engine, jack_request_t *req); void jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req); int jack_check_clients (jack_engine_t* engine, int with_timeout_check); void jack_remove_clients (jack_engine_t* engine, int* exit_freewheeling); void jack_client_registration_notify (jack_engine_t *engine, const char* name, int yn); void jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client); jackd1-0.121.3+20120418git75e3e20b/jackd/md5_loc.h0000644001605600047420000000640111736346233016354 0ustar adiira/* * Local defines for the md5 functions. * */ /* * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it is * identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided that * such works are identified as "derived from the RSA Data Security, * Inc. MD5 Message-Digest Algorithm" in all material mentioning or * referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either the * merchantability of this software or the suitability of this * software for any particular purpose. It is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * documentation and/or software. */ #ifndef __MD5_LOC_H__ #define __MD5_LOC_H__ #define HEX_STRING "0123456789abcdef" /* to convert to hex */ #define BLOCK_SIZE_MASK (MD5_BLOCK_SIZE - 1) #include /* * Define my endian-ness. Could not do in a portable manner using the * include files -- grumble. */ #ifdef WORDS_BIGENDIAN /* * big endian - big is better */ #define SWAP(n) \ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) #else /* + * little endian + */ #define SWAP(n) (n) #endif /* * These are the four functions used in the four steps of the MD5 * algorithm and defined in the RFC 1321. The first function is a * little bit optimized (as found in Colin Plumbs public domain * implementation). */ /* #define FF(b, c, d) ((b & c) | (~b & d)) */ #define FF(b, c, d) (d ^ (b & (c ^ d))) #define FG(b, c, d) FF(d, b, c) #define FH(b, c, d) (b ^ c ^ d) #define FI(b, c, d) (c ^ (b | ~d)) /* * It is unfortunate that C does not provide an operator for cyclic * rotation. Hope the C compiler is smart enough. -- Modified to * remove the w = at the front - Gray 2/97 */ #define CYCLIC(w, s) ((w << s) | (w >> (32 - s))) /* * First Round: using the given function, the context and a constant * the next context is computed. Because the algorithms processing * unit is a 32-bit word and it is determined to work on words in * little endian byte order we perhaps have to change the byte order * before the computation. To reduce the work for the next steps we * store the swapped words in the array CORRECT_WORDS. -- Modified to * fix the handling of unaligned buffer spaces - Gray 7/97 */ #define OP1(a, b, c, d, b_p, c_p, s, T) \ do { \ memcpy(c_p, b_p, sizeof(md5_uint32)); \ *c_p = SWAP(*c_p); \ a += FF (b, c, d) + *c_p + T; \ a = CYCLIC (a, s); \ a += b; \ b_p = (char *)b_p + sizeof(md5_uint32); \ c_p++; \ } while (0) /* * Second to Fourth Round: we have the possibly swapped words in * CORRECT_WORDS. Redefine the macro to take an additional first * argument specifying the function to use. */ #define OP234(FUNC, a, b, c, d, k, s, T) \ do { \ a += FUNC (b, c, d) + k + T; \ a = CYCLIC (a, s); \ a += b; \ } while (0) #endif /* ! __MD5_LOC_H__ */ jackd1-0.121.3+20120418git75e3e20b/jackd/md5.c0000644001605600047420000004004511736346233015514 0ustar adiira/* * Functions to compute MD5 message digest of files or memory blocks * according to the definition of MD5 in RFC 1321 from April 1992. * Copyright (C) 1995, 1996 Free Software Foundation, Inc. NOTE: The * canonical source of this file is maintained with the GNU C Library. * Bugs can be reported to bug-glibc@prep.ai.mit.edu. * * 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, 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Written by Ulrich Drepper , 1995. * Modified by Gray Watson , 1997. * */ /* * NOTE: during quick performance tests on a Sun Sparc Ultra 1 and an * Alpha 255 300, these functions performed upwards of 3mb/sec * including disk I/O time. */ /* * MD5 Test Suite from RFC1321: http://ds.internic.net:/rfc/rfc1321.txt * * MD5 ("") = d41d8cd98f00b204e9800998ecf8427e * MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661 * MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72 * MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0 * MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b * MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = * d174ab98d277d9f5a5611c2c9f419d9f * MD5 ("123456789012345678901234567890123456789012345678901234567890123456 * 78901234567890") = 57edf4a22be3c955ac49da2e2107b67a */ #include #include #include #include "md5.h" #include "md5_loc.h" /* static char *rcs_id = /* version id for the library */ /* static char *version_id = "$MD5Version: 1.0.0 November-19-1997 $"; */ /****************************** local routines *******************************/ /* * process_block * * DESCRIPTION: * * Process a block of bytes into a MD5 state structure. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to MD5 structure from which we are getting the result. * * buffer - A buffer of bytes whose MD5 signature we are calculating. * * buf_len - The length of the buffer. */ static void process_block(md5_t *md5_p, const void *buffer, const unsigned int buf_len) { md5_uint32 correct[16]; const void *buf_p = buffer, *end_p; unsigned int words_n; md5_uint32 A, B, C, D; words_n = buf_len / sizeof(md5_uint32); end_p = (char *)buf_p + words_n * sizeof(md5_uint32); A = md5_p->md_A; B = md5_p->md_B; C = md5_p->md_C; D = md5_p->md_D; /* * First increment the byte count. RFC 1321 specifies the possible * length of the file up to 2^64 bits. Here we only compute the * number of bytes with a double word increment. Modified to do * this to better avoid overflows in the lower word -- Gray 10/97. */ if (md5_p->md_total[0] > MAX_MD5_UINT32 - buf_len) { md5_p->md_total[1]++; md5_p->md_total[0] -= (MAX_MD5_UINT32 - buf_len); } else { md5_p->md_total[0] += buf_len; } /* * Process all bytes in the buffer with MD5_BLOCK bytes in each * round of the loop. */ while (buf_p < end_p) { md5_uint32 A_save, B_save, C_save, D_save; md5_uint32 *corr_p = correct; A_save = A; B_save = B; C_save = C; D_save = D; /* * Before we start, one word to the strange constants. They are * defined in RFC 1321 as * * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..MD5_BLOCK */ /* Round 1. */ OP1 (A, B, C, D, buf_p, corr_p, 7, 0xd76aa478); OP1 (D, A, B, C, buf_p, corr_p, 12, 0xe8c7b756); OP1 (C, D, A, B, buf_p, corr_p, 17, 0x242070db); OP1 (B, C, D, A, buf_p, corr_p, 22, 0xc1bdceee); OP1 (A, B, C, D, buf_p, corr_p, 7, 0xf57c0faf); OP1 (D, A, B, C, buf_p, corr_p, 12, 0x4787c62a); OP1 (C, D, A, B, buf_p, corr_p, 17, 0xa8304613); OP1 (B, C, D, A, buf_p, corr_p, 22, 0xfd469501); OP1 (A, B, C, D, buf_p, corr_p, 7, 0x698098d8); OP1 (D, A, B, C, buf_p, corr_p, 12, 0x8b44f7af); OP1 (C, D, A, B, buf_p, corr_p, 17, 0xffff5bb1); OP1 (B, C, D, A, buf_p, corr_p, 22, 0x895cd7be); OP1 (A, B, C, D, buf_p, corr_p, 7, 0x6b901122); OP1 (D, A, B, C, buf_p, corr_p, 12, 0xfd987193); OP1 (C, D, A, B, buf_p, corr_p, 17, 0xa679438e); OP1 (B, C, D, A, buf_p, corr_p, 22, 0x49b40821); /* Round 2. */ OP234 (FG, A, B, C, D, correct[ 1], 5, 0xf61e2562); OP234 (FG, D, A, B, C, correct[ 6], 9, 0xc040b340); OP234 (FG, C, D, A, B, correct[ 11], 14, 0x265e5a51); OP234 (FG, B, C, D, A, correct[ 0], 20, 0xe9b6c7aa); OP234 (FG, A, B, C, D, correct[ 5], 5, 0xd62f105d); OP234 (FG, D, A, B, C, correct[ 10], 9, 0x02441453); OP234 (FG, C, D, A, B, correct[ 15], 14, 0xd8a1e681); OP234 (FG, B, C, D, A, correct[ 4], 20, 0xe7d3fbc8); OP234 (FG, A, B, C, D, correct[ 9], 5, 0x21e1cde6); OP234 (FG, D, A, B, C, correct[ 14], 9, 0xc33707d6); OP234 (FG, C, D, A, B, correct[ 3], 14, 0xf4d50d87); OP234 (FG, B, C, D, A, correct[ 8], 20, 0x455a14ed); OP234 (FG, A, B, C, D, correct[ 13], 5, 0xa9e3e905); OP234 (FG, D, A, B, C, correct[ 2], 9, 0xfcefa3f8); OP234 (FG, C, D, A, B, correct[ 7], 14, 0x676f02d9); OP234 (FG, B, C, D, A, correct[ 12], 20, 0x8d2a4c8a); /* Round 3. */ OP234 (FH, A, B, C, D, correct[ 5], 4, 0xfffa3942); OP234 (FH, D, A, B, C, correct[ 8], 11, 0x8771f681); OP234 (FH, C, D, A, B, correct[ 11], 16, 0x6d9d6122); OP234 (FH, B, C, D, A, correct[ 14], 23, 0xfde5380c); OP234 (FH, A, B, C, D, correct[ 1], 4, 0xa4beea44); OP234 (FH, D, A, B, C, correct[ 4], 11, 0x4bdecfa9); OP234 (FH, C, D, A, B, correct[ 7], 16, 0xf6bb4b60); OP234 (FH, B, C, D, A, correct[ 10], 23, 0xbebfbc70); OP234 (FH, A, B, C, D, correct[ 13], 4, 0x289b7ec6); OP234 (FH, D, A, B, C, correct[ 0], 11, 0xeaa127fa); OP234 (FH, C, D, A, B, correct[ 3], 16, 0xd4ef3085); OP234 (FH, B, C, D, A, correct[ 6], 23, 0x04881d05); OP234 (FH, A, B, C, D, correct[ 9], 4, 0xd9d4d039); OP234 (FH, D, A, B, C, correct[ 12], 11, 0xe6db99e5); OP234 (FH, C, D, A, B, correct[ 15], 16, 0x1fa27cf8); OP234 (FH, B, C, D, A, correct[ 2], 23, 0xc4ac5665); /* Round 4. */ OP234 (FI, A, B, C, D, correct[ 0], 6, 0xf4292244); OP234 (FI, D, A, B, C, correct[ 7], 10, 0x432aff97); OP234 (FI, C, D, A, B, correct[ 14], 15, 0xab9423a7); OP234 (FI, B, C, D, A, correct[ 5], 21, 0xfc93a039); OP234 (FI, A, B, C, D, correct[ 12], 6, 0x655b59c3); OP234 (FI, D, A, B, C, correct[ 3], 10, 0x8f0ccc92); OP234 (FI, C, D, A, B, correct[ 10], 15, 0xffeff47d); OP234 (FI, B, C, D, A, correct[ 1], 21, 0x85845dd1); OP234 (FI, A, B, C, D, correct[ 8], 6, 0x6fa87e4f); OP234 (FI, D, A, B, C, correct[ 15], 10, 0xfe2ce6e0); OP234 (FI, C, D, A, B, correct[ 6], 15, 0xa3014314); OP234 (FI, B, C, D, A, correct[ 13], 21, 0x4e0811a1); OP234 (FI, A, B, C, D, correct[ 4], 6, 0xf7537e82); OP234 (FI, D, A, B, C, correct[ 11], 10, 0xbd3af235); OP234 (FI, C, D, A, B, correct[ 2], 15, 0x2ad7d2bb); OP234 (FI, B, C, D, A, correct[ 9], 21, 0xeb86d391); /* Add the starting values of the context. */ A += A_save; B += B_save; C += C_save; D += D_save; } /* Put checksum in context given as argument. */ md5_p->md_A = A; md5_p->md_B = B; md5_p->md_C = C; md5_p->md_D = D; } /* * md5_get_result * * DESCRIPTION: * * Copy the resulting MD5 signature from MD5_P into the first 16 bytes * (MD5_SIZE) of the result buffer. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to MD5 structure from which we are getting the result. * * result - A 16 byte buffer that will contain the MD5 signature. */ static void md5_get_result(const md5_t *md5_p, void *result) { md5_uint32 hold; void *res_p = result; hold = SWAP(md5_p->md_A); memcpy(res_p, &hold, sizeof(md5_uint32)); res_p = (char *)res_p + sizeof(md5_uint32); hold = SWAP(md5_p->md_B); memcpy(res_p, &hold, sizeof(md5_uint32)); res_p = (char *)res_p + sizeof(md5_uint32); hold = SWAP(md5_p->md_C); memcpy(res_p, &hold, sizeof(md5_uint32)); res_p = (char *)res_p + sizeof(md5_uint32); hold = SWAP(md5_p->md_D); memcpy(res_p, &hold, sizeof(md5_uint32)); } /***************************** exported routines *****************************/ /* * md5_init * * DESCRIPTION: * * Initialize structure containing state of MD5 computation. (RFC 1321, * 3.3: Step 3). This is for progressive MD5 calculations only. If * you have the complete string available, md5_buffer should be used. * md5_process should be called for each bunch of bytes and after the * last process call, md5_finish should be called to get the * signature. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to md5 structure that we are initializing. */ void md5_init(md5_t *md5_p) { md5_p->md_A = 0x67452301; md5_p->md_B = 0xefcdab89; md5_p->md_C = 0x98badcfe; md5_p->md_D = 0x10325476; md5_p->md_total[0] = 0; md5_p->md_total[1] = 0; md5_p->md_buf_len = 0; } /* * md5_process * * DESCRIPTION: * * This function is used to progressively calculate a MD5 signature some * number of bytes at a time. If you have the complete string * available, md5_buffer should be used. The MD5 structure should * have been initialized with md5_init and after the last process * call, md5_finish should be called to get the results. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to MD5 structure which we are progressively updating. * * buffer - A buffer of bytes whose MD5 signature we are calculating. * * buf_len - The length of the buffer. */ void md5_process(md5_t *md5_p, const void *buffer, const unsigned int buf_len) { unsigned int len = buf_len; unsigned int in_block, add; /* * When we already have some bytes in our internal buffer, copy some * from the user to fill the block. */ if (md5_p->md_buf_len > 0) { in_block = md5_p->md_buf_len; if (in_block + len > sizeof(md5_p->md_buffer)) { add = sizeof(md5_p->md_buffer) - in_block; } else { add = len; } memcpy (md5_p->md_buffer + in_block, buffer, add); md5_p->md_buf_len += add; in_block += add; if (in_block > MD5_BLOCK_SIZE) { process_block (md5_p, md5_p->md_buffer, in_block & ~BLOCK_SIZE_MASK); /* the regions in the following copy operation will not overlap. */ memcpy (md5_p->md_buffer, md5_p->md_buffer + (in_block & ~BLOCK_SIZE_MASK), in_block & BLOCK_SIZE_MASK); md5_p->md_buf_len = in_block & BLOCK_SIZE_MASK; } buffer = (const char *)buffer + add; len -= add; } /* process available complete blocks right from the user buffer */ if (len > MD5_BLOCK_SIZE) { process_block (md5_p, buffer, len & ~BLOCK_SIZE_MASK); buffer = (const char *) buffer + (len & ~BLOCK_SIZE_MASK); len &= BLOCK_SIZE_MASK; } /* copy remaining bytes into the internal buffer */ if (len > 0) { memcpy (md5_p->md_buffer, buffer, len); md5_p->md_buf_len = len; } } /* * md5_finish * * DESCRIPTION: * * Finish a progressing MD5 calculation and copy the resulting MD5 * signature into the result buffer which should be 16 bytes * (MD5_SIZE). After this call, the MD5 structure is invalid. * * RETURNS: * * None. * * ARGUMENTS: * * md5_p - Pointer to MD5 structure which we are finishing. * * signature - A 16 byte buffer that will contain the MD5 signature. */ void md5_finish(md5_t *md5_p, void *signature) { md5_uint32 bytes, hold; int pad; /* take yet unprocessed bytes into account */ bytes = md5_p->md_buf_len; /* * Count remaining bytes. Modified to do this to better avoid * overflows in the lower word -- Gray 10/97. */ if (md5_p->md_total[0] > MAX_MD5_UINT32 - bytes) { md5_p->md_total[1]++; md5_p->md_total[0] -= (MAX_MD5_UINT32 - bytes); } else { md5_p->md_total[0] += bytes; } /* * Pad the buffer to the next MD5_BLOCK-byte boundary. (RFC 1321, * 3.1: Step 1). We need enough room for two size words and the * bytes left in the buffer. For some reason even if we are equal * to the block-size, we add an addition block of pad bytes. */ pad = MD5_BLOCK_SIZE - (sizeof(md5_uint32) * 2) - bytes; if (pad <= 0) { pad += MD5_BLOCK_SIZE; } /* * Modified from a fixed array to this assignment and memset to be * more flexible with block-sizes -- Gray 10/97. */ if (pad > 0) { /* some sort of padding start byte */ md5_p->md_buffer[bytes] = (unsigned char)0x80; if (pad > 1) { memset (md5_p->md_buffer + bytes + 1, 0, pad - 1); } bytes += pad; } /* put the 64-bit file length in _bits_ (i.e. *8) at the end of the buffer */ hold = SWAP(md5_p->md_total[0] << 3); memcpy(md5_p->md_buffer + bytes, &hold, sizeof(md5_uint32)); bytes += sizeof(md5_uint32); /* shift the high word over by 3 and add in the top 3 bits from the low */ hold = SWAP((md5_p->md_total[1] << 3) | (md5_p->md_total[0] >> 29)); memcpy(md5_p->md_buffer + bytes, &hold, sizeof(md5_uint32)); bytes += sizeof(md5_uint32); /* process last bytes, the padding chars, and size words */ process_block(md5_p, md5_p->md_buffer, bytes); md5_get_result(md5_p, signature); } /* * md5_buffer * * DESCRIPTION: * * This function is used to calculate a MD5 signature for a buffer of * bytes. If you only have part of a buffer that you want to process * then md5_init, md5_process, and md5_finish should be used. * * RETURNS: * * None. * * ARGUMENTS: * * buffer - A buffer of bytes whose MD5 signature we are calculating. * * buf_len - The length of the buffer. * * signature - A 16 byte buffer that will contain the MD5 signature. */ void md5_buffer(const char *buffer, const unsigned int buf_len, void *signature) { md5_t md5; /* initialize the computation context */ md5_init(&md5); /* process whole buffer but last buf_len % MD5_BLOCK bytes */ md5_process(&md5, buffer, buf_len); /* put result in desired memory area */ md5_finish(&md5, signature); } /* * md5_sig_to_string * * DESCRIPTION: * * Convert a MD5 signature in a 16 byte buffer into a hexadecimal string * representation. * * RETURNS: * * None. * * ARGUMENTS: * * signature - a 16 byte buffer that contains the MD5 signature. * * str - a string of charactes which should be at least 33 bytes long (2 * characters per MD5 byte and 1 for the \0). * * str_len - the length of the string. */ void md5_sig_to_string(void *signature, char *str, const int str_len) { unsigned char *sig_p; char *str_p, *max_p; unsigned int high, low; str_p = str; max_p = str + str_len; for (sig_p = (unsigned char *)signature; sig_p < (unsigned char *)signature + MD5_SIZE; sig_p++) { high = *sig_p / 16; low = *sig_p % 16; /* account for 2 chars */ if (str_p + 1 >= max_p) { break; } *str_p++ = HEX_STRING[high]; *str_p++ = HEX_STRING[low]; } /* account for 2 chars */ if (str_p < max_p) { *str_p++ = '\0'; } } /* * md5_sig_from_string * * DESCRIPTION: * * Convert a MD5 signature from a hexadecimal string representation into * a 16 byte buffer. * * RETURNS: * * None. * * ARGUMENTS: * * signature - A 16 byte buffer that will contain the MD5 signature. * * str - A string of charactes which _must_ be at least 32 bytes long (2 * characters per MD5 byte). */ void md5_sig_from_string(void *signature, const char *str) { unsigned char *sig_p; const char *str_p; char *hex; unsigned int high, low, val; hex = HEX_STRING; sig_p = signature; for (str_p = str; str_p < str + MD5_SIZE * 2; str_p += 2) { high = strchr(hex, *str_p) - hex; low = strchr(hex, *(str_p + 1)) - hex; val = high * 16 + low; *sig_p++ = val; } } jackd1-0.121.3+20120418git75e3e20b/jackd/clientengine.c0000644001605600047420000007252711736346233017505 0ustar adiira/* -*- mode: c; c-file-style: "bsd"; -*- */ /* * Client creation and destruction interfaces for JACK engine. * * Copyright (C) 2001-2003 Paul Davis * Copyright (C) 2004 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. * */ #include #include #include #include #include #include #include "internal.h" #include "engine.h" #include "messagebuffer.h" #include "version.h" #include "driver.h" #include #include #include "clientengine.h" #include "transengine.h" #include "libjack/local.h" static void jack_client_disconnect_ports (jack_engine_t *engine, jack_client_internal_t *client) { JSList *node; jack_port_internal_t *port; /* call tree **** MUST HOLD *** engine->client_lock */ for (node = client->ports; node; node = jack_slist_next (node)) { port = (jack_port_internal_t *) node->data; jack_port_clear_connections (engine, port); jack_port_registration_notify (engine, port->shared->id, FALSE); jack_port_release (engine, port); } jack_slist_free (client->ports); jack_slist_free (client->truefeeds); jack_slist_free (client->sortfeeds); client->truefeeds = 0; client->sortfeeds = 0; client->ports = 0; } int jack_client_do_deactivate (jack_engine_t *engine, jack_client_internal_t *client, int sort_graph) { /* caller must hold engine->client_lock and must have checked for and/or * cleared all connections held by client. */ VERBOSE(engine,"+++ deactivate %s", client->control->name); client->control->active = FALSE; jack_transport_client_exit (engine, client); if (!jack_client_is_internal (client) && engine->external_client_cnt > 0) { engine->external_client_cnt--; } if (sort_graph) { jack_sort_graph (engine); } return 0; } static int jack_load_client (jack_engine_t *engine, jack_client_internal_t *client, const char *so_name) { const char *errstr; char path_to_so[PATH_MAX+1]; snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name); client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); if (client->handle == 0) { if ((errstr = dlerror ()) != 0) { jack_error ("%s", errstr); } else { jack_error ("bizarre error loading %s", so_name); } return -1; } client->initialize = dlsym (client->handle, "jack_initialize"); if ((errstr = dlerror ()) != 0) { jack_error ("%s has no initialize() function\n", so_name); dlclose (client->handle); client->handle = 0; return -1; } client->finish = (void (*)(void *)) dlsym (client->handle, "jack_finish"); if ((errstr = dlerror ()) != 0) { jack_error ("%s has no finish() function", so_name); dlclose (client->handle); client->handle = 0; return -1; } return 0; } static void jack_client_unload (jack_client_internal_t *client) { if (client->handle) { if (client->finish) { client->finish (client->private_client->process_arg); } dlclose (client->handle); } } static void jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client) { VERBOSE (engine, "removing client \"%s\" from the processing chain", client->control->name); /* caller must hold the client_lock */ /* this stops jack_deliver_event() from contacing this client */ client->control->dead = TRUE; jack_client_disconnect_ports (engine, client); jack_client_do_deactivate (engine, client, FALSE); } void jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) { JSList *node; jack_client_id_t finalizer=0; /* caller must write-hold the client lock */ VERBOSE (engine, "removing client \"%s\"", client->control->name); if (client->control->type == ClientInternal) { /* unload it while its still a regular client */ jack_client_unload (client); } /* if its not already a zombie, make it so */ if (!client->control->dead) { jack_zombify_client (engine, client); } if (client->session_reply_pending) { engine->session_pending_replies -= 1; if (engine->session_pending_replies == 0) { if (write (engine->session_reply_fd, &finalizer, sizeof (finalizer)) < (ssize_t) sizeof (finalizer)) { jack_error ("cannot write SessionNotify result " "to client via fd = %d (%s)", engine->session_reply_fd, strerror (errno)); } engine->session_reply_fd = -1; } } if (client->control->type == ClientExternal) { /* try to force the server thread to return from poll */ close (client->event_fd); close (client->request_fd); } for (node = engine->clients; node; node = jack_slist_next (node)) { if (((jack_client_internal_t *) node->data)->control->id == client->control->id) { engine->clients = jack_slist_remove_link (engine->clients, node); jack_slist_free_1 (node); break; } } jack_client_delete (engine, client); /* ignore the driver, which counts as a client. */ if (engine->temporary && (jack_slist_length(engine->clients) <= 1)) { if (engine->wait_pid >= 0) { /* block new clients from being created after we release the lock. */ engine->new_clients_allowed = 0; /* tell the waiter we're done to initiate a normal shutdown. */ VERBOSE (engine, "Kill wait pid to stop"); kill (engine->wait_pid, SIGUSR2); /* unlock the graph so that the server thread can finish */ jack_unlock_graph (engine); sleep (-1); } else { exit (0); } } } int jack_check_clients (jack_engine_t* engine, int with_timeout_check) { /* CALLER MUST HOLD graph read lock */ JSList* node; jack_client_internal_t* client; int errs = 0; for (node = engine->clients; node; node = jack_slist_next (node)) { client = (jack_client_internal_t *) node->data; if (client->error) { errs++; continue; } if (with_timeout_check) { /* we can only consider the timeout a client error if * it actually woke up. its possible that the kernel * scheduler screwed us up and never woke up the * client in time. sigh. */ VERBOSE (engine, "checking client %s: awake at %" PRIu64 " finished at %" PRIu64, client->control->name, client->control->awake_at, client->control->finished_at); if (client->control->awake_at > 0) { if (client->control->finished_at == 0) { jack_time_t now = jack_get_microseconds(); if ((now - client->control->awake_at) < engine->driver->period_usecs) { /* we give the client a bit of time, to finish the cycle * we assume here, that we dont get signals delivered to this thread. */ struct timespec wait_time; wait_time.tv_sec = 0; wait_time.tv_nsec = (engine->driver->period_usecs - (now - client->control->awake_at)) * 1000; VERBOSE (engine, "client %s seems to have timed out. we may have mercy of %d ns." , client->control->name, (int) wait_time.tv_nsec ); nanosleep (&wait_time, NULL); } if (client->control->finished_at == 0) { client->control->timed_out++; client->error++; errs++; VERBOSE (engine, "client %s has timed out", client->control->name); } else { /* * the client recovered. if this is a single occurence, thats probably fine. * however, we increase the continuous_stream flag. */ engine->timeout_count += 1; } } } } } if (errs) { jack_engine_signal_problems (engine); } return errs; } void jack_remove_clients (jack_engine_t* engine, int* exit_freewheeling_when_done) { JSList *tmp, *node; int need_sort = FALSE; jack_client_internal_t *client; /* CALLER MUST HOLD GRAPH LOCK */ VERBOSE (engine, "++ Removing failed clients ..."); /* remove all dead clients */ for (node = engine->clients; node; ) { tmp = jack_slist_next (node); client = (jack_client_internal_t *) node->data; VERBOSE(engine, "client %s error status %d", client->control->name, client->error); if (client->error) { if (engine->freewheeling && client->control->id == engine->fwclient) { VERBOSE (engine, "freewheeling client has errors"); *exit_freewheeling_when_done = 1; } /* if we have a communication problem with the client, remove it. otherwise, turn it into a zombie. the client will/should realize this and will close its sockets. then we'll end up back here again and will finally remove the client. */ if (client->error >= JACK_ERROR_WITH_SOCKETS) { VERBOSE (engine, "removing failed " "client %s state = %s errors" " = %d", client->control->name, jack_client_state_name (client), client->error); jack_remove_client (engine, (jack_client_internal_t *) node->data); } else { VERBOSE (engine, "client failure: " "client %s state = %s errors" " = %d", client->control->name, jack_client_state_name (client), client->error); if (!engine->nozombies) { jack_zombify_client (engine, (jack_client_internal_t *) node->data); client->error = 0; } } need_sort = TRUE; } node = tmp; } if (need_sort) { jack_sort_graph (engine); } jack_engine_reset_rolling_usecs (engine); VERBOSE (engine, "-- Removing failed clients ..."); } jack_client_internal_t * jack_client_by_name (jack_engine_t *engine, const char *name) { jack_client_internal_t *client = NULL; JSList *node; jack_rdlock_graph (engine); for (node = engine->clients; node; node = jack_slist_next (node)) { if (strcmp ((const char *) ((jack_client_internal_t *) node->data)->control->name, name) == 0) { client = (jack_client_internal_t *) node->data; break; } } jack_unlock_graph (engine); return client; } static jack_client_id_t jack_client_id_by_name (jack_engine_t *engine, const char *name) { jack_client_id_t id = 0; /* NULL client ID */ JSList *node; jack_rdlock_graph (engine); for (node = engine->clients; node; node = jack_slist_next (node)) { if (strcmp ((const char *) ((jack_client_internal_t *) node->data)->control->name, name) == 0) { jack_client_internal_t *client = (jack_client_internal_t *) node->data; id = client->control->id; break; } } jack_unlock_graph (engine); return id; } jack_client_internal_t * jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id) { jack_client_internal_t *client = NULL; JSList *node; /* call tree ***MUST HOLD*** the graph lock */ for (node = engine->clients; node; node = jack_slist_next (node)) { if (((jack_client_internal_t *) node->data)->control->id == id) { client = (jack_client_internal_t *) node->data; break; } } return client; } int jack_client_name_reserved( jack_engine_t *engine, const char *name ) { JSList *node; for (node = engine->reserved_client_names; node; node = jack_slist_next (node)) { jack_reserved_name_t *reservation = (jack_reserved_name_t *) node->data; if( !strcmp( reservation->name, name ) ) return 1; } return 0; } /* generate a unique client name * * returns 0 if successful, updates name in place */ static inline int jack_generate_unique_name (jack_engine_t *engine, char *name) { int tens, ones; int length = strlen (name); if (length > JACK_CLIENT_NAME_SIZE - 4) { jack_error ("%s exists and is too long to make unique", name); return 1; /* failure */ } /* generate a unique name by appending "-01".."-99" */ name[length++] = '-'; tens = length++; ones = length++; name[tens] = '0'; name[ones] = '1'; name[length] = '\0'; while (jack_client_by_name (engine, name) || jack_client_name_reserved( engine, name )) { if (name[ones] == '9') { if (name[tens] == '9') { jack_error ("client %s has 99 extra" " instances already", name); return 1; /* give up */ } name[tens]++; name[ones] = '0'; } else { name[ones]++; } } return 0; } static int jack_client_name_invalid (jack_engine_t *engine, char *name, jack_options_t options, jack_status_t *status) { /* Since this is always called from the server thread, no * other new client will be created at the same time. So, * testing a name for uniqueness is valid here. When called * from jack_engine_load_driver() this is not strictly true, * but that seems to be adequately serialized due to engine * startup. There are no other clients at that point, anyway. */ if (jack_client_by_name (engine, name) || jack_client_name_reserved(engine, name )) { *status |= JackNameNotUnique; if (options & JackUseExactName) { jack_error ("cannot create new client; %s already" " exists", name); *status |= JackFailure; return TRUE; } if (jack_generate_unique_name(engine, name)) { *status |= JackFailure; return TRUE; } } return FALSE; } /* Set up the engine's client internal and control structures for both * internal and external clients. */ static jack_client_internal_t * jack_setup_client_control (jack_engine_t *engine, int fd, ClientType type, const char *name, jack_client_id_t uuid) { jack_client_internal_t *client; client = (jack_client_internal_t *) malloc (sizeof (jack_client_internal_t)); client->request_fd = fd; client->event_fd = -1; client->ports = 0; client->truefeeds = 0; client->sortfeeds = 0; client->execution_order = UINT_MAX; client->next_client = NULL; client->handle = NULL; client->finish = NULL; client->error = 0; if (type != ClientExternal) { client->control = (jack_client_control_t *) malloc (sizeof (jack_client_control_t)); } else { if (jack_shmalloc (sizeof (jack_client_control_t), &client->control_shm)) { jack_error ("cannot create client control block for %s", name); free (client); return 0; } if (jack_attach_shm (&client->control_shm)) { jack_error ("cannot attach to client control block " "for %s (%s)", name, strerror (errno)); jack_destroy_shm (&client->control_shm); free (client); return 0; } client->control = (jack_client_control_t *) jack_shm_addr (&client->control_shm); } client->control->type = type; client->control->active = 0; client->control->dead = FALSE; client->control->timed_out = 0; client->control->id = engine->next_client_id++; client->control->uid = uuid; strcpy ((char *) client->control->name, name); client->subgraph_start_fd = -1; client->subgraph_wait_fd = -1; client->session_reply_pending = FALSE; client->control->process_cbset = FALSE; client->control->bufsize_cbset = FALSE; client->control->srate_cbset = FALSE; client->control->xrun_cbset = FALSE; client->control->port_register_cbset = FALSE; client->control->port_connect_cbset = FALSE; client->control->graph_order_cbset = FALSE; client->control->client_register_cbset = FALSE; client->control->thread_cb_cbset = FALSE; client->control->session_cbset = FALSE; #if 0 if (type != ClientExternal) { client->process = NULL; client->process_arg = NULL; client->bufsize = NULL; client->bufsize_arg = NULL; client->srate = NULL; client->srate_arg = NULL; client->xrun = NULL; client->xrun_arg = NULL; client->port_register = NULL; client->port_register_arg = NULL; client->port_connect = NULL; client->port_connect_arg = NULL; client->graph_order = NULL; client->graph_order_arg = NULL; client->client_register = NULL; client->client_register_arg = NULL; client->thread_cb = NULL; client->thread_cb_arg = NULL; } #endif jack_transport_client_new (client); #ifdef JACK_USE_MACH_THREADS /* specific resources for server/client real-time thread * communication */ allocate_mach_serverport(engine, client); client->running = FALSE; #endif return client; } static void jack_ensure_uuid_unique (jack_engine_t *engine, jack_client_id_t uuid) { JSList *node; jack_lock_graph (engine); for (node=engine->clients; node; node=jack_slist_next (node)) { jack_client_internal_t *client = (jack_client_internal_t *) node->data; if (client->control->uid == uuid) client->control->uid = 0; } jack_unlock_graph (engine); } /* set up all types of clients */ static jack_client_internal_t * setup_client (jack_engine_t *engine, ClientType type, char *name, jack_client_id_t uuid, jack_options_t options, jack_status_t *status, int client_fd, const char *object_path, const char *object_data) { /* called with the request_lock */ jack_client_internal_t *client; /* validate client name, generate a unique one if appropriate */ if (jack_client_name_invalid (engine, name, options, status)) return NULL; if (uuid != 0) jack_ensure_uuid_unique (engine, uuid); /* create a client struct for this name */ if ((client = jack_setup_client_control (engine, client_fd, type, name, uuid )) == NULL) { *status |= (JackFailure|JackInitFailure); jack_error ("cannot create new client object"); return NULL; } /* only for internal clients, driver is already loaded */ if (type == ClientInternal) { if (jack_load_client (engine, client, object_path)) { jack_error ("cannot dynamically load client from" " \"%s\"", object_path); jack_client_delete (engine, client); *status |= (JackFailure|JackLoadFailure); return NULL; } } VERBOSE (engine, "new client: %s, id = %" PRIu32 " type %d @ %p fd = %d", client->control->name, client->control->id, type, client->control, client_fd); if (jack_client_is_internal(client)) { // XXX: do i need to lock the graph here ? // i moved this one up in the init process, lets see what happens. /* Internal clients need to make regular JACK API * calls, which need a jack_client_t structure. * Create one here. */ client->private_client = jack_client_alloc_internal (client->control, engine); /* Set up the pointers necessary for the request * system to work. The client is in the same address * space */ client->private_client->deliver_request = internal_client_request; client->private_client->deliver_arg = engine; } /* add new client to the clients list */ jack_lock_graph (engine); engine->clients = jack_slist_prepend (engine->clients, client); jack_engine_reset_rolling_usecs (engine); if (jack_client_is_internal(client)) { jack_unlock_graph (engine); /* Call its initialization function. This function * may make requests of its own, so we temporarily * release and then reacquire the request_lock. */ if (client->control->type == ClientInternal) { pthread_mutex_unlock (&engine->request_lock); if (client->initialize (client->private_client, object_data)) { /* failed: clean up client data */ VERBOSE (engine, "%s jack_initialize() failed!", client->control->name); jack_lock_graph (engine); jack_remove_client (engine, client); jack_unlock_graph (engine); *status |= (JackFailure|JackInitFailure); client = NULL; //JOQ: not clear that all allocated //storage has been cleaned up properly. } pthread_mutex_lock (&engine->request_lock); } } else { /* external client */ jack_unlock_graph (engine); } return client; } jack_client_internal_t * jack_create_driver_client (jack_engine_t *engine, char *name) { jack_client_connect_request_t req; jack_status_t status; jack_client_internal_t *client; snprintf (req.name, sizeof (req.name), "%s", name); pthread_mutex_lock (&engine->request_lock); client = setup_client (engine, ClientDriver, name, 0, JackUseExactName, &status, -1, NULL, NULL); pthread_mutex_unlock (&engine->request_lock); return client; } static jack_status_t handle_unload_client (jack_engine_t *engine, jack_client_id_t id) { /* called *without* the request_lock */ jack_client_internal_t *client; jack_status_t status = (JackNoSuchClient|JackFailure); jack_lock_graph (engine); if ((client = jack_client_internal_by_id (engine, id))) { VERBOSE (engine, "unloading client \"%s\"", client->control->name); jack_remove_client (engine, client); status = 0; } jack_unlock_graph (engine); return status; } static char * jack_get_reserved_name( jack_engine_t *engine, jack_client_id_t uuid ) { JSList *node; for (node = engine->reserved_client_names; node; node = jack_slist_next (node)) { jack_reserved_name_t *reservation = (jack_reserved_name_t *) node->data; if( reservation->uuid== uuid ) { char *retval = strdup( reservation->name ); free( reservation ); engine->reserved_client_names = jack_slist_remove( engine->reserved_client_names, reservation ); return retval; } } return 0; } int jack_client_create (jack_engine_t *engine, int client_fd) { /* called *without* the request_lock */ jack_client_internal_t *client; jack_client_connect_request_t req; jack_client_connect_result_t res; ssize_t nbytes; res.status = 0; nbytes = read (client_fd, &req, sizeof (req)); if (nbytes == 0) { /* EOF? */ jack_error ("cannot read connection request from client"); return -1; } /* First verify protocol version (first field of request), if * present, then make sure request has the expected length. */ if ((nbytes < sizeof (req.protocol_v)) || (req.protocol_v != jack_protocol_version) || (nbytes != sizeof (req))) { /* JACK protocol incompatibility */ res.status |= (JackFailure|JackVersionError); jack_error ("JACK protocol mismatch (%d vs %d)", req.protocol_v, jack_protocol_version); if (write (client_fd, &res, sizeof (res)) != sizeof (res)) { jack_error ("cannot write client connection response"); } return -1; } if (!req.load) { /* internal client close? */ int rc = -1; jack_client_id_t id; if ((id = jack_client_id_by_name(engine, req.name))) { rc = handle_unload_client (engine, id); } /* close does not send a reply */ return rc; } pthread_mutex_lock (&engine->request_lock); if( req.uuid ) { char *res_name = jack_get_reserved_name( engine, req.uuid ); if( res_name ) { snprintf( req.name, sizeof(req.name), "%s", res_name ); free(res_name); } } client = setup_client (engine, req.type, req.name, req.uuid, req.options, &res.status, client_fd, req.object_path, req.object_data); pthread_mutex_unlock (&engine->request_lock); if (client == NULL) { res.status |= JackFailure; /* just making sure */ return -1; } res.client_shm_index = client->control_shm.index; res.engine_shm_index = engine->control_shm.index; res.realtime = engine->control->real_time; res.realtime_priority = engine->rtpriority - 1; strncpy (res.name, req.name, sizeof(res.name)); #ifdef JACK_USE_MACH_THREADS /* Mach port number for server/client communication */ res.portnum = client->portnum; #endif if (jack_client_is_internal(client)) { /* the ->control pointers are for an internal client so we know they are the right sized pointers for this server. however, to keep the result structure the same size for both 32 and 64 bit clients/servers, the result structure stores them as 64 bit integer, so we have to do a slightly forced cast here. */ res.client_control = (uint64_t) ((intptr_t) client->control); res.engine_control = (uint64_t) ((intptr_t) engine->control); } else { strcpy (res.fifo_prefix, engine->fifo_prefix); } if (write (client_fd, &res, sizeof (res)) != sizeof (res)) { jack_error ("cannot write connection response to client"); jack_lock_graph (engine); client->control->dead = 1; jack_remove_client (engine, client); jack_unlock_graph (engine); return -1; } if (jack_client_is_internal (client)) { close (client_fd); } jack_client_registration_notify (engine, (const char*) client->control->name, 1); return 0; } int jack_client_activate (jack_engine_t *engine, jack_client_id_t id) { jack_client_internal_t *client; JSList *node; int ret = -1; int i; jack_event_t event; jack_lock_graph (engine); if ((client = jack_client_internal_by_id (engine, id))) { client->control->active = TRUE; jack_transport_activate(engine, client); /* we call this to make sure the FIFO is * built+ready by the time the client needs * it. we don't care about the return value at * this point. */ jack_get_fifo_fd (engine, ++engine->external_client_cnt); jack_sort_graph (engine); for (i = 0; i < engine->control->n_port_types; ++i) { event.type = AttachPortSegment; event.y.ptid = i; jack_deliver_event (engine, client, &event); } event.type = BufferSizeChange; jack_deliver_event (engine, client, &event); // send delayed notifications for ports. for (node = client->ports; node; node = jack_slist_next (node)) { jack_port_internal_t *port = (jack_port_internal_t *) node->data; jack_port_registration_notify (engine, port->shared->id, TRUE); } ret = 0; } jack_unlock_graph (engine); return ret; } int jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id) { JSList *node; int ret = -1; jack_lock_graph (engine); for (node = engine->clients; node; node = jack_slist_next (node)) { jack_client_internal_t *client = (jack_client_internal_t *) node->data; if (client->control->id == id) { JSList *portnode; jack_port_internal_t *port; for (portnode = client->ports; portnode; portnode = jack_slist_next (portnode)) { port = (jack_port_internal_t *) portnode->data; jack_port_clear_connections (engine, port); } ret = jack_client_do_deactivate (engine, client, TRUE); break; } } jack_unlock_graph (engine); return ret; } int jack_mark_client_socket_error (jack_engine_t *engine, int fd) { /* CALLER MUST HOLD GRAPH LOCK */ jack_client_internal_t *client = 0; JSList *node; for (node = engine->clients; node; node = jack_slist_next (node)) { if (jack_client_is_internal((jack_client_internal_t *) node->data)) { continue; } if (((jack_client_internal_t *) node->data)->request_fd == fd) { client = (jack_client_internal_t *) node->data; break; } } if (client) { VERBOSE (engine, "marking client %s with SOCKET error state = " "%s errors = %d", client->control->name, jack_client_state_name (client), client->error); client->error += JACK_ERROR_WITH_SOCKETS; } return 0; } void jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client) { jack_client_registration_notify (engine, (const char*) client->control->name, 0); if (jack_client_is_internal (client)) { free (client->private_client); free ((void *) client->control); } else { /* release the client segment, mark it for destruction, and free up the shm registry information so that it can be reused. */ jack_release_shm (&client->control_shm); jack_destroy_shm (&client->control_shm); } free (client); } void jack_intclient_handle_request (jack_engine_t *engine, jack_request_t *req) { jack_client_internal_t *client; req->status = 0; if ((client = jack_client_by_name (engine, req->x.intclient.name))) { req->x.intclient.id = client->control->id; } else { req->status |= (JackNoSuchClient|JackFailure); } } void jack_intclient_load_request (jack_engine_t *engine, jack_request_t *req) { /* called with the request_lock */ jack_client_internal_t *client; jack_status_t status = 0; VERBOSE (engine, "load internal client %s from %s, init `%s', " "options: 0x%x", req->x.intclient.name, req->x.intclient.path, req->x.intclient.init, req->x.intclient.options); client = setup_client (engine, ClientInternal, req->x.intclient.name, 0, req->x.intclient.options, &status, -1, req->x.intclient.path, req->x.intclient.init); if (client == NULL) { status |= JackFailure; /* just making sure */ req->x.intclient.id = 0; VERBOSE (engine, "load failed, status = 0x%x", status); } else { req->x.intclient.id = client->control->id; } req->status = status; } void jack_intclient_name_request (jack_engine_t *engine, jack_request_t *req) { jack_client_internal_t *client; jack_rdlock_graph (engine); if ((client = jack_client_internal_by_id (engine, req->x.intclient.id))) { strncpy ((char *) req->x.intclient.name, (char *) client->control->name, sizeof (req->x.intclient.name)); req->status = 0; } else { req->status = (JackNoSuchClient|JackFailure); } jack_unlock_graph (engine); } void jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req) { /* Called with the request_lock, but we need to call * handle_unload_client() *without* it. */ if (req->x.intclient.id) { pthread_mutex_unlock (&engine->request_lock); req->status = handle_unload_client (engine, req->x.intclient.id); pthread_mutex_lock (&engine->request_lock); } else { VERBOSE (engine, "invalid unload request"); req->status = JackFailure; } } jackd1-0.121.3+20120418git75e3e20b/COPYING0000644001605600047420000000041711736346233014641 0ustar adiiraFiles in this tree are mainly licensed under the GPL, as noted in the file headers. However, the libjack/ tree is licensed under the LGPL in order to allow for proprietary usage of Jack. Please see COPYING.GPL and COPYING.LGPL for more information on these two licenses. jackd1-0.121.3+20120418git75e3e20b/include/0000755001605600047420000000000011743611406015222 5ustar adiirajackd1-0.121.3+20120418git75e3e20b/include/varargs.h0000644001605600047420000000341311736346233017046 0ustar adiira/* * Copyright (C) 2004 Jack O'Quin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __jack_varargs_h__ #define __jack_varargs_h__ #ifdef __cplusplus extern "C" { #endif /* variable argument structure */ typedef struct { char *server_name; /* server name */ char *load_name; /* load module name */ char *load_init; /* initialization string */ char *sess_uuid; } jack_varargs_t; static inline void jack_varargs_init (jack_varargs_t *va) { memset (va, 0, sizeof(jack_varargs_t)); va->server_name = jack_default_server_name (); } static inline void jack_varargs_parse (jack_options_t options, va_list ap, jack_varargs_t *va) { /* initialize default settings */ jack_varargs_init (va); if ((options & JackServerName)) { char *sn = va_arg(ap, char *); if (sn) va->server_name = sn; } if ((options & JackLoadName)) va->load_name = va_arg(ap, char *); if ((options & JackLoadInit)) va->load_init = va_arg(ap, char *); if ((options & JackSessionID)) va->sess_uuid = va_arg(ap, char *); } #ifdef __cplusplus } #endif #endif /* __jack_varargs_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/sanitycheck.h0000644001605600047420000000062111736346233017704 0ustar adiira#ifndef __jack_sanitycheck_h__ #define __jack_sanitycheck_h__ /** * GPL etc. * * @author Florian Faber * * @version 0.1 (2009-01-17) [FF] * - initial version **/ /** * Performs a range of sanity checks on the system. The number of * found problems is returned. * **/ int sanitycheck (int do_realtime_check, int do_freqscaling_check); #endif /* __jack_sanitycheck_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/memops.h0000644001605600047420000001766611736346233016720 0ustar adiira/* Copyright (C) 1999-2000 Paul Davis 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. */ #ifndef __jack_memops_h__ #define __jack_memops_h__ #include typedef enum { None, Rectangular, Triangular, Shaped } DitherAlgorithm; #define DITHER_BUF_SIZE 8 #define DITHER_BUF_MASK 7 typedef struct { unsigned int depth; float rm1; unsigned int idx; float e[DITHER_BUF_SIZE]; } dither_state_t; /* float functions */ void sample_move_floatLE_sSs (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long dst_skip); void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); /* integer functions */ void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_merge_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_merge_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); static __inline__ void sample_merge (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) { while (cnt--) { *dst += *src; dst++; src++; } } static __inline__ void sample_memcpy (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) { memcpy (dst, src, cnt * sizeof (jack_default_audio_sample_t)); } void memset_interleave (char *dst, char val, unsigned long bytes, unsigned long unit_bytes, unsigned long skip_bytes); void memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); void memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); void merge_memcpy_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); void merge_memcpy_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); #endif /* __jack_memops_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/unlock.h0000644001605600047420000000170511736346233016676 0ustar adiira/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Copyright (C) 2001-2003 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __jack_mlock_h__ #define __jack_mlock_h__ extern void cleanup_mlock (void); #endif /* __jack_mlock_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/start.h0000644001605600047420000000145211736346233016537 0ustar adiira/* Copyright (C) 2002 Fernando Lopez-Lezcano 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. */ #define PIPE_READ_FD (3) #define PIPE_WRITE_FD (4) jackd1-0.121.3+20120418git75e3e20b/include/shm.h0000644001605600047420000000752511736346233016200 0ustar adiira#ifndef __jack_shm_h__ #define __jack_shm_h__ #include #include #include #define MAX_SERVERS 8 /* maximum concurrent servers */ #define MAX_SHM_ID 256 /* generally about 16 per server */ #define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */ #define JACK_SHM_MAGIC 0x4a41434b /* shm magic number: "JACK" */ #define JACK_SHM_NULL_INDEX -1 /* NULL SHM index */ #define JACK_SHM_REGISTRY_INDEX -2 /* pseudo SHM index for registry */ /* On Mac OS X, SHM_NAME_MAX is the maximum length of a shared memory * segment name (instead of NAME_MAX or PATH_MAX as defined by the * standard). */ #ifdef USE_POSIX_SHM #ifndef SHM_NAME_MAX #define SHM_NAME_MAX NAME_MAX #endif typedef char shm_name_t[SHM_NAME_MAX]; typedef shm_name_t jack_shm_id_t; #else /* System V SHM */ typedef int jack_shm_id_t; #endif /* SHM type */ /* shared memory type */ typedef enum { shm_POSIX = 1, /* POSIX shared memory */ shm_SYSV = 2 /* System V shared memory */ } jack_shmtype_t; typedef int16_t jack_shm_registry_index_t; /** * A structure holding information about shared memory allocated by * JACK. this persists across invocations of JACK, and can be used by * multiple JACK servers. It contains no pointers and is valid across * address spaces. * * The registry consists of two parts: a header including an array of * server names, followed by an array of segment registry entries. */ typedef struct _jack_shm_server { pid_t pid; /* process ID */ char name[JACK_SERVER_NAME_SIZE]; } jack_shm_server_t; typedef struct _jack_shm_header { uint32_t magic; /* magic number */ uint16_t protocol; /* JACK protocol version */ jack_shmtype_t type; /* shm type */ jack_shmsize_t size; /* total registry segment size */ jack_shmsize_t hdr_len; /* size of header */ jack_shmsize_t entry_len; /* size of registry entry */ jack_shm_server_t server[MAX_SERVERS]; /* current server array */ } jack_shm_header_t; typedef struct _jack_shm_registry { jack_shm_registry_index_t index; /* offset into the registry */ pid_t allocator; /* PID that created shm segment */ jack_shmsize_t size; /* for POSIX unattach */ jack_shm_id_t id; /* API specific, see above */ } jack_shm_registry_t; #define JACK_SHM_REGISTRY_SIZE (sizeof (jack_shm_header_t) \ + sizeof (jack_shm_registry_t) * MAX_SHM_ID) /** * a structure holding information about shared memory * allocated by JACK. this version is valid only * for a given address space. It contains a pointer * indicating where the shared memory has been * attached to the address space. */ typedef struct _jack_shm_info { jack_shm_registry_index_t index; /* offset into the registry */ void *attached_at; /* address where attached */ } jack_shm_info_t; /* utility functions used only within JACK */ extern void jack_shm_copy_from_registry (jack_shm_info_t*, jack_shm_registry_index_t); extern void jack_shm_copy_to_registry (jack_shm_info_t*, jack_shm_registry_index_t*); extern void jack_release_shm_info (jack_shm_registry_index_t); static inline char* jack_shm_addr (jack_shm_info_t* si) { return si->attached_at; } /* here beginneth the API */ extern int jack_register_server (const char *server_name, int new_registry); extern void jack_unregister_server (const char *server_name); extern int jack_initialize_shm (const char *server_name); extern int jack_cleanup_shm (void); extern int jack_shmalloc (jack_shmsize_t size, jack_shm_info_t* result); extern void jack_release_shm (jack_shm_info_t*); extern void jack_destroy_shm (jack_shm_info_t*); extern int jack_attach_shm (jack_shm_info_t*); extern int jack_resize_shm (jack_shm_info_t*, jack_shmsize_t size); #endif /* __jack_shm_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/systemtest.h0000644001605600047420000000416611736346233017633 0ustar adiira#ifndef __jack_systemtest_h__ #define __jack_systemtest_h__ /** * GPL, yabbadabba * * Set of functions to gather system information for the jack setup wizard. * * @author Florian Faber, faber@faberman.de * * @version 0.1 (2009-01-15) [FF] * - initial version * **/ /** * This function checks for the existence of known frequency scaling mechanisms * in this system. * * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise. **/ int system_has_frequencyscaling(); /** * This function determines wether the CPU has a variable clock speed if frequency * scaling is available. * * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise **/ int system_uses_frequencyscaling(); /*** * Checks for a definition in /etc/security/limits.conf that looks * as if it allows RT scheduling priority. * * @returns 1 if there appears to be such a line **/ int system_has_rtprio_limits_conf (); /** * Checks for the existence of the 'audio' group on this system * * @returns 0 is there is no 'audio' group, non-0 otherwise **/ int system_has_audiogroup(); /** * Tests wether the owner of this process is in the 'audio' group. * * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise **/ int system_user_in_audiogroup(); /** * Determines wether the owner of this process can enable rt priority. * * @returns 0 if this process can not be switched to rt prio, non-0 otherwise **/ int system_user_can_rtprio(); long long unsigned int system_memlock_amount(); /** * Checks wether the memlock limit is unlimited * * @returns 0 if the memlock limit is limited, non-0 otherwise **/ int system_memlock_is_unlimited(); long long unsigned int system_available_physical_mem(); /** * Gets the version of the currently running kernel * * @returns String with the full version of the kernel **/ char* system_kernel_version(); /** * Returns the username. The caller is in charge of disposal of * the returned name. * * @returns Pointer to a username or NULL **/ char* system_get_username(); #endif /* __jack_systemtest_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/messagebuffer.h0000644001605600047420000000307511736346233020223 0ustar adiira/* * messagebuffer.h -- realtime-safe message interface for jackd. * * This function is included in libjack so backend drivers can use * it, *not* for external client processes. The VERBOSE() and * MESSAGE() macros are realtime-safe. */ /* * Copyright (C) 2004 Rui Nuno Capela, Steve Harris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __jack_messagebuffer_h__ #define __jack_messagebuffer_h__ #define MESSAGE(fmt,args...) jack_messagebuffer_add(fmt , ##args) #define VERBOSE(engine,fmt,args...) \ if ((engine)->verbose) \ jack_messagebuffer_add(fmt , ##args) void jack_messagebuffer_init(); void jack_messagebuffer_exit(); void jack_message_buffer_thread_init (void (*cb)(void*), void*); void jack_messagebuffer_add(const char *fmt, ...); void jack_messagebuffer_thread_init (void (*cb)(void*), void* arg); #endif /* __jack_messagebuffer_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/atomicity.h0000644001605600047420000000271611736346233017410 0ustar adiira/* Copyright (C) 2004 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. */ #ifndef __jack_atomicity_h__ #define __jack_atomicity_h__ /* * Interface with various machine-dependent headers derived from the * gcc/libstdc++.v3 sources. We try to modify the GCC sources as * little as possible. The following include is resolved using the * config/configure.hosts mechanism. It will use an OS-dependent * version if available, otherwise the one for this CPU. Some of * these files might not work with older GCC compilers. */ #include /* These functions are defined for each platform. The C++ library * function names start with "__" to avoid namespace pollution. */ #define exchange_and_add __exchange_and_add #define atomic_add __atomic_add #endif /* __jack_atomicity_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/hardware.h0000644001605600047420000000401111736346233017171 0ustar adiira/* Copyright (C) 2001 Paul Davis 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. */ #ifndef __jack_hardware_h__ #define __jack_hardware_h__ #include typedef enum { AutoSync, WordClock, ClockMaster } SampleClockMode; typedef enum { Cap_HardwareMonitoring = 0x1, Cap_AutoSync = 0x2, Cap_WordClock = 0x4, Cap_ClockMaster = 0x8, Cap_ClockLockReporting = 0x10, Cap_HardwareMetering = 0x20 } Capabilities; struct _jack_hardware; typedef void (*JackHardwareReleaseFunction)(struct _jack_hardware *); typedef int (*JackHardwareSetInputMonitorMaskFunction)(struct _jack_hardware *, unsigned long); typedef int (*JackHardwareChangeSampleClockFunction)(struct _jack_hardware *, SampleClockMode); typedef double (*JackHardwareGetHardwarePeak)(jack_port_t *port, jack_nframes_t frames); typedef double (*JackHardwareGetHardwarePower)(jack_port_t *port, jack_nframes_t frames); typedef struct _jack_hardware { unsigned long capabilities; unsigned long input_monitor_mask; JackHardwareChangeSampleClockFunction change_sample_clock; JackHardwareSetInputMonitorMaskFunction set_input_monitor_mask; JackHardwareReleaseFunction release; JackHardwareGetHardwarePeak get_hardware_peak; JackHardwareGetHardwarePower get_hardware_power; void *private; } jack_hardware_t; jack_hardware_t * jack_hardware_new (); #endif /* __jack_hardware_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/engine.h0000644001605600047420000002226311736346233016652 0ustar adiira/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Copyright (C) 2001-2003 Paul Davis 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. */ #ifndef __jack_engine_h__ #define __jack_engine_h__ #include #include "internal.h" #include "driver_interface.h" struct _jack_driver; struct _jack_client_internal; struct _jack_port_internal; /* Structures is allocated by the engine in local memory to keep track * of port buffers and connections. */ typedef struct { jack_shm_info_t* shm_info; jack_shmsize_t offset; } jack_port_buffer_info_t; /* The engine keeps an array of these in its local memory. */ typedef struct _jack_port_internal { struct _jack_port_shared *shared; JSList *connections; jack_port_buffer_info_t *buffer_info; } jack_port_internal_t; /* The engine's internal port type structure. */ typedef struct _jack_port_buffer_list { pthread_mutex_t lock; /* only lock within server */ JSList *freelist; /* list of free buffers */ jack_port_buffer_info_t *info; /* jack_buffer_info_t array */ } jack_port_buffer_list_t; typedef struct _jack_reserved_name { jack_client_id_t uuid; char name[JACK_CLIENT_NAME_SIZE]; } jack_reserved_name_t; #define JACKD_WATCHDOG_TIMEOUT 10000 #define JACKD_CLIENT_EVENT_TIMEOUT 2000 /* The main engine structure in local memory. */ struct _jack_engine { jack_control_t *control; JSList *drivers; struct _jack_driver *driver; jack_driver_desc_t *driver_desc; JSList *driver_params; JSList *slave_drivers; /* these are "callbacks" made by the driver backend */ int (*set_buffer_size) (struct _jack_engine *, jack_nframes_t frames); int (*set_sample_rate) (struct _jack_engine *, jack_nframes_t frames); int (*run_cycle) (struct _jack_engine *, jack_nframes_t nframes, float delayed_usecs); void (*delay) (struct _jack_engine *, float delayed_usecs); void (*transport_cycle_start) (struct _jack_engine *, jack_time_t time); void (*driver_exit) (struct _jack_engine *); jack_time_t (*get_microseconds)(void); /* "private" sections starts here */ /* engine serialization -- use precedence for deadlock avoidance */ pthread_mutex_t request_lock; /* precedes client_lock */ pthread_rwlock_t client_lock; pthread_mutex_t port_lock; pthread_mutex_t problem_lock; /* must hold write lock on client_lock */ int process_errors; int period_msecs; /* Time to wait for clients in msecs. Used when jackd is run * without realtime priority enabled. */ int client_timeout_msecs; /* info on the shm segment containing this->control */ jack_shm_info_t control_shm; /* address-space local port buffer and segment info, indexed by the port type_id */ jack_port_buffer_list_t port_buffers[JACK_MAX_PORT_TYPES]; jack_shm_info_t port_segment[JACK_MAX_PORT_TYPES]; unsigned int port_max; pthread_t server_thread; pthread_t watchdog_thread; int fds[2]; int cleanup_fifo[2]; jack_client_id_t next_client_id; size_t pfd_size; size_t pfd_max; struct pollfd *pfd; char fifo_prefix[PATH_MAX+1]; int *fifo; unsigned long fifo_size; /* session handling */ int session_reply_fd; int session_pending_replies; unsigned long external_client_cnt; int rtpriority; volatile char freewheeling; volatile char stop_freewheeling; jack_client_id_t fwclient; pthread_t freewheel_thread; char verbose; char do_munlock; const char *server_name; char temporary; int reordered; int watchdog_check; int feedbackcount; int removing_clients; pid_t wait_pid; int nozombies; int timeout_count_threshold; volatile int problems; volatile int timeout_count; volatile int new_clients_allowed; /* these lists are protected by `client_lock' */ JSList *clients; JSList *clients_waiting; JSList *reserved_client_names; jack_port_internal_t *internal_ports; jack_client_internal_t *timebase_client; jack_port_buffer_info_t *silent_buffer; jack_client_internal_t *current_client; #define JACK_ENGINE_ROLLING_COUNT 32 #define JACK_ENGINE_ROLLING_INTERVAL 1024 jack_time_t rolling_client_usecs[JACK_ENGINE_ROLLING_COUNT]; int rolling_client_usecs_cnt; int rolling_client_usecs_index; int rolling_interval; float max_usecs; float spare_usecs; int first_wakeup; #ifdef JACK_USE_MACH_THREADS /* specific resources for server/client real-time thread communication */ mach_port_t servertask, bp; int portnum; #endif /* used for port names munging */ int audio_out_cnt; int audio_in_cnt; int midi_out_cnt; int midi_in_cnt; }; /* public functions */ jack_engine_t *jack_engine_new (int real_time, int real_time_priority, int do_mlock, int do_unlock, const char *server_name, int temporary, int verbose, int client_timeout, unsigned int port_max, pid_t waitpid, jack_nframes_t frame_time_offset, int nozombies, int timeout_count_threshold, JSList *drivers); void jack_engine_delete (jack_engine_t *); int jack_run (jack_engine_t *engine); int jack_wait (jack_engine_t *engine); int jack_engine_load_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc, JSList * driver_params); int jack_engine_load_slave_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc, JSList * driver_params); void jack_dump_configuration(jack_engine_t *engine, int take_lock); /* private engine functions */ void jack_engine_reset_rolling_usecs (jack_engine_t *engine); int internal_client_request (void* ptr, jack_request_t *request); int jack_get_fifo_fd (jack_engine_t *engine, unsigned int which_fifo); extern jack_timer_type_t clock_source; extern jack_client_internal_t * jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id); #define jack_rdlock_graph(e) { DEBUG ("acquiring graph read lock"); if (pthread_rwlock_rdlock (&e->client_lock)) abort(); } #define jack_lock_graph(e) { DEBUG ("acquiring graph write lock"); if (pthread_rwlock_wrlock (&e->client_lock)) abort(); } #define jack_try_rdlock_graph(e) pthread_rwlock_tryrdlock (&e->client_lock) #define jack_unlock_graph(e) { DEBUG ("release graph lock"); if (pthread_rwlock_unlock (&e->client_lock)) abort(); } #define jack_trylock_problems(e) pthread_mutex_trylock (&e->problem_lock) #define jack_lock_problems(e) { DEBUG ("acquiring problem lock"); if (pthread_mutex_lock (&e->problem_lock)) abort(); } #define jack_unlock_problems(e) { DEBUG ("release problem lock"); if (pthread_mutex_unlock (&e->problem_lock)) abort(); } #if 0 static inline void jack_rdlock_graph (jack_engine_t* engine) { DEBUG ("acquiring graph read lock"); pthread_rwlock_rdlock (&engine->client_lock); } static inline void jack_lock_graph (jack_engine_t* engine) { DEBUG ("acquiring graph lock"); pthread_rwlock_wrlock (&engine->client_lock); } static inline int jack_try_rdlock_graph (jack_engine_t *engine) { DEBUG ("TRYING to acquiring graph read lock"); return pthread_rwlock_tryrdlock (&engine->client_lock); } static inline void jack_unlock_graph (jack_engine_t* engine) { DEBUG ("releasing graph lock"); pthread_rwlock_unlock (&engine->client_lock); } #endif static inline unsigned int jack_power_of_two (unsigned int n) { return !(n & (n - 1)); } /* Internal port handling interfaces for JACK engine. */ void jack_port_clear_connections (jack_engine_t *engine, jack_port_internal_t *port); void jack_port_registration_notify (jack_engine_t *, jack_port_id_t, int); void jack_port_release (jack_engine_t *engine, jack_port_internal_t *); void jack_sort_graph (jack_engine_t *engine); int jack_stop_freewheeling (jack_engine_t* engine, int engine_exiting); jack_client_internal_t * jack_client_by_name (jack_engine_t *engine, const char *name); int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *); void jack_stop_watchdog (jack_engine_t * ); void jack_engine_signal_problems (jack_engine_t* engine); int jack_use_driver (jack_engine_t *engine, struct _jack_driver *driver); int jack_drivers_start (jack_engine_t *engine); int jack_add_slave_driver (jack_engine_t *engine, struct _jack_driver *driver); #endif /* __jack_engine_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/driver.h0000644001605600047420000002374411736346233016705 0ustar adiira/* Copyright (C) 2001 Paul Davis 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. */ #ifndef __jack_driver_h__ #define __jack_driver_h__ #include #include #include "port.h" #include "driver_interface.h" typedef float gain_t; typedef unsigned long channel_t; typedef enum { Lock = 0x1, NoLock = 0x2, Sync = 0x4, NoSync = 0x8 } ClockSyncStatus; typedef void (*ClockSyncListenerFunction)(channel_t,ClockSyncStatus,void*); typedef struct { unsigned long id; ClockSyncListenerFunction function; void *arg; } ClockSyncListener; struct _jack_engine; struct _jack_driver; typedef int (*JackDriverAttachFunction)(struct _jack_driver *, struct _jack_engine *); typedef int (*JackDriverDetachFunction)(struct _jack_driver *, struct _jack_engine *); typedef int (*JackDriverReadFunction)(struct _jack_driver *, jack_nframes_t nframes); typedef int (*JackDriverWriteFunction)(struct _jack_driver *, jack_nframes_t nframes); typedef int (*JackDriverNullCycleFunction)(struct _jack_driver *, jack_nframes_t nframes); typedef int (*JackDriverStopFunction)(struct _jack_driver *); typedef int (*JackDriverStartFunction)(struct _jack_driver *); typedef int (*JackDriverBufSizeFunction)(struct _jack_driver *, jack_nframes_t nframes); /* Call sequence summary: 1) engine loads driver via runtime dynamic linking - calls jack_driver_load - we call dlsym for "driver_initialize" and execute it 2) engine attaches to driver 3) engine starts driver 4) driver runs its own thread, calling while () { driver->wait (); driver->engine->run_cycle () } 5) engine stops driver 6) engine detaches from driver 7) engine calls driver `finish' routine Note that stop/start may be called multiple times in the event of an error return from the `wait' function. */ typedef struct _jack_driver { /* The _jack_driver structure fields are included at the beginning of each driver-specific structure using the JACK_DRIVER_DECL macro, which is defined below. The comments that follow describe each common field. The driver should set this to be the interval it expects to elapse between returning from the `wait' function. if set to zero, it implies that the driver does not expect regular periodic wakeups. jack_time_t period_usecs; The driver should set this within its "wait" function to indicate the UST of the most recent determination that the engine cycle should run. it should not be set if the "extra_fd" argument of the wait function is set to a non-zero value. jack_time_t last_wait_ust; These are not used by the driver. They should not be written to or modified in any way void *handle; struct _jack_internal_client *internal_client; This should perform any cleanup associated with the driver. it will be called when jack server process decides to get rid of the driver. in some systems, it may not be called at all, so the driver should never rely on a call to this. it can set it to NULL if it has nothing do do. void (*finish)(struct _jack_driver *); The JACK engine will call this when it wishes to attach itself to the driver. the engine will pass a pointer to itself, which the driver may use in anyway it wishes to. the driver may assume that this is the same engine object that will make `wait' calls until a `detach' call is made. JackDriverAttachFunction attach; The JACK engine will call this when it is finished using a driver. JackDriverDetachFunction detach; The JACK engine will call this when it wants to wait until the driver decides that its time to process some data. the driver returns a count of the number of audioframes that can be processed. it should set the variable pointed to by `status' as follows: zero: the wait completed normally, processing may begin negative: the wait failed, and recovery is not possible positive: the wait failed, and the driver stopped itself. a call to `start' will return the driver to a correct and known state. the driver should also fill out the `delayed_usecs' variable to indicate any delay in its expected periodic execution. for example, if it discovers that its return from poll(2) is later than it expects it to be, it would place an estimate of the delay in this variable. the engine will use this to decide if it plans to continue execution. JackDriverWaitFunction wait; The JACK engine will call this to ask the driver to move data from its inputs to its output port buffers. it should return 0 to indicate successful completion, negative otherwise. This function will always be called after the wait function (above). JackDriverReadFunction read; The JACK engine will call this to ask the driver to move data from its input port buffers to its outputs. it should return 0 to indicate successful completion, negative otherwise. this function will always be called after the read function (above). JackDriverWriteFunction write; The JACK engine will call this after the wait function (above) has been called, but for some reason the engine is unable to execute a full "cycle". the driver should do whatever is necessary to keep itself running correctly, but cannot reference ports or other JACK data structures in any way. JackDriverNullCycleFunction null_cycle; The engine will call this when it plans to stop calling the `wait' function for some period of time. the driver should take appropriate steps to handle this (possibly no steps at all). NOTE: the driver must silence its capture buffers (if any) from within this function or the function that actually implements the change in state. JackDriverStopFunction stop; The engine will call this to let the driver know that it plans to start calling the `wait' function on a regular basis. the driver should take any appropriate steps to handle this (possibly no steps at all). NOTE: The driver may wish to silence its playback buffers (if any) from within this function or the function that actually implements the change in state. JackDriverStartFunction start; The engine will call this to let the driver know that some client has requested a new buffer size. The stop function will be called prior to this, and the start function after this one has returned. JackDriverBufSizeFunction bufsize; */ /* define the fields here... */ #define JACK_DRIVER_DECL \ jack_time_t period_usecs; \ jack_time_t last_wait_ust; \ void *handle; \ struct _jack_client_internal * internal_client; \ void (*finish)(struct _jack_driver *);\ JackDriverAttachFunction attach; \ JackDriverDetachFunction detach; \ JackDriverReadFunction read; \ JackDriverWriteFunction write; \ JackDriverNullCycleFunction null_cycle; \ JackDriverStopFunction stop; \ JackDriverStartFunction start; \ JackDriverBufSizeFunction bufsize; JACK_DRIVER_DECL /* expand the macro */ } jack_driver_t; typedef jack_driver_desc_t * (*JackDriverDescFunction) (); void jack_driver_init (jack_driver_t *); void jack_driver_release (jack_driver_t *); jack_driver_t *jack_driver_load (int argc, char **argv); void jack_driver_unload (jack_driver_t *); /**************************** *** Non-Threaded Drivers *** ****************************/ /* Call sequence summary: 1) engine loads driver via runtime dynamic linking - calls jack_driver_load - we call dlsym for "driver_initialize" and execute it - driver_initialize calls jack_driver_nt_init 2) nt layer attaches to driver 3) nt layer starts driver 4) nt layer runs a thread, calling while () { driver->nt_run_ctcle(); } 5) nt layer stops driver 6) nt layer detaches driver 7) engine calls driver `finish' routine which calls jack_driver_nt_finish Note that stop/start may be called multiple times in the event of an error return from the `wait' function. */ struct _jack_driver_nt; typedef int (*JackDriverNTAttachFunction)(struct _jack_driver_nt *); typedef int (*JackDriverNTDetachFunction)(struct _jack_driver_nt *); typedef int (*JackDriverNTStopFunction)(struct _jack_driver_nt *); typedef int (*JackDriverNTStartFunction)(struct _jack_driver_nt *); typedef int (*JackDriverNTBufSizeFunction)(struct _jack_driver_nt *, jack_nframes_t nframes); typedef int (*JackDriverNTRunCycleFunction)(struct _jack_driver_nt *); typedef struct _jack_driver_nt { #define JACK_DRIVER_NT_DECL \ JACK_DRIVER_DECL \ struct _jack_engine * engine; \ volatile int nt_run; \ pthread_t nt_thread; \ pthread_mutex_t nt_run_lock; \ JackDriverNTAttachFunction nt_attach; \ JackDriverNTDetachFunction nt_detach; \ JackDriverNTStopFunction nt_stop; \ JackDriverNTStartFunction nt_start; \ JackDriverNTBufSizeFunction nt_bufsize; \ JackDriverNTRunCycleFunction nt_run_cycle; #define nt_read read #define nt_write write #define nt_null_cycle null_cycle JACK_DRIVER_NT_DECL } jack_driver_nt_t; void jack_driver_nt_init (jack_driver_nt_t * driver); void jack_driver_nt_finish (jack_driver_nt_t * driver); #endif /* __jack_driver_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/intsimd.h0000644001605600047420000000335611736346233017056 0ustar adiira/* Copyright (C) 2005-2007 Jussi Laako 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. */ #ifndef __jack_intsimd_h__ #define __jack_intsimd_h__ #ifdef USE_DYNSIMD #if (defined(__i386__) || defined(__x86_64__)) #define ARCH_X86 #endif /* __i386__ || __x86_64__ */ #endif /* USE_DYNSIMD */ #ifdef ARCH_X86 #define ARCH_X86_SSE(x) ((x) & 0xff) #define ARCH_X86_HAVE_SSE2(x) (ARCH_X86_SSE(x) >= 2) #define ARCH_X86_3DNOW(x) ((x) >> 8) #define ARCH_X86_HAVE_3DNOW(x) (ARCH_X86_3DNOW(x)) typedef float v2sf __attribute__((vector_size(8))); typedef float v4sf __attribute__((vector_size(16))); typedef v2sf * pv2sf; typedef v4sf * pv4sf; extern int cpu_type; int have_3dnow (void); int have_sse (void); void x86_3dnow_copyf (float *, const float *, int); void x86_3dnow_add2f (float *, const float *, int); void x86_sse_copyf (float *, const float *, int); void x86_sse_add2f (float *, const float *, int); void x86_sse_f2i (int *, const float *, int, float); void x86_sse_i2f (float *, const int *, int, float); #endif /* ARCH_X86 */ void jack_port_set_funcs (void); #endif /* __jack_intsimd_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/pool.h0000644001605600047420000000172111736346233016352 0ustar adiira/* Copyright (C) 2001 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __jack_pool_h__ #define __jack_pool_h__ #include void * jack_pool_alloc (size_t bytes); void jack_pool_release (void *); #endif /* __jack_pool_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/Makefile.am0000644001605600047420000000063611736346233017270 0ustar adiiraMAINTAINERCLEANFILES = Makefile.in version.h noinst_HEADERS = \ atomicity.h \ bitset.h \ driver.h \ driver_interface.h \ driver_parse.h \ engine.h \ hardware.h \ internal.h \ intsimd.h \ memops.h \ messagebuffer.h \ pool.h \ port.h \ ringbuffer.h \ sanitycheck.h \ shm.h \ start.h \ systemtest.h \ unlock.h \ varargs.h \ version.h jackd1-0.121.3+20120418git75e3e20b/include/driver_parse.h0000644001605600047420000001303711736346233020071 0ustar adiira/* -*- mode: c; c-file-style: "linux"; -*- */ /* Copyright (C) 2003 Bob Ham #include "driver_interface.h" static void jack_print_driver_options (jack_driver_desc_t * desc, FILE *file) { unsigned long i; char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1]; for (i = 0; i < desc->nparams; i++) { switch (desc->params[i].type) { case JackDriverParamInt: sprintf (arg_default, "%" PRId32, desc->params[i].value.i); break; case JackDriverParamUInt: sprintf (arg_default, "%" PRIu32, desc->params[i].value.ui); break; case JackDriverParamChar: sprintf (arg_default, "%c", desc->params[i].value.c); break; case JackDriverParamString: if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0) sprintf (arg_default, "%s", desc->params[i].value.str); else sprintf (arg_default, "none"); break; case JackDriverParamBool: sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false"); break; } fprintf (file, "\t-%c, --%s \t%s (default: %s)\n", desc->params[i].character, desc->params[i].name, desc->params[i].short_desc, arg_default); } } static void jack_print_driver_param_usage (jack_driver_desc_t * desc, unsigned long param, FILE *file) { fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n", desc->params[param].name, desc->name); fprintf (file, "%s\n", desc->params[param].long_desc); } static int jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char **argv, JSList ** param_ptr) { struct option * long_options; char * options, * options_ptr; unsigned long i; int opt, param_index; JSList * params = NULL; jack_driver_param_t * driver_param; if (argc <= 1) { *param_ptr = NULL; return 0; } /* check for help */ if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) { if (argc > 2) { for (i = 0; i < desc->nparams; i++) { if (strcmp (desc->params[i].name, argv[2]) == 0) { jack_print_driver_param_usage (desc, i, stdout); return 1; } } fprintf (stderr, "jackd: unknown option '%s' " "for driver '%s'\n", argv[2], desc->name); } printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name); jack_print_driver_options (desc, stdout); return 1; } /* set up the stuff for getopt */ options = calloc (desc->nparams*3 + 1, sizeof (char)); long_options = calloc (desc->nparams + 1, sizeof (struct option)); options_ptr = options; for (i = 0; i < desc->nparams; i++) { sprintf (options_ptr, "%c::", desc->params[i].character); options_ptr += 3; long_options[i].name = desc->params[i].name; long_options[i].flag = NULL; long_options[i].val = desc->params[i].character; long_options[i].has_arg = optional_argument; } /* create the params */ optind = 0; opterr = 0; while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) { if (opt == ':' || opt == '?') { if (opt == ':') { fprintf (stderr, "Missing option to argument '%c'\n", optopt); } else { fprintf (stderr, "Unknownage with option '%c'\n", optopt); } fprintf (stderr, "Options for driver '%s':\n", desc->name); jack_print_driver_options (desc, stderr); exit (1); } for (param_index = 0; param_index < desc->nparams; param_index++) { if (opt == desc->params[param_index].character) { break; } } driver_param = calloc (1, sizeof (jack_driver_param_t)); driver_param->character = desc->params[param_index].character; if (!optarg && optind < argc && strlen(argv[optind]) && argv[optind][0] != '-') { optarg = argv[optind]; } if (optarg) { switch (desc->params[param_index].type) { case JackDriverParamInt: driver_param->value.i = atoi (optarg); break; case JackDriverParamUInt: driver_param->value.ui = strtoul (optarg, NULL, 10); break; case JackDriverParamChar: driver_param->value.c = optarg[0]; break; case JackDriverParamString: strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX); break; case JackDriverParamBool: if (strcasecmp ("false", optarg) == 0 || strcasecmp ("off", optarg) == 0 || strcasecmp ("no", optarg) == 0 || strcasecmp ("0", optarg) == 0 || strcasecmp ("(null)", optarg) == 0 ) { driver_param->value.i = FALSE; } else { driver_param->value.i = TRUE; } break; } } else { if (desc->params[param_index].type == JackDriverParamBool) { driver_param->value.i = TRUE; } else { driver_param->value = desc->params[param_index].value; } } params = jack_slist_append (params, driver_param); } free (options); free (long_options); if (param_ptr) *param_ptr = params; return 0; } #endif /* __jack_driver_parse_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/driver_interface.h0000644001605600047420000000737011736346233020722 0ustar adiira/* Copyright (C) 2003 Bob Ham This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __jack_driver_interface_h__ #define __jack_driver_interface_h__ #ifdef __cplusplus extern "C" { #endif #include #include #include "internal.h" #define JACK_DRIVER_NAME_MAX 15 #define JACK_DRIVER_PARAM_NAME_MAX 15 #define JACK_DRIVER_PARAM_STRING_MAX 63 #define JACK_CONSTRAINT_FLAG_RANGE ((uint32_t)1) /**< if set, constraint is a range (min-max) */ #define JACK_CONSTRAINT_FLAG_STRICT ((uint32_t)2) /**< if set, constraint is strict, i.e. supplying non-matching value will not work */ #define JACK_CONSTRAINT_FLAG_FAKE_VALUE ((uint32_t)4) /**< if set, values have no user meaningful meaning */ /** Driver parameter types */ typedef enum { JackDriverParamInt = 1, JackDriverParamUInt, JackDriverParamChar, JackDriverParamString, JackDriverParamBool } jack_driver_param_type_t; /** Driver parameter value */ typedef union { uint32_t ui; int32_t i; char c; char str[JACK_DRIVER_PARAM_STRING_MAX+1]; } jack_driver_param_value_t; typedef struct { jack_driver_param_value_t value; char short_desc[64]; /**< A short (~30 chars) description for the user */ } jack_driver_param_value_enum_t; typedef struct { uint32_t flags; /**< JACK_CONSTRAINT_FLAG_XXX */ union { struct { jack_driver_param_value_t min; jack_driver_param_value_t max; } range; /**< valid when JACK_CONSTRAINT_FLAG_RANGE flag is set */ struct { uint32_t count; jack_driver_param_value_enum_t * possible_values_array; } enumeration; /**< valid when JACK_CONSTRAINT_FLAG_RANGE flag is not set */ } constraint; } jack_driver_param_constraint_desc_t; /** A driver parameter descriptor */ typedef struct { char name[JACK_DRIVER_NAME_MAX+1]; /**< The parameter's name */ char character; /**< The parameter's character (for getopt, etc) */ jack_driver_param_type_t type; /**< The parameter's type */ jack_driver_param_value_t value; /**< The parameter's (default) value */ jack_driver_param_constraint_desc_t * constraint; /**< Pointer to parameter constraint descriptor. NULL if there is no constraint */ char short_desc[64]; /**< A short (~30 chars) description for the user */ char long_desc[1024]; /**< A longer description for the user */ } jack_driver_param_desc_t; /** A driver parameter */ typedef struct { char character; jack_driver_param_value_t value; } jack_driver_param_t; /** A struct for describing a jack driver */ typedef struct { char name[JACK_DRIVER_NAME_MAX+1]; /**< The driver's canonical name */ char file[PATH_MAX+1]; /**< The filename of the driver's shared object file */ uint32_t nparams; /**< The number of parameters the driver has */ jack_driver_param_desc_t * params; /**< An array of parameter descriptors */ } jack_driver_desc_t; #ifdef __cplusplus } #endif #endif /* __jack_driver_interface_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/internal.h0000644001605600047420000004063411736346233017223 0ustar adiira/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Internal shared data and functions. If you edit this file, you should carefully consider changing the JACK_PROTOCOL_VERSION in configure.in. Copyright (C) 2001-2003 Paul Davis 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. */ #ifndef __jack_internal_h__ #define __jack_internal_h__ #include #include #include #include #include #include #include #ifndef POST_PACKED_STRUCTURE #ifdef __GNUC__ /* POST_PACKED_STRUCTURE needs to be a macro which expands into a compiler directive. The directive must tell the compiler to arrange the preceding structure declaration so that it is packed on byte-boundaries rather than use the natural alignment of the processor and/or compiler. */ #define POST_PACKED_STRUCTURE __attribute__((__packed__)) #else /* Add other things here for non-gcc platforms */ #endif #endif /* Needed by */ extern void jack_error (const char *fmt, ...); extern void jack_info (const char *fmt, ...); #include #include #include #include #include #include "port.h" extern jack_thread_creator_t jack_thread_creator; typedef enum { JACK_TIMER_SYSTEM_CLOCK, JACK_TIMER_CYCLE_COUNTER, JACK_TIMER_HPET, } jack_timer_type_t; void jack_init_time (); void jack_set_clock_source (jack_timer_type_t); const char* jack_clock_source_name (jack_timer_type_t); #include #include #ifdef JACK_USE_MACH_THREADS #include #endif #include "messagebuffer.h" #ifndef PATH_MAX #ifdef MAXPATHLEN #define PATH_MAX MAXPATHLEN #else #define PATH_MAX 1024 #endif /* MAXPATHLEN */ #endif /* !PATH_MAX */ #ifdef DEBUG_ENABLED /* grab thread id instead of PID on linux */ #if defined(__gnu_linux__) #ifdef gettid /* glibc has a version */ #define GETTID() gettid() #else /* use our own version */ #include #define GETTID() syscall(__NR_gettid) #endif #else #define GETTID() getpid() #endif #define DEBUG(format,args...) \ MESSAGE("jack:%5d:%" PRIu64 " %s:%s:%d: " format "", GETTID(), jack_get_microseconds(), __FILE__, __FUNCTION__, __LINE__ , ## args) #else #if JACK_CPP_VARARGS_BROKEN #define DEBUG(format...) #else #define DEBUG(format,args...) #endif #endif /* Enable preemption checking for Linux Realtime Preemption kernels. * * This checks if any RT-safe code section does anything to cause CPU * preemption. Examples are sleep() or other system calls that block. * If a problem is detected, the kernel writes a syslog entry, and * sends SIGUSR2 to the client. */ #ifdef DO_PREEMPTION_CHECKING #define CHECK_PREEMPTION(engine, onoff) \ if ((engine)->real_time) gettimeofday (1, (onoff)) #else #define CHECK_PREEMPTION(engine, onoff) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (1) #endif typedef struct _jack_engine jack_engine_t; typedef struct _jack_request jack_request_t; typedef void * dlhandle; typedef enum { TransportCommandNone = 0, TransportCommandStart = 1, TransportCommandStop = 2, } transport_command_t; typedef struct { volatile uint32_t guard1; volatile jack_nframes_t frames; volatile jack_time_t current_wakeup; volatile jack_time_t next_wakeup; volatile float period_usecs; volatile int32_t initialized; volatile uint32_t guard2; /* not accessed by clients */ int32_t reset_pending; /* xrun happened, deal with it */ float filter_omega; /* set once, never altered */ } POST_PACKED_STRUCTURE jack_frame_timer_t; /* JACK engine shared memory data structure. */ typedef struct { jack_transport_state_t transport_state; volatile transport_command_t transport_cmd; transport_command_t previous_cmd; /* previous transport_cmd */ jack_position_t current_time; /* position for current cycle */ jack_position_t pending_time; /* position for next cycle */ jack_position_t request_time; /* latest requested position */ jack_unique_t prev_request; /* previous request unique ID */ volatile _Atomic_word seq_number; /* unique ID sequence number */ int8_t new_pos; /* new position this cycle */ int8_t pending_pos; /* new position request pending */ jack_nframes_t pending_frame; /* pending frame number */ int32_t sync_clients; /* number of active_slowsync clients */ int32_t sync_remain; /* number of them with sync_poll */ jack_time_t sync_timeout; jack_time_t sync_time_left; jack_frame_timer_t frame_timer; int32_t internal; jack_timer_type_t clock_source; pid_t engine_pid; jack_nframes_t buffer_size; int8_t real_time; int8_t do_mlock; int8_t do_munlock; int32_t client_priority; int32_t max_client_priority; int32_t has_capabilities; float cpu_load; float xrun_delayed_usecs; float max_delayed_usecs; uint32_t port_max; int32_t engine_ok; jack_port_type_id_t n_port_types; jack_port_type_info_t port_types[JACK_MAX_PORT_TYPES]; jack_port_shared_t ports[0]; } POST_PACKED_STRUCTURE jack_control_t; typedef enum { BufferSizeChange, SampleRateChange, AttachPortSegment, PortConnected, PortDisconnected, GraphReordered, PortRegistered, PortUnregistered, XRun, StartFreewheel, StopFreewheel, ClientRegistered, ClientUnregistered, SaveSession, LatencyCallback } JackEventType; typedef struct { JackEventType type; union { uint32_t n; char name[JACK_PORT_NAME_SIZE]; jack_port_id_t port_id; jack_port_id_t self_id; } x; union { uint32_t n; jack_port_type_id_t ptid; jack_port_id_t other_id; } y; } POST_PACKED_STRUCTURE jack_event_t; typedef enum { ClientInternal, /* connect request just names .so */ ClientDriver, /* code is loaded along with driver */ ClientExternal /* client is in another process */ } ClientType; typedef enum { NotTriggered, Triggered, Running, Finished } jack_client_state_t; /* JACK client shared memory data structure. */ typedef volatile struct { volatile jack_client_id_t id; /* w: engine r: engine and client */ volatile jack_client_id_t uid; /* w: engine r: engine and client */ volatile jack_client_state_t state; /* w: engine and client r: engine */ volatile char name[JACK_CLIENT_NAME_SIZE]; volatile char session_command[JACK_PORT_NAME_SIZE]; volatile jack_session_flags_t session_flags; volatile ClientType type; /* w: engine r: engine and client */ volatile int8_t active; /* w: engine r: engine and client */ volatile int8_t dead; /* r/w: engine */ volatile int8_t timed_out; /* r/w: engine */ volatile int8_t is_timebase; /* w: engine, r: engine and client */ volatile int8_t timebase_new; /* w: engine and client, r: engine */ volatile int8_t is_slowsync; /* w: engine, r: engine and client */ volatile int8_t active_slowsync; /* w: engine, r: engine and client */ volatile int8_t sync_poll; /* w: engine and client, r: engine */ volatile int8_t sync_new; /* w: engine and client, r: engine */ volatile pid_t pid; /* w: client r: engine; client pid */ volatile pid_t pgrp; /* w: client r: engine; client pgrp */ volatile uint64_t signalled_at; volatile uint64_t awake_at; volatile uint64_t finished_at; volatile int32_t last_status; /* w: client, r: engine and client */ /* indicators for whether callbacks have been set for this client. We do not include ptrs to the callbacks here (or their arguments) so that we can avoid 32/64 bit pointer size mismatches between the jack server and a client. The pointers are in the client- local structure which is part of the libjack compiled for either 32 bit or 64 bit clients. */ volatile uint8_t process_cbset; volatile uint8_t thread_init_cbset; volatile uint8_t bufsize_cbset; volatile uint8_t srate_cbset; volatile uint8_t port_register_cbset; volatile uint8_t port_connect_cbset; volatile uint8_t graph_order_cbset; volatile uint8_t xrun_cbset; volatile uint8_t sync_cb_cbset; volatile uint8_t timebase_cb_cbset; volatile uint8_t freewheel_cb_cbset; volatile uint8_t client_register_cbset; volatile uint8_t thread_cb_cbset; volatile uint8_t session_cbset; volatile uint8_t latency_cbset; } POST_PACKED_STRUCTURE jack_client_control_t; typedef struct { uint32_t protocol_v; /* protocol version, must go first */ int32_t load; ClientType type; jack_options_t options; jack_client_id_t uuid; char name[JACK_CLIENT_NAME_SIZE]; char object_path[PATH_MAX+1]; char object_data[1024]; } POST_PACKED_STRUCTURE jack_client_connect_request_t; typedef struct { jack_status_t status; jack_shm_registry_index_t client_shm_index; jack_shm_registry_index_t engine_shm_index; char fifo_prefix[PATH_MAX+1]; int32_t realtime; int32_t realtime_priority; char name[JACK_CLIENT_NAME_SIZE]; /* unique name, if assigned */ /* these are actually pointers, but they must be the same size regardless of whether the server and/or client are 64 bit or 32 bit. force them to be 64 bit. */ uint64_t client_control; uint64_t engine_control; #ifdef JACK_USE_MACH_THREADS /* specific resources for server/client real-time thread communication */ int32_t portnum; #endif } POST_PACKED_STRUCTURE jack_client_connect_result_t; typedef struct { jack_client_id_t client_id; } POST_PACKED_STRUCTURE jack_client_connect_ack_request_t; typedef struct { int8_t status; } POST_PACKED_STRUCTURE jack_client_connect_ack_result_t; typedef enum { RegisterPort = 1, UnRegisterPort = 2, ConnectPorts = 3, DisconnectPorts = 4, SetTimeBaseClient = 5, ActivateClient = 6, DeactivateClient = 7, DisconnectPort = 8, SetClientCapabilities = 9, GetPortConnections = 10, GetPortNConnections = 11, ResetTimeBaseClient = 12, SetSyncClient = 13, ResetSyncClient = 14, SetSyncTimeout = 15, SetBufferSize = 16, FreeWheel = 17, StopFreeWheel = 18, IntClientHandle = 19, IntClientLoad = 20, IntClientName = 21, IntClientUnload = 22, RecomputeTotalLatencies = 23, RecomputeTotalLatency = 24, SessionNotify = 25, GetClientByUUID = 26, ReserveName = 30, SessionReply = 31, SessionHasCallback = 32 } RequestType; struct _jack_request { //RequestType type; uint32_t type; union { struct { char name[JACK_PORT_NAME_SIZE]; char type[JACK_PORT_TYPE_SIZE]; uint32_t flags; jack_shmsize_t buffer_size; jack_port_id_t port_id; jack_client_id_t client_id; } POST_PACKED_STRUCTURE port_info; struct { char source_port[JACK_PORT_NAME_SIZE]; char destination_port[JACK_PORT_NAME_SIZE]; } POST_PACKED_STRUCTURE connect; struct { char path[JACK_PORT_NAME_SIZE]; jack_session_event_type_t type; char target[JACK_CLIENT_NAME_SIZE]; } POST_PACKED_STRUCTURE session; struct { int32_t nports; const char **ports; /* this is only exposed to internal clients, so there is no 64/32 issue. external clients read the ports one by one from the server, and allocate their own "ports" array in their own address space. we are lucky, because this is part of a union whose other components are bigger than this one. otherwise it would change structure size when comparing the 64 and 32 bit versions. */ } POST_PACKED_STRUCTURE port_connections; struct { jack_client_id_t client_id; int32_t conditional; } POST_PACKED_STRUCTURE timebase; struct { char name[JACK_CLIENT_NAME_SIZE]; jack_client_id_t uuid; } POST_PACKED_STRUCTURE reservename; struct { //jack_options_t options; uint32_t options; jack_client_id_t id; char name[JACK_CLIENT_NAME_SIZE]; char path[PATH_MAX+1]; char init[JACK_LOAD_INIT_LIMIT]; } POST_PACKED_STRUCTURE intclient; jack_client_id_t client_id; jack_nframes_t nframes; jack_time_t timeout; pid_t cap_pid; char name[JACK_CLIENT_NAME_SIZE]; } POST_PACKED_STRUCTURE x; int32_t status; } POST_PACKED_STRUCTURE; /* Per-client structure allocated in the server's address space. * It's here because its not part of the engine structure. */ typedef struct _jack_client_internal { jack_client_control_t *control; int request_fd; int event_fd; int subgraph_start_fd; int subgraph_wait_fd; JSList *ports; /* protected by engine->client_lock */ JSList *truefeeds; /* protected by engine->client_lock */ JSList *sortfeeds; /* protected by engine->client_lock */ int fedcount; int tfedcount; jack_shm_info_t control_shm; unsigned long execution_order; struct _jack_client_internal *next_client; /* not a linked list! */ dlhandle handle; int (*initialize)(jack_client_t*, const char*); /* int. clients only */ void (*finish)(void *); /* internal clients only */ int error; int session_reply_pending; #ifdef JACK_USE_MACH_THREADS /* specific resources for server/client real-time thread communication */ mach_port_t serverport; trivial_message message; int running; int portnum; #endif /* JACK_USE_MACH_THREADS */ jack_client_t *private_client; } jack_client_internal_t; typedef struct _jack_thread_arg { jack_client_t* client; void* (*work_function)(void*); int priority; int realtime; void* arg; pid_t cap_pid; } jack_thread_arg_t; extern int jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event); extern jack_client_t *jack_driver_client_new (jack_engine_t *, const char *client_name); extern jack_client_t *jack_client_alloc_internal (jack_client_control_t*, jack_engine_t*); /* internal clients call this. it's defined in jack/engine.c */ void handle_internal_client_request (jack_control_t*, jack_request_t*); extern char *jack_tmpdir; extern char *jack_user_dir (void); extern char *jack_server_dir (const char *server_name, char *server_dir); extern void *jack_zero_filled_buffer; extern jack_port_functions_t jack_builtin_audio_functions; extern jack_port_type_info_t jack_builtin_port_types[]; extern void jack_client_fix_port_buffers (jack_client_t *client); extern void jack_transport_copy_position (jack_position_t *from, jack_position_t *to); extern void jack_call_sync_client (jack_client_t *client); extern void jack_call_timebase_master (jack_client_t *client); extern char *jack_default_server_name (void); void silent_jack_error_callback (const char *desc); /* needed for port management */ extern jack_port_t *jack_port_by_id_int (const jack_client_t *client, jack_port_id_t id, int* free); extern jack_port_t *jack_port_by_name_int (jack_client_t *client, const char *port_name); extern int jack_port_name_equals (jack_port_shared_t* port, const char* target); /** Get the size (in bytes) of the data structure used to store * MIDI events internally. */ extern size_t jack_midi_internal_event_size (); extern int jack_client_handle_latency_callback (jack_client_t *client, jack_event_t *event, int is_driver); #ifdef __GNUC__ # define likely(x) __builtin_expect((x),1) # define unlikely(x) __builtin_expect((x),0) #else # define likely(x) (x) # define unlikely(x) (x) #endif #ifdef VALGRIND_CLEAN #include #define VALGRIND_MEMSET(ptr,val,size) memset ((ptr),(val),(size)) #else #define VALGRIND_MEMSET(ptr,val,size) #endif #endif /* __jack_internal_h__ */ jackd1-0.121.3+20120418git75e3e20b/include/version.h.in0000644001605600047420000000147211736346233017476 0ustar adiira/* Copyright (C) 2003 Paul Davis @configure_input@ 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. */ #define jack_protocol_version @JACK_PROTOCOL_VERSION@ jackd1-0.121.3+20120418git75e3e20b/include/bitset.h0000644001605600047420000000607211736346233016677 0ustar adiira/* * bitset.h -- some simple bit vector set operations. * * This is useful for sets of small non-negative integers. There are * some obvious set operations that are not implemented because I * don't need them right now. * * These functions represent sets as arrays of unsigned 32-bit * integers allocated on the heap. The first entry contains the set * cardinality (number of elements allowed), followed by one or more * words containing bit vectors. * */ /* * Copyright (C) 2005 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. */ #ifndef __bitset_h__ #define __bitset_h__ #include /* POSIX standard fixed-size types */ #include /* `#define NDEBUG' to disable */ /* On some 64-bit machines, this implementation may be slightly * inefficient, depending on how compilers allocate space for * uint32_t. For the set sizes I currently need, this is acceptable. * It should not be hard to pack the bits better, if that becomes * worthwhile. */ typedef uint32_t _bitset_word_t; typedef _bitset_word_t *bitset_t; #define WORD_SIZE(cardinality) (1+((cardinality)+31)/32) #define BYTE_SIZE(cardinality) (WORD_SIZE(cardinality)*sizeof(_bitset_word_t)) #define WORD_INDEX(element) (1+(element)/32) #define BIT_INDEX(element) ((element)&037) static inline void bitset_add(bitset_t set, unsigned int element) { assert(element < set[0]); set[WORD_INDEX(element)] |= (1 << BIT_INDEX(element)); } static inline void bitset_copy(bitset_t to_set, bitset_t from_set) { assert(to_set[0] == from_set[0]); memcpy(to_set, from_set, BYTE_SIZE(to_set[0])); } static inline void bitset_create(bitset_t *set, unsigned int cardinality) { *set = (bitset_t) calloc(WORD_SIZE(cardinality), sizeof(_bitset_word_t)); assert(*set); *set[0] = cardinality; } static inline void bitset_destroy(bitset_t *set) { if (*set) { free(*set); *set = (bitset_t) 0; } } static inline int bitset_empty(bitset_t set) { int i; _bitset_word_t result = 0; int nwords = WORD_SIZE(set[0]); for (i = 1; i < nwords; i++) { result |= set[i]; } return (result == 0); } static inline int bitset_contains(bitset_t set, unsigned int element) { assert(element < set[0]); return (0 != (set[WORD_INDEX(element)] & (1< #include #include #include "shm.h" #define JACK_PORT_NAME_SIZE 256 #define JACK_PORT_TYPE_SIZE 32 /* The relatively low value of this constant reflects the fact that * JACK currently only knows about *2* port types. (May 2006) * * Further, the 4 covers: * - a single non-negotiated audio format * - music data (ie. MIDI) * - video * - one other * * which is probably enough for more than just the foreseeable future. */ #define JACK_MAX_PORT_TYPES 4 #define JACK_AUDIO_PORT_TYPE 0 #define JACK_MIDI_PORT_TYPE 1 /* these should probably go somewhere else, but not in */ #define JACK_CLIENT_NAME_SIZE 33 typedef uint32_t jack_client_id_t; /* JACK shared memory segments are limited to MAX_INT32, they can be * shared between 32-bit and 64-bit clients. */ #define JACK_SHM_MAX (MAX_INT32) typedef int32_t jack_port_type_id_t; #define JACK_BACKEND_ALIAS "system" #ifndef POST_PACKED_STRUCTURE #ifdef __GNUC__ /* POST_PACKED_STRUCTURE needs to be a macro which expands into a compiler directive. The directive must tell the compiler to arrange the preceding structure declaration so that it is packed on byte-boundaries rather than use the natural alignment of the processor and/or compiler. */ #define POST_PACKED_STRUCTURE __attribute__((__packed__)) #else /* Add other things here for non-gcc platforms */ #endif #endif /* Port type structure. * * (1) One for each port type is part of the engine's jack_control_t * shared memory structure. * * (2) One for each port type is appended to the engine's * jack_client_connect_result_t response. The client reads them into * its local memory, using them to attach the corresponding shared * memory segments. */ typedef struct _jack_port_type_info { jack_port_type_id_t ptype_id; const char type_name[JACK_PORT_TYPE_SIZE]; /* If == 1, then a buffer to handle nframes worth of data has * sizeof(jack_default_audio_sample_t) * nframes bytes. * * If > 1, the buffer allocated for input mixing will be * this value times sizeof(jack_default_audio_sample_t) * * nframes bytes in size. For non-audio data types, * it may have a different value. * * If < 0, the value should be ignored, and buffer_size * should be used. */ int32_t buffer_scale_factor; /* ignored unless buffer_scale_factor is < 0. see above */ jack_shmsize_t buffer_size; jack_shm_registry_index_t shm_registry_index; jack_shmsize_t zero_buffer_offset; } POST_PACKED_STRUCTURE jack_port_type_info_t; /* Allocated by the engine in shared memory. */ typedef struct _jack_port_shared { jack_port_type_id_t ptype_id; /* index into port type array */ jack_shmsize_t offset; /* buffer offset in shm segment */ jack_port_id_t id; /* index into engine port array */ uint32_t flags; char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; char alias1[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; char alias2[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; jack_client_id_t client_id; /* who owns me */ volatile jack_nframes_t latency; volatile jack_nframes_t total_latency; volatile jack_latency_range_t playback_latency; volatile jack_latency_range_t capture_latency; volatile uint8_t monitor_requests; char has_mixdown; /* port has a mixdown function */ char in_use; char unused; /* legacy locked field */ } POST_PACKED_STRUCTURE jack_port_shared_t; typedef struct _jack_port_functions { /* Function to initialize port buffer. Cannot be NULL. * NOTE: This must take a buffer rather than jack_port_t as it is called * in jack_engine_place_buffers() before any port creation. * A better solution is to make jack_engine_place_buffers to be type-specific, * but this works. */ void (*buffer_init)(void *buffer, size_t size, jack_nframes_t); /* Function to mixdown multiple inputs to a buffer. Can be NULL, * indicating that multiple input connections are not legal for * this data type. */ void (*mixdown)(jack_port_t *, jack_nframes_t); } jack_port_functions_t; /** * Get port functions. * @param ptid port type id. * * @return pointer to port type functions or NULL if port type is unknown. */ /*const*/ jack_port_functions_t * jack_get_port_functions(jack_port_type_id_t ptid); /* Allocated by the client in local memory. */ struct _jack_port { void **client_segment_base; void *mix_buffer; jack_port_type_info_t *type_info; /* shared memory type info */ struct _jack_port_shared *shared; /* corresponding shm struct */ struct _jack_port *tied; /* locally tied source port */ jack_port_functions_t fptr; pthread_mutex_t connection_lock; JSList *connections; }; /* Inline would be cleaner, but it needs to be fast even in * non-optimized code. jack_output_port_buffer() only handles output * ports. jack_port_buffer() works for both input and output ports. */ #define jack_port_buffer(p) \ ((void *) ((p)->mix_buffer? (p)->mix_buffer: \ *(p)->client_segment_base + (p)->shared->offset)) #define jack_output_port_buffer(p) \ ((void *) (*(p)->client_segment_base + (p)->shared->offset)) /* not for use by JACK applications */ size_t jack_port_type_buffer_size (jack_port_type_info_t* port_type_info, jack_nframes_t nframes); #endif /* __jack_port_h__ */ jackd1-0.121.3+20120418git75e3e20b/TODO0000644001605600047420000000757411736346233014311 0ustar adiira======================================================================= *** TODO - A one file mini-bugzilla for JACK developers *** ======================================================================= Version: $Id$ NOTE: web-based bug tracker for JACK was put online in Oct 2003. It is now the preferred way to report and track bugs and feature requests. This TODO file is now used only for tracking release issues (mapping features and other todo-items to release roadmap, etc). The new bug tracker can be found at: http://jackit.sourceforge.net/mantis/ ----------------------------------------------------------------------- You can update this list directly via CVS or alternatively send a change request to jackit-devel mailing list. ----------------------------------------------------------------------- TODO for merging Mac OS X support - clean up other header files -- , fakepoll.h, etc. -- , in shm.c TODO before-1.0 - add explanation of protocol versioning to README.developers (kaiv) TODO post-1.0 - jack session handling (taybin) - first client run without jackd becomes jackd (joq) - TBD TODO general - no agreed timeline - better scheme for handling machine and system dependencies (joq) - proper handling of client return values in libjack - pool based malloc for rt client-local mem allocation (paul, moved back here) TO BE DECIDED - no agreed timeline - dropping the use of CAP_RESOURCE (nando) - support for on-the-fly sampling rate change - whether to default to triangular dithering for 16bit output. (swh) TO THINK ABOUT - no agreed timeline - ensure that UST/MSC pairs work for transport API - whether we want to support varispeed (resampling and/or changing the actual rate) - per-block timestamping against system clock (UST stamps at driver level) - dynamically increase the total number of ports in the system CLOSED (date,who,comment) - handle mixed-mode 64bit and 32bit clients (2008/10, done by torben) - don't build static libraries of drivers and ip-clients (2003/10/07,paul) - API to change buffer size (joq) (2003/10/07) - added code to enforce the 'bufsize==2^x' rule (taybin) (2003/8/28) - make sure that process callbacks always have nframes equal to buffersize (2003/08/27,done,kaiv) - add Paul's graph/subgraph explanation to the design doc (2003/08/27,done,kaiv) - add support for custom jackd --tmpdir in libjack (2003/05/06,done,jesse) - capture_client has pthread_mutex_lock() in its process() (2003/05/30,fixed,joq) - update at least the user-visible copyrights with year 2003 (2003/04/05,done,paul) - add a sane way handle situations where the unix sockets already exist when jackd is started (2003/04/05,sockets removed on startup,paul) - figure out how to have pools of buffers for ports by type - (2003/04/05, paul, implicit in new shm/port segment system) - passing args to drivers and clients? (?,done long ago,paul) - pool based malloc for rt client-local mem allocation (paul) - getting callbacks and args from dynamically loaded clients? (2003/02/25, paul, see jack/jack.h) - how do dynamically loaded clients (un)register ports, activate, etc. (2003/02/25, paul, see example-clients/inprocess.c) - server<->libjack interface version handshake (2003/02/11, trutkin, done) - alsa-driver parameter parsing patch (2003/02/25, joq, done) - jack_deactive called unconditionally in jack_client_close (2003/02/05, kaiv, fixed) - call time client before all others (2003/01/28, kaiv, another solution) - finalize discussion on transport API, and implement (2003/08/04, joq) - whether to hide the transport.h structs from clients (2003/08/04, joq) - define transport info struct contents (2003/08/13, joq) - resolve helper thread design question? (2003/08/31, joq) - get portaudio driver working under Linux (2003/10/29, joq) ----------------------------------------------------------------------- jackd1-0.121.3+20120418git75e3e20b/tools/0000755001605600047420000000000011743611406014737 5ustar adiirajackd1-0.121.3+20120418git75e3e20b/tools/midi_dump.c0000644001605600047420000000454311731642255017063 0ustar adiira#include #include #include #include #include static jack_port_t* port; static void describe (jack_midi_event_t* event, char* buffer, size_t buflen) { assert (buflen > 0); buffer[0] = '\0'; if (event->size == 0) { return; } int type = event->buffer[0] & 0xf0; int channel = event->buffer[0] & 0xf; switch (type) { case 0x90: assert (event->size == 3); snprintf (buffer, buflen, "note on (channel %d): pitch %d, velocity %d", channel, event->buffer[1], event->buffer[2]); break; case 0x80: assert (event->size == 3); snprintf (buffer, buflen, "note off (channel %d): pitch %d, velocity %d", channel, event->buffer[1], event->buffer[2]); break; case 0xb0: assert (event->size == 3); snprintf (buffer, buflen, "control change (channel %d): controller %d, value %d", channel, event->buffer[1], event->buffer[2]); break; default: break; } } int process (jack_nframes_t frames, void* arg) { void* buffer; jack_nframes_t N; jack_nframes_t i; char description[256]; buffer = jack_port_get_buffer (port, frames); assert (buffer); N = jack_midi_get_event_count (buffer); for (i = 0; i < N; ++i) { jack_midi_event_t event; int r; r = jack_midi_event_get (&event, buffer, i); if (r == 0) { size_t j; printf ("%d:", event.time); for (j = 0; j < event.size; ++j) { printf (" %x", event.buffer[j]); } describe (&event, description, sizeof (description)); printf (" %s", description); printf ("\n"); } } return 0; } int main (int argc, char* argv[]) { jack_client_t* client; char const default_name[] = "midi-monitor"; char const * client_name; int r; if (argc == 2) { client_name = argv[1]; } else { client_name = default_name; } client = jack_client_open (client_name, JackNullOption, NULL); if (client == NULL) { fprintf (stderr, "Could not create JACK client.\n"); exit (EXIT_FAILURE); } jack_set_process_callback (client, process, 0); port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); if (port == NULL) { fprintf (stderr, "Could not register port.\n"); exit (EXIT_FAILURE); } r = jack_activate (client); if (r != 0) { fprintf (stderr, "Could not activate client.\n"); exit (EXIT_FAILURE); } sleep (-1); return 0; } jackd1-0.121.3+20120418git75e3e20b/tools/ipload.c0000644001605600047420000000736011731642255016364 0ustar adiira#include #include #include #include #include #include #include #include jack_client_t *client; jack_intclient_t intclient; char *client_name; char *intclient_name; char *load_name; char *load_init = NULL; char *server_name = NULL; int wait_opt = 0; void signal_handler (int sig) { jack_status_t status; fprintf (stderr, "signal received, unloading..."); status = jack_internal_client_unload (client, intclient); if (status & JackFailure) fprintf (stderr, "(failed), status = 0x%2.0x\n", status); else fprintf (stderr, "(succeeded)\n"); jack_client_close (client); exit (0); } void show_usage () { fprintf (stderr, "usage: %s [ options ] client-name [ load-name " "[ init-string]]\n\noptions:\n", client_name); fprintf (stderr, "\t-h, --help \t\t print help message\n" "\t-i, --init string\t initialize string\n" "\t-s, --server name\t select JACK server\n" "\t-w, --wait \t\t wait for signal, then unload\n" "\n" ); } int parse_args (int argc, char *argv[]) { int c; int option_index = 0; char *short_options = "hi:s:w"; struct option long_options[] = { { "help", 0, 0, 'h' }, { "init", required_argument, 0, 'i' }, { "server", required_argument, 0, 's' }, { "wait", 0, 0, 'w' }, { 0, 0, 0, 0 } }; client_name = strrchr(argv[0], '/'); if (client_name == NULL) { client_name = argv[0]; } else { client_name++; } while ((c = getopt_long (argc, argv, short_options, long_options, &option_index)) >= 0) { switch (c) { case 'i': load_init = optarg; break; case 's': server_name = optarg; break; case 'w': wait_opt = 1; break; case 'h': default: show_usage (); return 1; } } if (optind == argc) { /* no positional args? */ show_usage (); return 1; } if (optind < argc) load_name = intclient_name = argv[optind++]; if (optind < argc) load_name = argv[optind++]; if (optind < argc) load_init = argv[optind++]; //fprintf (stderr, "client-name = `%s', load-name = `%s', " // "load-init = `%s', wait = %d\n", // intclient_name, load_name, load_init, wait_opt); return 0; /* args OK */ } int main (int argc, char *argv[]) { jack_status_t status; /* parse and validate command arguments */ if (parse_args (argc, argv)) exit (1); /* invalid command line */ /* first, become a JACK client */ client = jack_client_open (client_name, JackServerName, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* then, load the internal client */ intclient = jack_internal_client_load (client, intclient_name, (JackLoadName|JackLoadInit), &status, load_name, load_init); if (status & JackFailure) { fprintf (stderr, "could not load %s, status = 0x%2.0x\n", load_name, status); return 2; } if (status & JackNameNotUnique) { intclient_name = jack_get_internal_client_name (client, intclient); fprintf (stderr, "unique internal client name `%s' assigned\n", intclient_name); } fprintf (stdout, "%s is running.\n", load_name); if (wait_opt) { /* define a signal handler to unload the client, then * wait for it to exit */ signal (SIGQUIT, signal_handler); signal (SIGTERM, signal_handler); signal (SIGHUP, signal_handler); signal (SIGINT, signal_handler); while (1) { sleep (1); } } return 0; } jackd1-0.121.3+20120418git75e3e20b/tools/bufsize.c0000644001605600047420000000556011731642255016563 0ustar adiira/* * bufsize.c -- change JACK buffer size. * * 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. */ #include #include #include #include #include #include #include #include char *package; /* program name */ jack_client_t *client; jack_nframes_t nframes; int just_print_bufsize=0; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; if (argc==1) { just_print_bufsize = 1; return; } if (argc < 2) { fprintf(stderr, "usage: %s \n", package); exit(9); } if (strspn (argv[1], "0123456789") != strlen (argv[1])) { fprintf(stderr, "usage: %s \n", package); exit(8); } nframes = strtoul(argv[1], NULL, 0); if (errno == ERANGE) { fprintf(stderr, "%s: invalid buffer size: %s (range is 1-16384)\n", package, argv[1]); exit(2); } if (nframes < 1 || nframes > 16384) { fprintf(stderr, "%s: invalid buffer size: %s (range is 1-16384)\n", package, argv[1]); exit(3); } } void silent_function( const char *ignore ) { } int main(int argc, char *argv[]) { int rc; parse_arguments(argc, argv); if (just_print_bufsize) jack_set_info_function( silent_function ); /* become a JACK client */ if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); exit(1); } signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); if (just_print_bufsize) { fprintf(stdout, "%d\n", jack_get_buffer_size( client ) ); rc=0; } else { rc = jack_set_buffer_size(client, nframes); if (rc) fprintf(stderr, "jack_set_buffer_size(): %s\n", strerror(rc)); } jack_client_close(client); return rc; } jackd1-0.121.3+20120418git75e3e20b/tools/connect.c0000644001605600047420000001263211731642255016543 0ustar adiira/* Copyright (C) 2002 Jeremy Hall 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. */ #include #include #include #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 void show_version (char *my_name) { fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name); } void show_usage (char *my_name) { show_version (my_name); fprintf (stderr, "\nusage: %s [options] port1 port2\n", my_name); fprintf (stderr, "Connects two JACK ports together.\n\n"); fprintf (stderr, " -s, --server Connect to the jack server named \n"); fprintf (stderr, " -v, --version Output version information and exit\n"); fprintf (stderr, " -h, --help Display this help message\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; char *server_name = NULL; int c; int option_index; jack_options_t options = JackNoStartServer; char *my_name = strrchr(argv[0], '/'); jack_port_t *src_port = 0; jack_port_t *dst_port = 0; jack_port_t *port1 = 0; jack_port_t *port2 = 0; char portA[300]; char portB[300]; int use_uuid=0; int connecting, disconnecting; int port1_flags, port2_flags; int rc = 1; struct option long_options[] = { { "server", 1, 0, 's' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { "uuid", 0, 0, 'u' }, { 0, 0, 0, 0 } }; while ((c = getopt_long (argc, argv, "s:hvu", long_options, &option_index)) >= 0) { switch (c) { case 's': server_name = (char *) malloc (sizeof (char) * strlen(optarg)); strcpy (server_name, optarg); options |= JackServerName; break; case 'u': use_uuid = 1; break; case 'h': show_usage (my_name); return 1; break; case 'v': show_version (my_name); return 1; break; default: show_usage (my_name); return 1; break; } } connecting = disconnecting = FALSE; if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } if (strstr(my_name, "disconnect")) { disconnecting = 1; } else if (strstr(my_name, "connect")) { connecting = 1; } else { fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); return 1; } if (argc < 3) { show_usage(my_name); return 1; } /* try to become a client of the JACK server */ if ((client = jack_client_open (my_name, options, &status, server_name)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } /* find the two ports */ if( use_uuid ) { char *tmpname; char *clientname; char *portname; tmpname = strdup( argv[argc-1] ); portname = strchr( tmpname, ':' ); portname[0] = '\0'; portname+=1; clientname = jack_get_client_name_by_uuid( client, tmpname ); if( clientname ) { snprintf( portA, sizeof(portA), "%s:%s", clientname, portname ); jack_free( clientname ); } else { snprintf( portA, sizeof(portA), "%s", argv[argc-1] ); } free( tmpname ); tmpname = strdup( argv[argc-2] ); portname = strchr( tmpname, ':' ); portname[0] = '\0'; portname+=1; clientname = jack_get_client_name_by_uuid( client, tmpname ); if( clientname ) { snprintf( portB, sizeof(portB), "%s:%s", clientname, portname ); jack_free( clientname ); } else { snprintf( portB, sizeof(portB), "%s", argv[argc-2] ); } free( tmpname ); } else { snprintf( portA, sizeof(portA), "%s", argv[argc-1] ); snprintf( portB, sizeof(portB), "%s", argv[argc-2] ); } if ((port1 = jack_port_by_name(client, portA)) == 0) { fprintf (stderr, "ERROR %s not a valid port\n", portA); goto exit; } if ((port2 = jack_port_by_name(client, portB)) == 0) { fprintf (stderr, "ERROR %s not a valid port\n", portB); goto exit; } port1_flags = jack_port_flags (port1); port2_flags = jack_port_flags (port2); if (port1_flags & JackPortIsInput) { if (port2_flags & JackPortIsOutput) { src_port = port2; dst_port = port1; } } else { if (port2_flags & JackPortIsInput) { src_port = port1; dst_port = port2; } } if (!src_port || !dst_port) { fprintf (stderr, "arguments must include 1 input port and 1 output port\n"); goto exit; } /* connect the ports. Note: you can't do this before the client is activated (this may change in the future). */ if (connecting) { if (jack_connect(client, jack_port_name(src_port), jack_port_name(dst_port))) { goto exit; } } if (disconnecting) { if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) { goto exit; } } /* everything was ok, so setting exitcode to 0 */ rc = 0; exit: jack_client_close (client); exit (rc); } jackd1-0.121.3+20120418git75e3e20b/tools/freewheel.c0000644001605600047420000000403711731642255017060 0ustar adiira/* * freewheel - start/stop JACK "freewheeling" mode * * Copyright (C) 2003 Paul Davis. * * 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. */ #include #include #include #include #include #include #include #include char *package; /* program name */ jack_client_t *client; int onoff; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "usage: %s y|n\n", package); exit(9); } if (argv[1][0] == 'y' || argv[1][0] == 'Y' || argv[1][0] == '1') { onoff = 1; } else { onoff = 0; } } int main (int argc, char *argv[]) { parse_arguments (argc, argv); /* become a JACK client */ if ((client = jack_client_open ("freewheel", JackNullOption, NULL)) == 0) { fprintf (stderr, "JACK server not running?\n"); exit(1); } signal (SIGQUIT, signal_handler); signal (SIGTERM, signal_handler); signal (SIGHUP, signal_handler); signal (SIGINT, signal_handler); jack_on_shutdown (client, jack_shutdown, 0); if (jack_set_freewheel (client, onoff)) { fprintf (stderr, "failed to reset freewheel mode\n"); } jack_client_close(client); return 0; } jackd1-0.121.3+20120418git75e3e20b/tools/evmon.c0000644001605600047420000000473311731642255016241 0ustar adiira/* Copyright (C) 2007 Paul Davis 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. */ #include #include #include #include #include #include void port_callback (jack_port_id_t port, int yn, void* arg) { printf ("Port %d %s\n", port, (yn ? "registered" : "unregistered")); } void connect_callback (jack_port_id_t a, jack_port_id_t b, int yn, void* arg) { printf ("Ports %d and %d %s\n", a, b, (yn ? "connected" : "disconnected")); } void client_callback (const char* client, int yn, void* arg) { printf ("Client %s %s\n", client, (yn ? "registered" : "unregistered")); } int graph_callback (void* arg) { printf ("Graph reordered\n"); return 0; } int main (int argc, char *argv[]) { jack_client_t *client; jack_options_t options = JackNullOption; jack_status_t status; if ((client = jack_client_open ("event-monitor", options, &status, NULL)) == 0) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } return 1; } if (jack_set_port_registration_callback (client, port_callback, NULL)) { fprintf (stderr, "cannot set port registration callback\n"); return 1; } if (jack_set_port_connect_callback (client, connect_callback, NULL)) { fprintf (stderr, "cannot set port connect callback\n"); return 1; } if (jack_set_client_registration_callback (client, client_callback, NULL)) { fprintf (stderr, "cannot set client registration callback\n"); return 1; } if (jack_set_graph_order_callback (client, graph_callback, NULL)) { fprintf (stderr, "cannot set graph order registration callback\n"); return 1; } if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } sleep (-1); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/monitor_client.c0000644001605600047420000000162711731642255020141 0ustar adiira#include #include #include #include #include #define TRUE 1 #define FALSE 0 int main (int argc, char *argv[]) { jack_client_t *client; char *my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } if (argc != 2) { fprintf (stderr, "Usage: %s client\n", my_name); return 1; } if ((client = jack_client_open ("input monitoring", JackNullOption, NULL)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } if (jack_port_request_monitor_by_name (client, argv[1], TRUE)) { fprintf (stderr, "could not enable monitoring for %s\n", argv[1]); jack_client_close (client); return 1; } sleep (30); if (jack_port_request_monitor_by_name (client, argv[1], FALSE)) { fprintf (stderr, "could not disable monitoring for %s\n", argv[1]); } jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/samplerate.c0000644001605600047420000000373411731642255017252 0ustar adiira/* * smaplerate.c -- get current samplerate * * 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. */ #include #include #include #include #include #include #include #include char *package; /* program name */ jack_client_t *client; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; if (argc==1) { return; } fprintf(stderr, "usage: %s\n", package); exit(9); } int main(int argc, char *argv[]) { parse_arguments(argc, argv); /* become a JACK client */ if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); exit(1); } signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); fprintf(stdout, "%d\n", jack_get_sample_rate( client ) ); jack_client_close(client); return 0; } jackd1-0.121.3+20120418git75e3e20b/tools/alias.c0000644001605600047420000000467711731642255016215 0ustar adiira#include #include #include #include #include #include #include char * my_name; void show_version (void) { fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name); } void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options] portname alias\n", my_name); fprintf (stderr, "List active Jack ports, and optionally display extra information.\n\n"); fprintf (stderr, "Display options:\n"); fprintf (stderr, " -u, --unalias remove `alias' as an alias for `port'\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; char* portname; char* alias; int unset = 0; int ret; int c; int option_index; extern int optind; jack_port_t* port; struct option long_options[] = { { "unalias", 0, 0, 'u' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; if (argc < 3) { show_usage (); return 1; } my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "uhv", long_options, &option_index)) >= 0) { switch (c) { case 'u': unset = 1; break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } portname = argv[optind++]; alias = argv[optind]; /* Open a client connection to the JACK server. Starting a * new server only to list its ports seems pointless, so we * specify JackNoStartServer. */ //JOQ: need a new server name option client = jack_client_open ("lsp", JackNoStartServer, &status); if (client == NULL) { if (status & JackServerFailed) { fprintf (stderr, "JACK server not running\n"); } else { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); } return 1; } if ((port = jack_port_by_name (client, portname)) == 0) { fprintf (stderr, "No port named \"%s\"\n", portname); return 1; } if (!unset) { ret = jack_port_set_alias (port, alias); } else { ret = jack_port_unset_alias (port, alias); } jack_client_close (client); return ret; } jackd1-0.121.3+20120418git75e3e20b/tools/lsp.c0000644001605600047420000001353111731642255015707 0ustar adiira#include #include #include #include #include #include #include char * my_name; void show_version (void) { fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name); } void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options] [filter string]\n", my_name); fprintf (stderr, "List active Jack ports, and optionally display extra information.\n"); fprintf (stderr, "Optionally filter ports which match ALL strings provided after any options.\n\n"); fprintf (stderr, "Display options:\n"); fprintf (stderr, " -s, --server Connect to the jack server named \n"); fprintf (stderr, " -A, --aliases List aliases for each port\n"); fprintf (stderr, " -c, --connections List connections to/from each port\n"); fprintf (stderr, " -l, --latency Display per-port latency in frames at each port\n"); fprintf (stderr, " -L, --latency Display total latency in frames at each port\n"); fprintf (stderr, " -p, --properties Display port properties. Output may include:\n" " input|output, can-monitor, physical, terminal\n\n"); fprintf (stderr, " -t, --type Display port type\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; jack_options_t options = JackNoStartServer; const char **ports, **connections; unsigned int i, j, k; int skip_port; int show_aliases = 0; int show_con = 0; int show_port_latency = 0; int show_total_latency = 0; int show_properties = 0; int show_type = 0; int c; int option_index; char* aliases[2]; char *server_name = NULL; struct option long_options[] = { { "server", 1, 0, 's' }, { "aliases", 0, 0, 'A' }, { "connections", 0, 0, 'c' }, { "port-latency", 0, 0, 'l' }, { "total-latency", 0, 0, 'L' }, { "properties", 0, 0, 'p' }, { "type", 0, 0, 't' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "s:AclLphvt", long_options, &option_index)) >= 0) { switch (c) { case 's': server_name = (char *) malloc (sizeof (char) * strlen(optarg)); strcpy (server_name, optarg); options |= JackServerName; break; case 'A': aliases[0] = (char *) malloc (jack_port_name_size()); aliases[1] = (char *) malloc (jack_port_name_size()); show_aliases = 1; break; case 'c': show_con = 1; break; case 'l': show_port_latency = 1; break; case 'L': show_total_latency = 1; break; case 'p': show_properties = 1; break; case 't': show_type = 1; break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } /* Open a client connection to the JACK server. Starting a * new server only to list its ports seems pointless, so we * specify JackNoStartServer. */ client = jack_client_open ("lsp", options, &status, server_name); if (client == NULL) { if (status & JackServerFailed) { fprintf (stderr, "JACK server not running\n"); } else { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); } return 1; } ports = jack_get_ports (client, NULL, NULL, 0); for (i = 0; ports && ports[i]; ++i) { // skip over any that don't match ALL of the strings presented at command line skip_port = 0; for(k=optind; k < argc; k++){ if(strstr(ports[i], argv[k]) == NULL ){ skip_port = 1; } } if(skip_port) continue; printf ("%s\n", ports[i]); jack_port_t *port = jack_port_by_name (client, ports[i]); if (show_aliases) { int cnt; int i; cnt = jack_port_get_aliases (port, aliases); for (i = 0; i < cnt; ++i) { printf (" %s\n", aliases[i]); } } if (show_con) { if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { for (j = 0; connections[j]; j++) { printf (" %s\n", connections[j]); } free (connections); } } if (show_port_latency) { if (port) { jack_latency_range_t range; printf (" port latency = %" PRIu32 " frames\n", jack_port_get_latency (port)); jack_port_get_latency_range (port, JackPlaybackLatency, &range); printf (" port playback latency = [ %" PRIu32 " %" PRIu32 " ] frames\n", range.min, range.max); jack_port_get_latency_range (port, JackCaptureLatency, &range); printf (" port capture latency = [ %" PRIu32 " %" PRIu32 " ] frames\n", range.min, range.max); } } if (show_total_latency) { if (port) { printf (" total latency = %" PRIu32 " frames\n", jack_port_get_total_latency (client, port)); } } if (show_properties) { if (port) { int flags = jack_port_flags (port); printf (" properties: "); if (flags & JackPortIsInput) { fputs ("input,", stdout); } if (flags & JackPortIsOutput) { fputs ("output,", stdout); } if (flags & JackPortCanMonitor) { fputs ("can-monitor,", stdout); } if (flags & JackPortIsPhysical) { fputs ("physical,", stdout); } if (flags & JackPortIsTerminal) { fputs ("terminal,", stdout); } putc ('\n', stdout); } } if (show_type) { if (port) { putc ('\t', stdout); fputs (jack_port_type (port), stdout); putc ('\n', stdout); } } } if (ports) jack_free (ports); jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/ipunload.c0000644001605600047420000000323111731642255016720 0ustar adiira#include #include #include #include #include int main (int argc, char *argv[]) { char *my_name; char *client_name; jack_client_t *client; jack_status_t status; jack_intclient_t intclient; /* validate args */ if ((argc < 2) || (argc > 3)) { fprintf (stderr, "usage: %s client-name [ server-name ]]\n", argv[0]); return 1; } /* use `basename $0` for my own client name */ my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name++; } /* first, become a JACK client */ if (argc > 2) { client = jack_client_open (my_name, (JackServerName|JackNoStartServer), &status, argv[2]); } else { client = jack_client_open (my_name, JackNoStartServer, &status); } if (client == NULL) { if (status & JackServerFailed) { fprintf (stderr, "JACK server not running.\n"); } else { fprintf (stderr, "JACK open failed, " "status = 0x%2.0x\n", status); } exit (1); } /* then, get the internal client handle */ client_name = argv[1]; intclient = jack_internal_client_handle (client, client_name, &status); if (status & JackFailure) { fprintf (stderr, "client %s not found.\n", client_name); exit (2); } /* now, unload the internal client */ status = jack_internal_client_unload (client, intclient); if (status & JackFailure) { if (status & JackNoSuchClient) { fprintf (stderr, "client %s is gone.\n", client_name); } else { fprintf (stderr, "could not unload %s, " "returns 0x%2.0x\n", client_name, status); } exit (3); } else { fprintf (stdout, "%s unloaded.\n", client_name); } return 0; } jackd1-0.121.3+20120418git75e3e20b/tools/alsa_in.c0000644001605600047420000005650611731642255016530 0ustar adiira/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #include #include #include #include "memops.h" #include "alsa/asoundlib.h" #include // Here are the lists of the jack ports... JSList *capture_ports = NULL; JSList *capture_srcs = NULL; JSList *playback_ports = NULL; JSList *playback_srcs = NULL; jack_client_t *client; snd_pcm_t *alsa_handle; int jack_sample_rate; int jack_buffer_size; int quit = 0; double resample_mean = 1.0; double static_resample_factor = 1.0; double resample_lower_limit = 0.25; double resample_upper_limit = 4.0; double *offset_array; double *window_array; int offset_differential_index = 0; double offset_integral = 0; // ------------------------------------------------------ commandline parameters const char* alsa_device = "hw:0"; int sample_rate = 0; /* stream rate */ int num_channels = 2; /* count of channels */ int period_size = 1024; int num_periods = 2; int target_delay = 0; /* the delay which the program should try to approach. */ int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */ int catch_factor = 100000; int catch_factor2 = 10000; double pclamp = 15.0; double controlquant = 10000.0; int smooth_size = 256; int good_window=0; int verbose = 0; int instrument = 0; int samplerate_quality = 2; // Debug stuff: volatile float output_resampling_factor = 1.0; volatile int output_new_delay = 0; volatile float output_offset = 0.0; volatile float output_integral = 0.0; volatile float output_diff = 0.0; snd_pcm_uframes_t real_buffer_size; snd_pcm_uframes_t real_period_size; // buffers char *tmpbuf; char *outbuf; float *resampbuf; // format selection, and corresponding functions from memops in a nice set of structs. typedef struct alsa_format { snd_pcm_format_t format_id; size_t sample_size; void (*jack_to_soundcard) (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void (*soundcard_to_jack) (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); const char *name; } alsa_format_t; alsa_format_t formats[] = { { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } }; #define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) int format=0; // Alsa stuff... i dont want to touch this bullshit in the next years.... please... static int xrun_recovery(snd_pcm_t *handle, int err) { // printf( "xrun !!!.... %d\n", err ); if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); return 0; } else if (err == -EAGAIN) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) usleep(100); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); } return 0; } return err; } static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) { int i; int err; for( i=0; i (target_delay+max_diff) ) { output_new_delay = (int) delay; while ((delay-target_delay) > 0) { snd_pcm_uframes_t to_read = ((delay-target_delay) > 512) ? 512 : (delay-target_delay); snd_pcm_readi( alsa_handle, tmpbuf, to_read ); delay -= to_read; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) / current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; // get the data... again: err = snd_pcm_readi(alsa_handle, outbuf, rlen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { //printf("Write error: %s\n", snd_strerror(err)); //exit(EXIT_FAILURE); } goto again; } if( err != rlen ) { //printf( "read = %d\n", rlen ); } /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = capture_ports; JSList *src_node = capture_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; formats[format].soundcard_to_jack( resampbuf, outbuf + format[formats].sample_size * chn, rlen, num_channels*format[formats].sample_size ); src.data_in = resampbuf; src.input_frames = rlen; src.data_out = buf; src.output_frames = nframes; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); put_back_samples = rlen-src.input_frames_used; src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // Put back the samples libsamplerate did not consume. //printf( "putback = %d\n", put_back_samples ); snd_pcm_rewind( alsa_handle, put_back_samples ); return 0; } /** * the latency callback. * sets up the latencies on the ports. */ void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; JSList *node; range.min = range.max = target_delay; if (mode == JackCaptureLatency) { for (node = capture_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } else { for (node = playback_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } } /** * Allocate the necessary jack ports... */ void alloc_ports( int n_capture, int n_playback ) { int port_flags = JackPortIsOutput; int chn; jack_port_t *port; char buf[32]; capture_ports = NULL; for (chn = 0; chn < n_capture; chn++) { snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } capture_srcs = jack_slist_append( capture_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); capture_ports = jack_slist_append (capture_ports, port); } port_flags = JackPortIsInput; playback_ports = NULL; for (chn = 0; chn < n_playback; chn++) { snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } playback_srcs = jack_slist_append( playback_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); playback_ports = jack_slist_append (playback_ports, port); } } /** * This is the shutdown callback for this JACK application. * It is called by JACK if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } /** * be user friendly. * be user friendly. * be user friendly. */ void printUsage() { fprintf(stderr, "usage: alsa_out [options]\n" "\n" " -j - client name\n" " -d \n" " -c \n" " -p \n" " -n \n" " -r \n" " -q \n" " -t \n" " -i turns on instrumentation\n" " -v turns on printouts\n" "\n"); } /** * the main function.... */ void sigterm_handler( int signal ) { quit = 1; } int main (int argc, char *argv[]) { char jack_name[30] = "alsa_in"; extern char *optarg; extern int optind, optopt; int errflg=0; int c; while ((c = getopt(argc, argv, "ivj:r:c:p:n:d:q:m:t:f:F:C:Q:s:")) != -1) { switch(c) { case 'j': strcpy(jack_name,optarg); break; case 'r': sample_rate = atoi(optarg); break; case 'c': num_channels = atoi(optarg); break; case 'p': period_size = atoi(optarg); break; case 'n': num_periods = atoi(optarg); break; case 'd': alsa_device = strdup (optarg); break; case 't': target_delay = atoi(optarg); break; case 'q': samplerate_quality = atoi(optarg); break; case 'm': max_diff = atoi(optarg); break; case 'f': catch_factor = atoi(optarg); break; case 'F': catch_factor2 = atoi(optarg); break; case 'C': pclamp = (double) atoi(optarg); break; case 'Q': controlquant = (double) atoi(optarg); break; case 'v': verbose = 1; break; case 'i': instrument = 1; break; case 's': smooth_size = atoi(optarg); break; case ':': fprintf(stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf(stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage(); exit(2); } if( (samplerate_quality < 0) || (samplerate_quality > 4) ) { fprintf (stderr, "invalid samplerate quality\n"); return 1; } if ((client = jack_client_open (jack_name, 0, NULL)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* handle freewheeling */ jack_set_freewheel_callback (client, freewheel, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); if (jack_set_latency_callback) jack_set_latency_callback (client, latency_cb, 0); // get jack sample_rate jack_sample_rate = jack_get_sample_rate( client ); if( !sample_rate ) sample_rate = jack_sample_rate; // now open the alsa fd... alsa_handle = open_audiofd( alsa_device, 1, sample_rate, num_channels, period_size, num_periods); if( alsa_handle == 0 ) exit(20); printf( "selected sample format: %s\n", formats[format].name ); static_resample_factor = (double) jack_sample_rate / (double) sample_rate; resample_lower_limit = static_resample_factor * 0.25; resample_upper_limit = static_resample_factor * 4.0; resample_mean = static_resample_factor; offset_array = malloc( sizeof(double) * smooth_size ); if( offset_array == NULL ) { fprintf( stderr, "no memory for offset_array !!!\n" ); exit(20); } window_array = malloc( sizeof(double) * smooth_size ); if( window_array == NULL ) { fprintf( stderr, "no memory for window_array !!!\n" ); exit(20); } int i; for( i=0; i target_delay ) { fprintf( stderr, "target_delay (%d) cant be smaller than max_diff(%d)\n", target_delay, max_diff ); exit(20); } if( (target_delay+max_diff) > (num_periods*period_size) ) { fprintf( stderr, "target_delay+max_diff (%d) cant be bigger than buffersize(%d)\n", target_delay+max_diff, num_periods*period_size ); exit(20); } // alloc input ports, which are blasted out to alsa... alloc_ports( num_channels, 0 ); outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels ); resampbuf = malloc( num_periods * period_size * sizeof( float ) ); tmpbuf = malloc( 512 * formats[format].sample_size * num_channels ); if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL)) { fprintf( stderr, "no memory for buffers.\n" ); exit(20); } memset( tmpbuf, 0, 512 * formats[format].sample_size * num_channels); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); if( verbose ) { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset ); } } else if( instrument ) { printf( "# n\tresamp\tdiff\toffseti\tintegral\n"); int n=0; while(!quit) { usleep(1000); printf( "%d\t%f\t%f\t%f\t%f\n", n++, output_resampling_factor, output_diff, output_offset, output_integral ); } } else { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } } } jack_deactivate( client ); jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/Makefile.am0000644001605600047420000001067011731642255017002 0ustar adiiraMAINTAINERCLEANFILES = Makefile.in if HAVE_READLINE JACK_TRANSPORT = jack_transport dist-check-readline: else JACK_TRANSPORT = dist-check-readline: @echo @echo ' ******' You need readline installed to make dist.' ******' @echo @false endif NETJACK_TOOLS = jack_netsource if HAVE_SAMPLERATE if HAVE_ALSA NETJACK_TOOLS += alsa_in alsa_out endif dist-check-samplerate: else dist-check-samplerate: @echo @echo ' ******' You need libsamplerate installed to make dist.' ******' @echo @false endif bin_PROGRAMS = jack_load \ jack_unload \ jack_monitor_client \ jack_connect \ jack_disconnect \ jack_lsp \ jack_freewheel \ jack_evmon \ jack_alias \ jack_bufsize \ jack_samplerate \ jack_session_notify \ jack_wait \ jack_midi_dump \ jack_iodelay \ jack_load_test \ $(JACK_TRANSPORT) \ $(NETJACK_TOOLS) noinst_PROGRAMS = jack_thread_wait 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) jack_connect_SOURCES = connect.c jack_connect_LDFLAGS = @OS_LDFLAGS@ jack_connect_LDADD = $(top_builddir)/libjack/libjack.la jack_disconnect_SOURCES = connect.c jack_disconnect_LDFLAGS = @OS_LDFLAGS@ jack_disconnect_LDADD = $(top_builddir)/libjack/libjack.la jack_monitor_client_SOURCES = monitor_client.c jack_monitor_client_LDFLAGS = @OS_LDFLAGS@ jack_monitor_client_LDADD = $(top_builddir)/libjack/libjack.la jack_thread_wait_SOURCES = tw.c jack_thread_wait_LDFLAGS = @OS_LDFLAGS@ jack_thread_wait_LDADD = $(top_builddir)/libjack/libjack.la jack_wait_SOURCES = wait.c jack_wait_LDFLAGS = @OS_LDFLAGS@ jack_wait_LDADD = $(top_builddir)/libjack/libjack.la jack_evmon_SOURCES = evmon.c jack_evmon_LDFLAGS = @OS_LDFLAGS@ jack_evmon_LDADD = $(top_builddir)/libjack/libjack.la jack_alias_SOURCES = alias.c jack_alias_LDFLAGS = @OS_LDFLAGS@ jack_alias_LDADD = $(top_builddir)/libjack/libjack.la jack_lsp_SOURCES = lsp.c jack_lsp_LDFLAGS = @OS_LDFLAGS@ jack_lsp_LDADD = $(top_builddir)/libjack/libjack.la jack_freewheel_SOURCES = freewheel.c jack_freewheel_LDFLAGS = @OS_LDFLAGS@ jack_freewheel_LDADD = $(top_builddir)/libjack/libjack.la jack_bufsize_SOURCES = bufsize.c jack_bufsize_LDFLAGS = @OS_LDFLAGS@ jack_bufsize_LDADD = $(top_builddir)/libjack/libjack.la jack_samplerate_SOURCES = samplerate.c jack_samplerate_LDFLAGS = @OS_LDFLAGS@ jack_samplerate_LDADD = $(top_builddir)/libjack/libjack.la jack_session_notify_SOURCES = session_notify.c jack_session_notify_LDFLAGS = @OS_LDFLAGS@ jack_session_notify_LDADD = $(top_builddir)/libjack/libjack.la jack_midi_dump_SOURCES = midi_dump.c jack_midi_dump_LDFLAGS = @OS_LDFLAGS@ jack_midi_dump_LDADD = $(top_builddir)/libjack/libjack.la jack_iodelay_SOURCES = iodelay.c jack_iodelay_LDFLAGS = @OS_LDFLAGS@ jack_iodelay_LDADD = $(top_builddir)/libjack/libjack.la if HAVE_READLINE jack_transport_SOURCES = transport.c jack_transport_LDFLAGS = -lreadline @READLINE_DEPS@ @OS_LDFLAGS@ jack_transport_LDADD = $(top_builddir)/libjack/libjack.la endif jack_load_test_SOURCES = load_test.c jack_load_test_LDFLAGS = @OS_LDFLAGS@ jack_load_test_LDADD = $(top_builddir)/libjack/libjack.la # # General purpose in-process loader/unloader # jack_load_SOURCES = ipload.c jack_load_LDFLAGS = @OS_LDFLAGS@ jack_load_LDADD = $(top_builddir)/libjack/libjack.la jack_unload_SOURCES = ipunload.c jack_unload_LDFLAGS = @OS_LDFLAGS@ jack_unload_LDADD = $(top_builddir)/libjack/libjack.la # # Netjack slave tools # jack_netsource_SOURCES = netsource.c $(top_builddir)/drivers/netjack/netjack_packet.c jack_netsource_CFLAGS = @NETJACK_CFLAGS@ -I$(top_srcdir)/drivers/netjack jack_netsource_LDFLAGS = @NETJACK_LIBS@ @OS_LDFLAGS@ jack_netsource_LDADD = $(top_builddir)/libjack/libjack.la if HAVE_SAMPLERATE if HAVE_ALSA alsa_in_SOURCES = alsa_in.c $(top_builddir)/drivers/alsa/memops.c alsa_in_CFLAGS = @NETJACK_CFLAGS@ -I$(top_builddir)/drivers/alsa alsa_in_LDFLAGS = -lasound -lsamplerate @OS_LDFLAGS@ alsa_in_LDADD = $(top_builddir)/libjack/libjack.la alsa_out_SOURCES = alsa_out.c $(top_builddir)/drivers/alsa/memops.c alsa_out_CFLAGS = @NETJACK_CFLAGS@ -I$(top_builddir)/drivers/alsa alsa_out_LDFLAGS = -lasound -lsamplerate @OS_LDFLAGS@ alsa_out_LDADD = $(top_builddir)/libjack/libjack.la endif #HAVE_ALSA endif #HAVE_SAMPLERATE # XXX ? dist-hook: dist-check-sndfile dist-check-samplerate jackd1-0.121.3+20120418git75e3e20b/tools/netsource.c0000644001605600047420000006021311731642255017117 0ustar adiira/* NetJack Client Copyright (C) 2008 Marc-Olivier Barre Copyright (C) 2008 Pieter Palmers Copyright (C) 2006 Torben Hohn 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. */ /** @file netsource.c * * @brief This client connects a remote slave JACK to a local JACK server assumed to be the master */ #include "config.h" #include #include #include #include #include #include #ifdef WIN32 #include #include #else #include #include #include #endif /* These two required by FreeBSD. */ #include #include //#include #include #if HAVE_SAMPLERATE #include #endif #if HAVE_CELT #include #endif #include JSList *capture_ports = NULL; JSList *capture_srcs = NULL; int capture_channels = 0; int capture_channels_audio = 2; int capture_channels_midi = 1; JSList *playback_ports = NULL; JSList *playback_srcs = NULL; int playback_channels = 0; int playback_channels_audio = 2; int playback_channels_midi = 1; int dont_htonl_floats = 0; int latency = 5; jack_nframes_t factor = 1; int bitdepth = 0; int mtu = 1400; int reply_port = 0; int bind_port = 0; int redundancy = 1; jack_client_t *client; packet_cache * packcache = 0; int state_connected = 0; int state_latency = 0; int state_netxruns = 0; int state_currentframe = 0; int state_recv_packet_queue_time = 0; int quit=0; int outsockfd; int insockfd; #ifdef WIN32 struct sockaddr_in destaddr; struct sockaddr_in bindaddr; #else struct sockaddr destaddr; struct sockaddr bindaddr; #endif int sync_state; jack_transport_state_t last_transport_state; int framecnt = 0; int cont_miss = 0; int freewheeling = 0; /** * This Function allocates all the I/O Ports which are added the lists. */ void alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int n_playback_midi) { int port_flags = JackPortIsOutput; int chn; jack_port_t *port; char buf[32]; capture_ports = NULL; /* Allocate audio capture channels */ for (chn = 0; chn < n_capture_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jack_netsource: cannot register %s port\n", buf); break; } if( bitdepth == 1000 ) { #if HAVE_CELT #if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL ); capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); #else CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), 1, jack_get_buffer_size(client), NULL ); capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode ) ); #endif #endif } else { #if HAVE_SAMPLERATE capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL)); #endif } capture_ports = jack_slist_append (capture_ports, port); } /* Allocate midi capture channels */ for (chn = n_capture_audio; chn < n_capture_midi + n_capture_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0); if (!port) { printf ("jack_netsource: cannot register %s port\n", buf); break; } capture_ports = jack_slist_append(capture_ports, port); } /* Allocate audio playback channels */ port_flags = JackPortIsInput; playback_ports = NULL; for (chn = 0; chn < n_playback_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf ("jack_netsource: cannot register %s port\n", buf); break; } if( bitdepth == 1000 ) { #if HAVE_CELT #if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL ); playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); #else CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), 1, jack_get_buffer_size(client), NULL ); playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode ) ); #endif #endif } else { #if HAVE_SAMPLERATE playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL)); #endif } playback_ports = jack_slist_append (playback_ports, port); } /* Allocate midi playback channels */ for (chn = n_playback_audio; chn < n_playback_midi + n_playback_audio; chn++) { snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1); port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0); if (!port) { printf ("jack_netsource: cannot register %s port\n", buf); break; } playback_ports = jack_slist_append (playback_ports, port); } } /** * The Sync callback... sync state is set elsewhere... * we will see if this is working correctly. * i dont really believe in it yet. */ int sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg) { static int latency_count = 0; int retval = sync_state; if (! state_connected) { return 1; } if (latency_count) { latency_count--; retval = 0; } else if (state == JackTransportStarting && last_transport_state != JackTransportStarting) { retval = 0; latency_count = latency - 1; } last_transport_state = state; return retval; } void freewheel_cb (int starting, void *arg) { freewheeling = starting; } int deadline_goodness=0; /** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { jack_nframes_t net_period; int rx_bufsize, tx_bufsize; jack_default_audio_sample_t *buf; jack_port_t *port; JSList *node; int chn; int size, i; const char *porttype; int input_fd; jack_position_t local_trans_pos; uint32_t *packet_buf_tx, *packet_bufX; uint32_t *rx_packet_ptr; jack_time_t packet_recv_timestamp; if( bitdepth == 1000 ) net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ; else net_period = (float) nframes / (float) factor; rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header); /* Allocate a buffer where both In and Out Buffer will fit */ packet_buf_tx = alloca (tx_bufsize); jacknet_packet_header *pkthdr_tx = (jacknet_packet_header *) packet_buf_tx; /* * for latency==0 we need to send out the packet before we wait on the reply. * but this introduces a cycle of latency, when netsource is connected to itself. * so we send out before read only in zero latency mode. * */ if( latency == 0 ) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); /* ---------- Send ---------- */ render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period, dont_htonl_floats); /* fill in packet hdr */ pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos); pkthdr_tx->transport_frame = local_trans_pos.frame; pkthdr_tx->framecnt = framecnt; pkthdr_tx->latency = latency; pkthdr_tx->reply_port = reply_port; pkthdr_tx->sample_rate = jack_get_sample_rate (client); pkthdr_tx->period_size = nframes; /* playback for us is capture on the other side */ pkthdr_tx->capture_channels_audio = playback_channels_audio; pkthdr_tx->playback_channels_audio = capture_channels_audio; pkthdr_tx->capture_channels_midi = playback_channels_midi; pkthdr_tx->playback_channels_midi = capture_channels_midi; pkthdr_tx->mtu = mtu; if( freewheeling!= 0 ) pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS; else pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness; //printf("goodness=%d\n", deadline_goodness ); packet_header_hton (pkthdr_tx); if (cont_miss < 3*latency+5) { int r; for( r=0; r 50+5*latency) { state_connected = 0; packet_cache_reset_master_address( packcache ); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); cont_miss = 0; } } /* * ok... now the RECEIVE code. * */ if( reply_port ) input_fd = insockfd; else input_fd = outsockfd; // for latency == 0 we can poll. if( (latency == 0) || (freewheeling!=0) ) { jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client)/jack_get_sample_rate(client); // Now loop until we get the right packet. while(1) { jack_nframes_t got_frame; if ( ! netjack_poll_deadline( input_fd, deadline, jack_get_time ) ) break; packet_cache_drain_socket(packcache, input_fd, jack_get_time); if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame )) if( got_frame == (framecnt - latency) ) break; } } else { // normally: // only drain socket. packet_cache_drain_socket(packcache, input_fd, jack_get_time); } size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); /* First alternative : we received what we expected. Render the data * to the JACK ports so it can be played. */ if (size == rx_bufsize) { uint32_t *packet_buf_rx = rx_packet_ptr; jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx; packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); // calculate how much time there would have been, if this packet was sent at the deadline. int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp); packet_header_ntoh (pkthdr_rx); deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency; //printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset ); if (cont_miss) { //printf("Frame %d \tRecovered from dropouts\n", framecnt); cont_miss = 0; } render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes, dont_htonl_floats); state_currentframe = framecnt; state_recv_packet_queue_time = recv_time_offset; state_connected = 1; sync_state = pkthdr_rx->sync_state; packet_cache_release_packet( packcache, framecnt - latency ); } /* Second alternative : we've received something that's not * as big as expected or we missed a packet. We render silence * to the ouput ports */ else { jack_nframes_t latency_estimate; if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) //if( (state_latency == 0) || (latency_estimate < state_latency) ) state_latency = latency_estimate; // Set the counters up. state_currentframe = framecnt; //state_latency = framecnt - pkthdr->framecnt; state_netxruns += 1; //printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size); //printf ("Frame %d \tPacket missed or incomplete\n", framecnt); cont_miss += 1; chn = 0; node = capture_ports; while (node != NULL) { port = (jack_port_t *) node->data; buf = jack_port_get_buffer (port, nframes); porttype = jack_port_type (port); if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0) for (i = 0; i < nframes; i++) buf[i] = 0.0; else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0) jack_midi_clear_buffer (buf); node = jack_slist_next (node); chn++; } } if( latency != 0 ) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); /* ---------- Send ---------- */ render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period, dont_htonl_floats); /* fill in packet hdr */ pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos); pkthdr_tx->transport_frame = local_trans_pos.frame; pkthdr_tx->framecnt = framecnt; pkthdr_tx->latency = latency; pkthdr_tx->reply_port = reply_port; pkthdr_tx->sample_rate = jack_get_sample_rate (client); pkthdr_tx->period_size = nframes; /* playback for us is capture on the other side */ pkthdr_tx->capture_channels_audio = playback_channels_audio; pkthdr_tx->playback_channels_audio = capture_channels_audio; pkthdr_tx->capture_channels_midi = playback_channels_midi; pkthdr_tx->playback_channels_midi = capture_channels_midi; pkthdr_tx->mtu = mtu; if( freewheeling!= 0 ) pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS; else pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness; //printf("goodness=%d\n", deadline_goodness ); packet_header_hton (pkthdr_tx); if (cont_miss < 3*latency+5) { int r; for( r=0; r 50+5*latency) { state_connected = 0; packet_cache_reset_master_address( packcache ); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); cont_miss = 0; } } framecnt++; return 0; } /** * This is the shutdown callback for this JACK application. * It is called by JACK if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } void init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t port) { name->sin_family = AF_INET ; name->sin_port = htons (port); if (hostname) { struct hostent *hostinfo = gethostbyname (hostname); if (hostinfo == NULL) { fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); fflush( stderr ); } #ifdef WIN32 name->sin_addr.s_addr = inet_addr( hostname ); #else name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; #endif } else name->sin_addr.s_addr = htonl (INADDR_ANY) ; } void printUsage () { fprintf (stderr, "usage: jack_netsource [options]\n" "\n" " -h this help text\n" " -H - Host name of the slave JACK\n" " -o - Number of audio playback channels\n" " -i - Number of audio capture channels\n" " -O - Number of midi playback channels\n" " -I - Number of midi capture channels\n" " -n - Network latency in JACK periods\n" " -p - UDP port that the slave is listening on\n" " -r - UDP port that we are listening on\n" " -B - reply port, for use in NAT environments\n" " -b - Set transport to use 16bit or 8bit\n" " -c - Use CELT encoding with kbits per channel\n" " -m - Assume this mtu for the link\n" " -R - Redundancy: send out packets N times.\n" " -e - skip host-to-network endianness conversion\n" " -N - Reports a different name to jack\n" " -s - The name of the local jack server\n" "\n"); } void sigterm_handler( int signal ) { quit = 1; } int main (int argc, char *argv[]) { /* Some startup related basics */ char *client_name, *server_name = NULL, *peer_ip; int peer_port = 3000; jack_options_t options = JackNullOption; jack_status_t status; #ifdef WIN32 WSADATA wsa; int rc = WSAStartup(MAKEWORD(2,0),&wsa); #endif /* Torben's famous state variables, aka "the reporting API" ! */ /* heh ? these are only the copies of them ;) */ int statecopy_connected, statecopy_latency, statecopy_netxruns; jack_nframes_t net_period; /* Argument parsing stuff */ extern char *optarg; extern int optind, optopt; int errflg=0, c; if (argc < 3) { printUsage (); return 1; } client_name = (char *) malloc (sizeof (char) * 10); peer_ip = (char *) malloc (sizeof (char) * 10); sprintf(client_name, "netjack"); sprintf(peer_ip, "localhost"); while ((c = getopt (argc, argv, ":h:H:o:i:O:I:n:p:r:B:b:c:m:R:e:N:s:")) != -1) { switch (c) { case 'h': printUsage(); exit (0); break; case 'H': free(peer_ip); peer_ip = (char *) malloc (sizeof (char) * strlen (optarg)+1); strcpy (peer_ip, optarg); break; case 'o': playback_channels_audio = atoi (optarg); break; case 'i': capture_channels_audio = atoi (optarg); break; case 'O': playback_channels_midi = atoi (optarg); break; case 'I': capture_channels_midi = atoi (optarg); break; case 'n': latency = atoi (optarg); break; case 'p': peer_port = atoi (optarg); break; case 'r': reply_port = atoi (optarg); break; case 'B': bind_port = atoi (optarg); break; case 'f': factor = atoi (optarg); printf("This feature is deprecated and will be removed in future netjack versions. CELT offers a superiour way to conserve bandwidth"); break; case 'b': bitdepth = atoi (optarg); break; case 'c': #if HAVE_CELT bitdepth = 1000; factor = atoi (optarg); #else printf( "not built with celt supprt\n" ); exit(10); #endif break; case 'm': mtu = atoi (optarg); break; case 'R': redundancy = atoi (optarg); break; case 'e': dont_htonl_floats = 1; break; case 'N': free(client_name); client_name = (char *) malloc (sizeof (char) * strlen (optarg)+1); strcpy (client_name, optarg); break; case 's': server_name = (char *) malloc (sizeof (char) * strlen (optarg)+1); strcpy (server_name, optarg); options |= JackServerName; break; case ':': fprintf (stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf (stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage (); exit (2); } capture_channels = capture_channels_audio + capture_channels_midi; playback_channels = playback_channels_audio + playback_channels_midi; outsockfd = socket (AF_INET, SOCK_DGRAM, 0); insockfd = socket (AF_INET, SOCK_DGRAM, 0); if( (outsockfd == -1) || (insockfd == -1) ) { fprintf (stderr, "cant open sockets\n" ); return 1; } init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); if(bind_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { fprintf (stderr, "bind failure\n" ); } } if(reply_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { fprintf (stderr, "bind failure\n" ); } } /* try to become a client of the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n" "Is the JACK server running ?\n", status); return 1; } /* Set up jack callbacks */ jack_set_process_callback (client, process, 0); jack_set_sync_callback (client, sync_cb, 0); jack_set_freewheel_callback (client, freewheel_cb, 0); jack_on_shutdown (client, jack_shutdown, 0); alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi); if( bitdepth == 1000 ) net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ; else net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor); int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "Cannot activate client"); return 1; } /* Now sleep forever... and evaluate the state_ vars */ signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); statecopy_connected = 2; // make it report unconnected on start. statecopy_latency = state_latency; statecopy_netxruns = state_netxruns; while ( !quit ) { #ifdef WIN32 Sleep (1000); #else sleep(1); #endif if (statecopy_connected != state_connected) { statecopy_connected = state_connected; if (statecopy_connected) { state_netxruns = 1; // We want to reset the netxrun count on each new connection printf ("Connected :-)\n"); } else printf ("Not Connected\n"); fflush(stdout); } if (statecopy_connected) { if (statecopy_netxruns != state_netxruns) { statecopy_netxruns = state_netxruns; printf ("%s: at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", client_name, state_currentframe, statecopy_netxruns, 100*statecopy_netxruns/state_currentframe, state_recv_packet_queue_time); fflush(stdout); } } else { if (statecopy_latency != state_latency) { statecopy_latency = state_latency; if (statecopy_latency > 1) printf ("current latency %d\n", statecopy_latency); fflush(stdout); } } } jack_client_close (client); packet_cache_free (packcache); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/session_notify.c0000644001605600047420000001076611731642255020173 0ustar adiira/* * session_notify.c -- ultra minimal session manager * * Copyright (C) 2010 Torben Hohn. * * 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. */ #include #include #include #include #include #include #include #include #include #include char *package; /* program name */ jack_client_t *client; jack_session_event_type_t notify_type; char *save_path = NULL; void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } void parse_arguments(int argc, char *argv[]) { /* basename $0 */ package = strrchr(argv[0], '/'); if (package == 0) package = argv[0]; else package++; if (argc==2) { if( !strcmp( argv[1], "quit" ) ) { notify_type = JackSessionSaveAndQuit; return; } } if (argc==3) { if( !strcmp( argv[1], "save" ) ) { notify_type = JackSessionSave; save_path = argv[2]; return; } } fprintf(stderr, "usage: %s quit|save [path]\n", package); exit(9); } typedef struct { char name[32]; char uuid[16]; } uuid_map_t; JSList *uuid_map = NULL; void add_uuid_mapping( const char *uuid ) { char *clientname = jack_get_client_name_by_uuid( client, uuid ); if( !clientname ) { printf( "error... cant find client for uuid" ); return; } uuid_map_t *mapping = malloc( sizeof(uuid_map_t) ); snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid ); snprintf( mapping->name, sizeof(mapping->name), "%s", clientname ); uuid_map = jack_slist_append( uuid_map, mapping ); } char *map_port_name_to_uuid_port( const char *port_name ) { JSList *node; char retval[300]; char *port_component = strchr( port_name,':' ); char *client_component = strdup( port_name ); strchr( client_component, ':' )[0] = '\0'; sprintf( retval, "%s", port_name ); for( node=uuid_map; node; node=jack_slist_next(node) ) { uuid_map_t *mapping = node->data; if( !strcmp( mapping->name, client_component ) ) { sprintf( retval, "%s%s", mapping->uuid, port_component ); break; } } return strdup(retval); } int main(int argc, char *argv[]) { parse_arguments(argc, argv); jack_session_command_t *retval; int k,i,j; /* become a JACK client */ if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { fprintf(stderr, "JACK server not running?\n"); exit(1); } signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); jack_activate(client); retval = jack_session_notify( client, NULL, notify_type, save_path ); for(i=0; retval[i].uuid; i++ ) { printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name ); printf( "%s &\n", retval[i].command ); add_uuid_mapping(retval[i].uuid); } printf( "sleep 10\n" ); for(k=0; retval[k].uuid; k++ ) { char* port_regexp = alloca( jack_client_name_size()+3 ); char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid ); snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name ); jack_free(client_name); const char **ports = jack_get_ports( client, port_regexp, NULL, 0 ); if( !ports ) { continue; } for (i = 0; ports[i]; ++i) { const char **connections; if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { for (j = 0; connections[j]; j++) { char *src = map_port_name_to_uuid_port( ports[i] ); char *dst = map_port_name_to_uuid_port( connections[j] ); printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst ); } jack_free (connections); } } jack_free(ports); } jack_session_commands_free(retval); jack_client_close(client); return 0; } jackd1-0.121.3+20120418git75e3e20b/tools/iodelay.c0000644001605600047420000001464211731642255016543 0ustar adiira/* Copyright (C) 2003-2008 Fons Adriaensen 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. */ // -------------------------------------------------------------------------------- #include #include #include #include #include struct Freq { int p; int f; float a; float xa; float ya; float xf; float yf; }; struct MTDM { double _del; double _err; int _cnt; int _inv; struct Freq _freq [5]; }; struct MTDM * mtdm_new (void) { int i; struct Freq *F; struct MTDM *retval = malloc( sizeof(struct MTDM) ); if (retval==NULL) return NULL; retval->_cnt = 0; retval->_inv = 0; retval->_freq [0].f = 4096; retval->_freq [1].f = 512; retval->_freq [2].f = 1088; retval->_freq [3].f = 1544; retval->_freq [4].f = 2049; retval->_freq [0].a = 0.2f; retval->_freq [1].a = 0.1f; retval->_freq [2].a = 0.1f; retval->_freq [3].a = 0.1f; retval->_freq [4].a = 0.1f; for (i = 0, F = retval->_freq; i < 5; i++, F++) { F->p = 128; F->xa = F->ya = 0.0f; F->xf = F->yf = 0.0f; } return retval; } int mtdm_process (struct MTDM *self, size_t len, float *ip, float *op) { int i; float vip, vop, a, c, s; struct Freq *F; while (len--) { vop = 0.0f; vip = *ip++; for (i = 0, F = self->_freq; i < 5; i++, F++) { a = 2 * (float) M_PI * (F->p & 65535) / 65536.0; F->p += F->f; c = cosf (a); s = -sinf (a); vop += F->a * s; F->xa += s * vip; F->ya += c * vip; } *op++ = vop; if (++(self->_cnt) == 16) { for (i = 0, F = self->_freq; i < 5; i++, F++) { F->xf += 1e-3f * (F->xa - F->xf + 1e-20); F->yf += 1e-3f * (F->ya - F->yf + 1e-20); F->xa = F->ya = 0.0f; } self->_cnt = 0; } } return 0; } int mtdm_resolve (struct MTDM *self) { int i, k, m; double d, e, f0, p; struct Freq *F = self->_freq; if (hypot (F->xf, F->yf) < 0.01) return -1; d = atan2 (F->yf, F->xf) / (2 * M_PI); if (self->_inv) d += 0.5f; if (d > 0.5f) d -= 1.0f; f0 = self->_freq [0].f; m = 1; self->_err = 0.0; for (i = 0; i < 4; i++) { F++; p = atan2 (F->yf, F->xf) / (2 * M_PI) - d * F->f / f0; if (self->_inv) p += 0.5f; p -= floor (p); p *= 8; k = (int)(floor (p + 0.5)); e = fabs (p - k); if (e > self->_err) self->_err = e; if (e > 0.4) return 1; d += m * (k & 7); m *= 8; } self->_del = 16 * d; return 0; } void mtdm_invert (struct MTDM *self) { self->_inv ^= 1; } // -------------------------------------------------------------------------------- static struct MTDM *mtdm; static jack_client_t *jack_handle; static jack_port_t *jack_capt; static jack_port_t *jack_play; jack_latency_range_t capture_latency = {-1, -1}; jack_latency_range_t playback_latency = {-1, -1}; void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; range.min = range.max = 0; if (mode == JackCaptureLatency) { jack_port_set_latency_range (jack_play, mode, &range); jack_port_get_latency_range (jack_capt, mode, &range); if ((range.min != capture_latency.min) || (range.max != capture_latency.max)) { capture_latency = range; printf ("new capture latency: [%d, %d]\n", range.min, range.max); } } else { jack_port_set_latency_range (jack_capt, mode, &range); jack_port_get_latency_range (jack_play, mode, &range); if ((range.min != playback_latency.min) || (range.max != playback_latency.max)) { playback_latency = range; printf ("new playback latency: [%d, %d]\n", range.min, range.max); } } } int jack_callback (jack_nframes_t nframes, void *arg) { float *ip, *op; ip = (float *)(jack_port_get_buffer (jack_capt, nframes)); op = (float *)(jack_port_get_buffer (jack_play, nframes)); mtdm_process (mtdm, nframes, ip, op); return 0; } int main (int ac, char *av []) { float t; jack_status_t s; mtdm = mtdm_new(); jack_handle = jack_client_open ("jack_delay", JackNoStartServer, &s); if (jack_handle == 0) { fprintf (stderr, "Can't connect to Jack, is the server running ?\n"); exit (1); } jack_set_process_callback (jack_handle, jack_callback, 0); if (jack_set_latency_callback) jack_set_latency_callback (jack_handle, latency_cb, 0); jack_capt = jack_port_register (jack_handle, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); jack_play = jack_port_register (jack_handle, "out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); t = 1000.0f / jack_get_sample_rate (jack_handle); if (jack_activate (jack_handle)) { fprintf(stderr, "Can't activate Jack"); return 1; } while (1) { #ifdef WIN32 Sleep (250); #else usleep (250000); #endif if (mtdm_resolve (mtdm) < 0) printf ("Signal below threshold...\n"); else { jack_nframes_t systemic_latency; if (mtdm->_err > 0.3) { mtdm_invert ( mtdm ); mtdm_resolve ( mtdm ); } systemic_latency = (jack_nframes_t) floor (mtdm->_del - (capture_latency.max + playback_latency.max)); printf ("%10.3lf frames %10.3lf ms total roundtrip latency\n\textra loopback latency: %u frames\n\tuse %u for the backend arguments -I and -O", mtdm->_del, mtdm->_del * t, systemic_latency, systemic_latency/2); if (mtdm->_err > 0.2) printf (" ??"); if (mtdm->_inv) printf (" Inv"); printf ("\n"); } } return 0; } // -------------------------------------------------------------------------------- jackd1-0.121.3+20120418git75e3e20b/tools/alsa_out.c0000644001605600047420000005521711731642255016727 0ustar adiira/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include #include #include #include #include "memops.h" #include "alsa/asoundlib.h" #include // Here are the lists of the jack ports... JSList *capture_ports = NULL; JSList *capture_srcs = NULL; JSList *playback_ports = NULL; JSList *playback_srcs = NULL; jack_client_t *client; snd_pcm_t *alsa_handle; int jack_sample_rate; int jack_buffer_size; int quit = 0; double resample_mean = 1.0; double static_resample_factor = 1.0; double resample_lower_limit = 0.25; double resample_upper_limit = 4.0; double *offset_array; double *window_array; int offset_differential_index = 0; double offset_integral = 0; // ------------------------------------------------------ commandline parameters int sample_rate = 0; /* stream rate */ int num_channels = 2; /* count of channels */ int period_size = 1024; int num_periods = 2; int target_delay = 0; /* the delay which the program should try to approach. */ int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */ int catch_factor = 100000; int catch_factor2 = 10000; double pclamp = 15.0; double controlquant = 10000.0; int smooth_size = 256; int good_window=0; int verbose = 0; int instrument = 0; int samplerate_quality = 2; // Debug stuff: volatile float output_resampling_factor = 1.0; volatile int output_new_delay = 0; volatile float output_offset = 0.0; volatile float output_integral = 0.0; volatile float output_diff = 0.0; snd_pcm_uframes_t real_buffer_size; snd_pcm_uframes_t real_period_size; // buffers char *tmpbuf; char *outbuf; float *resampbuf; // format selection, and corresponding functions from memops in a nice set of structs. typedef struct alsa_format { snd_pcm_format_t format_id; size_t sample_size; void (*jack_to_soundcard) (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void (*soundcard_to_jack) (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); const char *name; } alsa_format_t; alsa_format_t formats[] = { { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } }; #define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) int format=0; // Alsa stuff... i dont want to touch this bullshit in the next years.... please... static int xrun_recovery(snd_pcm_t *handle, int err) { // printf( "xrun !!!.... %d\n", err ); if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); return 0; } else if (err == -EAGAIN) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) usleep(100); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); } return 0; } return err; } static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) { int i; int err; for( i=0; i (target_delay+max_diff) ) { snd_pcm_rewind( alsa_handle, delay - target_delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i 0) { snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); snd_pcm_writei( alsa_handle, tmpbuf, to_write ); delay += to_write; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; /* * now this should do it... */ outbuf = alloca( rlen * formats[format].sample_size * num_channels ); resampbuf = alloca( rlen * sizeof( float ) ); /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = resampbuf; src.output_frames = rlen; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL); src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // now write the output... again: err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); //err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } goto again; } return 0; } /** * the latency callback. * sets up the latencies on the ports. */ void latency_cb (jack_latency_callback_mode_t mode, void *arg) { jack_latency_range_t range; JSList *node; range.min = range.max = target_delay; if (mode == JackCaptureLatency) { for (node = capture_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } else { for (node = playback_ports; node; node = jack_slist_next (node)) { jack_port_t *port = node->data; jack_port_set_latency_range (port, mode, &range); } } } /** * Allocate the necessary jack ports... */ void alloc_ports( int n_capture, int n_playback ) { int port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; int chn; jack_port_t *port; char buf[32]; capture_ports = NULL; for (chn = 0; chn < n_capture; chn++) { snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } capture_srcs = jack_slist_append( capture_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); capture_ports = jack_slist_append (capture_ports, port); } port_flags = JackPortIsInput; playback_ports = NULL; for (chn = 0; chn < n_playback; chn++) { snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1); port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); if (!port) { printf( "jacknet_client: cannot register port for %s", buf); break; } playback_srcs = jack_slist_append( playback_srcs, src_new( 4-samplerate_quality, 1, NULL ) ); playback_ports = jack_slist_append (playback_ports, port); } } /** * This is the shutdown callback for this JACK application. * It is called by JACK if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } /** * be user friendly. * be user friendly. * be user friendly. */ void printUsage() { fprintf(stderr, "usage: alsa_out [options]\n" "\n" " -j - client name\n" " -d \n" " -c \n" " -p \n" " -n \n" " -r \n" " -q \n" " -t \n" " -i turns on instrumentation\n" " -v turns on printouts\n" "\n"); } /** * the main function.... */ void sigterm_handler( int signal ) { quit = 1; } int main (int argc, char *argv[]) { char jack_name[30] = "alsa_out"; char alsa_device[30] = "hw:0"; extern char *optarg; extern int optind, optopt; int errflg=0; int c; while ((c = getopt(argc, argv, "ivj:r:c:p:n:d:q:m:t:f:F:C:Q:s:")) != -1) { switch(c) { case 'j': strcpy(jack_name,optarg); break; case 'r': sample_rate = atoi(optarg); break; case 'c': num_channels = atoi(optarg); break; case 'p': period_size = atoi(optarg); break; case 'n': num_periods = atoi(optarg); break; case 'd': strcpy(alsa_device,optarg); break; case 't': target_delay = atoi(optarg); break; case 'q': samplerate_quality = atoi(optarg); break; case 'm': max_diff = atoi(optarg); break; case 'f': catch_factor = atoi(optarg); break; case 'F': catch_factor2 = atoi(optarg); break; case 'C': pclamp = (double) atoi(optarg); break; case 'Q': controlquant = (double) atoi(optarg); break; case 'v': verbose = 1; break; case 'i': instrument = 1; break; case 's': smooth_size = atoi(optarg); break; case ':': fprintf(stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf(stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage(); exit(2); } if( (samplerate_quality < 0) || (samplerate_quality > 4) ) { fprintf (stderr, "invalid samplerate quality\n"); return 1; } if ((client = jack_client_open (jack_name, 0, NULL)) == 0) { fprintf (stderr, "jack server not running?\n"); return 1; } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); if (jack_set_latency_callback) jack_set_latency_callback (client, latency_cb, 0); // get jack sample_rate jack_sample_rate = jack_get_sample_rate( client ); if( !sample_rate ) sample_rate = jack_sample_rate; static_resample_factor = (double) sample_rate / (double) jack_sample_rate; resample_lower_limit = static_resample_factor * 0.25; resample_upper_limit = static_resample_factor * 4.0; resample_mean = static_resample_factor; offset_array = malloc( sizeof(double) * smooth_size ); if( offset_array == NULL ) { fprintf( stderr, "no memory for offset_array !!!\n" ); exit(20); } window_array = malloc( sizeof(double) * smooth_size ); if( window_array == NULL ) { fprintf( stderr, "no memory for window_array !!!\n" ); exit(20); } int i; for( i=0; i target_delay ) { fprintf( stderr, "target_delay (%d) cant be smaller than max_diff(%d)\n", target_delay, max_diff ); exit(20); } if( (target_delay+max_diff) > (num_periods*period_size) ) { fprintf( stderr, "target_delay+max_diff (%d) cant be bigger than buffersize(%d)\n", target_delay+max_diff, num_periods*period_size ); exit(20); } // now open the alsa fd... alsa_handle = open_audiofd( alsa_device, 0, sample_rate, num_channels, period_size, num_periods); if( alsa_handle == 0 ) exit(20); printf( "selected sample format: %s\n", formats[format].name ); // alloc input ports, which are blasted out to alsa... alloc_ports( 0, num_channels ); outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels ); resampbuf = malloc( num_periods * period_size * sizeof( float ) ); tmpbuf = malloc( 512 * formats[format].sample_size * num_channels ); if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL)) { fprintf( stderr, "no memory for buffers.\n" ); exit(20); } /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); return 1; } signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); if( verbose ) { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset ); } } else if( instrument ) { printf( "# n\tresamp\tdiff\toffseti\tintegral\n"); int n=0; while(!quit) { usleep(1000); printf( "%d\t%f\t%f\t%f\t%f\n", n++, output_resampling_factor, output_diff, output_offset, output_integral ); } } else { while(!quit) { usleep(500000); if( output_new_delay ) { printf( "delay = %d\n", output_new_delay ); output_new_delay = 0; } } } jack_deactivate( client ); jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/wait.c0000644001605600047420000000676211731642255016065 0ustar adiira#include #include #include #include #include #include #include #include char * my_name; void show_version (void) { fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name); } void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options]\n", my_name); fprintf (stderr, "Check for jack existence, or wait, until it either quits, or gets started\n"); fprintf (stderr, "options:\n"); fprintf (stderr, " -s, --server Connect to the jack server named \n"); fprintf (stderr, " -w, --wait Wait for server to become available\n"); fprintf (stderr, " -q, --quit Wait until server is quit\n"); fprintf (stderr, " -c, --check Check wether server is running\n"); fprintf (stderr, " -t, --timeout Wait timeout in seconds\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } void silent_function( const char *ignore ) { } int main (int argc, char *argv[]) { jack_client_t *client; jack_status_t status; jack_options_t options = JackNoStartServer; int c; int option_index; char *server_name = NULL; int wait_for_start = 0; int wait_for_quit = 0; int just_check = 0; int wait_timeout = 0; time_t start_timestamp; struct option long_options[] = { { "server", 1, 0, 's' }, { "wait", 0, 0, 'w' }, { "quit", 0, 0, 'q' }, { "check", 0, 0, 'c' }, { "timeout", 1, 0, 't' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "s:wqct:hv", long_options, &option_index)) >= 0) { switch (c) { case 's': server_name = (char *) malloc (sizeof (char) * strlen(optarg)); strcpy (server_name, optarg); options |= JackServerName; break; case 'w': wait_for_start = 1; break; case 'q': wait_for_quit = 1; break; case 'c': just_check = 1; break; case 't': wait_timeout = atoi(optarg); break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } /* try to open server in a loop. breaking under certein conditions */ start_timestamp = time( NULL ); jack_set_info_function( silent_function ); while(1) { client = jack_client_open ("wait", options, &status, server_name); /* check for some real error and bail out */ if( (client == NULL) && !(status & JackServerFailed) ) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); return 1; } if( client == NULL ) { if( wait_for_quit ) { fprintf( stdout, "server is gone\n" ); break; } if( just_check ) { fprintf( stdout, "not running\n" ); break; } } else { jack_client_close( client ); if( wait_for_start ) { fprintf( stdout, "server is available\n" ); break; } if( just_check ) { fprintf( stdout, "running\n" ); break; } } if( wait_timeout ) { if( (time( NULL ) - start_timestamp) > wait_timeout ) { fprintf( stdout, "timeout\n" ); break; } } // Wait a second, and repeat sleep(1); } exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/tw.c0000644001605600047420000001135511731642255015545 0ustar adiira/** @file simple_client.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. */ #include #include #include #include #include #include jack_port_t *input_port; jack_port_t *output_port; jack_client_t *client; /* a simple state machine for this client */ volatile enum { Init, Run, Exit } client_state = Init; /** * The process callback for this JACK application is called in a * special realtime thread once for each audio cycle. * * This client follows a simple rule: when the JACK transport is * running, copy the input port to the output. When it stops, exit. */ int _process (jack_nframes_t nframes) { jack_default_audio_sample_t *in, *out; jack_transport_state_t ts = jack_transport_query(client, NULL); if (ts == JackTransportRolling) { if (client_state == Init) client_state = Run; in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); } else if (ts == JackTransportStopped) { if (client_state == Run) client_state = Exit; } return 0; } int process (jack_nframes_t nframes, void* arg) { jack_client_t* client = (jack_client_t*) arg; while ((nframes = jack_thread_wait (client, _process (nframes))) != 0); return 0; } /** * JACK calls this shutdown_callback if the server ever shuts down or * decides to disconnect the client. */ void jack_shutdown (void *arg) { exit (1); } int main (int argc, char *argv[]) { const char **ports; const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; if (argc >= 2) { /* client name specified? */ client_name = argv[1]; if (argc >= 3) { /* server name specified? */ server_name = argv[2]; options |= JackServerName; } } else { /* use basename of argv[0] */ client_name = strrchr(argv[0], '/'); if (client_name == 0) { client_name = argv[0]; } else { client_name++; } } /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, client); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if ((input_port == NULL) || (output_port == NULL)) { fprintf(stderr, "no more JACK ports available\n"); exit (1); } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports == NULL) { fprintf(stderr, "no physical capture ports\n"); exit (1); } if (jack_connect (client, ports[0], jack_port_name (input_port))) { fprintf (stderr, "cannot connect input ports\n"); } free (ports); ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { fprintf(stderr, "no physical playback ports\n"); exit (1); } if (jack_connect (client, jack_port_name (output_port), ports[0])) { fprintf (stderr, "cannot connect output ports\n"); } free (ports); /* keep running until the transport stops */ while (client_state != Exit) { sleep (1); } jack_client_close (client); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/load_test.c0000644001605600047420000000453411731642255017072 0ustar adiira#include #include #include #include #include #include #include #include #include char * my_name; jack_client_t *client; unsigned int wait_timeout = 1000; void show_version (void) { fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name); } void show_usage (void) { show_version (); fprintf (stderr, "\nUsage: %s [options]\n", my_name); fprintf (stderr, "this is a test client, which just sleeps in its process_cb to simulate cpu load\n"); fprintf (stderr, "options:\n"); fprintf (stderr, " -t, --timeout Wait timeout in seconds\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); fprintf (stderr, "For more information see http://jackaudio.org/\n"); } void jack_shutdown(void *arg) { fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } int process_cb (jack_nframes_t nframes, void *arg) { jack_time_t now = jack_get_time(); jack_time_t wait = now + wait_timeout; while (jack_get_time() < wait) ; return 0; } int main (int argc, char *argv[]) { int c; int option_index; struct option long_options[] = { { "timeout", 1, 0, 't' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { 0, 0, 0, 0 } }; my_name = strrchr(argv[0], '/'); if (my_name == 0) { my_name = argv[0]; } else { my_name ++; } while ((c = getopt_long (argc, argv, "t:hv", long_options, &option_index)) >= 0) { switch (c) { case 't': wait_timeout = atoi(optarg); break; case 'h': show_usage (); return 1; break; case 'v': show_version (); return 1; break; default: show_usage (); return 1; break; } } /* try to open server in a loop. breaking under certein conditions */ client = jack_client_open( "load_test", JackNullOption, NULL ); signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); jack_on_shutdown(client, jack_shutdown, 0); jack_set_process_callback( client, process_cb, NULL ); jack_activate (client); sleep( -1 ); exit (0); } jackd1-0.121.3+20120418git75e3e20b/tools/transport.c0000644001605600047420000002553111731642255017150 0ustar adiira/* * transport.c -- JACK transport master example client. * * 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. */ #include #include #include #include #include #include #include #include #include #include char *package; /* program name */ int done = 0; jack_client_t *client; /* Time and tempo variables. These are global to the entire, * transport timeline. There is no attempt to keep a true tempo map. * The default time signature is: "march time", 4/4, 120bpm */ float time_beats_per_bar = 4.0; float time_beat_type = 4.0; double time_ticks_per_beat = 1920.0; double time_beats_per_minute = 120.0; volatile int time_reset = 1; /* true when time values change */ volatile int avr_set = 0; float audio_frames_per_video_frame; /* JACK timebase callback. * * Runs in the process thread. Realtime, must not wait. */ void timebase(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg) { double min; /* minutes since frame 0 */ long abs_tick; /* ticks since frame 0 */ long abs_beat; /* beats since frame 0 */ if (new_pos || time_reset) { pos->valid = JackPositionBBT; pos->beats_per_bar = time_beats_per_bar; pos->beat_type = time_beat_type; pos->ticks_per_beat = time_ticks_per_beat; pos->beats_per_minute = time_beats_per_minute; time_reset = 0; /* time change complete */ /* Compute BBT info from frame number. This is relatively * simple here, but would become complex if we supported tempo * or time signature changes at specific locations in the * transport timeline. */ min = pos->frame / ((double) pos->frame_rate * 60.0); abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; abs_beat = abs_tick / pos->ticks_per_beat; pos->bar = abs_beat / pos->beats_per_bar; pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat); pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat; pos->bar++; /* adjust start to bar 1 */ #if 0 /* some debug code... */ fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n", pos->frame, pos->bar, pos->beat, pos->tick); #endif } else { /* Compute BBT info based on previous period. */ pos->tick += nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60); while (pos->tick >= pos->ticks_per_beat) { pos->tick -= pos->ticks_per_beat; if (++pos->beat > pos->beats_per_bar) { pos->beat = 1; ++pos->bar; pos->bar_start_tick += pos->beats_per_bar * pos->ticks_per_beat; } } } if (avr_set) { pos->valid |= JackAudioVideoRatio; pos->audio_frames_per_video_frame = audio_frames_per_video_frame; } } void jack_shutdown(void *arg) { #if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0400 rl_cleanup_after_signal(); #endif fprintf(stderr, "JACK shut down, exiting ...\n"); exit(1); } void signal_handler(int sig) { jack_client_close(client); fprintf(stderr, "signal received, exiting ...\n"); exit(0); } /* Command functions: see commands[] table following. */ void com_activate(char *arg) { if (jack_activate(client)) { fprintf(stderr, "cannot activate client"); } } void com_deactivate(char *arg) { if (jack_deactivate(client)) { fprintf(stderr, "cannot deactivate client"); } } void com_exit(char *arg) { done = 1; } void com_help(char *); /* forward declaration */ void com_locate(char *arg) { jack_nframes_t frame = 0; if (*arg != '\0') frame = atoi(arg); jack_transport_locate(client, frame); } void com_master(char *arg) { int cond = (*arg != '\0'); if (jack_set_timebase_callback(client, cond, timebase, NULL) != 0) fprintf(stderr, "Unable to take over timebase.\n"); } void com_play(char *arg) { jack_transport_start(client); } void com_release(char *arg) { jack_release_timebase(client); } void com_stop(char *arg) { jack_transport_stop(client); } /* Change the tempo for the entire timeline, not just from the current * location. */ void com_tempo(char *arg) { float tempo = 120.0; if (*arg != '\0') tempo = atof(arg); time_beats_per_minute = tempo; time_reset = 1; } /* Set sync timeout in seconds. */ void com_timeout(char *arg) { double timeout = 2.0; if (*arg != '\0') timeout = atof(arg); jack_set_sync_timeout(client, (jack_time_t) (timeout*1000000)); } /* Change the tempo for the entire timeline, not just from the current * location. */ void com_av_ratio(char *arg) { float avr = 0; if (*arg != '\0') avr = atof(arg); audio_frames_per_video_frame = avr; avr_set = 1; } /* Command parsing based on GNU readline info examples. */ typedef void cmd_function_t(char *); /* command function type */ /* Transport command table. */ typedef struct { char *name; /* user printable name */ cmd_function_t *func; /* function to call */ char *doc; /* documentation */ } command_t; /* command table must be in alphabetical order */ command_t commands[] = { {"activate", com_activate, "Call jack_activate()"}, {"avr", com_av_ratio, "Set audio/video frame ratio