| @@ -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 | |||
| @@ -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); | |||
| /*@}*/ | |||
| @@ -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. | |||
| @@ -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) { | |||
| @@ -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 | |||
| @@ -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) | |||
| { | |||
| @@ -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 */ | |||