void JACKInput::PortConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) { // This callback is called from the notification thread (not the realtime processing thread), so sadly the timing can never be fully accurate. // To make things worse, we're not allowed to connect/disconnect ports from this thread, so we have to send a command to the input thread instead. JACKInput *input = (JACKInput*) arg; if(input->m_connect_system_playback) { jack_port_t *port_a = jack_port_by_id(input->m_jack_client, a); if(port_a == NULL) return; jack_port_t *port_b = jack_port_by_id(input->m_jack_client, b); if(port_b == NULL) return; const char *port_a_name = jack_port_name(port_a); const char *port_b_name = jack_port_name(port_b); for(unsigned int i = 0; i < input->m_channels; ++i) { std::string playback_name = "system:playback_" + NumToString(i + 1); if(port_b_name == playback_name) { std::string port_name_full = std::string(jack_get_client_name(input->m_jack_client)) + ":in_" + NumToString(i + 1); SharedLock lock(&input->m_shared_data); ConnectCommand cmd; cmd.m_connect = connect; cmd.m_source = port_a_name; cmd.m_destination = port_name_full; lock->m_connect_commands.push_back(cmd); } } } }
void JackProxyDriver::connect_callback(jack_port_id_t a, jack_port_id_t b, int connect) { jack_port_t* port; int i; // skip port if not our own port = jack_port_by_id(fClient, a); if (!jack_port_is_mine(fClient, port)) { port = jack_port_by_id(fClient, b); if (!jack_port_is_mine(fClient, port)) { return; } } for (i = 0; i < fCaptureChannels; i++) { if (fUpstreamPlaybackPorts[i] == port) { fUpstreamPlaybackPortConnected[i] = connect; } } for (i = 0; i < fPlaybackChannels; i++) { if (fUpstreamCapturePorts[i] == port) { fUpstreamCapturePortConnected[i] = connect; } } }
/* handle jack port connection change */ void Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect ) { if ( _deleting ) return; /* this is called from JACK non-RT thread... */ if ( jack_port_is_mine( client()->jack_client(), jack_port_by_id( client()->jack_client(), a ) ) || jack_port_is_mine( client()->jack_client(), jack_port_by_id( client()->jack_client(), b ) )) { Fl::awake( Chain::update_connection_status, this ); } }
static void handle_port_connection_change(jack_port_id_t port_id_1, jack_port_id_t port_id_2, int connected, void *arg) { jack_port_t *port_1; jack_port_t *port_2; if ((remote_in_port != NULL) && (remote_out_port != NULL)) { return; } port_1 = jack_port_by_id(client, port_id_1); port_2 = jack_port_by_id(client, port_id_2); /* The 'update_connection' call is not RT-safe. It calls 'jack_port_get_connections' and 'jack_free'. This might be a problem with JACK 1, as this callback runs in the process thread in JACK 1. */ if (port_1 == in_port) { remote_in_port = update_connection(port_2, connected, in_port, remote_in_port, target_in_port_name); } else if (port_2 == in_port) { remote_in_port = update_connection(port_1, connected, in_port, remote_in_port, target_in_port_name); } else if (port_1 == out_port) { remote_out_port = update_connection(port_2, connected, out_port, remote_out_port, target_out_port_name); } else if (port_2 == out_port) { remote_out_port = update_connection(port_1, connected, out_port, remote_out_port, target_out_port_name); } if ((remote_in_port != NULL) && (remote_out_port != NULL)) { connections_established = 1; if (! signal_semaphore(connect_semaphore)) { /* Sigh ... */ die("post_semaphore", get_semaphore_error()); } if (! signal_semaphore(init_semaphore)) { /* Sigh ... */ die("post_semaphore", get_semaphore_error()); } } }
static void port_connect_cb(jack_port_id_t port, int registered, void *arg) { struct cbox_jack_io_impl *jii = arg; if (registered) { jack_port_t *portobj = jack_port_by_id(jii->client, port); jack_ringbuffer_write(jii->rb_autoconnect, (char *)&portobj, sizeof(portobj)); } }
static gboolean cbox_jack_io_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)ct->user_data; struct cbox_io *io = jii->ioi.pio; gboolean handled = FALSE; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return cbox_execute_on(fb, NULL, "/client_type", "s", error, "JACK") && cbox_execute_on(fb, NULL, "/client_name", "s", error, jii->client_name) && cbox_execute_on(fb, NULL, "/external_tempo", "i", error, jii->external_tempo) && cbox_io_process_cmd(io, fb, cmd, error, &handled); } else if (!strcmp(cmd->command, "/rename_midi_port") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *new_name = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (!midiout && !midiin) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port : ((struct cbox_jack_midi_input *)midiin)->port; char **pname = midiout ? &midiout->name : &midiin->name; if (0 != jack_port_rename_fn(jii->client, port, new_name)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set port name to '%s'", new_name); return FALSE; } g_free(*pname); *pname = g_strdup(new_name); return TRUE; } else if (!strcmp(cmd->command, "/rename_audio_port") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *new_name = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid); if (!audioout) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } if (0 != jack_port_rename_fn(jii->client, ((struct cbox_jack_audio_output *)audioout)->port, new_name)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set port name to '%s'", new_name); return FALSE; } g_free(audioout->name); audioout->name = g_strdup(new_name); return TRUE; } else if (!strcmp(cmd->command, "/autoconnect") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *spec = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (midiout) { cbox_jack_midi_output_set_autoconnect((struct cbox_jack_midi_output *)midiout, spec); return TRUE; } struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); if (midiin) { cbox_jack_midi_input_set_autoconnect((struct cbox_jack_midi_input *)midiin, spec); return TRUE; } struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid); if (audioout) { cbox_jack_audio_output_set_autoconnect((struct cbox_jack_audio_output *)audioout, spec); return TRUE; } g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } else if (!strcmp(cmd->command, "/disconnect_audio_output") && !strcmp(cmd->arg_types, "s")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid); if (!audioout) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_disconnect(jii->client, ((struct cbox_jack_audio_output *)audioout)->port); return TRUE; } else if (!strncmp(cmd->command, "/disconnect_midi_", 17) && !strcmp(cmd->arg_types, "s")) { bool is_both = !strcmp(cmd->command + 17, "port"); bool is_in = is_both || !strcmp(cmd->command + 17, "input"); bool is_out = is_both || !strcmp(cmd->command + 17, "output"); if (is_in || is_out) { const char *uuidstr = CBOX_ARG_S(cmd, 0); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_input *midiin = is_in ? cbox_io_get_midi_input(io, NULL, &uuid) : NULL; struct cbox_midi_output *midiout = is_out ? cbox_io_get_midi_output(io, NULL, &uuid) : NULL; if (!midiout && !midiin) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port : ((struct cbox_jack_midi_input *)midiin)->port; jack_port_disconnect(jii->client, port); return TRUE; } } if (!strcmp(cmd->command, "/port_connect") && !strcmp(cmd->arg_types, "ss")) { const char *port_from = CBOX_ARG_S(cmd, 0); const char *port_to = CBOX_ARG_S(cmd, 1); int res = jack_connect(jii->client, port_from, port_to); if (res == EEXIST) res = 0; if (res) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot connect port '%s' to '%s'", port_from, port_to); return res == 0; } else if (!strcmp(cmd->command, "/port_disconnect") && !strcmp(cmd->arg_types, "ss")) { const char *port_from = CBOX_ARG_S(cmd, 0); const char *port_to = CBOX_ARG_S(cmd, 1); int res = jack_disconnect(jii->client, port_from, port_to); if (res) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot disconnect port '%s' from '%s'", port_from, port_to); return res == 0; } else if (!strcmp(cmd->command, "/get_connected_ports") && !strcmp(cmd->arg_types, "s")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; const char *name = CBOX_ARG_S(cmd, 0); jack_port_t *port = NULL; if (!strchr(name, ':')) { // try UUID struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, name, error)) return FALSE; struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (midiout) port = ((struct cbox_jack_midi_output *)midiout)->port; else { struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); if (midiin) port = ((struct cbox_jack_midi_input *)midiin)->port; } } else port = jack_port_by_name(jii->client, name); if (!port) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", name); return FALSE; } const char** ports = jack_port_get_all_connections(jii->client, port); for (int i = 0; ports && ports[i]; i++) { if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i])) return FALSE; } jack_free(ports); return TRUE; } else if (!strcmp(cmd->command, "/get_ports") && !strcmp(cmd->arg_types, "ssi")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; const char *mask = CBOX_ARG_S(cmd, 0); const char *type = CBOX_ARG_S(cmd, 1); uint32_t flags = CBOX_ARG_I(cmd, 2); const char** ports = jack_get_ports(jii->client, mask, type, flags); for (int i = 0; ports && ports[i]; i++) { if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i])) return FALSE; } jack_free(ports); return TRUE; } else if (!strcmp(cmd->command, "/external_tempo") && !strcmp(cmd->arg_types, "i")) { jii->external_tempo = CBOX_ARG_I(cmd, 0); return TRUE; } //Metadata else if (!strcmp(cmd->command, "/set_property") && !strcmp(cmd->arg_types, "ssss")) //parameters: "client:port", key, value, type according to jack_property_t (empty or NULL for string) { const char *name = CBOX_ARG_S(cmd, 0); const char *key = CBOX_ARG_S(cmd, 1); const char *value = CBOX_ARG_S(cmd, 2); const char *type = CBOX_ARG_S(cmd, 3); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; if (jack_set_property(jii->client, subject, key, value, type)) // 0 on success { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Set property key:'%s' value: '%s' to port '%s' was not successful", key, value, name); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/get_property") && !strcmp(cmd->arg_types, "ss")) //parameters: "client:port", key //returns python key, value and type as strings { const char *name = CBOX_ARG_S(cmd, 0); const char *key = CBOX_ARG_S(cmd, 1); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; char* value = NULL; char* type = NULL; if (jack_get_property(subject, key, &value, &type)) // 0 on success, -1 if the subject has no key property. { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' does not have key '%s'", name, key); return FALSE; } char* returntype; //We need to call jack_free on type in any case so it can't be our own data. if (type == NULL) returntype = ""; else returntype = type; if (!cbox_execute_on(fb, NULL, "/value", "ss", error, value, returntype)) //send return values to Python. return FALSE; jack_free(value); jack_free(type); return TRUE; } else if (!strcmp(cmd->command, "/get_properties") && !strcmp(cmd->arg_types, "s")) //parameters: "client:port" { const char *name = CBOX_ARG_S(cmd, 0); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; jack_description_t desc; if (!jack_get_properties(subject, &desc)) // 0 on success, -1 if no subject with any properties exists. { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' with uuid '%lli' does not have any properties", name, (long long)subject); return FALSE; } const char *returntype; for (uint32_t i = 0; i<desc.property_cnt ; i++) { if (desc.properties[i].type == NULL) returntype = ""; else returntype = desc.properties[i].type; if (!cbox_execute_on(fb, NULL, "/properties", "sss", error, desc.properties[i].key, desc.properties[i].data, returntype)) return FALSE; } jack_free_description(&desc, 0); //if non-zero desc will also be passed to free() return TRUE; } else if (!strcmp(cmd->command, "/get_all_properties") && !strcmp(cmd->arg_types, "")) { jack_description_t *descs; int counter; counter = jack_get_all_properties(&descs); const char *returntype; for (int j = 0; j < counter; j++) { jack_description_t *one_desc = &descs[j]; for (uint32_t i = 0; i < one_desc->property_cnt ; i++) { if (one_desc->properties[i].type == NULL) returntype = ""; else returntype = one_desc->properties[i].type; /* index = jack_uuid_to_index(one_desc->subject) portid = jack_port_by_id(jii->client, index); portname = jack_port_name(port); */ if (!cbox_execute_on(fb, NULL, "/all_properties", "ssss", error, jack_port_name(jack_port_by_id(jii->client, jack_uuid_to_index(one_desc->subject))), one_desc->properties[i].key, one_desc->properties[i].data, returntype)) return FALSE; } jack_free_description(one_desc, 0); //if non-zero one_desc will also be passed to free() } jack_free(descs); return TRUE; } else if (!strcmp(cmd->command, "/remove_property") && !strcmp(cmd->arg_types, "ss")) { const char *name = CBOX_ARG_S(cmd, 0); const char *key = CBOX_ARG_S(cmd, 1); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; if (jack_remove_property(jii->client, subject, key)) // 0 on success, -1 otherwise { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Could not remove port '%s' key '%s'", name, key); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/remove_properties") && !strcmp(cmd->arg_types, "s")) { const char *name = CBOX_ARG_S(cmd, 0); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; if (jack_remove_properties(jii->client, subject) == -1) // number of removed properties returned, -1 on error { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Could not remove properties of port '%s'", name); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/remove_all_properties") && !strcmp(cmd->arg_types, "")) { if (jack_remove_all_properties(jii->client)) // 0 on success, -1 otherwise { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Remove all JACK properties was not successful"); return FALSE; } return TRUE; } else { gboolean result = cbox_io_process_cmd(io, fb, cmd, error, &handled); if (!handled) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types); return result; } }