diff --git a/jack/internal.h b/jack/internal.h index b51ef44..249ba47 100644 --- a/jack/internal.h +++ b/jack/internal.h @@ -217,7 +217,8 @@ typedef enum { StartFreewheel, StopFreewheel, ClientRegistered, - ClientUnregistered + ClientUnregistered, + SaveSession } JackEventType; typedef struct { @@ -252,9 +253,11 @@ typedef enum { 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_nframes_t nframes; /* w: engine r: 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 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 */ @@ -292,6 +295,7 @@ typedef volatile struct { volatile uint8_t freewheel_cb_cbset; volatile uint8_t client_register_cbset; volatile uint8_t thread_cb_cbset; + volatile uint8_t session_cbset; } POST_PACKED_STRUCTURE jack_client_control_t; @@ -370,7 +374,8 @@ typedef enum { IntClientName = 21, IntClientUnload = 22, RecomputeTotalLatencies = 23, - RecomputeTotalLatency = 24 + RecomputeTotalLatency = 24, + SessionNotify = 25 } RequestType; struct _jack_request { @@ -390,6 +395,10 @@ struct _jack_request { 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_t type; + } POST_PACKED_STRUCTURE session; struct { int32_t nports; const char **ports; /* this is only exposed to internal clients, so there diff --git a/jack/jack.h b/jack/jack.h index b76cdc1..96c921d 100644 --- a/jack/jack.h +++ b/jack/jack.h @@ -412,6 +412,16 @@ int jack_set_graph_order_callback (jack_client_t *, */ int jack_set_xrun_callback (jack_client_t *, JackXRunCallback xrun_callback, void *arg); +/** + * Tell the JACK server to call @a save_callback the session handler wants + * to save. + * + * @return 0 on success, otherwise a non-zero error code + */ + +int jack_set_session_callback(jack_client_t *client, + JackSessionCallback session_save_callback, + void *arg); /*@}*/ diff --git a/jack/types.h b/jack/types.h index f3afe9e..b9cdd36 100644 --- a/jack/types.h +++ b/jack/types.h @@ -214,6 +214,13 @@ enum JackStatus { */ typedef enum JackStatus jack_status_t; +enum JackSessionEvent { + JackSessionSave = 1, + JackSessionQuit = 2 +}; + +typedef enum JackSessionEvent jack_session_event_t; + /** * Prototype for the client supplied function that is called * by the engine anytime there is work to be done. @@ -364,6 +371,9 @@ typedef void (*JackShutdownCallback)(void *arg); */ typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg); + +typedef char *(*JackSessionCallback)(jack_session_event_t code, const char* session_dir, const char* prefix, void *arg); + /** * Used for the type argument of jack_port_register() for default * audio and midi ports. diff --git a/jackd/clientengine.c b/jackd/clientengine.c index 4e245ca..300a365 100644 --- a/jackd/clientengine.c +++ b/jackd/clientengine.c @@ -538,6 +538,7 @@ jack_setup_client_control (jack_engine_t *engine, int fd, 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) { diff --git a/jackd/engine.c b/jackd/engine.c index 70f61a6..75ea340 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -133,6 +133,7 @@ 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 void jack_engine_signal_problems (jack_engine_t* engine); +static int jack_session_notify (jack_engine_t *engine, jack_session_event_t type, const char *path ); static inline int jack_rolling_interval (jack_time_t period_usecs) @@ -1339,6 +1340,12 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) req->status = 0; break; + case SessionNotify: + jack_lock_graph (engine); + jack_session_notify (engine, req->x.session.type, req->x.session.path); + jack_unlock_graph (engine); + req->status = 0; + break; default: /* some requests are handled entirely on the client * side, by adjusting the shared memory area(s) */ @@ -2423,6 +2430,34 @@ jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event) jack_unlock_graph (engine); } +static int +jack_session_notify (jack_engine_t *engine, jack_session_event_t type, const char *path ) +{ + JSList *node; + jack_event_t event; + + int retval = 0; + int reply; + + event.type = SessionNotify; + snprintf (event.x.name, sizeof (event.x.name), "%s", path ); + event.x.n = type; + + /* GRAPH MUST BE LOCKED : see callers of jack_send_connection_notification() + */ + + 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) { + + reply = jack_deliver_event (engine, client, &event); + if( reply >= 0 ) + retval |= reply; + } + } + return retval; +} + 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) { @@ -2453,7 +2488,7 @@ static int jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event) { - char status; + char status=-1; /* caller must hold the graph lock */ @@ -2603,7 +2638,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, client->event_fd, pfd[0].revents, poll_timeout); - status = 1; + status = -2; #ifdef __linux } #endif @@ -2628,7 +2663,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, event->type); } - if (status) { + if (status<0) { client->error += JACK_ERROR_WITH_SOCKETS; jack_engine_signal_problems (engine); } @@ -2636,7 +2671,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, } DEBUG ("event delivered"); - return 0; + return status; } int diff --git a/libjack/client.c b/libjack/client.c index 3589896..5793857 100644 --- a/libjack/client.c +++ b/libjack/client.c @@ -490,6 +490,27 @@ jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event) return 0; } +int +jack_client_handle_session_callback (jack_client_t *client, jack_event_t *event) +{ + int retval = 0; + char *cb_ret = NULL; + char prefix[32]; + snprintf( prefix, sizeof(prefix), "%d", client->control->uid ); + + if (client->control->session_cbset) { + cb_ret = client->session_cb ( event->x.n, event->x.name, prefix, + client->session_cb_arg); + if(cb_ret) { + retval = 1; + snprintf( (char *)client->control->session_command, sizeof(client->control->session_command), + "%s", cb_ret ); + free( cb_ret ); + } + } + + return retval; +} #if JACK_USE_MACH_THREADS static int @@ -1277,6 +1298,17 @@ jack_set_freewheel (jack_client_t* client, int onoff) return jack_client_deliver_request (client, &request); } +int +jack_session_notify (jack_client_t* client, jack_session_event_t code, const char *path ) +{ + jack_request_t request; + + request.type = SaveSession; + snprintf( request.x.session.path, sizeof( request.x.session.path ), "%s", path ); + request.x.session.type = code; + return jack_client_deliver_request (client, &request); +} + void jack_start_freewheel (jack_client_t* client) { @@ -1448,6 +1480,9 @@ jack_client_process_events (jack_client_t* client) case StopFreewheel: jack_stop_freewheel (client); break; + case SaveSession: + status = jack_client_handle_session_callback (client, &event ); + break; } DEBUG ("client has dealt with the event, writing " @@ -2417,6 +2452,19 @@ jack_set_process_thread(jack_client_t* client, JackThreadCallback callback, void return 0; } +int +jack_set_session_callback(jack_client_t* client, JackSessionCallback callback, void *arg) +{ + if (client->control->active) { + jack_error ("You cannot set callbacks on an active client."); + return -1; + } + + client->session_cb_arg = arg; + client->session_cb = callback; + client->control->session_cbset = (callback != NULL); + return 0; +} int jack_get_process_done_fd (jack_client_t *client) { diff --git a/libjack/local.h b/libjack/local.h index ef03235..302541e 100644 --- a/libjack/local.h +++ b/libjack/local.h @@ -70,8 +70,10 @@ struct _jack_client { void *freewheel_arg; JackClientRegistrationCallback client_register; void *client_register_arg; - JackThreadCallback thread_cb; + JackThreadCallback thread_cb; void *thread_cb_arg; + JackSessionCallback session_cb; + void *session_cb_arg; /* external clients: set by libjack * internal clients: set by engine */