void gst_jack_audio_client_init (void) { GST_DEBUG_CATEGORY_INIT (gst_jack_audio_client_debug, "jackclient", 0, "jackclient helpers"); jack_set_error_function (jack_log_error); jack_set_info_function (jack_info_error); }
jack_raw_output::jack_raw_output (const char* client, const char* server, int rate, int channels, callback_type cb) : detail::async_base_impl (cb) , _out_ports (channels) , _buffer_size (0) { jack_set_error_function (log_jack_error); jack_set_info_function (log_jack_info); jack_options_t options = !server ? JackNullOption : JackServerName; _client = jack_client_open (client, options, 0, server); if (!_client) throw jack_open_error (); auto grd_client = base::make_guard ([&] { jack_client_close (_client); }); PSYNTH_JACK_CHECK (jack_set_process_callback ( _client, &jack_raw_output::_process_cb, this), jack_param_error); PSYNTH_JACK_CHECK (jack_set_sample_rate_callback ( _client, &jack_raw_output::_sample_rate_cb, this), jack_param_error); jack_on_shutdown (_client, &jack_raw_output::_shutdown_cb, this); _actual_rate = jack_get_sample_rate (_client); if (_actual_rate != rate) PSYNTH_LOG << base::log::warning << "Jackd sample rate and application sample rate mismatch." << "Better sound quality is achieved if both are the same."; _buffer_size = jack_get_buffer_size (_client); PSYNTH_LOG << base::log::info << "Jackd buffer size is: " << _buffer_size; for (size_t i = 0; i < _out_ports.size(); ++i) { std::string port_name = std::string ("out_") + boost::lexical_cast<std::string> (i); _out_ports [i] = jack_port_register ( _client, port_name.c_str (), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (_out_ports [i] == 0) throw jack_param_error (); } grd_client.dismiss (); }
static SCM start_jack(void *data) { int i; char name[16]; jack_status_t jstatus; jack_client = jack_client_open(client_name, JackServerName, &jstatus, server_name); if (jack_client == 0) { log_msg("JACK server not running?\n") ; cleanup(); return SCM_UNSPECIFIED; } log_msg("JACK status: %04x\n", jstatus); if (jstatus & JackServerStarted) log_msg("\tserver started\n"); if (jstatus & JackServerFailed) log_msg("\tcan't connect\n"); if (jstatus & JackInitFailure) log_msg("\tcan't initialize client\n"); client_name = (const char *)jack_get_client_name(jack_client); sampling_rate = jack_get_sample_rate(jack_client) ; period_frames = jack_get_buffer_size(jack_client); jack_set_error_function(jack_error); jack_set_info_function(jack_info); jack_set_xrun_callback(jack_client, jack_xrun, NULL); jack_set_process_callback(jack_client, mixmaster, NULL); jack_set_port_registration_callback(jack_client, check_ports, NULL); jack_on_shutdown(jack_client, jack_shutdown, 0); for (i = 0; i < QMX_CHANNELS; i++) { sprintf(name, "out%02d", i + 1); jack_cauldron[i] = jack_port_register(jack_client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); } if (jack_activate(jack_client)) { log_msg("Cannot activate client.\n"); cleanup(); return SCM_UNSPECIFIED; } log_msg("JACK client activated: '%s'\n", client_name); return SCM_UNSPECIFIED; }
int soundio_jack_init(struct SoundIoPrivate *si) { SoundIoJack *sij = &si->backend_data.jack; SoundIo *soundio = &si->pub; if (!global_msg_callback_flag.test_and_set()) { if (soundio->jack_error_callback) jack_set_error_function(soundio->jack_error_callback); if (soundio->jack_info_callback) jack_set_info_function(soundio->jack_info_callback); global_msg_callback_flag.clear(); } sij->mutex = soundio_os_mutex_create(); if (!sij->mutex) { destroy_jack(si); return SoundIoErrorNoMem; } sij->cond = soundio_os_cond_create(); if (!sij->cond) { destroy_jack(si); return SoundIoErrorNoMem; } // We pass JackNoStartServer due to // https://github.com/jackaudio/jack2/issues/138 jack_status_t status; sij->client = jack_client_open(soundio->app_name, JackNoStartServer, &status); if (!sij->client) { destroy_jack(si); assert(!(status & JackInvalidOption)); if (status & JackShmFailure) return SoundIoErrorSystemResources; if (status & JackNoSuchClient) return SoundIoErrorNoSuchClient; return SoundIoErrorInitAudioBackend; } int err; if ((err = jack_set_buffer_size_callback(sij->client, buffer_size_callback, si))) { destroy_jack(si); return SoundIoErrorInitAudioBackend; } if ((err = jack_set_sample_rate_callback(sij->client, sample_rate_callback, si))) { destroy_jack(si); return SoundIoErrorInitAudioBackend; } if ((err = jack_set_port_registration_callback(sij->client, port_registration_callback, si))) { destroy_jack(si); return SoundIoErrorInitAudioBackend; } if ((err = jack_set_port_rename_callback(sij->client, port_rename_calllback, si))) { destroy_jack(si); return SoundIoErrorInitAudioBackend; } jack_on_shutdown(sij->client, shutdown_callback, si); sij->refresh_devices_flag.clear(); sij->period_size = jack_get_buffer_size(sij->client); sij->sample_rate = jack_get_sample_rate(sij->client); if ((err = jack_activate(sij->client))) { destroy_jack(si); return SoundIoErrorInitAudioBackend; } if ((err = refresh_devices(si))) { destroy_jack(si); return err; } si->destroy = destroy_jack; si->flush_events = flush_events_jack; si->wait_events = wait_events_jack; si->wakeup = wakeup_jack; si->force_device_scan = force_device_scan_jack; si->outstream_open = outstream_open_jack; si->outstream_destroy = outstream_destroy_jack; si->outstream_start = outstream_start_jack; si->outstream_begin_write = outstream_begin_write_jack; si->outstream_end_write = outstream_end_write_jack; si->outstream_clear_buffer = outstream_clear_buffer_jack; si->outstream_pause = outstream_pause_jack; si->outstream_get_latency = outstream_get_latency_jack; si->instream_open = instream_open_jack; si->instream_destroy = instream_destroy_jack; si->instream_start = instream_start_jack; si->instream_begin_read = instream_begin_read_jack; si->instream_end_read = instream_end_read_jack; si->instream_pause = instream_pause_jack; si->instream_get_latency = instream_get_latency_jack; return 0; }
int main(int argc, char **argv) { int jitter_plot[101]; int latency_plot[101]; int long_index = 0; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"message-size", 1, NULL, 'm'}, {"samples", 1, NULL, 's'}, {"timeout", 1, NULL, 't'} }; size_t name_arg_count; size_t name_size; char *option_string = "hm:s:t:"; int show_usage = 0; connections_established = 0; error_message = NULL; message_size = 3; program_name = argv[0]; remote_in_port = 0; remote_out_port = 0; samples = 1024; timeout = 5; for (;;) { signed char c = getopt_long(argc, argv, option_string, long_options, &long_index); switch (c) { case 'h': show_usage = 1; break; case 'm': message_size = parse_positive_number_arg(optarg, "message-size"); break; case 's': samples = parse_positive_number_arg(optarg, "samples"); break; case 't': timeout = parse_positive_number_arg(optarg, "timeout"); break; default: { char *s = "'- '"; s[2] = c; die(s, "invalid switch"); } case -1: if (show_usage) { output_usage(); exit(EXIT_SUCCESS); } goto parse_port_names; case 1: /* end of switch :) */ ; } } parse_port_names: name_arg_count = argc - optind; switch (name_arg_count) { case 2: target_in_port_name = argv[optind + 1]; target_out_port_name = argv[optind]; break; case 0: target_in_port_name = 0; target_out_port_name = 0; break; default: output_usage(); return EXIT_FAILURE; } name_size = jack_port_name_size(); alias1 = malloc(name_size * sizeof(char)); if (alias1 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto show_error; } alias2 = malloc(name_size * sizeof(char)); if (alias2 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_alias1; } latency_values = malloc(sizeof(jack_nframes_t) * samples); if (latency_values == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_alias2; } latency_time_values = malloc(sizeof(jack_time_t) * samples); if (latency_time_values == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_latency_values; } message_1 = malloc(message_size * sizeof(jack_midi_data_t)); if (message_1 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_latency_time_values; } message_2 = malloc(message_size * sizeof(jack_midi_data_t)); if (message_2 == NULL) { error_message = strerror(errno); error_source = "malloc"; goto free_message_1; } switch (message_size) { case 1: message_1[0] = 0xf6; message_2[0] = 0xfe; break; case 2: message_1[0] = 0xc0; message_1[1] = 0x00; message_2[0] = 0xd0; message_2[1] = 0x7f; break; case 3: message_1[0] = 0x80; message_1[1] = 0x00; message_1[2] = 0x00; message_2[0] = 0x90; message_2[1] = 0x7f; message_2[2] = 0x7f; break; default: message_1[0] = 0xf0; memset(message_1 + 1, 0, (message_size - 2) * sizeof(jack_midi_data_t)); message_1[message_size - 1] = 0xf7; message_2[0] = 0xf0; memset(message_2 + 1, 0x7f, (message_size - 2) * sizeof(jack_midi_data_t)); message_2[message_size - 1] = 0xf7; } client = jack_client_open(program_name, JackNullOption, NULL); if (client == NULL) { error_message = "failed to open JACK client"; error_source = "jack_client_open"; goto free_message_2; } in_port = jack_port_register(client, "in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); if (in_port == NULL) { error_message = "failed to register MIDI-in port"; error_source = "jack_port_register"; goto close_client; } out_port = jack_port_register(client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); if (out_port == NULL) { error_message = "failed to register MIDI-out port"; error_source = "jack_port_register"; goto unregister_in_port; } if (jack_set_process_callback(client, handle_process, NULL)) { error_message = "failed to set process callback"; error_source = "jack_set_process_callback"; goto unregister_out_port; } if (jack_set_xrun_callback(client, handle_xrun, NULL)) { error_message = "failed to set xrun callback"; error_source = "jack_set_xrun_callback"; goto unregister_out_port; } if (jack_set_port_connect_callback(client, handle_port_connection_change, NULL)) { error_message = "failed to set port connection callback"; error_source = "jack_set_port_connect_callback"; goto unregister_out_port; } jack_on_shutdown(client, handle_shutdown, NULL); jack_set_info_function(handle_info); process_state = 0; connect_semaphore = create_semaphore(0); if (connect_semaphore == NULL) { error_message = get_semaphore_error(); error_source = "create_semaphore"; goto unregister_out_port; } init_semaphore = create_semaphore(1); if (init_semaphore == NULL) { error_message = get_semaphore_error(); error_source = "create_semaphore"; goto destroy_connect_semaphore;; } process_semaphore = create_semaphore(2); if (process_semaphore == NULL) { error_message = get_semaphore_error(); error_source = "create_semaphore"; goto destroy_init_semaphore; } if (jack_activate(client)) { error_message = "could not activate client"; error_source = "jack_activate"; goto destroy_process_semaphore; } if (name_arg_count) { if (jack_connect(client, jack_port_name(out_port), target_out_port_name)) { error_message = "could not connect MIDI out port"; error_source = "jack_connect"; goto deactivate_client; } if (jack_connect(client, target_in_port_name, jack_port_name(in_port))) { error_message = "could not connect MIDI in port"; error_source = "jack_connect"; goto deactivate_client; } } if (! register_signal_handler(handle_signal)) { error_message = strerror(errno); error_source = "register_signal_handler"; goto deactivate_client; } printf("Waiting for connections ...\n"); if (wait_semaphore(connect_semaphore, 1) == -1) { error_message = get_semaphore_error(); error_source = "wait_semaphore"; goto deactivate_client; } if (connections_established) { printf("Waiting for test completion ...\n\n"); if (wait_semaphore(process_semaphore, 1) == -1) { error_message = get_semaphore_error(); error_source = "wait_semaphore"; goto deactivate_client; } } if (! register_signal_handler(SIG_DFL)) { error_message = strerror(errno); error_source = "register_signal_handler"; goto deactivate_client; } if (process_state == 2) { double average_latency = ((double) total_latency) / samples; double average_latency_time = total_latency_time / samples; size_t i; double latency_plot_offset = floor(((double) lowest_latency_time) / 100.0) / 10.0; double sample_rate = (double) jack_get_sample_rate(client); jack_nframes_t total_jitter = 0; jack_time_t total_jitter_time = 0; for (i = 0; i <= 100; i++) { jitter_plot[i] = 0; latency_plot[i] = 0; } for (i = 0; i < samples; i++) { double latency_time_value = (double) latency_time_values[i]; double latency_plot_time = (latency_time_value / 1000.0) - latency_plot_offset; double jitter_time = ABS(average_latency_time - latency_time_value); if (latency_plot_time >= 10.0) { (latency_plot[100])++; } else { (latency_plot[(int) (latency_plot_time * 10.0)])++; } if (jitter_time >= 10000.0) { (jitter_plot[100])++; } else { (jitter_plot[(int) (jitter_time / 100.0)])++; } total_jitter += ABS(average_latency - ((double) latency_values[i])); total_jitter_time += jitter_time; } printf("Reported out-port latency: %.2f-%.2f ms (%u-%u frames)\n" "Reported in-port latency: %.2f-%.2f ms (%u-%u frames)\n" "Average latency: %.2f ms (%.2f frames)\n" "Lowest latency: %.2f ms (%u frames)\n" "Highest latency: %.2f ms (%u frames)\n" "Peak MIDI jitter: %.2f ms (%u frames)\n" "Average MIDI jitter: %.2f ms (%.2f frames)\n", (out_latency_range.min / sample_rate) * 1000.0, (out_latency_range.max / sample_rate) * 1000.0, out_latency_range.min, out_latency_range.max, (in_latency_range.min / sample_rate) * 1000.0, (in_latency_range.max / sample_rate) * 1000.0, in_latency_range.min, in_latency_range.max, average_latency_time / 1000.0, average_latency, lowest_latency_time / 1000.0, lowest_latency, highest_latency_time / 1000.0, highest_latency, (highest_latency_time - lowest_latency_time) / 1000.0, highest_latency - lowest_latency, (total_jitter_time / 1000.0) / samples, ((double) total_jitter) / samples); printf("\nJitter Plot:\n"); for (i = 0; i < 100; i++) { if (jitter_plot[i]) { printf("%.1f - %.1f ms: %d\n", ((float) i) / 10.0, ((float) (i + 1)) / 10.0, jitter_plot[i]); } } if (jitter_plot[100]) { printf(" > 10 ms: %d\n", jitter_plot[100]); } printf("\nLatency Plot:\n"); for (i = 0; i < 100; i++) { if (latency_plot[i]) { printf("%.1f - %.1f ms: %d\n", latency_plot_offset + (((float) i) / 10.0), latency_plot_offset + (((float) (i + 1)) / 10.0), latency_plot[i]); } } if (latency_plot[100]) { printf(" > %.1f ms: %d\n", latency_plot_offset + 10.0, latency_plot[100]); } } deactivate_client: jack_deactivate(client); printf("\nMessages sent: %d\nMessages received: %d\n", messages_sent, messages_received); if (unexpected_messages) { printf("Unexpected messages received: %d\n", unexpected_messages); } if (xrun_count) { printf("Xruns: %d\n", xrun_count); } destroy_process_semaphore: destroy_semaphore(process_semaphore, 2); destroy_init_semaphore: destroy_semaphore(init_semaphore, 1); destroy_connect_semaphore: destroy_semaphore(connect_semaphore, 0); unregister_out_port: jack_port_unregister(client, out_port); unregister_in_port: jack_port_unregister(client, in_port); close_client: jack_client_close(client); free_message_2: free(message_2); free_message_1: free(message_1); free_latency_time_values: free(latency_time_values); free_latency_values: free(latency_values); free_alias2: free(alias2); free_alias1: free(alias1); if (error_message != NULL) { show_error: output_error(error_source, error_message); exit(EXIT_FAILURE); } return EXIT_SUCCESS; }
mfp_context * mfp_jack_startup(char * client_name, int num_inputs, int num_outputs) { mfp_context * ctxt; jack_status_t status; jack_port_t * port; int i; char namebuf[16]; ctxt = mfp_context_new(CTYPE_JACK); if ((ctxt->info.jack->client = jack_client_open(client_name, JackNullOption, &status, NULL)) == 0) { fprintf (stderr, "jack_client_open() failed."); return NULL; } /* callbacks */ jack_set_process_callback(ctxt->info.jack->client, process_cb, ctxt); jack_set_graph_order_callback(ctxt->info.jack->client, reorder_cb, ctxt); /* no info logging to console */ jack_set_info_function(info_cb); jack_set_error_function(info_cb); /* create application input and output ports */ if (num_inputs > 0) { ctxt->info.jack->input_ports = g_array_new(TRUE, TRUE, sizeof(jack_port_t *)); for(i=0; i<num_inputs; i++) { snprintf(namebuf, 16, "in_%d", i); port = jack_port_register (ctxt->info.jack->client, namebuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, i); g_array_append_val(ctxt->info.jack->input_ports, port); } } if (num_outputs > 0) { ctxt->info.jack->output_ports = g_array_new(TRUE, TRUE, sizeof(jack_port_t *)); for(i=0; i<num_outputs; i++) { snprintf(namebuf, 16, "out_%d", i); port = jack_port_register (ctxt->info.jack->client, namebuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, i); g_array_append_val(ctxt->info.jack->output_ports, port); } } /* find out sample rate */ ctxt->samplerate = jack_get_sample_rate(ctxt->info.jack->client); ctxt->blocksize = jack_get_buffer_size(ctxt->info.jack->client); mfp_in_latency = 3000.0 * ctxt->blocksize / ctxt->samplerate; mfp_out_latency = 3000.0 * ctxt->blocksize / ctxt->samplerate; printf("jack_startup: samplerate=%d, blocksize=%d, in_latency=%.1f, out_latency = %.1f\n", ctxt->samplerate, ctxt->blocksize, mfp_in_latency, mfp_out_latency); /* tell the JACK server that we are ready to roll */ if (jack_activate (ctxt->info.jack->client)) { fprintf (stderr, "cannot activate client"); return NULL; } else { ctxt->activated = 1; } return ctxt; }
int run(size_t port_count, const char** ports, const char* client_name, const char* file_path, jackoff_format_t* format, int bitrate, size_t channels, float buffer_duration, time_t recording_duration, jack_options_t options) { jackoff_client_t* client; jackoff_encoder_t* encoder; jackoff_session_t* session; time_t stop_time = (time_t) 0; size_t i; long result; jack_set_error_function(handle_jack_error); jack_set_info_function(handle_jack_info); if (recording_duration) { stop_time = time(NULL) + recording_duration; } client = jackoff_create_client(client_name, options, channels, buffer_duration); if (jackoff_activate_client(client) != 0) { jackoff_destroy_client(client); jackoff_error("Failed to activate JACK client."); } signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGHUP, handle_signal); if (port_count == 0) { jackoff_auto_connect_client_ports(client); } else { for (i = 0; i < port_count; i++) { jackoff_connect_client_port(client, i, ports[i]); } } encoder = jackoff_create_encoder(client, format, bitrate); if (!encoder) { jackoff_destroy_client(client); return 1; } session = jackoff_open_session(client, encoder, file_path); if (!session) { jackoff_destroy_encoder(encoder); jackoff_destroy_client(client); return 2; } running = 1; jackoff_info("Recording."); while (running && (stop_time == 0 || time(NULL) < stop_time)) { if (client->ring_buffer_overflowed) { jackoff_warn("Ring buffer overflow; some audio was not written."); client->ring_buffer_overflowed = 0; } if (!client->status) { break; } result = jackoff_write_session(session); if (result == 0) { // Sleep for 1/4th the ring buffer duration. jackoff_debug("Sleeping for %.04fms.", (buffer_duration / 4)); usleep(1000000 * (buffer_duration / 4)); } else if (result == -1) { jackoff_close_session(session); jackoff_destroy_encoder(encoder); jackoff_destroy_client(client); jackoff_error("Encoding error. Shutting down."); return 3; } } jackoff_close_session(session); jackoff_destroy_encoder(encoder); jackoff_destroy_client(client); return 0; }