git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@4181 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
| @@ -27,16 +27,75 @@ Mario Lang | |||
| Arnold Krille | |||
| Jan Engelhardt | |||
| Adrian Knoth | |||
| David Garcia Garzon | |||
| David Garcia Garzon | |||
| Valerio Pilo | |||
| --------------------------- | |||
| Jackdmp changes log | |||
| --------------------------- | |||
| 2011-03-11 Stephane Letz <letz@grame.fr> | |||
| * Correct JackNetMaster::SetBufferSize. | |||
| 2011-03-10 Stephane Letz <letz@grame.fr> | |||
| * Latency callback must always be activated. | |||
| * Correct TopologicalSort. | |||
| * Add jack_midi_dump client. | |||
| * Synchronize netjack1 with JACK1 version. | |||
| * Synchronize jack_connect/jack_disconnect with JACK1 version. | |||
| 2011-03-09 Stephane Letz <letz@grame.fr> | |||
| * jack_client_has_session_callback implementation. | |||
| * Fix jdelay for new latency API. | |||
| * Check requested buffer size and limit to 1..8192 - avoids wierd behaviour caused by jack_bufsize foobar. | |||
| * jack_port_type_get_buffer_size implementation. | |||
| * Stop using alloca and allocate buffer on the heap for alsa_io. | |||
| * Rename jdelay to jack_iodelay as per Fons' request. | |||
| * Call buffer size callback in activate (actually this is done on client side in the RT thread Init method). | |||
| * JackEngine::ComputeTotalLatencies in progress. | |||
| 2011-03-08 Stephane Letz <letz@grame.fr> | |||
| * Use of latency range in all backends. | |||
| * ComputeTotalLatencies now a client/server call. | |||
| * Add latent test client for latency API. | |||
| * Also print playback and capture latency in jack_lsp. | |||
| 2011-03-04 Stephane Letz <letz@grame.fr> | |||
| * Revert r4119 (RT notification in the server). JackAudioDriver::ProcessSync now skip backend write in case of graph process failure. | |||
| * Fix incorrect error codes in alsa/usx2y.c and alsa/JackAlsaDriver.cpp. | |||
| * Synchronize public headers with JACK1. Update OSX project. | |||
| * New latency API implementation (in progress). | |||
| 2011-02-09 Stephane Letz <letz@grame.fr> | |||
| * Remove JackPortIsActive flag. | |||
| 2011-02-07 Stephane Letz <letz@grame.fr> | |||
| * Valerio Pilo second CAS for ARMv7 patch. | |||
| 2011-02-03 Stephane Letz <letz@grame.fr> | |||
| * Valerio Pilo CAS for ARMv7 patch. | |||
| 2011-01-11 Stephane Letz <letz@grame.fr> | |||
| * Adrian Knoth jack_lsp patch. | |||
| 2010-11-17 Stephane Letz <letz@grame.fr> | |||
| * ALSA backend : suspend/resume handling (jack1 r4075). | |||
| * Correct dummy driver. | |||
| 2010-11-05 Stephane Letz <letz@grame.fr> | |||
| * In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. | |||
| * Correct symbols export in backends. | |||
| * Correct symbols export in backends on OSX. | |||
| 2010-11-03 Stephane Letz <letz@grame.fr> | |||
| @@ -41,7 +41,7 @@ extern "C" | |||
| { | |||
| #endif | |||
| typedef void (*print_function)(const char *); | |||
| typedef void (*print_function)(const char*); | |||
| typedef void *(*thread_routine)(void*); | |||
| EXPORT | |||
| @@ -53,198 +53,219 @@ extern "C" | |||
| int *proto_ptr); | |||
| EXPORT | |||
| const char * | |||
| const char* | |||
| jack_get_version_string(); | |||
| jack_client_t * jack_client_new_aux (const char *client_name, | |||
| jack_client_t * jack_client_new_aux(const char* client_name, | |||
| jack_options_t options, | |||
| jack_status_t *status); | |||
| EXPORT jack_client_t * jack_client_open (const char *client_name, | |||
| EXPORT jack_client_t * jack_client_open(const char* client_name, | |||
| jack_options_t options, | |||
| jack_status_t *status, ...); | |||
| EXPORT jack_client_t * jack_client_new (const char *client_name); | |||
| EXPORT int jack_client_name_size (void); | |||
| EXPORT char* jack_get_client_name (jack_client_t *client); | |||
| EXPORT int jack_internal_client_new (const char *client_name, | |||
| const char *load_name, | |||
| const char *load_init); | |||
| EXPORT void jack_internal_client_close (const char *client_name); | |||
| EXPORT int jack_is_realtime (jack_client_t *client); | |||
| EXPORT void jack_on_shutdown (jack_client_t *client, | |||
| EXPORT jack_client_t * jack_client_new(const char* client_name); | |||
| EXPORT int jack_client_name_size(void); | |||
| EXPORT char* jack_get_client_name(jack_client_t *client); | |||
| EXPORT int jack_internal_client_new(const char* client_name, | |||
| const char* load_name, | |||
| const char* load_init); | |||
| EXPORT void jack_internal_client_close(const char* client_name); | |||
| EXPORT int jack_is_realtime(jack_client_t *client); | |||
| EXPORT void jack_on_shutdown(jack_client_t *client, | |||
| JackShutdownCallback shutdown_callback, void *arg); | |||
| EXPORT void jack_on_info_shutdown (jack_client_t *client, | |||
| EXPORT void jack_on_info_shutdown(jack_client_t *client, | |||
| JackInfoShutdownCallback shutdown_callback, void *arg); | |||
| EXPORT int jack_set_process_callback (jack_client_t *client, | |||
| EXPORT int jack_set_process_callback(jack_client_t *client, | |||
| JackProcessCallback process_callback, | |||
| void *arg); | |||
| EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status); | |||
| // new | |||
| EXPORT jack_nframes_t jack_cycle_wait (jack_client_t*); | |||
| EXPORT void jack_cycle_signal (jack_client_t*, int status); | |||
| EXPORT jack_nframes_t jack_cycle_wait(jack_client_t*); | |||
| EXPORT void jack_cycle_signal(jack_client_t*, int status); | |||
| EXPORT int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg); | |||
| EXPORT int jack_set_thread_init_callback (jack_client_t *client, | |||
| EXPORT int jack_set_thread_init_callback(jack_client_t *client, | |||
| JackThreadInitCallback thread_init_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_freewheel_callback (jack_client_t *client, | |||
| EXPORT int jack_set_freewheel_callback(jack_client_t *client, | |||
| JackFreewheelCallback freewheel_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_freewheel(jack_client_t* client, int onoff); | |||
| EXPORT int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes); | |||
| EXPORT int jack_set_buffer_size_callback (jack_client_t *client, | |||
| EXPORT int jack_set_buffer_size(jack_client_t *client, jack_nframes_t nframes); | |||
| EXPORT int jack_set_buffer_size_callback(jack_client_t *client, | |||
| JackBufferSizeCallback bufsize_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_sample_rate_callback (jack_client_t *client, | |||
| EXPORT int jack_set_sample_rate_callback(jack_client_t *client, | |||
| JackSampleRateCallback srate_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_client_registration_callback (jack_client_t *, | |||
| EXPORT int jack_set_client_registration_callback(jack_client_t *, | |||
| JackClientRegistrationCallback | |||
| registration_callback, void *arg); | |||
| EXPORT int jack_set_port_registration_callback (jack_client_t *, | |||
| EXPORT int jack_set_port_registration_callback(jack_client_t *, | |||
| JackPortRegistrationCallback | |||
| registration_callback, void *arg); | |||
| EXPORT int jack_set_port_connect_callback (jack_client_t *, | |||
| EXPORT int jack_set_port_connect_callback(jack_client_t *, | |||
| JackPortConnectCallback | |||
| connect_callback, void *arg); | |||
| EXPORT int jack_set_port_rename_callback (jack_client_t *, | |||
| EXPORT int jack_set_port_rename_callback(jack_client_t *, | |||
| JackPortRenameCallback | |||
| rename_callback, void *arg); | |||
| EXPORT int jack_set_graph_order_callback (jack_client_t *, | |||
| EXPORT int jack_set_graph_order_callback(jack_client_t *, | |||
| JackGraphOrderCallback graph_callback, | |||
| void *); | |||
| EXPORT int jack_set_xrun_callback (jack_client_t *, | |||
| EXPORT int jack_set_xrun_callback(jack_client_t *, | |||
| JackXRunCallback xrun_callback, void *arg); | |||
| EXPORT int jack_activate (jack_client_t *client); | |||
| EXPORT int jack_deactivate (jack_client_t *client); | |||
| EXPORT jack_port_t * jack_port_register (jack_client_t *client, | |||
| const char *port_name, | |||
| const char *port_type, | |||
| EXPORT int jack_set_latency_callback(jack_client_t *client, | |||
| JackLatencyCallback callback, void *arg); | |||
| EXPORT int jack_activate(jack_client_t *client); | |||
| EXPORT int jack_deactivate(jack_client_t *client); | |||
| EXPORT jack_port_t * jack_port_register(jack_client_t *client, | |||
| const char* port_name, | |||
| const char* port_type, | |||
| unsigned long flags, | |||
| unsigned long buffer_size); | |||
| EXPORT int jack_port_unregister (jack_client_t *, jack_port_t *); | |||
| EXPORT void * jack_port_get_buffer (jack_port_t *, jack_nframes_t); | |||
| EXPORT const char * jack_port_name (const jack_port_t *port); | |||
| EXPORT const char * jack_port_short_name (const jack_port_t *port); | |||
| EXPORT int jack_port_flags (const jack_port_t *port); | |||
| EXPORT const char * jack_port_type (const jack_port_t *port); | |||
| EXPORT jack_port_type_id_t jack_port_type_id (const jack_port_t *port); | |||
| EXPORT int jack_port_is_mine (const jack_client_t *, const jack_port_t *port); | |||
| EXPORT int jack_port_connected (const jack_port_t *port); | |||
| EXPORT int jack_port_connected_to (const jack_port_t *port, | |||
| const char *port_name); | |||
| EXPORT const char ** jack_port_get_connections (const jack_port_t *port); | |||
| EXPORT const char ** jack_port_get_all_connections (const jack_client_t *client, | |||
| EXPORT int jack_port_unregister(jack_client_t *, jack_port_t *); | |||
| EXPORT void * jack_port_get_buffer(jack_port_t *, jack_nframes_t); | |||
| EXPORT const char* jack_port_name(const jack_port_t *port); | |||
| EXPORT const char* jack_port_short_name(const jack_port_t *port); | |||
| EXPORT int jack_port_flags(const jack_port_t *port); | |||
| EXPORT const char* jack_port_type(const jack_port_t *port); | |||
| EXPORT jack_port_type_id_t jack_port_type_id(const jack_port_t *port); | |||
| EXPORT int jack_port_is_mine(const jack_client_t *, const jack_port_t *port); | |||
| EXPORT int jack_port_connected(const jack_port_t *port); | |||
| EXPORT int jack_port_connected_to(const jack_port_t *port, | |||
| const char* port_name); | |||
| EXPORT const char* * jack_port_get_connections(const jack_port_t *port); | |||
| EXPORT const char* * jack_port_get_all_connections(const jack_client_t *client, | |||
| const jack_port_t *port); | |||
| EXPORT int jack_port_tie (jack_port_t *src, jack_port_t *dst); | |||
| EXPORT int jack_port_untie (jack_port_t *port); | |||
| EXPORT jack_nframes_t jack_port_get_latency (jack_port_t *port); | |||
| EXPORT jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
| EXPORT int jack_port_tie(jack_port_t *src, jack_port_t *dst); | |||
| EXPORT int jack_port_untie(jack_port_t *port); | |||
| // Old latency API | |||
| EXPORT jack_nframes_t jack_port_get_latency(jack_port_t *port); | |||
| EXPORT jack_nframes_t jack_port_get_total_latency(jack_client_t *, | |||
| jack_port_t *port); | |||
| EXPORT void jack_port_set_latency (jack_port_t *, jack_nframes_t); | |||
| EXPORT int jack_recompute_total_latency (jack_client_t*, jack_port_t* port); | |||
| EXPORT int jack_recompute_total_latencies (jack_client_t*); | |||
| EXPORT int jack_port_set_name (jack_port_t *port, const char *port_name); | |||
| EXPORT int jack_port_set_alias (jack_port_t *port, const char *alias); | |||
| EXPORT int jack_port_unset_alias (jack_port_t *port, const char *alias); | |||
| EXPORT int jack_port_get_aliases (const jack_port_t *port, char* const aliases[2]); | |||
| EXPORT int jack_port_request_monitor (jack_port_t *port, int onoff); | |||
| EXPORT int jack_port_request_monitor_by_name (jack_client_t *client, | |||
| const char *port_name, int onoff); | |||
| EXPORT int jack_port_ensure_monitor (jack_port_t *port, int onoff); | |||
| EXPORT int jack_port_monitoring_input (jack_port_t *port); | |||
| EXPORT int jack_connect (jack_client_t *, | |||
| const char *source_port, | |||
| const char *destination_port); | |||
| EXPORT int jack_disconnect (jack_client_t *, | |||
| const char *source_port, | |||
| const char *destination_port); | |||
| EXPORT int jack_port_disconnect (jack_client_t *, jack_port_t *); | |||
| EXPORT void jack_port_set_latency(jack_port_t *, jack_nframes_t); | |||
| EXPORT int jack_recompute_total_latency(jack_client_t*, jack_port_t* port); | |||
| // New latency API | |||
| EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range); | |||
| EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range); | |||
| EXPORT int jack_recompute_total_latencies(jack_client_t*); | |||
| EXPORT int jack_port_set_name(jack_port_t *port, const char* port_name); | |||
| EXPORT int jack_port_set_alias(jack_port_t *port, const char* alias); | |||
| EXPORT int jack_port_unset_alias(jack_port_t *port, const char* alias); | |||
| EXPORT int jack_port_get_aliases(const jack_port_t *port, char* const aliases[2]); | |||
| EXPORT int jack_port_request_monitor(jack_port_t *port, int onoff); | |||
| EXPORT int jack_port_request_monitor_by_name(jack_client_t *client, | |||
| const char* port_name, int onoff); | |||
| EXPORT int jack_port_ensure_monitor(jack_port_t *port, int onoff); | |||
| EXPORT int jack_port_monitoring_input(jack_port_t *port); | |||
| EXPORT int jack_connect(jack_client_t *, | |||
| const char* source_port, | |||
| const char* destination_port); | |||
| EXPORT int jack_disconnect(jack_client_t *, | |||
| const char* source_port, | |||
| const char* destination_port); | |||
| EXPORT int jack_port_disconnect(jack_client_t *, jack_port_t *); | |||
| EXPORT int jack_port_name_size(void); | |||
| EXPORT int jack_port_type_size(void); | |||
| EXPORT jack_nframes_t jack_get_sample_rate (jack_client_t *); | |||
| EXPORT jack_nframes_t jack_get_buffer_size (jack_client_t *); | |||
| EXPORT const char ** jack_get_ports (jack_client_t *, | |||
| const char *port_name_pattern, | |||
| const char *type_name_pattern, | |||
| EXPORT size_t jack_port_type_get_buffer_size(jack_client_t *client, const char* port_type); | |||
| EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *); | |||
| EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *); | |||
| EXPORT const char* * jack_get_ports(jack_client_t *, | |||
| const char* port_name_pattern, | |||
| const char* type_name_pattern, | |||
| unsigned long flags); | |||
| EXPORT jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name); | |||
| EXPORT jack_port_t * jack_port_by_id (jack_client_t *client, | |||
| EXPORT jack_port_t * jack_port_by_name(jack_client_t *, const char* port_name); | |||
| EXPORT jack_port_t * jack_port_by_id(jack_client_t *client, | |||
| jack_port_id_t port_id); | |||
| EXPORT int jack_engine_takeover_timebase (jack_client_t *); | |||
| EXPORT jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | |||
| EXPORT int jack_engine_takeover_timebase(jack_client_t *); | |||
| EXPORT jack_nframes_t jack_frames_since_cycle_start(const jack_client_t *); | |||
| EXPORT jack_time_t jack_get_time(); | |||
| EXPORT jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t time); | |||
| EXPORT jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t frames); | |||
| EXPORT jack_nframes_t jack_frame_time (const jack_client_t *); | |||
| EXPORT jack_nframes_t jack_last_frame_time (const jack_client_t *client); | |||
| EXPORT float jack_cpu_load (jack_client_t *client); | |||
| EXPORT pthread_t jack_client_thread_id (jack_client_t *); | |||
| EXPORT void jack_set_error_function (print_function); | |||
| EXPORT void jack_set_info_function (print_function); | |||
| EXPORT float jack_get_max_delayed_usecs (jack_client_t *client); | |||
| EXPORT float jack_get_xrun_delayed_usecs (jack_client_t *client); | |||
| EXPORT void jack_reset_max_delayed_usecs (jack_client_t *client); | |||
| EXPORT int jack_release_timebase (jack_client_t *client); | |||
| EXPORT int jack_set_sync_callback (jack_client_t *client, | |||
| EXPORT jack_nframes_t jack_frame_time(const jack_client_t *); | |||
| EXPORT jack_nframes_t jack_last_frame_time(const jack_client_t *client); | |||
| EXPORT float jack_cpu_load(jack_client_t *client); | |||
| EXPORT jack_native_thread_t jack_client_thread_id(jack_client_t *); | |||
| EXPORT void jack_set_error_function(print_function); | |||
| EXPORT void jack_set_info_function(print_function); | |||
| EXPORT float jack_get_max_delayed_usecs(jack_client_t *client); | |||
| EXPORT float jack_get_xrun_delayed_usecs(jack_client_t *client); | |||
| EXPORT void jack_reset_max_delayed_usecs(jack_client_t *client); | |||
| EXPORT int jack_release_timebase(jack_client_t *client); | |||
| EXPORT int jack_set_sync_callback(jack_client_t *client, | |||
| JackSyncCallback sync_callback, | |||
| void *arg); | |||
| EXPORT int jack_set_sync_timeout (jack_client_t *client, | |||
| EXPORT int jack_set_sync_timeout(jack_client_t *client, | |||
| jack_time_t timeout); | |||
| EXPORT int jack_set_timebase_callback (jack_client_t *client, | |||
| EXPORT int jack_set_timebase_callback(jack_client_t *client, | |||
| int conditional, | |||
| JackTimebaseCallback timebase_callback, | |||
| void *arg); | |||
| EXPORT int jack_transport_locate (jack_client_t *client, | |||
| EXPORT int jack_transport_locate(jack_client_t *client, | |||
| jack_nframes_t frame); | |||
| EXPORT jack_transport_state_t jack_transport_query (const jack_client_t *client, | |||
| EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client, | |||
| jack_position_t *pos); | |||
| EXPORT jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client); | |||
| EXPORT int jack_transport_reposition (jack_client_t *client, | |||
| EXPORT jack_nframes_t jack_get_current_transport_frame(const jack_client_t *client); | |||
| EXPORT int jack_transport_reposition(jack_client_t *client, | |||
| jack_position_t *pos); | |||
| EXPORT void jack_transport_start (jack_client_t *client); | |||
| EXPORT void jack_transport_stop (jack_client_t *client); | |||
| EXPORT void jack_get_transport_info (jack_client_t *client, | |||
| EXPORT void jack_transport_start(jack_client_t *client); | |||
| EXPORT void jack_transport_stop(jack_client_t *client); | |||
| EXPORT void jack_get_transport_info(jack_client_t *client, | |||
| jack_transport_info_t *tinfo); | |||
| EXPORT void jack_set_transport_info (jack_client_t *client, | |||
| EXPORT void jack_set_transport_info(jack_client_t *client, | |||
| jack_transport_info_t *tinfo); | |||
| EXPORT int jack_client_real_time_priority (jack_client_t*); | |||
| EXPORT int jack_client_max_real_time_priority (jack_client_t*); | |||
| EXPORT int jack_acquire_real_time_scheduling (pthread_t thread, int priority); | |||
| EXPORT int jack_client_create_thread (jack_client_t* client, | |||
| pthread_t *thread, | |||
| EXPORT int jack_client_real_time_priority(jack_client_t*); | |||
| EXPORT int jack_client_max_real_time_priority(jack_client_t*); | |||
| EXPORT int jack_acquire_real_time_scheduling(jack_native_thread_t thread, int priority); | |||
| EXPORT int jack_client_create_thread(jack_client_t* client, | |||
| jack_native_thread_t *thread, | |||
| int priority, | |||
| int realtime, // boolean | |||
| thread_routine routine, | |||
| void *arg); | |||
| EXPORT int jack_drop_real_time_scheduling (pthread_t thread); | |||
| EXPORT int jack_drop_real_time_scheduling(jack_native_thread_t thread); | |||
| EXPORT int jack_client_stop_thread (jack_client_t* client, pthread_t thread); | |||
| EXPORT int jack_client_kill_thread (jack_client_t* client, pthread_t thread); | |||
| EXPORT int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread); | |||
| EXPORT int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread); | |||
| #ifndef WIN32 | |||
| EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc); | |||
| EXPORT void jack_set_thread_creator(jack_thread_creator_t jtc); | |||
| #endif | |||
| EXPORT char * jack_get_internal_client_name (jack_client_t *client, | |||
| EXPORT char * jack_get_internal_client_name(jack_client_t *client, | |||
| jack_intclient_t intclient); | |||
| EXPORT jack_intclient_t jack_internal_client_handle (jack_client_t *client, | |||
| const char *client_name, | |||
| EXPORT jack_intclient_t jack_internal_client_handle(jack_client_t *client, | |||
| const char* client_name, | |||
| jack_status_t *status); | |||
| EXPORT jack_intclient_t jack_internal_client_load (jack_client_t *client, | |||
| const char *client_name, | |||
| EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, | |||
| const char* client_name, | |||
| jack_options_t options, | |||
| jack_status_t *status, ...); | |||
| EXPORT jack_intclient_t jack_internal_client_load_aux (jack_client_t *client, | |||
| const char *client_name, | |||
| EXPORT jack_intclient_t jack_internal_client_load_aux(jack_client_t *client, | |||
| const char* client_name, | |||
| jack_options_t options, | |||
| jack_status_t *status, va_list ap); | |||
| EXPORT jack_status_t jack_internal_client_unload (jack_client_t *client, | |||
| EXPORT jack_status_t jack_internal_client_unload(jack_client_t *client, | |||
| jack_intclient_t intclient); | |||
| EXPORT void jack_free(void* ptr); | |||
| EXPORT int jack_set_session_callback(jack_client_t* ext_client, JackSessionCallback session_callback, void* arg); | |||
| EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path); | |||
| EXPORT int jack_session_reply(jack_client_t* ext_client, jack_session_event_t *event); | |||
| EXPORT void jack_session_event_free(jack_session_event_t* ev); | |||
| EXPORT char* jack_get_uuid_for_client_name(jack_client_t* ext_client, const char* client_name); | |||
| EXPORT char* jack_get_client_name_by_uuid(jack_client_t* ext_client, const char* client_uuid); | |||
| EXPORT int jack_reserve_client_name(jack_client_t* ext_client, const char* name, const char* uuid); | |||
| EXPORT void jack_session_commands_free(jack_session_command_t *cmds); | |||
| EXPORT int jack_client_has_session_callback(jack_client_t *client, const char* client_name); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -256,7 +277,7 @@ static inline bool CheckPort(jack_port_id_t port_index) | |||
| static inline bool CheckBufferSize(jack_nframes_t buffer_size) | |||
| { | |||
| return (buffer_size <= BUFFER_SIZE_MAX); | |||
| return (buffer_size >= 1 && buffer_size <= BUFFER_SIZE_MAX); | |||
| } | |||
| static inline void WaitGraphChange() | |||
| @@ -278,12 +299,12 @@ static inline void WaitGraphChange() | |||
| } | |||
| } | |||
| EXPORT void jack_set_error_function (print_function func) | |||
| EXPORT void jack_set_error_function(print_function func) | |||
| { | |||
| jack_error_callback = (func == NULL) ? &default_jack_error_callback : func; | |||
| } | |||
| EXPORT void jack_set_info_function (print_function func) | |||
| EXPORT void jack_set_info_function(print_function func) | |||
| { | |||
| jack_info_callback = (func == NULL) ? &default_jack_info_callback : func; | |||
| } | |||
| @@ -526,6 +547,40 @@ EXPORT void jack_port_set_latency(jack_port_t* port, jack_nframes_t frames) | |||
| } | |||
| } | |||
| EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_port_get_latency_range"); | |||
| #endif | |||
| uintptr_t port_aux = (uintptr_t)port; | |||
| jack_port_id_t myport = (jack_port_id_t)port_aux; | |||
| if (!CheckPort(myport)) { | |||
| jack_error("jack_port_get_latency_range called with an incorrect port %ld", myport); | |||
| } else { | |||
| WaitGraphChange(); | |||
| JackGraphManager* manager = GetGraphManager(); | |||
| if (manager) | |||
| manager->GetPort(myport)->GetLatencyRange(mode, range); | |||
| } | |||
| } | |||
| EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_port_set_latency_range"); | |||
| #endif | |||
| uintptr_t port_aux = (uintptr_t)port; | |||
| jack_port_id_t myport = (jack_port_id_t)port_aux; | |||
| if (!CheckPort(myport)) { | |||
| jack_error("jack_port_set_latency_range called with an incorrect port %ld", myport); | |||
| } else { | |||
| WaitGraphChange(); | |||
| JackGraphManager* manager = GetGraphManager(); | |||
| if (manager) | |||
| manager->GetPort(myport)->SetLatencyRange(mode, range); | |||
| } | |||
| } | |||
| EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* port) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| @@ -536,10 +591,10 @@ EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* | |||
| uintptr_t port_aux = (uintptr_t)port; | |||
| jack_port_id_t myport = (jack_port_id_t)port_aux; | |||
| if (client == NULL) { | |||
| jack_error("jack_recompute_total_latencies called with a NULL client"); | |||
| jack_error("jack_recompute_total_latency called with a NULL client"); | |||
| return -1; | |||
| } else if (!CheckPort(myport)) { | |||
| jack_error("jack_recompute_total_latencies called with a NULL port"); | |||
| jack_error("jack_recompute_total_latency called with a NULL port"); | |||
| return -1; | |||
| } else { | |||
| WaitGraphChange(); | |||
| @@ -559,9 +614,7 @@ EXPORT int jack_recompute_total_latencies(jack_client_t* ext_client) | |||
| jack_error("jack_recompute_total_latencies called with a NULL client"); | |||
| return -1; | |||
| } else { | |||
| WaitGraphChange(); | |||
| JackGraphManager* manager = GetGraphManager(); | |||
| return (manager ? manager->ComputeTotalLatencies() : -1); | |||
| return client->ComputeTotalLatencies(); | |||
| } | |||
| } | |||
| @@ -988,6 +1041,20 @@ EXPORT int jack_set_xrun_callback(jack_client_t* ext_client, JackXRunCallback xr | |||
| } | |||
| } | |||
| EXPORT int jack_set_latency_callback(jack_client_t* ext_client, JackLatencyCallback latency_callback, void *arg) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_set_latency_callback"); | |||
| #endif | |||
| JackClient* client = (JackClient*)ext_client; | |||
| if (client == NULL) { | |||
| jack_error("jack_set_latency_callback called with a NULL client"); | |||
| return -1; | |||
| } else { | |||
| return client->SetLatencyCallback(latency_callback, arg); | |||
| } | |||
| } | |||
| EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback init_callback, void *arg) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| @@ -1396,7 +1463,7 @@ EXPORT float jack_cpu_load(jack_client_t* ext_client) | |||
| } | |||
| } | |||
| EXPORT pthread_t jack_client_thread_id(jack_client_t* ext_client) | |||
| EXPORT jack_native_thread_t jack_client_thread_id(jack_client_t* ext_client) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_client_thread_id"); | |||
| @@ -1404,7 +1471,7 @@ EXPORT pthread_t jack_client_thread_id(jack_client_t* ext_client) | |||
| JackClient* client = (JackClient*)ext_client; | |||
| if (client == NULL) { | |||
| jack_error("jack_client_thread_id called with a NULL client"); | |||
| return (pthread_t)NULL; | |||
| return (jack_native_thread_t)NULL; | |||
| } else { | |||
| return client->GetThreadID(); | |||
| } | |||
| @@ -1439,6 +1506,26 @@ EXPORT int jack_port_type_size(void) | |||
| return JACK_PORT_TYPE_SIZE; | |||
| } | |||
| EXPORT size_t jack_port_type_get_buffer_size(jack_client_t* ext_client, const char* port_type) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_port_type_get_buffer_size"); | |||
| #endif | |||
| JackClient* client = (JackClient*)ext_client; | |||
| if (client == NULL) { | |||
| jack_error("jack_port_type_get_buffer_size called with a NULL client"); | |||
| return 0; | |||
| } else { | |||
| jack_port_type_id_t port_id = GetPortTypeId(port_type); | |||
| if (port_id == PORT_TYPES_MAX) { | |||
| jack_error("jack_port_type_get_buffer_size called with an unknown port type = %s", port_type); | |||
| return 0; | |||
| } else { | |||
| return GetPortType(port_id)->size(); | |||
| } | |||
| } | |||
| } | |||
| // transport.h | |||
| EXPORT int jack_release_timebase(jack_client_t* ext_client) | |||
| { | |||
| @@ -1595,7 +1682,7 @@ EXPORT void jack_set_transport_info(jack_client_t* ext_client, jack_transport_in | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_set_transport_info"); | |||
| #endif | |||
| #endif | |||
| jack_error("jack_set_transport_info: deprecated"); | |||
| if (tinfo) | |||
| memset(tinfo, 0, sizeof(jack_transport_info_t)); | |||
| @@ -1677,14 +1764,14 @@ EXPORT int jack_client_max_real_time_priority(jack_client_t* ext_client) | |||
| } | |||
| } | |||
| EXPORT int jack_acquire_real_time_scheduling(pthread_t thread, int priority) | |||
| EXPORT int jack_acquire_real_time_scheduling(jack_native_thread_t thread, int priority) | |||
| { | |||
| JackEngineControl* control = GetEngineControl(); | |||
| return (control ? JackThread::AcquireRealTimeImp(thread, priority, GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint) : -1); | |||
| } | |||
| EXPORT int jack_client_create_thread(jack_client_t* client, | |||
| pthread_t *thread, | |||
| jack_native_thread_t *thread, | |||
| int priority, | |||
| int realtime, /* boolean */ | |||
| thread_routine routine, | |||
| @@ -1692,28 +1779,28 @@ EXPORT int jack_client_create_thread(jack_client_t* client, | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_client_create_thread"); | |||
| #endif | |||
| #endif | |||
| return JackThread::StartImp(thread, priority, realtime, routine, arg); | |||
| } | |||
| EXPORT int jack_drop_real_time_scheduling(pthread_t thread) | |||
| EXPORT int jack_drop_real_time_scheduling(jack_native_thread_t thread) | |||
| { | |||
| return JackThread::DropRealTimeImp(thread); | |||
| } | |||
| EXPORT int jack_client_stop_thread(jack_client_t* client, pthread_t thread) | |||
| EXPORT int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_client_stop_thread"); | |||
| #endif | |||
| #endif | |||
| return JackThread::StopImp(thread); | |||
| } | |||
| EXPORT int jack_client_kill_thread(jack_client_t* client, pthread_t thread) | |||
| EXPORT int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_client_kill_thread"); | |||
| #endif | |||
| #endif | |||
| return JackThread::KillImp(thread); | |||
| } | |||
| @@ -1725,15 +1812,15 @@ EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc) | |||
| #endif | |||
| // intclient.h | |||
| EXPORT int jack_internal_client_new (const char *client_name, | |||
| const char *load_name, | |||
| const char *load_init) | |||
| EXPORT int jack_internal_client_new (const char* client_name, | |||
| const char* load_name, | |||
| const char* load_init) | |||
| { | |||
| jack_error("jack_internal_client_new: deprecated"); | |||
| return -1; | |||
| } | |||
| EXPORT void jack_internal_client_close (const char *client_name) | |||
| EXPORT void jack_internal_client_close (const char* client_name) | |||
| { | |||
| jack_error("jack_internal_client_close: deprecated"); | |||
| } | |||
| @@ -1803,7 +1890,7 @@ EXPORT jack_intclient_t jack_internal_client_load_aux(jack_client_t* ext_client, | |||
| } | |||
| } | |||
| EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, const char *client_name, jack_options_t options, jack_status_t *status, ...) | |||
| EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, const char* client_name, jack_options_t options, jack_status_t *status, ...) | |||
| { | |||
| va_list ap; | |||
| va_start(ap, status); | |||
| @@ -1847,7 +1934,7 @@ jack_get_version( | |||
| } | |||
| EXPORT | |||
| const char * | |||
| const char* | |||
| jack_get_version_string() | |||
| { | |||
| return VERSION; | |||
| @@ -1876,7 +1963,7 @@ EXPORT int jack_set_session_callback(jack_client_t* ext_client, JackSessionCallb | |||
| } | |||
| } | |||
| EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char *path) | |||
| EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_session_notify"); | |||
| @@ -1891,7 +1978,7 @@ EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, co | |||
| } | |||
| } | |||
| EXPORT int jack_session_reply(jack_client_t *ext_client, jack_session_event_t *event) | |||
| EXPORT int jack_session_reply(jack_client_t* ext_client, jack_session_event_t *event) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_session_reply"); | |||
| @@ -1919,7 +2006,7 @@ EXPORT void jack_session_event_free(jack_session_event_t* ev) | |||
| } | |||
| } | |||
| EXPORT char *jack_get_uuid_for_client_name( jack_client_t *ext_client, const char *client_name ) | |||
| EXPORT char *jack_get_uuid_for_client_name(jack_client_t* ext_client, const char* client_name) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_get_uuid_for_client_name"); | |||
| @@ -1934,7 +2021,7 @@ EXPORT char *jack_get_uuid_for_client_name( jack_client_t *ext_client, const cha | |||
| } | |||
| } | |||
| EXPORT char *jack_get_client_name_by_uuid( jack_client_t *ext_client, const char *client_uuid ) | |||
| EXPORT char *jack_get_client_name_by_uuid(jack_client_t* ext_client, const char* client_uuid) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_get_client_name_by_uuid"); | |||
| @@ -1945,11 +2032,11 @@ EXPORT char *jack_get_client_name_by_uuid( jack_client_t *ext_client, const char | |||
| jack_error("jack_get_client_name_by_uuid called with a NULL client"); | |||
| return NULL; | |||
| } else { | |||
| return client->GetClientNameForUUID(client_uuid); | |||
| return client->GetClientNameByUUID(client_uuid); | |||
| } | |||
| } | |||
| EXPORT int jack_reserve_client_name( jack_client_t *ext_client, const char *name, const char *uuid ) | |||
| EXPORT int jack_reserve_client_name(jack_client_t* ext_client, const char* client_name, const char* uuid) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_reserve_client_name"); | |||
| @@ -1960,17 +2047,17 @@ EXPORT int jack_reserve_client_name( jack_client_t *ext_client, const char *name | |||
| jack_error("jack_reserve_client_name called with a NULL client"); | |||
| return -1; | |||
| } else { | |||
| return client->ReserveClientName(name, uuid); | |||
| return client->ReserveClientName(client_name, uuid); | |||
| } | |||
| } | |||
| EXPORT void jack_session_commands_free( jack_session_command_t *cmds ) | |||
| EXPORT void jack_session_commands_free(jack_session_command_t *cmds) | |||
| { | |||
| if (!cmds) | |||
| return; | |||
| int i=0; | |||
| while(1) { | |||
| int i = 0; | |||
| while (1) { | |||
| if (cmds[i].client_name) | |||
| free ((char *)cmds[i].client_name); | |||
| if (cmds[i].command) | |||
| @@ -1985,3 +2072,18 @@ EXPORT void jack_session_commands_free( jack_session_command_t *cmds ) | |||
| free(cmds); | |||
| } | |||
| EXPORT int jack_client_has_session_callback(jack_client_t* ext_client, const char* client_name) | |||
| { | |||
| #ifdef __CLIENTDEBUG__ | |||
| JackGlobals::CheckContext("jack_client_has_session_callback"); | |||
| #endif | |||
| JackClient* client = (JackClient*)ext_client; | |||
| jack_log("jack_client_has_session_callback ext_client %x client %x ", ext_client, client); | |||
| if (client == NULL) { | |||
| jack_error("jack_client_has_session_callback called with a NULL client"); | |||
| return -1; | |||
| } else { | |||
| return client->ClientHasSessionCallback(client_name); | |||
| } | |||
| } | |||
| @@ -101,6 +101,7 @@ int JackAudioDriver::Attach() | |||
| jack_port_id_t port_index; | |||
| char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| jack_latency_range_t range; | |||
| int i; | |||
| jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); | |||
| @@ -114,7 +115,8 @@ int JackAudioDriver::Attach() | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| port->SetLatency(fEngineControl->fBufferSize + fCaptureLatency); | |||
| range.min = range.max = fEngineControl->fBufferSize + fCaptureLatency; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fCapturePortList[i] = port_index; | |||
| jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", port_index); | |||
| } | |||
| @@ -129,7 +131,8 @@ int JackAudioDriver::Attach() | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| // Add more latency if "async" mode is used... | |||
| port->SetLatency(fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency); | |||
| range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency; | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| fPlaybackPortList[i] = port_index; | |||
| jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); | |||
| @@ -143,7 +146,8 @@ int JackAudioDriver::Attach() | |||
| } else { | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| port->SetLatency(fEngineControl->fBufferSize); | |||
| range.min = range.max = fEngineControl->fBufferSize; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fMonitorPortList[i] = port_index; | |||
| } | |||
| } | |||
| @@ -188,13 +192,13 @@ int JackAudioDriver::ProcessNull() | |||
| { | |||
| // Keep begin cycle time | |||
| JackDriver::CycleTakeBeginTime(); | |||
| if (fEngineControl->fSyncMode) { | |||
| ProcessGraphSync(); | |||
| } else { | |||
| ProcessGraphAsync(); | |||
| } | |||
| // Keep end cycle time | |||
| JackDriver::CycleTakeEndTime(); | |||
| WaitUntilNextCycle(); | |||
| @@ -214,23 +218,24 @@ synchronize to the end of client graph execution. | |||
| int JackAudioDriver::ProcessAsync() | |||
| { | |||
| // Read input buffers for the current cycle | |||
| if (Read() < 0) { | |||
| if (Read() < 0) { | |||
| jack_error("JackAudioDriver::ProcessAsync: read error, stopping..."); | |||
| return -1; | |||
| return -1; | |||
| } | |||
| // Write output buffers from the previous cycle | |||
| if (Write() < 0) { | |||
| jack_error("JackAudioDriver::ProcessAsync: write error, stopping..."); | |||
| return -1; | |||
| return -1; | |||
| } | |||
| // Process graph | |||
| if (fIsMaster) { | |||
| ProcessGraphAsync(); | |||
| } else { | |||
| fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
| } | |||
| // Keep end cycle time | |||
| JackDriver::CycleTakeEndTime(); | |||
| return 0; | |||
| @@ -238,29 +243,38 @@ int JackAudioDriver::ProcessAsync() | |||
| /* | |||
| The driver SYNC mode: the server does synchronize to the end of client graph execution, | |||
| output buffers computed at the *current cycle* are used. | |||
| if graph process succeed, output buffers computed at the *current cycle* are used. | |||
| */ | |||
| int JackAudioDriver::ProcessSync() | |||
| { | |||
| // Read input buffers for the current cycle | |||
| if (Read() < 0) { | |||
| if (Read() < 0) { | |||
| jack_error("JackAudioDriver::ProcessSync: read error, stopping..."); | |||
| return -1; | |||
| return -1; | |||
| } | |||
| // Process graph | |||
| if (fIsMaster) { | |||
| ProcessGraphSync(); | |||
| if (ProcessGraphSync() < 0) { | |||
| jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); | |||
| goto end; | |||
| } | |||
| } else { | |||
| fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
| if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { | |||
| jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); | |||
| goto end; | |||
| } | |||
| } | |||
| // Write output buffers from the current cycle | |||
| if (Write() < 0) { | |||
| jack_error("JackAudioDriver::ProcessSync: write error, stopping..."); | |||
| return -1; | |||
| return -1; | |||
| } | |||
| end: | |||
| // Keep end cycle time | |||
| JackDriver::CycleTakeEndTime(); | |||
| return 0; | |||
| @@ -269,25 +283,34 @@ int JackAudioDriver::ProcessSync() | |||
| void JackAudioDriver::ProcessGraphAsync() | |||
| { | |||
| // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
| if (!fEngine->Process(fBeginDateUst, fEndDateUst)) | |||
| if (!fEngine->Process(fBeginDateUst, fEndDateUst)) | |||
| jack_error("JackAudioDriver::ProcessGraphAsync: Process error"); | |||
| fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
| if (ProcessSlaves() < 0) | |||
| jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error"); | |||
| } | |||
| void JackAudioDriver::ProcessGraphSync() | |||
| int JackAudioDriver::ProcessGraphSync() | |||
| { | |||
| int res = 0; | |||
| // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
| if (fEngine->Process(fBeginDateUst, fEndDateUst)) { | |||
| if (fEngine->Process(fBeginDateUst, fEndDateUst)) { | |||
| fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
| if (ProcessSlaves() < 0) | |||
| if (ProcessSlaves() < 0) { | |||
| jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!"); | |||
| if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) | |||
| res = -1; | |||
| } | |||
| if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { | |||
| jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!"); | |||
| res = -1; | |||
| } | |||
| } else { // Graph not finished: do not activate it | |||
| jack_error("JackAudioDriver::ProcessGraphSync: Process error"); | |||
| res = -1; | |||
| } | |||
| return res; | |||
| } | |||
| void JackAudioDriver::WaitUntilNextCycle() | |||
| @@ -316,4 +339,37 @@ jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index) | |||
| return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize); | |||
| } | |||
| int JackAudioDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) | |||
| { | |||
| switch (notify) { | |||
| case kLatencyCallback: | |||
| HandleLatencyCallback(value1); | |||
| break; | |||
| default: | |||
| JackDriver::ClientNotify(refnum, name, notify, sync, message, value1, value2); | |||
| break; | |||
| } | |||
| return 0; | |||
| } | |||
| void JackAudioDriver::HandleLatencyCallback(int status) | |||
| { | |||
| jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| if (mode == JackPlaybackLatency) { | |||
| fGraphManager->RecalculateLatency(fCapturePortList[i], mode); | |||
| } | |||
| } | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| if (mode == JackCaptureLatency) { | |||
| fGraphManager->RecalculateLatency(fPlaybackPortList[i], mode); | |||
| } | |||
| } | |||
| } | |||
| } // end of namespace | |||
| @@ -36,12 +36,12 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
| protected: | |||
| void ProcessGraphAsync(); | |||
| void ProcessGraphSync(); | |||
| int ProcessGraphSync(); | |||
| void WaitUntilNextCycle(); | |||
| virtual int ProcessAsync(); | |||
| virtual int ProcessSync(); | |||
| int fCaptureChannels; | |||
| int fPlaybackChannels; | |||
| @@ -57,6 +57,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
| jack_default_audio_sample_t* GetOutputBuffer(int port_index); | |||
| jack_default_audio_sample_t* GetMonitorBuffer(int port_index); | |||
| void HandleLatencyCallback(int status); | |||
| public: | |||
| JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | |||
| @@ -73,7 +75,7 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| virtual int Open(bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| @@ -83,18 +85,20 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| virtual int Process(); | |||
| virtual int ProcessNull(); | |||
| virtual int Attach(); | |||
| virtual int Detach(); | |||
| virtual int Write(); | |||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
| virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
| virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | |||
| }; | |||
| } // end of namespace | |||
| @@ -18,7 +18,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #include "JackGlobals.h" | |||
| #include "JackEngineControl.h" | |||
| #include "JackPortType.h" | |||
| #include <string.h> | |||
| #if defined (__APPLE__) | |||
| @@ -46,7 +49,7 @@ static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_ | |||
| frames = frames % 4; | |||
| while (frames_group > 0) { | |||
| #if defined (__SSE__) && !defined (__sun__) | |||
| #if defined (__SSE__) && !defined (__sun__) | |||
| __m128 vec = _mm_add_ps(_mm_load_ps(mixbuffer), _mm_load_ps(buffer)); | |||
| _mm_store_ps(mixbuffer, vec); | |||
| @@ -97,7 +100,7 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun | |||
| void* buffer; | |||
| // Copy first buffer | |||
| #if defined (__SSE__) && !defined (__sun__) | |||
| #if defined (__SSE__) && !defined (__sun__) | |||
| jack_nframes_t frames_group = nframes / 4; | |||
| jack_nframes_t remaining_frames = nframes % 4; | |||
| @@ -127,12 +130,18 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun | |||
| } | |||
| } | |||
| static size_t AudioBufferSize() | |||
| { | |||
| return GetEngineControl()->fBufferSize * sizeof(float); | |||
| } | |||
| const JackPortType gAudioPortType = | |||
| { | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| AudioBufferInit, | |||
| AudioBufferMixdown | |||
| }; | |||
| { | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| AudioBufferSize, | |||
| AudioBufferInit, | |||
| AudioBufferMixdown | |||
| }; | |||
| } // namespace Jack | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #ifndef __JackChannel__ | |||
| #define __JackChannel__ | |||
| #include "types.h" | |||
| #include "session.h" | |||
| namespace Jack | |||
| @@ -108,43 +107,39 @@ class JackClientChannelInterface | |||
| {} | |||
| virtual void SetFreewheel(int onoff, int* result) | |||
| {} | |||
| virtual void ComputeTotalLatencies(int* result) | |||
| {} | |||
| virtual void ReleaseTimebase(int refnum, int* result) | |||
| {} | |||
| virtual void SetTimebaseCallback(int refnum, int conditional, int* result) | |||
| {} | |||
| virtual void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | |||
| {} | |||
| virtual void InternalClientHandle(int refnum, const char* client_name, int* status, int* int_ref, int* result) | |||
| {} | |||
| virtual void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) | |||
| {} | |||
| virtual void InternalClientUnload(int refnum, int int_ref, int* status, int* result) | |||
| {} | |||
| virtual void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, jack_session_command_t **result) | |||
| {} | |||
| virtual void SessionReply(int refnum, int *result) | |||
| virtual void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result) | |||
| {} | |||
| virtual void GetUUIDForClientName(int refnum, const char *client_name, char *uuid_res, int *result) | |||
| virtual void SessionReply(int refnum, int* result) | |||
| {} | |||
| virtual void GetClientNameForUUID(int refnum, const char *uuid, char *name_res, int *result) | |||
| virtual void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result) | |||
| {} | |||
| virtual void ReserveClientName(int refnum, const char *client_name, const char *uuid, int *result) | |||
| virtual void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result) | |||
| {} | |||
| virtual void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result) | |||
| {} | |||
| virtual void ClientHasSessionCallback(const char* client_name, int* result) | |||
| {} | |||
| virtual bool IsChannelThread() | |||
| { | |||
| return false; | |||
| { | |||
| return false; | |||
| } | |||
| }; | |||
| @@ -13,12 +13,12 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #include "JackClient.h" | |||
| #include "JackSystemDeps.h" | |||
| #include "JackGraphManager.h" | |||
| #include "JackClientControl.h" | |||
| #include "JackEngineControl.h" | |||
| @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "driver_interface.h" | |||
| #include "JackLibGlobals.h" | |||
| #include <math.h> | |||
| #include <string> | |||
| #include <algorithm> | |||
| @@ -60,6 +61,9 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||
| fTimebase = NULL; | |||
| fSync = NULL; | |||
| fThreadFun = NULL; | |||
| fSession = NULL; | |||
| fLatency = NULL; | |||
| fProcessArg = NULL; | |||
| fGraphOrderArg = NULL; | |||
| fXrunArg = NULL; | |||
| @@ -75,6 +79,8 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||
| fSyncArg = NULL; | |||
| fTimebaseArg = NULL; | |||
| fThreadFunArg = NULL; | |||
| fSessionArg = NULL; | |||
| fLatencyArg = NULL; | |||
| } | |||
| JackClient::~JackClient() | |||
| @@ -84,17 +90,17 @@ int JackClient::Close() | |||
| { | |||
| jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); | |||
| int result = 0; | |||
| Deactivate(); | |||
| fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing | |||
| // Request close only if server is still running | |||
| if (JackGlobals::fServerRunning) { | |||
| fChannel->ClientClose(GetClientControl()->fRefNum, &result); | |||
| } else { | |||
| jack_log("JackClient::Close server is shutdown"); | |||
| jack_log("JackClient::Close server is shutdown"); | |||
| } | |||
| fChannel->Close(); | |||
| fSynchroTable[GetClientControl()->fRefNum].Disconnect(); | |||
| JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; | |||
| @@ -106,7 +112,7 @@ bool JackClient::IsActive() | |||
| return (GetClientControl()) ? GetClientControl()->fActive : false; | |||
| } | |||
| pthread_t JackClient::GetThreadID() | |||
| jack_native_thread_t JackClient::GetThreadID() | |||
| { | |||
| return fThread.GetThreadID(); | |||
| } | |||
| @@ -156,7 +162,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| case kActivateClient: | |||
| jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); | |||
| Init(); | |||
| InitAux(); | |||
| break; | |||
| } | |||
| @@ -188,7 +194,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| res = fBufferSize(value1, fBufferSizeArg); | |||
| } | |||
| break; | |||
| case kSampleRateCallback: | |||
| jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); | |||
| if (fSampleRate) { | |||
| @@ -219,7 +225,9 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| fFreewheel(0, fFreewheelArg); | |||
| } | |||
| if (GetEngineControl()->fRealTime) { | |||
| fThread.AcquireRealTime(); | |||
| if (fThread.AcquireRealTime() < 0) { | |||
| jack_error("JackClient::AcquireRealTime error"); | |||
| } | |||
| } | |||
| break; | |||
| @@ -250,7 +258,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| fPortConnect(value1, value2, 0, fPortConnectArg); | |||
| } | |||
| break; | |||
| case kPortRenameCallback: | |||
| jack_log("JackClient::kPortRenameCallback port = %ld", value1); | |||
| if (fPortRename) { | |||
| @@ -264,7 +272,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| res = fXrun(fXrunArg); | |||
| } | |||
| break; | |||
| case kShutDownCallback: | |||
| jack_log("JackClient::kShutDownCallback"); | |||
| if (fInfoShutdown) { | |||
| @@ -289,15 +297,109 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| res = (fImmediateSessionReply) ? 1 : 2; | |||
| } | |||
| break; | |||
| case kLatencyCallback: | |||
| res = HandleLatencyCallback(value1); | |||
| break; | |||
| } | |||
| } | |||
| return res; | |||
| } | |||
| int JackClient::HandleLatencyCallback(int status) | |||
| { | |||
| jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency; | |||
| jack_latency_range_t latency = { UINT32_MAX, 0 }; | |||
| /* first setup all latency values of the ports. | |||
| * this is based on the connections of the ports. | |||
| */ | |||
| list<jack_port_id_t>::iterator it; | |||
| for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
| JackPort* port = GetGraphManager()->GetPort(*it); | |||
| if ((port->GetFlags() & JackPortIsOutput) && (mode == JackPlaybackLatency)) { | |||
| GetGraphManager()->RecalculateLatency(*it, mode); | |||
| } | |||
| if ((port->GetFlags() & JackPortIsInput) && (mode == JackCaptureLatency)) { | |||
| GetGraphManager()->RecalculateLatency(*it, mode); | |||
| } | |||
| } | |||
| if (!fLatency) { | |||
| /* | |||
| * default action is to assume all ports depend on each other. | |||
| * then always take the maximum latency. | |||
| */ | |||
| if (mode == JackPlaybackLatency) { | |||
| /* iterate over all OutputPorts, to find maximum playback latency | |||
| */ | |||
| for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
| JackPort* port = GetGraphManager()->GetPort(*it); | |||
| if (port->GetFlags() & JackPortIsOutput) { | |||
| jack_latency_range_t other_latency; | |||
| port->GetLatencyRange(mode, &other_latency); | |||
| if (other_latency.max > latency.max) | |||
| latency.max = other_latency.max; | |||
| if (other_latency.min < latency.min) | |||
| latency.min = other_latency.min; | |||
| } | |||
| } | |||
| if (latency.min == UINT32_MAX) | |||
| latency.min = 0; | |||
| /* now set the found latency on all input ports | |||
| */ | |||
| for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
| JackPort* port = GetGraphManager()->GetPort(*it); | |||
| if (port->GetFlags() & JackPortIsInput) { | |||
| port->SetLatencyRange(mode, &latency); | |||
| } | |||
| } | |||
| } | |||
| if (mode == JackCaptureLatency) { | |||
| /* iterate over all InputPorts, to find maximum playback latency | |||
| */ | |||
| for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
| JackPort* port = GetGraphManager()->GetPort(*it); | |||
| if (port->GetFlags() & JackPortIsInput) { | |||
| jack_latency_range_t other_latency; | |||
| port->GetLatencyRange(mode, &other_latency); | |||
| if (other_latency.max > latency.max) | |||
| latency.max = other_latency.max; | |||
| if (other_latency.min < latency.min) | |||
| latency.min = other_latency.min; | |||
| } | |||
| } | |||
| if (latency.min == UINT32_MAX) | |||
| latency.min = 0; | |||
| /* now set the found latency on all output ports | |||
| */ | |||
| for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
| JackPort* port = GetGraphManager()->GetPort(*it); | |||
| if (port->GetFlags() & JackPortIsOutput) { | |||
| port->SetLatencyRange(mode, &latency); | |||
| } | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| /* we have a latency callback setup by the client, | |||
| * lets use it... | |||
| */ | |||
| fLatency(mode, fLatencyArg); | |||
| return 0; | |||
| } | |||
| /*! | |||
| \brief We need to start thread before activating in the server, otherwise the FW driver | |||
| connected to the client may not be activated. | |||
| connected to the client may not be activated. | |||
| */ | |||
| int JackClient::Activate() | |||
| { | |||
| @@ -310,13 +412,13 @@ int JackClient::Activate() | |||
| if (StartThread() < 0) | |||
| return -1; | |||
| } | |||
| /* | |||
| Insertion of client in the graph will cause a kGraphOrderCallback notification | |||
| Insertion of client in the graph will cause a kGraphOrderCallback notification | |||
| to be delivered by the server, the client wants to receive it. | |||
| */ | |||
| GetClientControl()->fActive = true; | |||
| // Transport related callback become "active" | |||
| GetClientControl()->fTransportSync = true; | |||
| GetClientControl()->fTransportTimebase = true; | |||
| @@ -337,18 +439,18 @@ int JackClient::Deactivate() | |||
| return 0; | |||
| GetClientControl()->fActive = false; | |||
| // Transport related callback become "unactive" | |||
| GetClientControl()->fTransportSync = false; | |||
| GetClientControl()->fTransportTimebase = false; | |||
| // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate | |||
| int result = -1; | |||
| fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | |||
| jack_log("JackClient::Deactivate res = %ld", result); | |||
| // RT thread is stopped only when needed... | |||
| if (IsRealTime()) | |||
| if (IsRealTime()) | |||
| fThread.Kill(); | |||
| return result; | |||
| } | |||
| @@ -357,15 +459,48 @@ int JackClient::Deactivate() | |||
| // RT thread management | |||
| //---------------------- | |||
| void JackClient::InitAux() | |||
| { | |||
| if (fInit) { | |||
| jack_log("JackClient::Init calling client thread init callback"); | |||
| fInit(fInitArg); | |||
| } | |||
| } | |||
| /*! | |||
| \brief Called once when the thread starts. | |||
| */ | |||
| bool JackClient::Init() | |||
| { | |||
| if (fInit) { | |||
| jack_log("JackClient::Init calling client thread init callback"); | |||
| fInit(fInitArg); | |||
| /* | |||
| Execute buffer_size callback. | |||
| Since StartThread uses fThread.StartSync, we are sure that buffer_size callback | |||
| is executed before StartThread returns (and then IsActive will be true). | |||
| So no RT callback can be called at the same time. | |||
| */ | |||
| jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize); | |||
| if (fBufferSize) { | |||
| fBufferSize(GetEngineControl()->fBufferSize, fBufferSizeArg); | |||
| } | |||
| // Init callback | |||
| InitAux(); | |||
| // Setup context | |||
| if (!jack_tls_set(JackGlobals::fRealTime, this)) | |||
| jack_error("failed to set thread realtime key"); | |||
| if (GetEngineControl()->fRealTime) | |||
| set_threaded_log_function(); | |||
| // Setup RT | |||
| if (GetEngineControl()->fRealTime) { | |||
| if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { | |||
| jack_error("JackClient::AcquireRealTime error"); | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| @@ -384,12 +519,6 @@ int JackClient::StartThread() | |||
| return -1; | |||
| } | |||
| if (GetEngineControl()->fRealTime) { | |||
| if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { | |||
| jack_error("AcquireRealTime error"); | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -399,21 +528,15 @@ int JackClient::StartThread() | |||
| bool JackClient::Execute() | |||
| { | |||
| if (!jack_tls_set(JackGlobals::fRealTime, this)) | |||
| jack_error("failed to set thread realtime key"); | |||
| if (GetEngineControl()->fRealTime) | |||
| set_threaded_log_function(); | |||
| // Execute a dummy cycle to be sure thread has the correct properties | |||
| DummyCycle(); | |||
| if (fThreadFun) { | |||
| fThreadFun(fThreadFunArg); | |||
| } else { | |||
| ExecuteThread(); | |||
| } | |||
| return false; | |||
| return false; | |||
| } | |||
| void JackClient::DummyCycle() | |||
| @@ -424,15 +547,15 @@ void JackClient::DummyCycle() | |||
| inline void JackClient::ExecuteThread() | |||
| { | |||
| while (true) { | |||
| while (true) { | |||
| CycleWaitAux(); | |||
| CycleSignalAux(CallProcessCallback()); | |||
| } | |||
| CycleSignalAux(CallProcessCallback()); | |||
| } | |||
| } | |||
| inline jack_nframes_t JackClient::CycleWaitAux() | |||
| { | |||
| if (!WaitSync()) | |||
| if (!WaitSync()) | |||
| Error(); // Terminates the thread | |||
| CallSyncCallbackAux(); | |||
| return GetEngineControl()->fBufferSize; | |||
| @@ -443,7 +566,7 @@ inline void JackClient::CycleSignalAux(int status) | |||
| if (status == 0) | |||
| CallTimebaseCallbackAux(); | |||
| SignalSync(); | |||
| if (status != 0) | |||
| if (status != 0) | |||
| End(); // Terminates the thread | |||
| } | |||
| @@ -531,7 +654,7 @@ int JackClient::PortRegister(const char* port_name, const char* port_type, unsig | |||
| int result = -1; | |||
| jack_port_id_t port_index = NO_PORT; | |||
| fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); | |||
| if (result == 0) { | |||
| jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index); | |||
| fPortList.push_back(port_index); | |||
| @@ -612,6 +735,13 @@ int JackClient::SetFreeWheel(int onoff) | |||
| return result; | |||
| } | |||
| int JackClient::ComputeTotalLatencies() | |||
| { | |||
| int result = -1; | |||
| fChannel->ComputeTotalLatencies(&result); | |||
| return result; | |||
| } | |||
| /* | |||
| ShutDown is called: | |||
| - from the RT thread when Execute method fails | |||
| @@ -621,9 +751,9 @@ ShutDown is called: | |||
| void JackClient::ShutDown() | |||
| { | |||
| jack_log("ShutDown"); | |||
| jack_log("JackClient::ShutDown"); | |||
| JackGlobals::fServerRunning = false; | |||
| if (fInfoShutdown) { | |||
| fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); | |||
| fInfoShutdown = NULL; | |||
| @@ -641,18 +771,18 @@ inline int JackClient::ActivateAux() | |||
| { | |||
| // If activated without RT thread... | |||
| if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { | |||
| jack_log("ActivateAux"); | |||
| jack_log("JackClient::ActivateAux"); | |||
| // RT thread is started | |||
| if (StartThread() < 0) | |||
| return -1; | |||
| int result = -1; | |||
| GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); | |||
| fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); | |||
| return result; | |||
| } else { | |||
| return 0; | |||
| } | |||
| @@ -683,7 +813,7 @@ int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timeba | |||
| { | |||
| int result = -1; | |||
| fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | |||
| if (result == 0) { | |||
| GetClientControl()->fTransportTimebase = true; | |||
| fTimebase = timebase_callback; | |||
| @@ -709,14 +839,14 @@ void JackClient::TransportLocate(jack_nframes_t frame) | |||
| jack_position_t pos; | |||
| pos.frame = frame; | |||
| pos.valid = (jack_position_bits_t)0; | |||
| jack_log("TransportLocate pos = %ld", pos.frame); | |||
| jack_log("JackClient::TransportLocate pos = %ld", pos.frame); | |||
| GetEngineControl()->fTransport.RequestNewPos(&pos); | |||
| } | |||
| int JackClient::TransportReposition(jack_position_t* pos) | |||
| { | |||
| jack_position_t tmp = *pos; | |||
| jack_log("TransportReposition pos = %ld", pos->frame); | |||
| jack_log("JackClient::TransportReposition pos = %ld", pos->frame); | |||
| if (tmp.valid & ~JACK_POSITION_MASK) { | |||
| return EINVAL; | |||
| } else { | |||
| @@ -758,11 +888,11 @@ void JackClient::CallSyncCallback() | |||
| inline void JackClient::CallSyncCallbackAux() | |||
| { | |||
| if (GetClientControl()->fTransportSync) { | |||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
| jack_position_t* cur_pos = transport.ReadCurrentState(); | |||
| jack_transport_state_t transport_state = transport.GetState(); | |||
| if (fSync != NULL) { | |||
| if (fSync(transport_state, cur_pos, fSyncArg)) { | |||
| GetClientControl()->fTransportState = JackTransportRolling; | |||
| @@ -785,21 +915,21 @@ inline void JackClient::CallTimebaseCallbackAux() | |||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
| int master; | |||
| bool unused; | |||
| transport.GetTimebaseMaster(master, unused); | |||
| if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... | |||
| jack_transport_state_t transport_state = transport.GetState(); | |||
| jack_position_t* cur_pos = transport.WriteNextStateStart(1); | |||
| if (GetClientControl()->fTransportTimebase) { | |||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); | |||
| GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true | |||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); | |||
| GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true | |||
| } else if (transport_state == JackTransportRolling) { | |||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); | |||
| } | |||
| } | |||
| transport.WriteNextStateStop(1); | |||
| } | |||
| } | |||
| @@ -817,7 +947,7 @@ void JackClient::OnShutdown(JackShutdownCallback callback, void *arg) | |||
| fShutdown = callback; | |||
| } | |||
| } | |||
| void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) | |||
| { | |||
| if (IsActive()) { | |||
| @@ -873,8 +1003,6 @@ int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||
| int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) | |||
| { | |||
| jack_log("SetGraphOrderCallback "); | |||
| if (IsActive()) { | |||
| jack_error("You cannot set callbacks on an active client"); | |||
| return -1; | |||
| @@ -908,8 +1036,8 @@ int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg | |||
| GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); | |||
| fSampleRateArg = arg; | |||
| fSampleRate = callback; | |||
| // Now invoke it | |||
| if (callback) | |||
| // Now invoke it | |||
| if (callback) | |||
| callback(GetEngineControl()->fSampleRate, arg); | |||
| return 0; | |||
| } | |||
| @@ -1011,6 +1139,19 @@ int JackClient::SetSessionCallback(JackSessionCallback callback, void *arg) | |||
| } | |||
| } | |||
| int JackClient::SetLatencyCallback(JackLatencyCallback callback, void *arg) | |||
| { | |||
| if (IsActive()) { | |||
| jack_error("You cannot set callbacks on an active client"); | |||
| return -1; | |||
| } else { | |||
| // fCallback[kLatencyCallback] must always be 'true' | |||
| fLatencyArg = arg; | |||
| fLatency = callback; | |||
| return 0; | |||
| } | |||
| } | |||
| //------------------ | |||
| // Internal clients | |||
| //------------------ | |||
| @@ -1072,65 +1213,64 @@ void JackClient::InternalClientUnload(int ref, jack_status_t* status) | |||
| // Session API | |||
| //------------------ | |||
| jack_session_command_t *JackClient::SessionNotify( const char* target, jack_session_event_type_t type, const char* path ) | |||
| jack_session_command_t* JackClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path) | |||
| { | |||
| jack_session_command_t *res; | |||
| fChannel->SessionNotify( GetClientControl()->fRefNum, target, type, path, &res ); | |||
| jack_session_command_t* res; | |||
| fChannel->SessionNotify(GetClientControl()->fRefNum, target, type, path, &res); | |||
| return res; | |||
| } | |||
| int JackClient::SessionReply( jack_session_event_t *ev ) | |||
| int JackClient::SessionReply(jack_session_event_t* ev) | |||
| { | |||
| if (ev->command_line) { | |||
| strncpy( GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand) ); | |||
| strncpy(GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand)); | |||
| } else { | |||
| GetClientControl()->fSessionCommand[0] = '\0'; | |||
| } | |||
| GetClientControl()->fSessionFlags = ev->flags; | |||
| jack_log( "JackClient::SessionReply... we are here" ); | |||
| jack_log("JackClient::SessionReply... we are here"); | |||
| if (fChannel->IsChannelThread()) { | |||
| jack_log( "JackClient::SessionReply... in callback reply" ); | |||
| jack_log( "JackClient::SessionReply... in callback reply"); | |||
| fImmediateSessionReply = true; | |||
| return 0; | |||
| } | |||
| jack_log( "JackClient::SessionReply... out of cb" ); | |||
| jack_log("JackClient::SessionReply... out of cb"); | |||
| int res; | |||
| fChannel->SessionReply( GetClientControl()->fRefNum, &res); | |||
| return res; | |||
| int result = -1; | |||
| fChannel->SessionReply(GetClientControl()->fRefNum, &result); | |||
| return result; | |||
| } | |||
| char* JackClient::GetUUIDForClientName(const char* client_name) | |||
| { | |||
| char uuid_res[JACK_UUID_SIZE]; | |||
| int result = -1; | |||
| fChannel->GetUUIDForClientName( GetClientControl()->fRefNum, client_name, uuid_res, &result); | |||
| if (result) | |||
| return NULL; | |||
| return strdup(uuid_res); | |||
| fChannel->GetUUIDForClientName(GetClientControl()->fRefNum, client_name, uuid_res, &result); | |||
| return (result) ? NULL : strdup(uuid_res); | |||
| } | |||
| char* JackClient::GetClientNameForUUID(const char* uuid) | |||
| char* JackClient::GetClientNameByUUID(const char* uuid) | |||
| { | |||
| char name_res[JACK_CLIENT_NAME_SIZE + 1]; | |||
| int result = -1; | |||
| fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result); | |||
| return (result) ? NULL : strdup(name_res); | |||
| } | |||
| if (result) | |||
| return NULL; | |||
| return strdup(name_res); | |||
| int JackClient::ReserveClientName(const char* client_name, const char* uuid) | |||
| { | |||
| int result = -1; | |||
| fChannel->ReserveClientName( GetClientControl()->fRefNum, client_name, uuid, &result); | |||
| return result; | |||
| } | |||
| int JackClient::ReserveClientName(const char *name, const char* uuid) | |||
| int JackClient::ClientHasSessionCallback(const char* client_name) | |||
| { | |||
| int result = -1; | |||
| fChannel->ReserveClientName( GetClientControl()->fRefNum, name, uuid, &result); | |||
| fChannel->ClientHasSessionCallback(client_name, &result); | |||
| return result; | |||
| } | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackSynchro.h" | |||
| #include "JackPlatformPlug.h" | |||
| #include "JackChannel.h" | |||
| #include "types.h" | |||
| #include "session.h" | |||
| #include "varargs.h" | |||
| #include <list> | |||
| @@ -68,6 +67,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| JackSyncCallback fSync; | |||
| JackThreadCallback fThreadFun; | |||
| JackSessionCallback fSession; | |||
| JackLatencyCallback fLatency; | |||
| void* fProcessArg; | |||
| void* fGraphOrderArg; | |||
| @@ -86,6 +86,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| void* fSyncArg; | |||
| void* fThreadFunArg; | |||
| void* fSessionArg; | |||
| void* fLatencyArg; | |||
| char fServerName[64]; | |||
| JackThread fThread; /*! Thread to execute the Process function */ | |||
| @@ -94,14 +95,14 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| std::list<jack_port_id_t> fPortList; | |||
| bool fImmediateSessionReply; | |||
| int StartThread(); | |||
| void SetupDriverSync(bool freewheel); | |||
| bool IsActive(); | |||
| void CallSyncCallback(); | |||
| void CallTimebaseCallback(); | |||
| virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value); | |||
| inline void DummyCycle(); | |||
| @@ -116,7 +117,10 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| inline void CallSyncCallbackAux(); | |||
| inline void CallTimebaseCallbackAux(); | |||
| inline int ActivateAux(); | |||
| inline void InitAux(); | |||
| int HandleLatencyCallback(int status); | |||
| public: | |||
| JackClient(); | |||
| @@ -138,8 +142,9 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| // Context | |||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
| virtual int SetFreeWheel(int onoff); | |||
| virtual int ComputeTotalLatencies(); | |||
| virtual void ShutDown(); | |||
| virtual pthread_t GetThreadID(); | |||
| virtual jack_native_thread_t GetThreadID(); | |||
| // Port management | |||
| virtual int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); | |||
| @@ -179,6 +184,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| virtual int SetPortConnectCallback(JackPortConnectCallback callback, void *arg); | |||
| virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg); | |||
| virtual int SetSessionCallback(JackSessionCallback callback, void *arg); | |||
| virtual int SetLatencyCallback(JackLatencyCallback callback, void *arg); | |||
| // Internal clients | |||
| virtual char* GetInternalClientName(int ref); | |||
| @@ -186,16 +192,18 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
| virtual int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va); | |||
| virtual void InternalClientUnload(int ref, jack_status_t* status); | |||
| // RT Thread | |||
| jack_nframes_t CycleWait(); | |||
| void CycleSignal(int status); | |||
| int SetProcessThread(JackThreadCallback fun, void *arg); | |||
| // Session api | |||
| virtual jack_session_command_t *SessionNotify(const char *target, jack_session_event_type_t type, const char *path); | |||
| virtual int SessionReply(jack_session_event_t *ev); | |||
| char* GetUUIDForClientName(const char* client_name); | |||
| char* GetClientNameForUUID(const char* uuid); | |||
| int ReserveClientName(const char *name, const char* uuid); | |||
| // Session API | |||
| virtual jack_session_command_t* SessionNotify(const char* target, jack_session_event_type_t type, const char* path); | |||
| virtual int SessionReply(jack_session_event_t* ev); | |||
| char* GetUUIDForClientName(const char* client_name); | |||
| char* GetClientNameByUUID(const char* uuid); | |||
| int ReserveClientName(const char* client_name, const char* uuid); | |||
| int ClientHasSessionCallback(const char* client_name); | |||
| // JackRunnableInterface interface | |||
| bool Init(); | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -25,8 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackPort.h" | |||
| #include "JackSynchro.h" | |||
| #include "JackNotification.h" | |||
| #include "jack/session.h" | |||
| #include "session.h" | |||
| namespace Jack | |||
| { | |||
| @@ -74,6 +73,7 @@ struct JackClientControl : public JackShmMemAble | |||
| fCallback[kAddClient] = true; | |||
| fCallback[kRemoveClient] = true; | |||
| fCallback[kActivateClient] = true; | |||
| fCallback[kLatencyCallback] = true; | |||
| // So that driver synchro are correctly setup in "flush" or "normal" mode | |||
| fCallback[kStartFreewheelCallback] = true; | |||
| fCallback[kStopFreewheelCallback] = true; | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackEngineControl.h" | |||
| #include "JackGlobals.h" | |||
| #include "JackError.h" | |||
| #include <set> | |||
| #include <iostream> | |||
| #include <assert.h> | |||
| @@ -246,7 +247,7 @@ int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro | |||
| int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) | |||
| { | |||
| jack_time_t current_date = GetMicroSeconds(); | |||
| const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum); | |||
| const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum); | |||
| int res = 0; | |||
| // Update state and timestamp of current client | |||
| @@ -256,7 +257,7 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* | |||
| for (int i = 0; i < CLIENT_NUM; i++) { | |||
| // Signal connected clients or drivers | |||
| if (outputRef[i] > 0) { | |||
| if (output_ref[i] > 0) { | |||
| // Update state and timestamp of destination clients | |||
| timing[i].fStatus = Triggered; | |||
| @@ -272,6 +273,44 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* | |||
| return res; | |||
| } | |||
| static bool HasNoConnection(jack_int_t* table) | |||
| { | |||
| for (int ref = 0; ref < CLIENT_NUM; ref++) { | |||
| if (table[ref] > 0) return false; | |||
| } | |||
| return true; | |||
| } | |||
| // Using http://en.wikipedia.org/wiki/Topological_sorting | |||
| void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted) | |||
| { | |||
| JackFixedMatrix<CLIENT_NUM> tmp; | |||
| std::set<jack_int_t> level; | |||
| fConnectionRef.Copy(tmp); | |||
| // Inputs of the graph | |||
| level.insert(AUDIO_DRIVER_REFNUM); | |||
| level.insert(FREEWHEEL_DRIVER_REFNUM); | |||
| while (level.size() > 0) { | |||
| jack_int_t refnum = *level.begin(); | |||
| sorted.push_back(refnum); | |||
| level.erase(level.begin()); | |||
| const jack_int_t* output_ref1 = tmp.GetItems(refnum); | |||
| for (int dst = 0; dst < CLIENT_NUM; dst++) { | |||
| if (output_ref1[dst] > 0) { | |||
| tmp.ClearItem(refnum, dst); | |||
| jack_int_t output_ref2[CLIENT_NUM]; | |||
| tmp.GetOutputTable1(dst, output_ref2); | |||
| if (HasNoConnection(output_ref2)) | |||
| level.insert(dst); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /*! | |||
| \brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated. | |||
| */ | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackActivationCount.h" | |||
| #include "JackError.h" | |||
| #include "JackCompilerDeps.h" | |||
| #include <vector> | |||
| #include <assert.h> | |||
| namespace Jack | |||
| @@ -151,7 +151,7 @@ class JackFixedArray1 : public JackFixedArray<SIZE> | |||
| return true; | |||
| } | |||
| } | |||
| } POST_PACKED_STRUCTURE; | |||
| /*! | |||
| @@ -200,6 +200,11 @@ class JackFixedMatrix | |||
| return fTable[index1][index2]; | |||
| } | |||
| void ClearItem(jack_int_t index1, jack_int_t index2) | |||
| { | |||
| fTable[index1][index2] = 0; | |||
| } | |||
| /*! | |||
| \brief Get the output indexes of a given index. | |||
| */ | |||
| @@ -218,6 +223,13 @@ class JackFixedMatrix | |||
| } | |||
| } | |||
| void GetOutputTable1(jack_int_t index, jack_int_t* output) const | |||
| { | |||
| for (int i = 0; i < SIZE; i++) { | |||
| output[i] = fTable[i][index]; | |||
| } | |||
| } | |||
| bool IsInsideTable(jack_int_t index, jack_int_t* output) const | |||
| { | |||
| for (int i = 0; i < SIZE && output[i] != EMPTY; i++) { | |||
| @@ -227,6 +239,14 @@ class JackFixedMatrix | |||
| return false; | |||
| } | |||
| void Copy(JackFixedMatrix& copy) | |||
| { | |||
| for (int i = 0; i < SIZE; i++) { | |||
| memcpy(copy.fTable[i], fTable[i], sizeof(jack_int_t) * SIZE); | |||
| } | |||
| } | |||
| } POST_PACKED_STRUCTURE; | |||
| /*! | |||
| @@ -359,7 +379,7 @@ struct JackClientTiming | |||
| } | |||
| ~JackClientTiming() | |||
| {} | |||
| void Init() | |||
| { | |||
| fSignaledAt = 0; | |||
| @@ -367,7 +387,7 @@ struct JackClientTiming | |||
| fFinishedAt = 0; | |||
| fStatus = NotTriggered; | |||
| } | |||
| } POST_PACKED_STRUCTURE; | |||
| /*! | |||
| @@ -375,11 +395,9 @@ struct JackClientTiming | |||
| <UL> | |||
| <LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port. | |||
| <LI>The <B>fConnectionCount</B> array contains the number of connected ports to a given port. | |||
| <LI>The <B>fInputPort</B> array contains the list (array line) of input connected ports for a given client. | |||
| <LI>The <B>fOutputPort</B> array contains the list (array line) of ouput connected ports for a given client. | |||
| <LI>The <B>fConnectionRef</B> array contains the number of ports connected between two clients. | |||
| <LI>The <B>fInputRef</B> array contains the number of input clients connected to a given client. | |||
| <LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose. | |||
| </UL> | |||
| */ | |||
| @@ -461,7 +479,8 @@ class SERVER_EXPORT JackConnectionManager | |||
| void ResetGraph(JackClientTiming* timing); | |||
| int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing); | |||
| int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec); | |||
| void TopologicalSort(std::vector<jack_int_t>& sorted); | |||
| } POST_PACKED_STRUCTURE; | |||
| } // end of namespace | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -116,17 +116,17 @@ int JackDebugClient::Close() | |||
| void JackDebugClient::CheckClient(const char* function_name) const | |||
| { | |||
| *fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl; | |||
| if (fIsClosed > 0) { | |||
| *fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl; | |||
| *fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl; | |||
| *fStream << "This is likely to cause crash !'" << endl; | |||
| #ifdef __APPLE__ | |||
| // Debugger(); | |||
| #endif | |||
| #endif | |||
| } | |||
| } | |||
| pthread_t JackDebugClient::GetThreadID() | |||
| jack_native_thread_t JackDebugClient::GetThreadID() | |||
| { | |||
| CheckClient("GetThreadID"); | |||
| return fClient->GetThreadID(); | |||
| @@ -428,7 +428,7 @@ void JackDebugClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *ar | |||
| CheckClient("OnInfoShutdown"); | |||
| fClient->OnInfoShutdown(callback, arg); | |||
| } | |||
| int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) | |||
| { | |||
| JackDebugClient* client = (JackDebugClient*)arg; | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -84,7 +84,7 @@ class JackDebugClient : public JackClient | |||
| int SetBufferSize(jack_nframes_t buffer_size); | |||
| int SetFreeWheel(int onoff); | |||
| void ShutDown(); | |||
| pthread_t GetThreadID(); | |||
| jack_native_thread_t GetThreadID(); | |||
| // Port management | |||
| int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); | |||
| @@ -167,7 +167,7 @@ int JackDriver::Open(jack_nframes_t buffer_size, | |||
| int JackDriver::Close() | |||
| { | |||
| if (fClientControl.fRefNum >= 0) { | |||
| if (fClientControl.fRefNum >= 0) { | |||
| jack_log("JackDriver::Close"); | |||
| fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync | |||
| fClientControl.fActive = false; | |||
| @@ -207,7 +207,7 @@ int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
| jack_log("JackDriver::kStopFreewheel"); | |||
| SetupDriverSync(fClientControl.fRefNum, false); | |||
| break; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -223,13 +223,13 @@ void JackDriver::CycleIncTime() | |||
| } | |||
| void JackDriver::CycleTakeBeginTime() | |||
| { | |||
| { | |||
| fBeginDateUst = GetMicroSeconds(); // Take callback date here | |||
| fEngineControl->CycleIncTime(fBeginDateUst); | |||
| } | |||
| void JackDriver::CycleTakeEndTime() | |||
| { | |||
| { | |||
| fEndDateUst = GetMicroSeconds(); // Take end date here | |||
| } | |||
| @@ -254,7 +254,7 @@ void JackDriver::NotifySampleRate(jack_nframes_t sample_rate) | |||
| fEngine->NotifySampleRate(sample_rate); | |||
| fEngineControl->InitFrameTime(); | |||
| } | |||
| void JackDriver::NotifyFailure(int code, const char* reason) | |||
| { | |||
| fEngine->NotifyFailure(code, reason); | |||
| @@ -1,21 +1,21 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-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. | |||
| */ | |||
| #ifndef __JackDriver__ | |||
| @@ -30,27 +30,27 @@ | |||
| namespace Jack | |||
| { | |||
| class JackLockedEngine; | |||
| class JackGraphManager; | |||
| struct JackEngineControl; | |||
| /*! | |||
| \brief The base interface for drivers. | |||
| */ | |||
| class SERVER_EXPORT JackDriverInterface | |||
| { | |||
| public: | |||
| JackDriverInterface() | |||
| {} | |||
| virtual ~JackDriverInterface() | |||
| {} | |||
| virtual int Open() = 0; | |||
| virtual int Open (bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| @@ -60,7 +60,7 @@ class SERVER_EXPORT JackDriverInterface | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) = 0; | |||
| virtual int Open(jack_nframes_t buffer_size, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| @@ -72,30 +72,30 @@ class SERVER_EXPORT JackDriverInterface | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) = 0; | |||
| virtual int Attach() = 0; | |||
| virtual int Detach() = 0; | |||
| virtual int Read() = 0; | |||
| virtual int Write() = 0; | |||
| virtual int Start() = 0; | |||
| virtual int Stop() = 0; | |||
| virtual bool IsFixedBufferSize() = 0; | |||
| virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; | |||
| virtual int SetSampleRate(jack_nframes_t sample_rate) = 0; | |||
| virtual int Process() = 0; | |||
| virtual int ProcessNull() = 0; | |||
| virtual void SetMaster(bool onoff) = 0; | |||
| virtual bool GetMaster() = 0; | |||
| virtual void AddSlave(JackDriverInterface* slave) = 0; | |||
| virtual void RemoveSlave(JackDriverInterface* slave) = 0; | |||
| virtual std::list<JackDriverInterface*> GetSlaves() = 0; | |||
| virtual int ProcessSlaves() = 0; | |||
| virtual bool IsRealTime() const = 0; | |||
| }; | |||
| @@ -109,16 +109,16 @@ class SERVER_EXPORT JackDriverClientInterface : public JackDriverInterface, publ | |||
| /*! | |||
| \brief The base class for drivers. | |||
| */ | |||
| #define CaptureDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive) | |||
| #define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive) | |||
| #define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsActive) | |||
| #define CaptureDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal) | |||
| #define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal) | |||
| #define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput) | |||
| class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| { | |||
| protected: | |||
| char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| char fAliasName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| @@ -134,27 +134,27 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| JackClientControl fClientControl; | |||
| std::list<JackDriverInterface*> fSlaveList; | |||
| bool fIsMaster; | |||
| void CycleIncTime(); | |||
| void CycleTakeBeginTime(); | |||
| void CycleTakeEndTime(); | |||
| void SetupDriverSync(int ref, bool freewheel); | |||
| void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver | |||
| void NotifyBufferSize(jack_nframes_t buffer_size); // BufferSize notification sent by the driver | |||
| void NotifySampleRate(jack_nframes_t sample_rate); // SampleRate notification sent by the driver | |||
| void NotifyFailure(int code, const char* reason); // Failure notification sent by the driver | |||
| public: | |||
| JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | |||
| JackDriver(); | |||
| virtual ~JackDriver(); | |||
| void SetMaster(bool onoff); | |||
| bool GetMaster(); | |||
| void AddSlave(JackDriverInterface* slave); | |||
| void RemoveSlave(JackDriverInterface* slave); | |||
| std::list<JackDriverInterface*> GetSlaves() | |||
| @@ -162,9 +162,9 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| return fSlaveList; | |||
| } | |||
| int ProcessSlaves(); | |||
| virtual int Open(); | |||
| virtual int Open (bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| @@ -174,7 +174,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| virtual int Open(jack_nframes_t buffer_size, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| @@ -187,31 +187,31 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| virtual int Close(); | |||
| virtual int Process(); | |||
| virtual int ProcessNull(); | |||
| virtual int Attach(); | |||
| virtual int Detach(); | |||
| virtual int Read(); | |||
| virtual int Write(); | |||
| virtual int Start(); | |||
| virtual int Stop(); | |||
| virtual bool IsFixedBufferSize(); | |||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
| virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
| virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | |||
| virtual JackClientControl* GetClientControl() const; | |||
| virtual bool IsRealTime() const; | |||
| virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one | |||
| virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one | |||
| }; | |||
| } // end of namespace | |||
| #endif | |||
| @@ -56,6 +56,12 @@ int JackDummyDriver::Open(jack_nframes_t buffer_size, | |||
| fEngineControl->fPeriod = 0; | |||
| fEngineControl->fComputation = 500 * 1000; | |||
| fEngineControl->fConstraint = 500 * 1000; | |||
| int buffer_size = int((fWaitTime * fEngineControl->fSampleRate) / 1000000.0f); | |||
| if (buffer_size > BUFFER_SIZE_MAX) { | |||
| buffer_size = BUFFER_SIZE_MAX; | |||
| jack_error("Buffer size set to %d ", BUFFER_SIZE_MAX); | |||
| } | |||
| SetBufferSize(buffer_size); | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include <iostream> | |||
| #include <fstream> | |||
| #include <set> | |||
| #include <assert.h> | |||
| #include "JackSystemDeps.h" | |||
| @@ -90,7 +91,7 @@ int JackEngine::Close() | |||
| return 0; | |||
| } | |||
| void JackEngine::NotifyQuit() | |||
| { | |||
| fChannel.NotifyQuit(); | |||
| @@ -137,8 +138,10 @@ void JackEngine::ReleaseRefnum(int ref) | |||
| void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) | |||
| { | |||
| fLastSwitchUsecs = cur_cycle_begin; | |||
| if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state | |||
| if (fGraphManager->RunNextGraph()) { // True if the graph actually switched to a new state | |||
| fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0); | |||
| //NotifyGraphReorder(); | |||
| } | |||
| fSignal.Signal(); // Signal for threads waiting for next cycle | |||
| } | |||
| @@ -195,16 +198,44 @@ void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions | |||
| if (status != NotTriggered && status != Finished) { | |||
| jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status); | |||
| fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | |||
| //NotifyXRun(ALL_CLIENTS); | |||
| } | |||
| if (status == Finished && (long)(finished_date - callback_usecs) > 0) { | |||
| jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName); | |||
| fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | |||
| //NotifyXRun(ALL_CLIENTS); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| int JackEngine::ComputeTotalLatencies() | |||
| { | |||
| std::vector<jack_int_t> sorted; | |||
| std::vector<jack_int_t>::iterator it; | |||
| std::vector<jack_int_t>::reverse_iterator rit; | |||
| fGraphManager->TopologicalSort(sorted); | |||
| /* iterate over all clients in graph order, and emit | |||
| * capture latency callback. | |||
| */ | |||
| for (it = sorted.begin(); it != sorted.end(); it++) { | |||
| jack_log("Sorted %d", *it); | |||
| NotifyClient(*it, kLatencyCallback, true, "", 0, 0); | |||
| } | |||
| /* now issue playback latency callbacks in reverse graph order. | |||
| */ | |||
| for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) { | |||
| NotifyClient(*rit, kLatencyCallback, true, "", 1, 0); | |||
| } | |||
| return 0; | |||
| } | |||
| //--------------- | |||
| // Notifications | |||
| //--------------- | |||
| @@ -215,8 +246,8 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, const char* messa | |||
| // The client may be notified by the RT thread while closing | |||
| if (client) { | |||
| if (client && client->GetClientControl()->fCallback[event]) { | |||
| if (client->GetClientControl()->fCallback[event]) { | |||
| /* | |||
| Important for internal clients : unlock before calling the notification callbacks. | |||
| */ | |||
| @@ -225,7 +256,7 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, const char* messa | |||
| jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2); | |||
| if (res) | |||
| fMutex.Lock(); | |||
| } else { | |||
| jack_log("JackEngine::NotifyClient: no callback for event = %ld", event); | |||
| } | |||
| @@ -277,6 +308,7 @@ void JackEngine::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
| // Use the audio thread => request thread communication channel | |||
| fEngineControl->NotifyXRun(callback_usecs, delayed_usecs); | |||
| fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); | |||
| //NotifyXRun(ALL_CLIENTS); | |||
| } | |||
| void JackEngine::NotifyXRun(int refnum) | |||
| @@ -290,6 +322,7 @@ void JackEngine::NotifyXRun(int refnum) | |||
| void JackEngine::NotifyGraphReorder() | |||
| { | |||
| ComputeTotalLatencies(); | |||
| NotifyClients(kGraphOrderCallback, false, "", 0, 0); | |||
| } | |||
| @@ -307,7 +340,7 @@ void JackEngine::NotifyFailure(int code, const char* reason) | |||
| { | |||
| NotifyClients(kShutDownCallback, false, reason, code, 0); | |||
| } | |||
| void JackEngine::NotifyFreewheel(bool onoff) | |||
| { | |||
| if (onoff) { | |||
| @@ -406,7 +439,7 @@ int JackEngine::ClientCheck(const char* name, int uuid, char* name_res, int prot | |||
| std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | |||
| if (res != fReservationMap.end()) { | |||
| strncpy( name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE ); | |||
| strncpy(name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE); | |||
| } else if (ClientCheckName(name)) { | |||
| *status |= JackNameNotUnique; | |||
| @@ -467,7 +500,7 @@ bool JackEngine::ClientCheckName(const char* name) | |||
| return true; | |||
| } | |||
| for (std::map<int,std::string>::iterator i=fReservationMap.begin(); i!=fReservationMap.end(); i++) { | |||
| for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) { | |||
| if (i->second == name) | |||
| return true; | |||
| } | |||
| @@ -522,14 +555,14 @@ int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref | |||
| if (uuid < 0) { | |||
| uuid = GetNewUUID(); | |||
| strncpy( real_name, name, JACK_CLIENT_NAME_SIZE ); | |||
| strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); | |||
| } else { | |||
| std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | |||
| if (res != fReservationMap.end()) { | |||
| strncpy( real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE ); | |||
| strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE); | |||
| fReservationMap.erase(uuid); | |||
| } else { | |||
| strncpy( real_name, name, JACK_CLIENT_NAME_SIZE ); | |||
| strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); | |||
| } | |||
| EnsureUUID(uuid); | |||
| @@ -689,7 +722,7 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time) | |||
| { | |||
| JackClientInterface* client = fClientTable[refnum]; | |||
| jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); | |||
| if (is_real_time) | |||
| fGraphManager->Activate(refnum); | |||
| @@ -702,18 +735,10 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time) | |||
| jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; | |||
| fGraphManager->GetInputPorts(refnum, input_ports); | |||
| fGraphManager->GetOutputPorts(refnum, output_ports); | |||
| // First add port state to JackPortIsActive | |||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
| fGraphManager->ActivatePort(input_ports[i]); | |||
| } | |||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { | |||
| fGraphManager->ActivatePort(output_ports[i]); | |||
| } | |||
| // Notify client | |||
| NotifyActivate(refnum); | |||
| // Then issue port registration notification | |||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
| NotifyPortRegistation(input_ports[i], true); | |||
| @@ -740,13 +765,11 @@ int JackEngine::ClientDeactivate(int refnum) | |||
| // First disconnect all ports and remove their JackPortIsActive state | |||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
| PortDisconnect(refnum, input_ports[i], ALL_PORTS); | |||
| fGraphManager->DeactivatePort(input_ports[i]); | |||
| } | |||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { | |||
| PortDisconnect(refnum, output_ports[i], ALL_PORTS); | |||
| fGraphManager->DeactivatePort(output_ports[i]); | |||
| } | |||
| // Then issue port registration notification | |||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
| NotifyPortRegistation(input_ports[i], false); | |||
| @@ -867,7 +890,7 @@ int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst) | |||
| int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst) | |||
| { | |||
| jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst); | |||
| if (dst == ALL_PORTS) { | |||
| jack_int_t connections[CONNECTION_NUM_FOR_PORT]; | |||
| @@ -910,6 +933,10 @@ int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name) | |||
| return 0; | |||
| } | |||
| //-------------------- | |||
| // Session management | |||
| //-------------------- | |||
| void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket) | |||
| { | |||
| if (fSessionPendingReplies != 0) { | |||
| @@ -940,11 +967,11 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||
| char path_buf[JACK_PORT_NAME_SIZE]; | |||
| snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR ); | |||
| int res = JackTools::MkDir(path_buf); | |||
| if (res) | |||
| if (res) | |||
| jack_error( "JackEngine::SessionNotify: can not create session directory '%s'", path_buf ); | |||
| int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int) type, 0); | |||
| if (result == 2) { | |||
| @@ -952,9 +979,9 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||
| } else if (result == 1) { | |||
| char uuid_buf[JACK_UUID_SIZE]; | |||
| snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID ); | |||
| fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf, | |||
| fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf, | |||
| client->GetClientControl()->fName, | |||
| client->GetClientControl()->fSessionCommand, | |||
| client->GetClientControl()->fSessionCommand, | |||
| client->GetClientControl()->fSessionFlags )); | |||
| } | |||
| } | |||
| @@ -973,11 +1000,11 @@ void JackEngine::SessionReply(int refnum) | |||
| { | |||
| JackClientInterface* client = fClientTable[refnum]; | |||
| char uuid_buf[JACK_UUID_SIZE]; | |||
| snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID ); | |||
| fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf, | |||
| client->GetClientControl()->fName, | |||
| client->GetClientControl()->fSessionCommand, | |||
| client->GetClientControl()->fSessionFlags )); | |||
| snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID); | |||
| fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf, | |||
| client->GetClientControl()->fName, | |||
| client->GetClientControl()->fSessionCommand, | |||
| client->GetClientControl()->fSessionFlags)); | |||
| fSessionPendingReplies -= 1; | |||
| if (fSessionPendingReplies == 0) { | |||
| @@ -998,9 +1025,8 @@ void JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res, i | |||
| return; | |||
| } | |||
| } | |||
| // did not find name. | |||
| // Did not find name. | |||
| *result = -1; | |||
| return; | |||
| } | |||
| void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *result) | |||
| @@ -1020,18 +1046,17 @@ void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *res | |||
| return; | |||
| } | |||
| } | |||
| // did not find uuid. | |||
| // Did not find uuid. | |||
| *result = -1; | |||
| return; | |||
| } | |||
| void JackEngine::ReserveClientName(const char *name, const char *uuid, int *result) | |||
| { | |||
| jack_log( "JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid ); | |||
| jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid); | |||
| if (ClientCheckName(name)) { | |||
| *result = -1; | |||
| jack_log( "name already taken" ); | |||
| jack_log("name already taken"); | |||
| return; | |||
| } | |||
| @@ -1040,5 +1065,21 @@ void JackEngine::ReserveClientName(const char *name, const char *uuid, int *resu | |||
| *result = 0; | |||
| } | |||
| void JackEngine::ClientHasSessionCallbackRequest(const char *name, int *result) | |||
| { | |||
| JackClientInterface* client = NULL; | |||
| for (int i = 0; i < CLIENT_NUM; i++) { | |||
| JackClientInterface* client = fClientTable[i]; | |||
| if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) | |||
| break; | |||
| } | |||
| if (client) { | |||
| *result = client->GetClientControl()->fCallback[kSessionCallback]; | |||
| } else { | |||
| *result = -1; | |||
| } | |||
| } | |||
| } // end of namespace | |||
| @@ -129,6 +129,8 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
| int PortRename(int refnum, jack_port_id_t port, const char* name); | |||
| int ComputeTotalLatencies(); | |||
| // Graph | |||
| bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | |||
| @@ -142,12 +144,14 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
| void NotifyFreewheel(bool onoff); | |||
| void NotifyQuit(); | |||
| void SessionNotify( int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket ); | |||
| void SessionReply( int refnum ); | |||
| // Session management | |||
| void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket); | |||
| void SessionReply(int refnum); | |||
| void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result); | |||
| void GetClientNameForUUID(const char *uuid, char *name_res, int *result); | |||
| void ReserveClientName(const char *name, const char *uuid, int *result); | |||
| void ClientHasSessionCallbackRequest(const char *name, int *result); | |||
| }; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -33,39 +33,39 @@ static inline jack_time_t JACK_MAX(jack_time_t a, jack_time_t b) | |||
| return (a < b) ? b : a; | |||
| } | |||
| void JackEngineControl::CalcCPULoad(JackClientInterface** table, | |||
| JackGraphManager* manager, | |||
| jack_time_t cur_cycle_begin, | |||
| void JackEngineControl::CalcCPULoad(JackClientInterface** table, | |||
| JackGraphManager* manager, | |||
| jack_time_t cur_cycle_begin, | |||
| jack_time_t prev_cycle_end) | |||
| { | |||
| fPrevCycleTime = fCurCycleTime; | |||
| fCurCycleTime = cur_cycle_begin; | |||
| jack_time_t last_cycle_end = prev_cycle_end; | |||
| // In Asynchronous mode, last cycle end is the max of client end dates | |||
| if (!fSyncMode) { | |||
| for (int i = fDriverNum; i < CLIENT_NUM; i++) { | |||
| JackClientInterface* client = table[i]; | |||
| JackClientTiming* timing = manager->GetClientTiming(i); | |||
| if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | |||
| if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | |||
| last_cycle_end = JACK_MAX(last_cycle_end, timing->fFinishedAt); | |||
| } | |||
| } | |||
| // Store the execution time for later averaging | |||
| // Store the execution time for later averaging | |||
| fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime; | |||
| if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||
| if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||
| fRollingClientUsecsIndex = 0; | |||
| // Every so often, recompute the current maximum use over the | |||
| // last JACK_ENGINE_ROLLING_COUNT client iterations. | |||
| if (++fRollingClientUsecsCnt % fRollingInterval == 0) { | |||
| jack_time_t max_usecs = 0; | |||
| for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) | |||
| for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) | |||
| max_usecs = JACK_MAX(fRollingClientUsecs[i], max_usecs); | |||
| fMaxUsecs = JACK_MAX(fMaxUsecs, max_usecs); | |||
| fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0); | |||
| fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f)); | |||
| @@ -80,7 +80,7 @@ void JackEngineControl::ResetRollingUsecs() | |||
| fSpareUsecs = 0; | |||
| fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs)); | |||
| } | |||
| void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
| { | |||
| ResetFrameTime(callback_usecs); | |||
| @@ -88,5 +88,5 @@ void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_use | |||
| if (delayed_usecs > fMaxDelayedUsecs) | |||
| fMaxDelayedUsecs = delayed_usecs; | |||
| } | |||
| } // end of namespace | |||
| @@ -7,12 +7,12 @@ | |||
| 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. | |||
| @@ -25,7 +25,6 @@ | |||
| #include <string.h> | |||
| #include <errno.h> | |||
| #include "JackCompilerDeps.h" | |||
| #include "types.h" | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| @@ -44,17 +43,17 @@ extern "C" | |||
| EXPORT extern void (*jack_error_callback)(const char *desc); | |||
| EXPORT extern void (*jack_info_callback)(const char *desc); | |||
| EXPORT extern void default_jack_error_callback(const char *desc); | |||
| EXPORT extern void default_jack_info_callback(const char *desc); | |||
| EXPORT extern void silent_jack_error_callback(const char *desc); | |||
| EXPORT extern void silent_jack_info_callback(const char *desc); | |||
| typedef void (* jack_log_function_t)(int level, const char *message); | |||
| void jack_log_function(int level, const char *message); | |||
| EXPORT int set_threaded_log_function(); | |||
| #ifdef __cplusplus | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -36,9 +36,9 @@ class SERVER_EXPORT JackTimer | |||
| { | |||
| friend class JackFrameTimer; | |||
| private: | |||
| private: | |||
| jack_nframes_t fFrames; | |||
| jack_time_t fCurrentWakeup; | |||
| jack_time_t fCurrentCallback; | |||
| @@ -47,21 +47,21 @@ class SERVER_EXPORT JackTimer | |||
| float fFilterCoefficient; /* set once, never altered */ | |||
| bool fInitialized; | |||
| public: | |||
| public: | |||
| JackTimer(); | |||
| ~JackTimer() | |||
| {} | |||
| jack_nframes_t Time2Frames(jack_time_t time, jack_nframes_t buffer_size); | |||
| jack_time_t Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size); | |||
| jack_nframes_t FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate); | |||
| jack_nframes_t CurFrame() | |||
| { | |||
| return fFrames; | |||
| } | |||
| jack_time_t CurTime() | |||
| { | |||
| return fCurrentWakeup; | |||
| @@ -75,7 +75,7 @@ class SERVER_EXPORT JackTimer | |||
| class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | |||
| { | |||
| private: | |||
| bool fFirstWakeUp; | |||
| @@ -93,7 +93,7 @@ class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | |||
| void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs); | |||
| void IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs); | |||
| void ReadFrameTime(JackTimer* timer); | |||
| } POST_PACKED_STRUCTURE; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -37,7 +37,7 @@ static void AssertBufferSize(jack_nframes_t buffer_size) | |||
| assert(buffer_size <= BUFFER_SIZE_MAX); | |||
| } | |||
| } | |||
| void JackGraphManager::AssertPort(jack_port_id_t port_index) | |||
| { | |||
| if (port_index >= fPortMax) { | |||
| @@ -45,7 +45,7 @@ void JackGraphManager::AssertPort(jack_port_id_t port_index) | |||
| assert(port_index < fPortMax); | |||
| } | |||
| } | |||
| JackGraphManager* JackGraphManager::Allocate(int port_max) | |||
| { | |||
| // Using "Placement" new | |||
| @@ -59,18 +59,18 @@ void JackGraphManager::Destroy(JackGraphManager* manager) | |||
| manager->~JackGraphManager(); | |||
| JackShmMem::operator delete(manager); | |||
| } | |||
| JackGraphManager::JackGraphManager(int port_max) | |||
| JackGraphManager::JackGraphManager(int port_max) | |||
| { | |||
| assert(port_max <= PORT_NUM_MAX); | |||
| for (int i = 0; i < port_max; i++) { | |||
| fPortArray[i].Release(); | |||
| } | |||
| fPortMax = port_max; | |||
| } | |||
| JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) | |||
| { | |||
| AssertPort(port_index); | |||
| @@ -127,6 +127,19 @@ int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* tab | |||
| return manager->SuspendRefNum(control, table, fClientTiming, usec); | |||
| } | |||
| void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& sorted) | |||
| { | |||
| UInt16 cur_index; | |||
| UInt16 next_index; | |||
| do { | |||
| cur_index = GetCurrentIndex(); | |||
| sorted.clear(); | |||
| ReadCurrentState()->TopologicalSort(sorted); | |||
| next_index = GetCurrentIndex(); | |||
| } while (cur_index != next_index); // Until a coherent state has been read | |||
| } | |||
| // Server | |||
| void JackGraphManager::DirectConnect(int ref1, int ref2) | |||
| { | |||
| @@ -176,14 +189,14 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff | |||
| jack_int_t len = manager->Connections(port_index); | |||
| // No connections : return a zero-filled buffer | |||
| if (len == 0) { | |||
| if (len == 0) { | |||
| port->ClearBuffer(buffer_size); | |||
| return port->GetBuffer(); | |||
| // One connection | |||
| } else if (len == 1) { | |||
| } else if (len == 1) { | |||
| jack_port_id_t src_index = manager->GetPort(port_index, 0); | |||
| // Ports in same client : copy the buffer | |||
| if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) { | |||
| void* buffers[1]; | |||
| @@ -194,10 +207,10 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff | |||
| } else { | |||
| return GetBuffer(src_index, buffer_size); | |||
| } | |||
| // Multiple connections : mix all buffers | |||
| } else { | |||
| } else { | |||
| const jack_int_t* connections = manager->GetConnections(port_index); | |||
| void* buffers[CONNECTION_NUM_FOR_PORT]; | |||
| jack_port_id_t src_index; | |||
| @@ -220,10 +233,10 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C | |||
| JackPort* port = GetPort(port_index); | |||
| /** | |||
| jackd.h | |||
| jackd.h | |||
| * If @ref JackPortCanMonitor is set for this @a port, turn input | |||
| * monitoring on or off. Otherwise, do nothing. | |||
| if (!(fFlags & JackPortCanMonitor)) | |||
| return -1; | |||
| */ | |||
| @@ -245,7 +258,7 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C | |||
| // Client | |||
| jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count) | |||
| { | |||
| const jack_int_t* connections = manager->GetConnections(port_index); | |||
| const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); | |||
| jack_nframes_t max_latency = 0; | |||
| jack_port_id_t dst_index; | |||
| @@ -296,6 +309,46 @@ int JackGraphManager::ComputeTotalLatencies() | |||
| return 0; | |||
| } | |||
| void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode) | |||
| { | |||
| const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); | |||
| JackPort* port = GetPort(port_index); | |||
| jack_latency_range_t latency = { UINT32_MAX, 0 }; | |||
| jack_port_id_t dst_index; | |||
| for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) { | |||
| AssertPort(dst_index); | |||
| JackPort* dst_port = GetPort(dst_index); | |||
| jack_latency_range_t other_latency; | |||
| dst_port->GetLatencyRange(mode, &other_latency); | |||
| if (other_latency.max > latency.max) | |||
| latency.max = other_latency.max; | |||
| if (other_latency.min < latency.min) | |||
| latency.min = other_latency.min; | |||
| } | |||
| if (latency.min == UINT32_MAX) | |||
| latency.min = 0; | |||
| port->SetLatencyRange(mode, &latency); | |||
| } | |||
| void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode) | |||
| { | |||
| UInt16 cur_index; | |||
| UInt16 next_index; | |||
| do { | |||
| cur_index = GetCurrentIndex(); | |||
| RecalculateLatencyAux(port_index, mode); | |||
| next_index = GetCurrentIndex(); | |||
| } while (cur_index != next_index); // Until a coherent state has been read | |||
| jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index); | |||
| } | |||
| // Server | |||
| void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size) | |||
| { | |||
| @@ -376,18 +429,6 @@ int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index) | |||
| return res; | |||
| } | |||
| void JackGraphManager::ActivatePort(jack_port_id_t port_index) | |||
| { | |||
| JackPort* port = GetPort(port_index); | |||
| port->fFlags = (JackPortFlags)(port->fFlags | JackPortIsActive); | |||
| } | |||
| void JackGraphManager::DeactivatePort(jack_port_id_t port_index) | |||
| { | |||
| JackPort* port = GetPort(port_index); | |||
| port->fFlags = (JackPortFlags)(port->fFlags & ~JackPortIsActive); | |||
| } | |||
| void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res) | |||
| { | |||
| JackConnectionManager* manager = WriteNextStateStart(); | |||
| @@ -430,7 +471,7 @@ void JackGraphManager::RemoveAllPorts(int refnum) | |||
| jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index); | |||
| assert(true); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| WriteNextStateStop(); | |||
| @@ -717,7 +758,7 @@ void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const c | |||
| const jack_int_t* connections = manager->GetConnections(port_index); | |||
| jack_int_t index; | |||
| int i; | |||
| // Cleanup connection array | |||
| memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT); | |||
| @@ -740,7 +781,7 @@ const char** JackGraphManager::GetConnections(jack_port_id_t port_index) | |||
| { | |||
| const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT); | |||
| UInt16 cur_index, next_index; | |||
| if (!res) | |||
| return NULL; | |||
| @@ -763,7 +804,7 @@ void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port | |||
| { | |||
| int match_cnt = 0; | |||
| regex_t port_regex, type_regex; | |||
| if (port_name_pattern && port_name_pattern[0]) { | |||
| regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB); | |||
| } | |||
| @@ -823,15 +864,15 @@ const char** JackGraphManager::GetPorts(const char* port_name_pattern, const cha | |||
| { | |||
| const char** res = (const char**)malloc(sizeof(char*) * fPortMax); | |||
| UInt16 cur_index, next_index; | |||
| if (!res) | |||
| return NULL; | |||
| do { | |||
| cur_index = GetCurrentIndex(); | |||
| GetPortsAux(res, port_name_pattern, type_name_pattern, flags); | |||
| next_index = GetCurrentIndex(); | |||
| } while (cur_index != next_index); // Until a coherent state has been read | |||
| } while (cur_index != next_index); // Until a coherent state has been read | |||
| if (res[0]) { // at least one port | |||
| return res; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -29,14 +29,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackPlatformPlug.h" | |||
| #include "JackSystemDeps.h" | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief Graph manager: contains the connection manager and the port array. | |||
| */ | |||
| class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState<JackConnectionManager> | |||
| { | |||
| @@ -53,6 +52,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
| float* GetBuffer(jack_port_id_t port_index); | |||
| void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames); | |||
| jack_nframes_t ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count); | |||
| void RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode); | |||
| public: | |||
| @@ -65,8 +65,6 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
| // Ports management | |||
| jack_port_id_t AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size); | |||
| int ReleasePort(int refnum, jack_port_id_t port_index); | |||
| void ActivatePort(jack_port_id_t port_index); | |||
| void DeactivatePort(jack_port_id_t port_index); | |||
| void GetInputPorts(int refnum, jack_int_t* res); | |||
| void GetOutputPorts(int refnum, jack_int_t* res); | |||
| void RemoveAllPorts(int refnum); | |||
| @@ -74,10 +72,13 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
| JackPort* GetPort(jack_port_id_t index); | |||
| jack_port_id_t GetPort(const char* name); | |||
| int ComputeTotalLatency(jack_port_id_t port_index); | |||
| int ComputeTotalLatencies(); | |||
| void RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode); | |||
| int RequestMonitor(jack_port_id_t port_index, bool onoff); | |||
| // Connections management | |||
| int Connect(jack_port_id_t src_index, jack_port_id_t dst_index); | |||
| int Disconnect(jack_port_id_t src_index, jack_port_id_t dst_index); | |||
| @@ -122,6 +123,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
| void InitRefNum(int refnum); | |||
| int ResumeRefNum(JackClientControl* control, JackSynchro* table); | |||
| int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs); | |||
| void TopologicalSort(std::vector<jack_int_t>& sorted); | |||
| JackClientTiming* GetClientTiming(int refnum) | |||
| { | |||
| @@ -130,7 +132,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
| void Save(JackConnectionManager* dst); | |||
| void Restore(JackConnectionManager* src); | |||
| static JackGraphManager* Allocate(int port_max); | |||
| static void Destroy(JackGraphManager* manager); | |||
| @@ -80,7 +80,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
| { | |||
| *result = fEngine->PortUnRegister(refnum, port_index); | |||
| } | |||
| void PortConnect(int refnum, const char* src, const char* dst, int* result) | |||
| { | |||
| *result = fEngine->PortConnect(refnum, src, dst); | |||
| @@ -89,7 +88,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
| { | |||
| *result = fEngine->PortDisconnect(refnum, src, dst); | |||
| } | |||
| void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) | |||
| { | |||
| *result = fEngine->PortConnect(refnum, src, dst); | |||
| @@ -111,10 +109,9 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
| { | |||
| *result = fServer->SetFreewheel(onoff); | |||
| } | |||
| void SessionNotify( int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t **result ) | |||
| void ComputeTotalLatencies(int* result) | |||
| { | |||
| *result = NULL; | |||
| *result = fEngine->ComputeTotalLatencies(); | |||
| } | |||
| void ReleaseTimebase(int refnum, int* result) | |||
| @@ -126,7 +123,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
| { | |||
| *result = fServer->SetTimebaseCallback(refnum, conditional); | |||
| } | |||
| void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | |||
| { | |||
| *result = fEngine->GetInternalClientName(int_ref, name_res); | |||
| @@ -139,7 +136,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
| void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) | |||
| { | |||
| *result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status); | |||
| *result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status); | |||
| } | |||
| void InternalClientUnload(int refnum, int int_ref, int* status, int* result) | |||
| @@ -147,6 +144,12 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
| *result = fEngine->InternalClientUnload(int_ref, status); | |||
| } | |||
| void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t** result) | |||
| { | |||
| *result = NULL; | |||
| } | |||
| }; | |||
| } // end of namespace | |||
| @@ -66,7 +66,7 @@ catch (...) { | |||
| \brief Locked Engine, access to methods is serialized using a mutex. | |||
| */ | |||
| class SERVER_EXPORT JackLockedEngine | |||
| class SERVER_EXPORT JackLockedEngine | |||
| { | |||
| private: | |||
| @@ -94,7 +94,7 @@ class SERVER_EXPORT JackLockedEngine | |||
| return fEngine.Close(); | |||
| CATCH_EXCEPTION_RETURN | |||
| } | |||
| // Client management | |||
| int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status) | |||
| { | |||
| @@ -226,6 +226,14 @@ class SERVER_EXPORT JackLockedEngine | |||
| CATCH_EXCEPTION_RETURN | |||
| } | |||
| int ComputeTotalLatencies() | |||
| { | |||
| TRY_CALL | |||
| JackLock lock(&fEngine); | |||
| return fEngine.ComputeTotalLatencies(); | |||
| CATCH_EXCEPTION_RETURN | |||
| } | |||
| // Graph | |||
| bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) | |||
| { | |||
| @@ -245,7 +253,7 @@ class SERVER_EXPORT JackLockedEngine | |||
| // RT : no lock | |||
| fEngine.NotifyXRun(refnum); | |||
| } | |||
| void NotifyGraphReorder() | |||
| { | |||
| TRY_CALL | |||
| @@ -298,7 +306,7 @@ class SERVER_EXPORT JackLockedEngine | |||
| return fEngine.GetClientRefNum(name); | |||
| CATCH_EXCEPTION_RETURN | |||
| } | |||
| void NotifyQuit() | |||
| { | |||
| TRY_CALL | |||
| @@ -314,7 +322,7 @@ class SERVER_EXPORT JackLockedEngine | |||
| fEngine.SessionNotify(refnum, target, type, path, socket); | |||
| CATCH_EXCEPTION | |||
| } | |||
| void SessionReply(int refnum) | |||
| { | |||
| TRY_CALL | |||
| @@ -322,7 +330,7 @@ class SERVER_EXPORT JackLockedEngine | |||
| fEngine.SessionReply(refnum); | |||
| CATCH_EXCEPTION | |||
| } | |||
| void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) | |||
| { | |||
| TRY_CALL | |||
| @@ -344,6 +352,14 @@ class SERVER_EXPORT JackLockedEngine | |||
| fEngine.ReserveClientName(name, uuid, result); | |||
| CATCH_EXCEPTION | |||
| } | |||
| void ClientHasSessionCallbackRequest(const char *name, int *result) | |||
| { | |||
| TRY_CALL | |||
| JackLock lock(&fEngine); | |||
| fEngine.ClientHasSessionCallbackRequest(name, result); | |||
| CATCH_EXCEPTION | |||
| } | |||
| }; | |||
| } // end of namespace | |||
| @@ -2,19 +2,19 @@ | |||
| * Copyright (C) 2004 Rui Nuno Capela, Steve Harris | |||
| * 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 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 | |||
| * along with this program; if not, write to the Free Software | |||
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| * | |||
| */ | |||
| @@ -34,7 +34,7 @@ JackMessageBuffer::JackMessageBuffer() | |||
| JackMessageBuffer::~JackMessageBuffer() | |||
| {} | |||
| void JackMessageBuffer::Start() | |||
| { | |||
| fRunning = true; | |||
| @@ -44,9 +44,9 @@ void JackMessageBuffer::Start() | |||
| void JackMessageBuffer::Stop() | |||
| { | |||
| if (fOverruns > 0) { | |||
| jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||
| jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||
| } else { | |||
| jack_log("no message buffer overruns"); | |||
| jack_log("no message buffer overruns"); | |||
| } | |||
| fGuard.Lock(); | |||
| fRunning = false; | |||
| @@ -55,7 +55,7 @@ void JackMessageBuffer::Stop() | |||
| fThread.Stop(); | |||
| Flush(); | |||
| } | |||
| void JackMessageBuffer::Flush() | |||
| { | |||
| while (fOutBuffer != fInBuffer) { | |||
| @@ -76,7 +76,7 @@ void JackMessageBuffer::AddMessage(int level, const char *message) | |||
| INC_ATOMIC(&fOverruns); | |||
| } | |||
| } | |||
| bool JackMessageBuffer::Execute() | |||
| { | |||
| while (fRunning) { | |||
| @@ -94,10 +94,10 @@ bool JackMessageBuffer::Execute() | |||
| Flush(); | |||
| fGuard.Unlock(); | |||
| } | |||
| return false; | |||
| return false; | |||
| } | |||
| void JackMessageBuffer::Create() | |||
| void JackMessageBuffer::Create() | |||
| { | |||
| if (fInstance == NULL) { | |||
| fInstance = new JackMessageBuffer(); | |||
| @@ -105,7 +105,7 @@ void JackMessageBuffer::Create() | |||
| } | |||
| } | |||
| void JackMessageBuffer::Destroy() | |||
| void JackMessageBuffer::Destroy() | |||
| { | |||
| if (fInstance != NULL) { | |||
| fInstance->Stop(); | |||
| @@ -114,7 +114,7 @@ void JackMessageBuffer::Destroy() | |||
| } | |||
| } | |||
| void JackMessageBufferAdd(int level, const char *message) | |||
| void JackMessageBufferAdd(int level, const char *message) | |||
| { | |||
| if (Jack::JackMessageBuffer::fInstance == NULL) { | |||
| /* Unable to print message with realtime safety. Complain and print it anyway. */ | |||
| @@ -137,7 +137,6 @@ void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *a | |||
| /* and we're done */ | |||
| fGuard.Unlock(); | |||
| } | |||
| }; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -133,11 +133,17 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count | |||
| mix->lost_events += event_count - events_done; | |||
| } | |||
| static size_t MidiBufferSize() | |||
| { | |||
| return BUFFER_SIZE_MAX * sizeof(float); | |||
| } | |||
| const JackPortType gMidiPortType = | |||
| { | |||
| JACK_DEFAULT_MIDI_TYPE, | |||
| MidiBufferInit, | |||
| MidiBufferMixdown | |||
| }; | |||
| { | |||
| JACK_DEFAULT_MIDI_TYPE, | |||
| MidiBufferSize, | |||
| MidiBufferInit, | |||
| MidiBufferMixdown | |||
| }; | |||
| } // namespace Jack | |||
| @@ -118,10 +118,10 @@ namespace Jack | |||
| //init and restart-------------------------------------------------------------------- | |||
| /* | |||
| JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves | |||
| JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves | |||
| as a "dummy driver, until Init method returns. | |||
| */ | |||
| bool JackNetDriver::Initialize() | |||
| { | |||
| jack_log("JackNetDriver::Initialize()"); | |||
| @@ -221,7 +221,7 @@ namespace Jack | |||
| void JackNetDriver::FreeAll() | |||
| { | |||
| FreePorts(); | |||
| delete[] fTxBuffer; | |||
| delete[] fRxBuffer; | |||
| delete fNetAudioCaptureBuffer; | |||
| @@ -230,7 +230,7 @@ namespace Jack | |||
| delete fNetMidiPlaybackBuffer; | |||
| delete[] fMidiCapturePortList; | |||
| delete[] fMidiPlaybackPortList; | |||
| fTxBuffer = NULL; | |||
| fRxBuffer = NULL; | |||
| fNetAudioCaptureBuffer = NULL; | |||
| @@ -239,7 +239,7 @@ namespace Jack | |||
| fNetMidiPlaybackBuffer = NULL; | |||
| fMidiCapturePortList = NULL; | |||
| fMidiPlaybackPortList = NULL; | |||
| #ifdef JACK_MONITOR | |||
| delete fNetTimeMon; | |||
| fNetTimeMon = NULL; | |||
| @@ -258,6 +258,7 @@ namespace Jack | |||
| unsigned long port_flags; | |||
| int audio_port_index; | |||
| uint midi_port_index; | |||
| jack_latency_range_t range; | |||
| //audio | |||
| port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; | |||
| @@ -274,7 +275,8 @@ namespace Jack | |||
| port = fGraphManager->GetPort ( port_id ); | |||
| port->SetAlias ( alias ); | |||
| //port latency | |||
| port->SetLatency ( fEngineControl->fBufferSize ); | |||
| range.min = range.max = fEngineControl->fBufferSize; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fCapturePortList[audio_port_index] = port_id; | |||
| jack_log ( "JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); | |||
| } | |||
| @@ -295,15 +297,16 @@ namespace Jack | |||
| switch ( fParams.fNetworkMode ) | |||
| { | |||
| case 'f' : | |||
| port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
| range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize; | |||
| break; | |||
| case 'n' : | |||
| port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
| range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
| break; | |||
| case 's' : | |||
| port->SetLatency ( 2 * fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
| range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
| break; | |||
| } | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| fPlaybackPortList[audio_port_index] = port_id; | |||
| jack_log ( "JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); | |||
| } | |||
| @@ -321,7 +324,8 @@ namespace Jack | |||
| } | |||
| port = fGraphManager->GetPort ( port_id ); | |||
| //port latency | |||
| port->SetLatency ( fEngineControl->fBufferSize ); | |||
| range.min = range.max = fEngineControl->fBufferSize; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fMidiCapturePortList[midi_port_index] = port_id; | |||
| jack_log ( "JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); | |||
| } | |||
| @@ -342,15 +346,16 @@ namespace Jack | |||
| switch ( fParams.fNetworkMode ) | |||
| { | |||
| case 'f' : | |||
| port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
| range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize; | |||
| break; | |||
| case 'n' : | |||
| port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ; | |||
| range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
| break; | |||
| case 's' : | |||
| port->SetLatency ( 2 * fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
| range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
| break; | |||
| } | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| fMidiPlaybackPortList[midi_port_index] = port_id; | |||
| jack_log ( "JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); | |||
| } | |||
| @@ -409,7 +414,7 @@ namespace Jack | |||
| //is there a transport state change to handle ? | |||
| if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) ) | |||
| { | |||
| switch ( fSendTransportData.fState ) | |||
| { | |||
| case JackTransportStopped : | |||
| @@ -458,13 +463,13 @@ namespace Jack | |||
| else | |||
| fReturnTransportData.fTimebaseMaster = NO_CHANGE; | |||
| */ | |||
| //update transport state and position | |||
| fReturnTransportData.fState = fEngineControl->fTransport.Query ( &fReturnTransportData.fPosition ); | |||
| //is it a new state (that the master need to know...) ? | |||
| fReturnTransportData.fNewState = (( fReturnTransportData.fState == JackTransportNetStarting) && | |||
| ( fReturnTransportData.fState != fLastTransportState ) && | |||
| ( fReturnTransportData.fState != fLastTransportState ) && | |||
| ( fReturnTransportData.fState != fSendTransportData.fState ) ); | |||
| if ( fReturnTransportData.fNewState ) | |||
| jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) ); | |||
| @@ -492,14 +497,14 @@ namespace Jack | |||
| return 0; | |||
| #ifdef JACK_MONITOR | |||
| // For timing | |||
| // For timing | |||
| fRcvSyncUst = GetMicroSeconds(); | |||
| #endif | |||
| //decode sync | |||
| //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified | |||
| DecodeSyncPacket(); | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - fRcvSyncUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f ); | |||
| #endif | |||
| @@ -534,7 +539,7 @@ namespace Jack | |||
| //sync | |||
| EncodeSyncPacket(); | |||
| //send sync | |||
| if ( SyncSend() == SOCKET_ERROR ) | |||
| return SOCKET_ERROR; | |||
| @@ -134,7 +134,7 @@ namespace Jack | |||
| if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0) | |||
| goto fail; | |||
| if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) | |||
| goto fail; | |||
| @@ -153,7 +153,7 @@ namespace Jack | |||
| jack_error ( "Can't activate jack client." ); | |||
| goto fail; | |||
| } | |||
| if (auto_connect) | |||
| ConnectPorts(); | |||
| jack_info ( "New NetMaster started." ); | |||
| @@ -172,7 +172,8 @@ namespace Jack | |||
| uint i; | |||
| char name[24]; | |||
| jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); | |||
| jack_latency_range_t range; | |||
| jack_log ( "JackNetMaster::AllocPorts" ); | |||
| //audio | |||
| @@ -182,9 +183,10 @@ namespace Jack | |||
| if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
| return -1; | |||
| //port latency | |||
| jack_port_set_latency ( fAudioCapturePorts[i], 0 ); | |||
| range.min = range.max = 0; | |||
| jack_port_set_latency_range(fAudioCapturePorts[i], JackCaptureLatency, &range); | |||
| } | |||
| for ( i = 0; i < fParams.fReturnAudioChannels; i++ ) | |||
| { | |||
| sprintf ( name, "from_slave_%d", i+1 ); | |||
| @@ -194,17 +196,20 @@ namespace Jack | |||
| switch ( fParams.fNetworkMode ) | |||
| { | |||
| case 'f' : | |||
| jack_port_set_latency ( fAudioPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
| range.min = range.max = (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
| jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range); | |||
| break; | |||
| case 'n' : | |||
| jack_port_set_latency ( fAudioPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
| range.min = range.max = port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
| jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range); | |||
| break; | |||
| case 's' : | |||
| jack_port_set_latency ( fAudioPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
| range.min = range.max = 2 * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
| jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range); | |||
| break; | |||
| } | |||
| } | |||
| //midi | |||
| for ( i = 0; i < fParams.fSendMidiChannels; i++ ) | |||
| { | |||
| @@ -212,7 +217,8 @@ namespace Jack | |||
| if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
| return -1; | |||
| //port latency | |||
| jack_port_set_latency ( fMidiCapturePorts[i], 0 ); | |||
| range.min = range.max = 0; | |||
| jack_port_set_latency_range(fMidiCapturePorts[i], JackCaptureLatency, &range); | |||
| } | |||
| for ( i = 0; i < fParams.fReturnMidiChannels; i++ ) | |||
| { | |||
| @@ -223,23 +229,26 @@ namespace Jack | |||
| switch ( fParams.fNetworkMode ) | |||
| { | |||
| case 'f' : | |||
| jack_port_set_latency ( fMidiPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
| range.min = range.max = (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
| jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range); | |||
| break; | |||
| case 'n' : | |||
| jack_port_set_latency ( fMidiPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
| range.min = range.max = port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
| jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range); | |||
| break; | |||
| case 's' : | |||
| jack_port_set_latency ( fMidiPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
| range.min = range.max = 2 * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
| jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range); | |||
| break; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| void JackNetMaster::ConnectPorts() | |||
| { | |||
| const char **ports; | |||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | |||
| if (ports != NULL) { | |||
| for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { | |||
| @@ -247,7 +256,7 @@ namespace Jack | |||
| } | |||
| free(ports); | |||
| } | |||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | |||
| if (ports != NULL) { | |||
| for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { | |||
| @@ -309,7 +318,7 @@ namespace Jack | |||
| else | |||
| jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName ); | |||
| break; | |||
| case TIMEBASEMASTER : | |||
| timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this ); | |||
| if ( timebase < 0 ) | |||
| @@ -317,7 +326,7 @@ namespace Jack | |||
| else | |||
| jack_info ( "'%s' is the new timebase master.", fParams.fName ); | |||
| break; | |||
| case CONDITIONAL_TIMEBASEMASTER : | |||
| timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this ); | |||
| if ( timebase != EBUSY ) | |||
| @@ -340,18 +349,18 @@ namespace Jack | |||
| jack_transport_stop ( fJackClient ); | |||
| jack_info ( "'%s' stops transport.", fParams.fName ); | |||
| break; | |||
| case JackTransportStarting : | |||
| if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL ) | |||
| jack_error ( "Can't set new position." ); | |||
| jack_transport_start ( fJackClient ); | |||
| jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); | |||
| break; | |||
| case JackTransportNetStarting : | |||
| jack_info ( "'%s' is ready to roll..", fParams.fName ); | |||
| break; | |||
| case JackTransportRolling : | |||
| jack_info ( "'%s' is rolling.", fParams.fName ); | |||
| break; | |||
| @@ -377,16 +386,19 @@ namespace Jack | |||
| } | |||
| //sync-------------------------------------------------------------------------------- | |||
| bool JackNetMaster::IsSlaveReadyToRoll() | |||
| { | |||
| return ( fReturnTransportData.fState == JackTransportNetStarting ); | |||
| } | |||
| int JackNetMaster::SetBufferSize (jack_nframes_t nframes, void* arg) | |||
| int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg) | |||
| { | |||
| jack_error("Cannot handle bufer size change, so proxy will be removed..."); | |||
| static_cast<JackNetMaster*> ( arg )->Exit(); | |||
| JackNetMaster* obj = static_cast<JackNetMaster*>(arg); | |||
| if (nframes != obj->fParams.fPeriodSize) { | |||
| jack_error("Cannot handle bufer size change, so JackNetMaster proxy will be removed..."); | |||
| obj->Exit(); | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -424,10 +436,10 @@ namespace Jack | |||
| fParams.fPeriodSize ) ) ); | |||
| if (IsSynched()) { // only send if connection is "synched" | |||
| //encode the first packet | |||
| EncodeSyncPacket(); | |||
| //send sync | |||
| if ( SyncSend() == SOCKET_ERROR ) | |||
| return SOCKET_ERROR; | |||
| @@ -443,7 +455,7 @@ namespace Jack | |||
| #ifdef JACK_MONITOR | |||
| fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f ); | |||
| #endif | |||
| } else { | |||
| jack_error("Connection is not synched, skip cycle..."); | |||
| } | |||
| @@ -459,7 +471,7 @@ namespace Jack | |||
| //decode sync | |||
| DecodeSyncPacket(); | |||
| //receive data | |||
| res = DataRecv(); | |||
| if ( ( res == 0 ) || ( res == SOCKET_ERROR ) ) | |||
| @@ -498,11 +510,11 @@ namespace Jack | |||
| else | |||
| jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP); | |||
| break; | |||
| case 'p': | |||
| fSocket.SetPort ( param->value.ui ); | |||
| break; | |||
| case 'c': | |||
| fAutoConnect = param->value.i; | |||
| break; | |||
| @@ -646,7 +658,7 @@ namespace Jack | |||
| JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params ) | |||
| { | |||
| jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName ); | |||
| //check MASTER <<==> SLAVE network protocol coherency | |||
| if (params.fProtocolVersion != MASTER_PROTOCOL) { | |||
| jack_error ( "Error : slave is running with a different protocol %s", params.fName ); | |||
| @@ -740,7 +752,7 @@ extern "C" | |||
| desc->params[i].value.i = DEFAULT_PORT; | |||
| strcpy ( desc->params[i].short_desc, "UDP port" ); | |||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | |||
| i++; | |||
| strcpy ( desc->params[i].name, "auto_connect" ); | |||
| desc->params[i].character = 'c'; | |||
| @@ -54,7 +54,7 @@ namespace Jack | |||
| //sync and transport | |||
| int fLastTransportState; | |||
| //monitoring | |||
| #ifdef JACK_MONITOR | |||
| jack_time_t fPeriodUsecs; | |||
| @@ -64,7 +64,7 @@ namespace Jack | |||
| bool Init(bool auto_connect); | |||
| int AllocPorts(); | |||
| void FreePorts(); | |||
| //transport | |||
| void EncodeTransportData(); | |||
| void DecodeTransportData(); | |||
| @@ -98,7 +98,7 @@ namespace Jack | |||
| const char* fManagerName; | |||
| char fMulticastIP[32]; | |||
| JackNetSocket fSocket; | |||
| pthread_t fManagerThread; | |||
| jack_native_thread_t fManagerThread; | |||
| master_list_t fMasterList; | |||
| uint32_t fGlobalID; | |||
| bool fRunning; | |||
| @@ -34,45 +34,47 @@ namespace Jack | |||
| class JackNetOneDriver : public JackAudioDriver | |||
| { | |||
| private: | |||
| netjack_driver_state_t netj; | |||
| void | |||
| render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
| void | |||
| render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); | |||
| #ifdef HAVE_CELT | |||
| void | |||
| render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes); | |||
| void | |||
| render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up); | |||
| #endif | |||
| void | |||
| render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
| void | |||
| render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats); | |||
| netjack_driver_state_t netj; | |||
| void | |||
| render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
| void | |||
| render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); | |||
| #ifdef HAVE_CELT | |||
| void | |||
| render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes); | |||
| void | |||
| render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up); | |||
| #endif | |||
| void | |||
| render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
| void | |||
| render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats); | |||
| public: | |||
| JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, | |||
| int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, | |||
| int sample_rate, int period_size, int resample_factor, | |||
| const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, | |||
| int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ); | |||
| ~JackNetOneDriver(); | |||
| JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, | |||
| int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, | |||
| int sample_rate, int period_size, int resample_factor, | |||
| const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, | |||
| int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ); | |||
| ~JackNetOneDriver(); | |||
| int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing, | |||
| int inchannels, int outchannels, bool monitor, const char* capture_driver_name, | |||
| const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency ); | |||
| int Close(); | |||
| int Close(); | |||
| int Attach(); | |||
| int Detach(); | |||
| int Read(); | |||
| int Write(); | |||
| bool Initialize(); | |||
| int AllocPorts(); | |||
| void FreePorts(); | |||
| bool Initialize(); | |||
| int AllocPorts(); | |||
| void FreePorts(); | |||
| // BufferSize can't be changed | |||
| bool IsFixedBufferSize() | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -46,6 +46,7 @@ enum NotificationType { | |||
| kShutDownCallback = 15, | |||
| kQUIT = 16, | |||
| kSessionCallback = 17, | |||
| kLatencyCallback = 18, | |||
| kMaxNotification | |||
| }; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -44,6 +44,8 @@ bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type | |||
| fInUse = true; | |||
| fLatency = 0; | |||
| fTotalLatency = 0; | |||
| fPlaybackLatency.min = fPlaybackLatency.max = 0; | |||
| fCaptureLatency.min = fCaptureLatency.max = 0; | |||
| fTied = NO_PORT; | |||
| // DB: At this point we do not know current buffer size in frames, | |||
| // but every time buffer will be returned to any user, | |||
| @@ -86,6 +88,48 @@ jack_nframes_t JackPort::GetTotalLatency() const | |||
| void JackPort::SetLatency(jack_nframes_t nframes) | |||
| { | |||
| fLatency = nframes; | |||
| /* setup the new latency values here, | |||
| * so we dont need to change the backend codes. | |||
| */ | |||
| if (fFlags & JackPortIsOutput) { | |||
| fCaptureLatency.min = nframes; | |||
| fCaptureLatency.max = nframes; | |||
| } | |||
| if (fFlags & JackPortIsInput) { | |||
| fPlaybackLatency.min = nframes; | |||
| fPlaybackLatency.max = nframes; | |||
| } | |||
| } | |||
| void JackPort::SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) | |||
| { | |||
| if (mode == JackCaptureLatency) { | |||
| fCaptureLatency = *range; | |||
| /* hack to set port->shared->latency up for | |||
| * backend ports | |||
| */ | |||
| if ((fFlags & JackPortIsOutput) && (fFlags & JackPortIsPhysical)) | |||
| fLatency = (range->min + range->max) / 2; | |||
| } else { | |||
| fPlaybackLatency = *range; | |||
| /* hack to set port->shared->latency up for | |||
| * backend ports | |||
| */ | |||
| if ((fFlags & JackPortIsInput) && (fFlags & JackPortIsPhysical)) | |||
| fLatency = (range->min + range->max) / 2; | |||
| } | |||
| } | |||
| void JackPort::GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const | |||
| { | |||
| if (mode == JackCaptureLatency) { | |||
| *range = fCaptureLatency; | |||
| } else { | |||
| *range = fPlaybackLatency; | |||
| } | |||
| } | |||
| int JackPort::Tie(jack_port_id_t port_index) | |||
| @@ -103,10 +147,10 @@ int JackPort::UnTie() | |||
| int JackPort::RequestMonitor(bool onoff) | |||
| { | |||
| /** | |||
| jackd.h | |||
| jackd.h | |||
| * If @ref JackPortCanMonitor is set for this @a port, turn input | |||
| * monitoring on or off. Otherwise, do nothing. | |||
| if (!(fFlags & JackPortCanMonitor)) | |||
| return -1; | |||
| */ | |||
| @@ -123,10 +167,10 @@ int JackPort::RequestMonitor(bool onoff) | |||
| int JackPort::EnsureMonitor(bool onoff) | |||
| { | |||
| /** | |||
| jackd.h | |||
| jackd.h | |||
| * If @ref JackPortCanMonitor is set for this @a port, turn input | |||
| * monitoring on or off. Otherwise, do nothing. | |||
| if (!(fFlags & JackPortCanMonitor)) | |||
| return -1; | |||
| */ | |||
| @@ -165,7 +209,7 @@ int JackPort::GetFlags() const | |||
| const char* JackPort::GetType() const | |||
| { | |||
| const JackPortType* type = GetPortType(fTypeId); | |||
| return type->name; | |||
| return type->fName; | |||
| } | |||
| void JackPort::SetName(const char* new_name) | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -51,12 +51,14 @@ class SERVER_EXPORT JackPort | |||
| jack_nframes_t fLatency; | |||
| jack_nframes_t fTotalLatency; | |||
| jack_latency_range_t fPlaybackLatency; | |||
| jack_latency_range_t fCaptureLatency; | |||
| uint8_t fMonitorRequests; | |||
| bool fInUse; | |||
| jack_port_id_t fTied; // Locally tied source port | |||
| float fBuffer[BUFFER_SIZE_MAX + 4]; | |||
| bool IsUsed() const | |||
| { | |||
| return fInUse; | |||
| @@ -88,9 +90,13 @@ class SERVER_EXPORT JackPort | |||
| int UnTie(); | |||
| jack_nframes_t GetLatency() const; | |||
| jack_nframes_t GetTotalLatency() const; | |||
| void SetLatency(jack_nframes_t latency); | |||
| void SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range); | |||
| void GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const; | |||
| jack_nframes_t GetTotalLatency() const; | |||
| int RequestMonitor(bool onoff); | |||
| int EnsureMonitor(bool onoff); | |||
| bool MonitoringInput() | |||
| @@ -105,7 +111,7 @@ class SERVER_EXPORT JackPort | |||
| } | |||
| int GetRefNum() const; | |||
| } POST_PACKED_STRUCTURE; | |||
| } // end of namespace | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -24,20 +24,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| namespace Jack | |||
| { | |||
| static const JackPortType* port_types[] = | |||
| static const JackPortType* gPortTypes[] = | |||
| { | |||
| &gAudioPortType, | |||
| &gMidiPortType, | |||
| }; | |||
| jack_port_type_id_t PORT_TYPES_MAX = sizeof(port_types) / sizeof(port_types[0]); | |||
| jack_port_type_id_t PORT_TYPES_MAX = sizeof(gPortTypes) / sizeof(gPortTypes[0]); | |||
| jack_port_type_id_t GetPortTypeId(const char* port_type) | |||
| { | |||
| for (jack_port_type_id_t i = 0; i < PORT_TYPES_MAX; ++i) { | |||
| const JackPortType* type = port_types[i]; | |||
| const JackPortType* type = gPortTypes[i]; | |||
| assert(type != 0); | |||
| if (strcmp(port_type, type->name) == 0) | |||
| if (strcmp(port_type, type->fName) == 0) | |||
| return i; | |||
| } | |||
| return PORT_TYPES_MAX; | |||
| @@ -46,7 +46,7 @@ jack_port_type_id_t GetPortTypeId(const char* port_type) | |||
| const JackPortType* GetPortType(jack_port_type_id_t type_id) | |||
| { | |||
| assert(type_id >= 0 && type_id <= PORT_TYPES_MAX); | |||
| const JackPortType* type = port_types[type_id]; | |||
| const JackPortType* type = gPortTypes[type_id]; | |||
| assert(type != 0); | |||
| return type; | |||
| } | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -31,7 +31,8 @@ extern jack_port_type_id_t PORT_TYPES_MAX; | |||
| struct JackPortType | |||
| { | |||
| const char* name; | |||
| const char* fName; | |||
| size_t (*size)(); | |||
| void (*init)(void* buffer, size_t buffer_size, jack_nframes_t nframes); | |||
| void (*mixdown)(void *mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes); | |||
| }; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -71,7 +71,9 @@ struct JackRequest | |||
| kSessionReply = 34, | |||
| kGetClientByUUID = 35, | |||
| kReserveClientName = 36, | |||
| kGetUUIDByClient = 37 | |||
| kGetUUIDByClient = 37, | |||
| kClientHasSessionCallback = 38, | |||
| kComputeTotalLatencies = 39 | |||
| }; | |||
| RequestType fType; | |||
| @@ -122,7 +124,7 @@ struct JackResult | |||
| { | |||
| return trans->Write(&fResult, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -161,7 +163,7 @@ struct JackClientCheckRequest : public JackRequest | |||
| CheckRes(trans->Write(&fOptions, sizeof(int))); | |||
| return trans->Write(&fUUID, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -197,7 +199,7 @@ struct JackClientCheckResult : public JackResult | |||
| CheckRes(trans->Write(&fStatus, sizeof(int))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -210,7 +212,7 @@ struct JackClientOpenRequest : public JackRequest | |||
| int fPID; | |||
| int fUUID; | |||
| char fName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| JackClientOpenRequest() | |||
| {} | |||
| JackClientOpenRequest(const char* name, int pid, int uuid): JackRequest(JackRequest::kClientOpen) | |||
| @@ -234,7 +236,7 @@ struct JackClientOpenRequest : public JackRequest | |||
| CheckRes(trans->Write(&fUUID, sizeof(int))); | |||
| return trans->Write(&fName, sizeof(fName)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -247,7 +249,7 @@ struct JackClientOpenResult : public JackResult | |||
| int fSharedEngine; | |||
| int fSharedClient; | |||
| int fSharedGraph; | |||
| JackClientOpenResult() | |||
| : JackResult(), fSharedEngine(-1), fSharedClient(-1), fSharedGraph(-1) | |||
| {} | |||
| @@ -272,7 +274,7 @@ struct JackClientOpenResult : public JackResult | |||
| CheckRes(trans->Write(&fSharedGraph, sizeof(int))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -299,7 +301,7 @@ struct JackClientCloseRequest : public JackRequest | |||
| CheckRes(JackRequest::Write(trans)); | |||
| return trans->Write(&fRefNum, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -402,7 +404,7 @@ struct JackPortRegisterRequest : public JackRequest | |||
| CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -428,7 +430,7 @@ struct JackPortRegisterResult : public JackResult | |||
| CheckRes(JackResult::Write(trans)); | |||
| return trans->Write(&fPortIndex, sizeof(jack_port_id_t)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -461,7 +463,7 @@ struct JackPortUnRegisterRequest : public JackRequest | |||
| CheckRes(trans->Write(&fPortIndex, sizeof(jack_port_id_t))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -501,7 +503,7 @@ struct JackPortConnectNameRequest : public JackRequest | |||
| CheckRes(trans->Write(&fDst, sizeof(fDst))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -540,7 +542,7 @@ struct JackPortDisconnectNameRequest : public JackRequest | |||
| CheckRes(trans->Write(&fDst, sizeof(fDst))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -576,7 +578,7 @@ struct JackPortConnectRequest : public JackRequest | |||
| CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -612,7 +614,7 @@ struct JackPortDisconnectRequest : public JackRequest | |||
| CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -651,7 +653,7 @@ struct JackPortRenameRequest : public JackRequest | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -679,7 +681,7 @@ struct JackSetBufferSizeRequest : public JackRequest | |||
| CheckRes(JackRequest::Write(trans)); | |||
| return trans->Write(&fBufferSize, sizeof(jack_nframes_t)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -707,7 +709,31 @@ struct JackSetFreeWheelRequest : public JackRequest | |||
| CheckRes(JackRequest::Write(trans)); | |||
| return trans->Write(&fOnOff, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| \brief ComputeTotalLatencies request. | |||
| */ | |||
| struct JackComputeTotalLatenciesRequest : public JackRequest | |||
| { | |||
| JackComputeTotalLatenciesRequest() | |||
| : JackRequest(JackRequest::kComputeTotalLatencies) | |||
| {} | |||
| int Read(JackChannelTransaction* trans) | |||
| { | |||
| return 0; | |||
| } | |||
| int Write(JackChannelTransaction* trans) | |||
| { | |||
| CheckRes(JackRequest::Write(trans)); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -735,7 +761,7 @@ struct JackReleaseTimebaseRequest : public JackRequest | |||
| CheckRes(JackRequest::Write(trans)); | |||
| return trans->Write(&fRefNum, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -766,7 +792,7 @@ struct JackSetTimebaseCallbackRequest : public JackRequest | |||
| CheckRes(trans->Write(&fRefNum, sizeof(int))); | |||
| return trans->Write(&fConditionnal, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -797,7 +823,7 @@ struct JackGetInternalClientNameRequest : public JackRequest | |||
| CheckRes(trans->Write(&fRefNum, sizeof(int))); | |||
| return trans->Write(&fIntRefNum, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -830,7 +856,7 @@ struct JackGetInternalClientNameResult : public JackResult | |||
| CheckRes(trans->Write(&fName, sizeof(fName))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -863,7 +889,7 @@ struct JackInternalClientHandleRequest : public JackRequest | |||
| CheckRes(trans->Write(&fRefNum, sizeof(int))); | |||
| return trans->Write(&fName, sizeof(fName)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -897,7 +923,7 @@ struct JackInternalClientHandleResult : public JackResult | |||
| CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -949,7 +975,7 @@ struct JackInternalClientLoadRequest : public JackRequest | |||
| CheckRes(trans->Write(&fUUID, sizeof(int))); | |||
| return trans->Write(&fOptions, sizeof(int)); | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -983,7 +1009,7 @@ struct JackInternalClientLoadResult : public JackResult | |||
| CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -1044,7 +1070,7 @@ struct JackInternalClientUnloadResult : public JackResult | |||
| CheckRes(trans->Write(&fStatus, sizeof(int))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -1147,7 +1173,7 @@ struct JackSessionNotifyResult : public JackResult | |||
| CheckRes(trans->Write(terminator, sizeof(terminator))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| @@ -1245,7 +1271,7 @@ struct JackClientNameResult : public JackResult | |||
| CheckRes(trans->Write(&fName, sizeof(fName))); | |||
| return 0; | |||
| } | |||
| }; | |||
| struct JackUUIDResult : public JackResult | |||
| @@ -1274,7 +1300,7 @@ struct JackUUIDResult : public JackResult | |||
| CheckRes(trans->Write(&fUUID, sizeof(fUUID))); | |||
| return 0; | |||
| } | |||
| }; | |||
| struct JackGetUUIDRequest : public JackRequest | |||
| @@ -1368,6 +1394,34 @@ struct JackReserveNameRequest : public JackRequest | |||
| }; | |||
| struct JackClientHasSessionCallbackRequest : public JackRequest | |||
| { | |||
| char fName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| JackClientHasSessionCallbackRequest() | |||
| {} | |||
| JackClientHasSessionCallbackRequest(const char *name) | |||
| : JackRequest(JackRequest::kClientHasSessionCallback) | |||
| { | |||
| strncpy(fName, name, sizeof(fName)); | |||
| } | |||
| int Read(JackChannelTransaction* trans) | |||
| { | |||
| CheckRes(trans->Read(&fName, sizeof(fName))); | |||
| return 0; | |||
| } | |||
| int Write(JackChannelTransaction* trans) | |||
| { | |||
| CheckRes(JackRequest::Write(trans)); | |||
| CheckRes(trans->Write(&fName, sizeof(fName))); | |||
| return 0; | |||
| } | |||
| }; | |||
| /*! | |||
| \brief ClientNotification. | |||
| */ | |||
| @@ -45,7 +45,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio | |||
| } else { | |||
| jack_info("JACK server starting in non-realtime mode"); | |||
| } | |||
| fGraphManager = JackGraphManager::Allocate(port_max); | |||
| fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); | |||
| fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); | |||
| @@ -72,17 +72,17 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||
| { | |||
| // TODO: move that in reworked JackServerGlobals::Init() | |||
| JackMessageBuffer::Create(); | |||
| if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | |||
| jack_error("Cannot initialize driver"); | |||
| goto fail_close1; | |||
| } | |||
| if (fChannel.Open(fEngineControl->fServerName, this) < 0) { | |||
| jack_error("Server channel open error"); | |||
| goto fail_close2; | |||
| } | |||
| if (fEngine->Open() < 0) { | |||
| jack_error("Cannot open engine"); | |||
| goto fail_close3; | |||
| @@ -92,12 +92,12 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||
| jack_error("Cannot open driver"); | |||
| goto fail_close4; | |||
| } | |||
| if (fAudioDriver->Attach() < 0) { | |||
| jack_error("Cannot attach audio driver"); | |||
| goto fail_close5; | |||
| } | |||
| fFreewheelDriver->SetMaster(false); | |||
| fAudioDriver->SetMaster(true); | |||
| fAudioDriver->AddSlave(fFreewheelDriver); // After ??? | |||
| @@ -113,11 +113,11 @@ fail_close4: | |||
| fail_close3: | |||
| fChannel.Close(); | |||
| fail_close2: | |||
| fail_close2: | |||
| fAudioDriver->Close(); | |||
| fail_close1: | |||
| fail_close1: | |||
| JackMessageBuffer::Destroy(); | |||
| return -1; | |||
| } | |||
| @@ -190,7 +190,7 @@ int JackServer::SetBufferSize(jack_nframes_t buffer_size) | |||
| jack_log("SetBufferSize: requirement for new buffer size equals current value"); | |||
| return 0; | |||
| } | |||
| if (fAudioDriver->IsFixedBufferSize()) { | |||
| jack_log("SetBufferSize: driver only supports a fixed buffer size"); | |||
| return -1; | |||
| @@ -316,37 +316,37 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par | |||
| fAudioDriver->Stop(); | |||
| fAudioDriver->Detach(); | |||
| fAudioDriver->Close(); | |||
| // Open new master | |||
| JackDriverInfo* info = new JackDriverInfo(); | |||
| JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | |||
| if (master == NULL || info == NULL) { | |||
| delete info; | |||
| delete master; | |||
| return -1; | |||
| } else { | |||
| // Get slaves list | |||
| std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); | |||
| std::list<JackDriverInterface*>::const_iterator it; | |||
| // Move slaves in new master | |||
| for (it = slave_list.begin(); it != slave_list.end(); it++) { | |||
| JackDriverInterface* slave = *it; | |||
| master->AddSlave(slave); | |||
| } | |||
| // Delete old master | |||
| delete fAudioDriver; | |||
| delete fDriverInfo; | |||
| // Activate master | |||
| fAudioDriver = master; | |||
| fDriverInfo = info; | |||
| fAudioDriver->Attach(); | |||
| fAudioDriver->SetMaster(true); | |||
| return fAudioDriver->Start(); | |||
| return fAudioDriver->Start(); | |||
| } | |||
| } | |||
| @@ -28,8 +28,10 @@ static char* server_name = NULL; | |||
| namespace Jack | |||
| { | |||
| JackServer* JackServerGlobals::fInstance; | |||
| JackServer* JackServerGlobals::fInstance; | |||
| unsigned int JackServerGlobals::fUserCount; | |||
| int JackServerGlobals::fRTNotificationSocket; | |||
| bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; | |||
| void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL; | |||
| @@ -95,7 +97,7 @@ bool JackServerGlobals::Init() | |||
| int argc = 0; | |||
| char* argv[32]; | |||
| jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; | |||
| // First user starts the server | |||
| if (fUserCount++ == 0) { | |||
| @@ -158,7 +160,7 @@ bool JackServerGlobals::Init() | |||
| (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; | |||
| @@ -168,7 +170,7 @@ bool JackServerGlobals::Init() | |||
| clock_source = JACK_TIMER_SYSTEM_CLOCK; | |||
| } else { | |||
| jack_error("unknown option character %c", optopt); | |||
| } | |||
| } | |||
| break; | |||
| case 'd': | |||
| @@ -38,9 +38,10 @@ struct SERVER_EXPORT JackServerGlobals | |||
| { | |||
| static JackServer* fInstance; | |||
| static unsigned int fUserCount; | |||
| static bool (* on_device_acquire)(const char * device_name); | |||
| static void (* on_device_release)(const char * device_name); | |||
| static int fRTNotificationSocket; // For debugging purpose | |||
| static bool (* on_device_acquire)(const char* device_name); | |||
| static void (* on_device_release)(const char* device_name); | |||
| JackServerGlobals(); | |||
| ~JackServerGlobals(); | |||
| @@ -1,21 +1,21 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackThread__ | |||
| @@ -26,23 +26,23 @@ | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief The base class for runnable objects, that have an <B> Init </B> and <B> Execute </B> method to be called in a thread. | |||
| */ | |||
| class JackRunnableInterface | |||
| { | |||
| protected: | |||
| JackRunnableInterface() | |||
| {} | |||
| virtual ~JackRunnableInterface() | |||
| {} | |||
| public: | |||
| virtual bool Init() /*! Called once when the thread is started */ | |||
| { | |||
| return true; | |||
| @@ -61,23 +61,23 @@ class SERVER_EXPORT JackThreadInterface | |||
| { | |||
| public: | |||
| enum kThreadState {kIdle, kStarting, kIniting, kRunning}; | |||
| protected: | |||
| JackRunnableInterface* fRunnable; | |||
| int fPriority; | |||
| bool fRealTime; | |||
| volatile kThreadState fStatus; | |||
| int fCancellation; | |||
| public: | |||
| JackThreadInterface(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation): | |||
| fRunnable(runnable), fPriority(priority), fRealTime(real_time), fStatus(kIdle), fCancellation(cancellation) | |||
| {} | |||
| kThreadState GetStatus() | |||
| { | |||
| return fStatus; | |||
| @@ -86,10 +86,10 @@ class SERVER_EXPORT JackThreadInterface | |||
| { | |||
| fStatus = status; | |||
| } | |||
| void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX... | |||
| {} | |||
| int Start(); | |||
| int StartSync(); | |||
| int Kill(); | |||
| @@ -98,24 +98,24 @@ class SERVER_EXPORT JackThreadInterface | |||
| int AcquireRealTime(); // Used when called from another thread | |||
| int AcquireSelfRealTime(); // Used when called from thread itself | |||
| int AcquireRealTime(int priority); // Used when called from another thread | |||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
| int DropRealTime(); // Used when called from another thread | |||
| int DropSelfRealTime(); // Used when called from thread itself | |||
| pthread_t GetThreadID(); | |||
| jack_native_thread_t GetThreadID(); | |||
| bool IsThread(); | |||
| static int AcquireRealTimeImp(pthread_t thread, int priority); | |||
| static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int DropRealTimeImp(pthread_t thread); | |||
| static int StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
| static int StopImp(pthread_t thread); | |||
| static int KillImp(pthread_t thread); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int DropRealTimeImp(jack_native_thread_t thread); | |||
| static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
| static int StopImp(jack_native_thread_t thread); | |||
| static int KillImp(jack_native_thread_t thread); | |||
| }; | |||
| } | |||
| } // end of namespace | |||
| @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #ifndef __JackTime__ | |||
| #define __JackTime__ | |||
| #include "types.h" | |||
| #include "JackCompilerDeps.h" | |||
| #include "JackTypes.h" | |||
| @@ -34,6 +34,12 @@ typedef signed long SInt32; | |||
| #include "JackTypes_os.h" | |||
| /** | |||
| * Type used to represent the value of free running | |||
| * monotonic clock with units of microseconds. | |||
| */ | |||
| typedef uint64_t jack_time_t; | |||
| typedef uint16_t jack_int_t; // Internal type for ports and refnum | |||
| typedef enum { | |||
| @@ -33,7 +33,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include "JackDriverLoader.h" | |||
| #if defined(JACK_DBUS) && defined(__linux__) | |||
| #include <dbus/dbus.h> | |||
| #include <dbus/dbus.h> | |||
| #include "audio_reserve.h" | |||
| #endif | |||
| @@ -85,7 +85,7 @@ static void copyright(FILE* file) | |||
| { | |||
| fprintf(file, "jackdmp " VERSION "\n" | |||
| "Copyright 2001-2005 Paul Davis and others.\n" | |||
| "Copyright 2004-2010 Grame.\n" | |||
| "Copyright 2004-2011 Grame.\n" | |||
| "jackdmp 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"); | |||
| @@ -114,10 +114,10 @@ static void usage(FILE* file) | |||
| " -d backend [ ... backend args ... ]\n" | |||
| #ifdef __APPLE__ | |||
| " Available backends may include: coreaudio, dummy or net.\n\n" | |||
| #endif | |||
| #endif | |||
| #ifdef WIN32 | |||
| " Available backends may include: portaudio, dummy or net.\n\n" | |||
| #endif | |||
| #endif | |||
| #ifdef __linux__ | |||
| " Available backends may include: alsa, dummy, freebob, firewire or net\n\n" | |||
| #endif | |||
| @@ -178,13 +178,13 @@ int main(int argc, char* argv[]) | |||
| jackctl_driver_t * midi_driver_ctl; | |||
| jackctl_driver_t * loopback_driver_ctl; | |||
| int replace_registry = 0; | |||
| const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" | |||
| #ifdef __linux__ | |||
| "c:" | |||
| #endif | |||
| ; | |||
| struct option long_options[] = { | |||
| #ifdef __linux__ | |||
| { "clock-source", 1, 0, 'c' }, | |||
| @@ -199,7 +199,7 @@ int main(int argc, char* argv[]) | |||
| { "name", 1, 0, 'n' }, | |||
| { "unlock", 0, 0, 'u' }, | |||
| { "realtime", 0, 0, 'R' }, | |||
| { "no-realtime", 0, 0, 'r' }, | |||
| { "no-realtime", 0, 0, 'r' }, | |||
| { "replace-registry", 0, &replace_registry, 0 }, | |||
| { "loopback", 0, 0, 'L' }, | |||
| { "realtime-priority", 1, 0, 'P' }, | |||
| @@ -239,23 +239,23 @@ int main(int argc, char* argv[]) | |||
| fprintf(stderr, "Failed to create server object\n"); | |||
| return -1; | |||
| } | |||
| server_parameters = jackctl_server_get_parameters(server_ctl); | |||
| // Default setting | |||
| param = jackctl_get_parameter(server_parameters, "realtime"); | |||
| if (param != NULL) { | |||
| value.b = true; | |||
| jackctl_parameter_set_value(param, &value); | |||
| } | |||
| opterr = 0; | |||
| while (!seen_audio_driver && | |||
| (opt = getopt_long(argc, argv, options, | |||
| long_options, &option_index)) != EOF) { | |||
| switch (opt) { | |||
| #ifdef __linux__ | |||
| #ifdef __linux__ | |||
| case 'c': | |||
| param = jackctl_get_parameter(server_parameters, "clock-source"); | |||
| if (param != NULL) { | |||
| @@ -280,7 +280,7 @@ int main(int argc, char* argv[]) | |||
| seen_audio_driver = true; | |||
| audio_driver_name = optarg; | |||
| break; | |||
| case 'L': | |||
| loopback = atoi(optarg); | |||
| break; | |||
| @@ -342,7 +342,7 @@ int main(int argc, char* argv[]) | |||
| jackctl_parameter_set_value(param, &value); | |||
| } | |||
| break; | |||
| case 'r': | |||
| param = jackctl_get_parameter(server_parameters, "realtime"); | |||
| if (param != NULL) { | |||
| @@ -388,14 +388,14 @@ int main(int argc, char* argv[]) | |||
| goto fail_free1; | |||
| } | |||
| } | |||
| // Long option with no letter so treated separately | |||
| param = jackctl_get_parameter(server_parameters, "replace-registry"); | |||
| if (param != NULL) { | |||
| value.b = replace_registry; | |||
| jackctl_parameter_set_value(param, &value); | |||
| } | |||
| if (show_version) { | |||
| printf( "jackdmp version " VERSION | |||
| " tmpdir " jack_server_dir | |||
| @@ -441,7 +441,7 @@ int main(int argc, char* argv[]) | |||
| // Setup signals then start server | |||
| signals = jackctl_setup_signals(0); | |||
| if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { | |||
| fprintf(stderr, "Failed to start server\n"); | |||
| goto fail_free1; | |||
| @@ -458,7 +458,7 @@ int main(int argc, char* argv[]) | |||
| jackctl_server_add_slave(server_ctl, midi_driver_ctl); | |||
| } | |||
| // Loopback driver | |||
| if (loopback > 0) { | |||
| loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); | |||
| @@ -480,7 +480,7 @@ int main(int argc, char* argv[]) | |||
| if (!jackctl_server_stop(server_ctl)) | |||
| fprintf(stderr, "Cannot stop server...\n"); | |||
| jackctl_server_destroy(server_ctl); | |||
| notify_server_stop(server_name); | |||
| return 0; | |||
| @@ -488,7 +488,7 @@ int main(int argc, char* argv[]) | |||
| fail_free1: | |||
| jackctl_server_destroy(server_ctl); | |||
| return -1; | |||
| fail_free2: | |||
| jackctl_server_stop(server_ctl); | |||
| jackctl_server_destroy(server_ctl); | |||
| @@ -1,19 +1,19 @@ | |||
| /* | |||
| Copyright (C) 2001 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 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -33,21 +33,21 @@ extern "C" | |||
| /** | |||
| * Note: More documentation can be found in jack/types.h. | |||
| */ | |||
| /************************************************************* | |||
| * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | |||
| * added to the JACK API after the 0.116.2 release. | |||
| * | |||
| * Functions that predate this release are marked with | |||
| * | |||
| * Functions that predate this release are marked with | |||
| * JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile | |||
| * time in a variety of ways. The default definition is empty, | |||
| * so that these symbols get normal linkage. If you wish to | |||
| * use all JACK symbols with weak linkage, include | |||
| * use all JACK symbols with weak linkage, include | |||
| * <jack/weakjack.h> before jack.h. | |||
| *************************************************************/ | |||
| #include <jack/weakmacros.h> | |||
| /** | |||
| * Call this function to get version of the JACK, in form of several numbers | |||
| * | |||
| @@ -200,7 +200,7 @@ int jack_get_client_pid (const char *name) JACK_OPTIONAL_WEAK_EXPORT; | |||
| * @return the pthread ID of the thread running the JACK client side | |||
| * code. | |||
| */ | |||
| pthread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
| jack_native_thread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /*@}*/ | |||
| @@ -228,7 +228,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_ | |||
| /** | |||
| * Wait until this JACK client should process data. | |||
| * | |||
| * | |||
| * @param client - pointer to a JACK client structure | |||
| * | |||
| * @return the number of frames of data to process | |||
| @@ -237,7 +237,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_ | |||
| /** | |||
| * Signal next clients in the graph. | |||
| * | |||
| * | |||
| * @param client - pointer to a JACK client structure | |||
| * @param status - if non-zero, calling thread should exit | |||
| */ | |||
| @@ -254,7 +254,7 @@ void jack_cycle_signal (jack_client_t* client, int status) JACK_OPTIONAL_WEAK_EX | |||
| * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 | |||
| * for more information. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code. | |||
| @@ -270,13 +270,13 @@ int jack_set_process_thread(jack_client_t* client, JackThreadCallback thread_cal | |||
| /** | |||
| * Tell JACK to call @a thread_init_callback once just after | |||
| * the creation of the thread in which all other callbacks | |||
| * the creation of the thread in which all other callbacks | |||
| * will be handled. | |||
| * | |||
| * The code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code, causing JACK | |||
| @@ -337,7 +337,7 @@ void jack_on_shutdown (jack_client_t *client, | |||
| */ | |||
| void jack_on_info_shutdown (jack_client_t *client, | |||
| JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Tell the Jack server to call @a process_callback whenever there is | |||
| * work be done, passing @a arg as the second argument. | |||
| @@ -350,7 +350,7 @@ void jack_on_info_shutdown (jack_client_t *client, | |||
| * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 | |||
| * for more information. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code. | |||
| @@ -370,7 +370,7 @@ int jack_set_process_callback (jack_client_t *client, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code. | |||
| @@ -389,7 +389,7 @@ int jack_set_freewheel_callback (jack_client_t *client, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @param client pointer to JACK client structure. | |||
| @@ -410,7 +410,7 @@ int jack_set_buffer_size_callback (jack_client_t *client, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| @@ -427,7 +427,7 @@ int jack_set_sample_rate_callback (jack_client_t *client, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| @@ -444,7 +444,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| @@ -452,7 +452,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
| int jack_set_port_registration_callback (jack_client_t *, | |||
| JackPortRegistrationCallback | |||
| registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Tell the JACK server to call @a connect_callback whenever a | |||
| * port is connected or disconnected, passing @a arg as a parameter. | |||
| @@ -461,7 +461,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| @@ -478,7 +478,7 @@ int jack_set_port_connect_callback (jack_client_t *, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| @@ -495,7 +495,7 @@ int jack_set_port_rename_callback (jack_client_t *, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| @@ -512,39 +512,97 @@ int jack_set_graph_order_callback (jack_client_t *, | |||
| * the code in the supplied function does not need to be | |||
| * suitable for real-time execution. | |||
| * | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * NOTE: this function cannot be called while the client is activated | |||
| * (after jack_activate has been called.) | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| */ | |||
| int jack_set_xrun_callback (jack_client_t *, | |||
| JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /*@}*/ | |||
| /** | |||
| * Tell the Jack server to call @a latency_callback whenever it | |||
| * is necessary to recompute the latencies for some or all | |||
| * Jack ports. | |||
| * | |||
| * @a latency_callback will be called twice each time it is | |||
| * needed, once being passed JackCaptureLatency and once | |||
| * JackPlaybackLatency. See @ref LatencyFunctions for | |||
| * the definition of each type of latency and related functions. | |||
| * | |||
| * <b>IMPORTANT: Most JACK clients do NOT need to register a latency | |||
| * callback.</b> | |||
| * | |||
| * Clients that meet any of the following conditions do NOT | |||
| * need to register a latency callback: | |||
| * | |||
| * - have only input ports | |||
| * - have only output ports | |||
| * - their output is totally unrelated to their input | |||
| * - their output is not delayed relative to their input | |||
| * (i.e. data that arrives in a given process() | |||
| * callback is processed and output again in the | |||
| * same callback) | |||
| * | |||
| * Clients NOT registering a latency callback MUST also | |||
| * satisfy this condition: | |||
| * | |||
| * - have no multiple distinct internal signal pathways | |||
| * | |||
| * This means that if your client has more than 1 input and | |||
| * output port, and considers them always "correlated" | |||
| * (e.g. as a stereo pair), then there is only 1 (e.g. stereo) | |||
| * signal pathway through the client. This would be true, | |||
| * for example, of a stereo FX rack client that has a | |||
| * left/right input pair and a left/right output pair. | |||
| * | |||
| * However, this is somewhat a matter of perspective. The | |||
| * same FX rack client could be connected so that its | |||
| * two input ports were connected to entirely separate | |||
| * sources. Under these conditions, the fact that the client | |||
| * does not register a latency callback MAY result | |||
| * in port latency values being incorrect. | |||
| * | |||
| * Clients that do not meet any of those conditions SHOULD | |||
| * register a latency callback. | |||
| * | |||
| * See the documentation for @ref jack_port_set_latency_range() | |||
| * on how the callback should operate. Remember that the @a mode | |||
| * argument given to the latency callback will need to be | |||
| * passed into @ref jack_port_set_latency_range() | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| */ | |||
| int jack_set_latency_callback (jack_client_t *, | |||
| JackLatencyCallback latency_callback, | |||
| void *) JACK_WEAK_EXPORT; | |||
| /*@}*/ | |||
| /** | |||
| * @defgroup ServerClientControl Controlling & querying JACK server operation | |||
| * @{ | |||
| */ | |||
| /** | |||
| * Start/Stop JACK's "freewheel" mode. | |||
| * | |||
| * When in "freewheel" mode, JACK no longer waits for | |||
| * any external event to begin the start of the next process | |||
| * cycle. | |||
| * cycle. | |||
| * | |||
| * As a result, freewheel mode causes "faster than realtime" | |||
| * execution of a JACK graph. If possessed, real-time | |||
| * scheduling is dropped when entering freewheel mode, and | |||
| * if appropriate it is reacquired when stopping. | |||
| * | |||
| * | |||
| * IMPORTANT: on systems using capabilities to provide real-time | |||
| * scheduling (i.e. Linux kernel 2.4), if onoff is zero, this function | |||
| * must be called from the thread that originally called jack_activate(). | |||
| * This restriction does not apply to other systems (e.g. Linux kernel 2.6 | |||
| * must be called from the thread that originally called jack_activate(). | |||
| * This restriction does not apply to other systems (e.g. Linux kernel 2.6 | |||
| * or OS X). | |||
| * | |||
| * | |||
| * @param client pointer to JACK client structure | |||
| * @param onoff if non-zero, freewheel mode starts. Otherwise | |||
| * freewheel mode ends. | |||
| @@ -569,7 +627,7 @@ int jack_set_freewheel(jack_client_t* client, int onoff) JACK_OPTIONAL_WEAK_EXPO | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| */ | |||
| int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * @return the sample rate of the jack system, as set by the user when | |||
| * jackd was started. | |||
| @@ -613,7 +671,7 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
| * @defgroup PortFunctions Creating & manipulating ports | |||
| * @{ | |||
| */ | |||
| /** | |||
| * Create a new port for the client. This is an object used for moving | |||
| * data of any type in or out of the client. Ports may be connected | |||
| @@ -625,16 +683,16 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
| * name. Exceeding that will cause the port registration to fail and | |||
| * return NULL. | |||
| * | |||
| * The @a port_name must be unique among all ports owned by this client. | |||
| * If the name is not unique, the registration will fail. | |||
| * | |||
| * The @a port_name must be unique among all ports owned by this client. | |||
| * If the name is not unique, the registration will fail. | |||
| * | |||
| * All ports have a type, which may be any non-NULL and non-zero | |||
| * length string, passed as an argument. Some port types are built | |||
| * into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE. | |||
| * | |||
| * @param client pointer to JACK client structure. | |||
| * @param port_name non-empty short name for the new port (not | |||
| * including the leading @a "client_name:"). Must be unique. | |||
| * including the leading @a "client_name:"). Must be unique. | |||
| * @param port_type port type name. If longer than | |||
| * jack_port_type_size(), only that many characters are significant. | |||
| * @param flags @ref JackPortFlags bit mask. | |||
| @@ -663,7 +721,7 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP | |||
| * that can be written to; for an input port, it will be an area | |||
| * containing the data from the port's connection(s), or | |||
| * zero-filled. if there are multiple inbound connections, the data | |||
| * will be mixed appropriately. | |||
| * will be mixed appropriately. | |||
| * | |||
| * FOR OUTPUT PORTS ONLY : DEPRECATED in Jack 2.0 !! | |||
| * --------------------------------------------------- | |||
| @@ -672,9 +730,9 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP | |||
| * either never cache the return value or ensure you have | |||
| * a "blocksize" callback and be sure to invalidate the cached | |||
| * address from there. | |||
| * | |||
| * | |||
| * Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). | |||
| * Port buffers have to be retrieved in each callback for proper functionning. | |||
| * Port buffers have to be retrieved in each callback for proper functionning. | |||
| */ | |||
| void * jack_port_get_buffer (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; | |||
| @@ -759,7 +817,7 @@ const char ** jack_port_get_connections (const jack_port_t *port) JACK_OPTIONAL_ | |||
| * you cannot use it in a GraphReordered handler. | |||
| * | |||
| * 2) You need not be the owner of the port to get information | |||
| * about its connections. | |||
| * about its connections. | |||
| * | |||
| * @see jack_port_name_size() | |||
| */ | |||
| @@ -768,8 +826,8 @@ const char ** jack_port_get_all_connections (const jack_client_t *client, | |||
| /** | |||
| * | |||
| * @deprecated This function will be removed from a future version | |||
| * of JACK. Do not use it. There is no replacement. It has | |||
| * @deprecated This function will be removed from a future version | |||
| * of JACK. Do not use it. There is no replacement. It has | |||
| * turned out to serve essentially no purpose in real-life | |||
| * JACK clients. | |||
| */ | |||
| @@ -777,73 +835,13 @@ int jack_port_tie (jack_port_t *src, jack_port_t *dst) JACK_OPTIONAL_WEAK_DEPREC | |||
| /** | |||
| * | |||
| * @deprecated This function will be removed from a future version | |||
| * of JACK. Do not use it. There is no replacement. It has | |||
| * @deprecated This function will be removed from a future version | |||
| * of JACK. Do not use it. There is no replacement. It has | |||
| * turned out to serve essentially no purpose in real-life | |||
| * JACK clients. | |||
| */ | |||
| int jack_port_untie (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
| /** | |||
| * @return the time (in frames) between data being available or | |||
| * delivered at/to a port, and the time at which it arrived at or is | |||
| * delivered to the "other side" of the port. E.g. for a physical | |||
| * audio output port, this is the time between writing to the port and | |||
| * when the signal will leave the connector. For a physical audio | |||
| * input port, this is the time between the sound arriving at the | |||
| * connector and the corresponding frames being readable from the | |||
| * port. | |||
| */ | |||
| jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * The maximum of the sum of the latencies in every | |||
| * connection path that can be drawn between the port and other | |||
| * ports with the @ref JackPortIsTerminal flag set. | |||
| */ | |||
| jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
| jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * The port latency is zero by default. Clients that control | |||
| * physical hardware with non-zero latency should call this | |||
| * to set the latency to its correct value. Note that the value | |||
| * should include any systemic latency present "outside" the | |||
| * physical hardware controlled by the client. For example, | |||
| * for a client controlling a digital audio interface connected | |||
| * to an external digital converter, the latency setting should | |||
| * include both buffering by the audio interface *and* the converter. | |||
| */ | |||
| void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Request a complete recomputation of a port's total latency. This | |||
| * can be called by a client that has just changed the internal | |||
| * latency of its port using @function jack_port_set_latency | |||
| * and wants to ensure that all signal pathways in the graph | |||
| * are updated with respect to the values that will be returned | |||
| * by @function jack_port_get_total_latency. | |||
| * | |||
| * @return zero for successful execution of the request. non-zero | |||
| * otherwise. | |||
| */ | |||
| int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Request a complete recomputation of all port latencies. This | |||
| * can be called by a client that has just changed the internal | |||
| * latency of its port using @function jack_port_set_latency | |||
| * and wants to ensure that all signal pathways in the graph | |||
| * are updated with respect to the values that will be returned | |||
| * by @function jack_port_get_total_latency. It allows a client | |||
| * to change multiple port latencies without triggering a | |||
| * recompute for each change. | |||
| * | |||
| * @return zero for successful execution of the request. non-zero | |||
| * otherwise. | |||
| */ | |||
| int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Modify a port's short name. May be called at any time. If the | |||
| * resulting full name (including the @a "client_name:" prefix) is | |||
| @@ -856,12 +854,12 @@ int jack_port_set_name (jack_port_t *port, const char *port_name) JACK_OPTIONAL_ | |||
| /** | |||
| * Set @a alias as an alias for @a port. May be called at any time. | |||
| * If the alias is longer than jack_port_name_size(), it will be truncated. | |||
| * | |||
| * | |||
| * After a successful call, and until JACK exits or | |||
| * @function jack_port_unset_alias() is called, @alias may be | |||
| * used as a alternate name for the port. | |||
| * | |||
| * Ports can have up to two aliases - if both are already | |||
| * Ports can have up to two aliases - if both are already | |||
| * set, this function will return an error. | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code. | |||
| @@ -870,8 +868,8 @@ int jack_port_set_alias (jack_port_t *port, const char *alias) JACK_OPTIONAL_WEA | |||
| /** | |||
| * Remove @a alias as an alias for @a port. May be called at any time. | |||
| * | |||
| * After a successful call, @a alias can no longer be | |||
| * | |||
| * After a successful call, @a alias can no longer be | |||
| * used as a alternate name for the port. | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code. | |||
| @@ -981,6 +979,224 @@ int jack_port_name_size(void) JACK_OPTIONAL_WEAK_EXPORT; | |||
| */ | |||
| int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * @return the buffersize of a port of type @arg port_type. | |||
| * | |||
| * this function may only be called in a buffer_size callback. | |||
| */ | |||
| size_t jack_port_type_get_buffer_size (jack_client_t *client, const char *port_type) JACK_WEAK_EXPORT; | |||
| /*@}*/ | |||
| /** | |||
| * @defgroup LatencyFunctions Managing and determining latency | |||
| * | |||
| * The purpose of JACK's latency API is to allow clients to | |||
| * easily answer two questions: | |||
| * | |||
| * - How long has it been since the data read from a port arrived | |||
| * at the edge of the JACK graph (either via a physical port | |||
| * or being synthesized from scratch)? | |||
| * | |||
| * - How long will it be before the data written to a port arrives | |||
| * at the edge of a JACK graph? | |||
| * To help answering these two questions, all JACK ports have two | |||
| * latency values associated with them, both measured in frames: | |||
| * | |||
| * <b>capture latency</b>: how long since the data read from | |||
| * the buffer of a port arrived at at | |||
| * a port marked with JackPortIsTerminal. | |||
| * The data will have come from the "outside | |||
| * world" if the terminal port is also | |||
| * marked with JackPortIsPhysical, or | |||
| * will have been synthesized by the client | |||
| * that owns the terminal port. | |||
| * | |||
| * <b>playback latency</b>: how long until the data | |||
| * written to the buffer of port will reach a port | |||
| * marked with JackPortIsTerminal. | |||
| * | |||
| * Both latencies might potentially have more than one value | |||
| * because there may be multiple pathways to/from a given port | |||
| * and a terminal port. Latency is therefore generally | |||
| * expressed a min/max pair. | |||
| * | |||
| * In most common setups, the minimum and maximum latency | |||
| * are the same, but this design accomodates more complex | |||
| * routing, and allows applications (and thus users) to | |||
| * detect cases where routing is creating an anomalous | |||
| * situation that may either need fixing or more | |||
| * sophisticated handling by clients that care about | |||
| * latency. | |||
| * | |||
| * See also @ref jack_set_latency_callback for details on how | |||
| * clients that add latency to the signal path should interact | |||
| * with JACK to ensure that the correct latency figures are | |||
| * used. | |||
| * @{ | |||
| */ | |||
| /** | |||
| * The port latency is zero by default. Clients that control | |||
| * physical hardware with non-zero latency should call this | |||
| * to set the latency to its correct value. Note that the value | |||
| * should include any systemic latency present "outside" the | |||
| * physical hardware controlled by the client. For example, | |||
| * for a client controlling a digital audio interface connected | |||
| * to an external digital converter, the latency setting should | |||
| * include both buffering by the audio interface *and* the converter. | |||
| * | |||
| * @deprecated This method will be removed in the next major | |||
| * release of JACK. It should not be used in new code, and should | |||
| * be replaced by a latency callback that calls @ref | |||
| * jack_port_set_latency_range(). | |||
| */ | |||
| void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
| /** | |||
| * return the latency range defined by @a mode for | |||
| * @a port, in frames. | |||
| * | |||
| * See @ref LatencyFunctions for the definition of each latency value. | |||
| * | |||
| * This is normally used in the LatencyCallback. | |||
| * and therefor safe to execute from callbacks. | |||
| */ | |||
| void jack_port_get_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) JACK_WEAK_EXPORT; | |||
| /** | |||
| * set the minimum and maximum latencies defined by | |||
| * @a mode for @a port, in frames. | |||
| * | |||
| * See @ref LatencyFunctions for the definition of each latency value. | |||
| * | |||
| * This function should ONLY be used inside a latency | |||
| * callback. The client should determine the current | |||
| * value of the latency using @ref jack_port_get_latency_range() | |||
| * (called using the same mode as @a mode) | |||
| * and then add some number of frames to that reflects | |||
| * latency added by the client. | |||
| * | |||
| * How much latency a client adds will vary | |||
| * dramatically. For most clients, the answer is zero | |||
| * and there is no reason for them to register a latency | |||
| * callback and thus they should never call this | |||
| * function. | |||
| * | |||
| * More complex clients that take an input signal, | |||
| * transform it in some way and output the result but | |||
| * not during the same process() callback will | |||
| * generally know a single constant value to add | |||
| * to the value returned by @ref jack_port_get_latency_range(). | |||
| * | |||
| * Such clients would register a latency callback (see | |||
| * @ref jack_set_latency_callback) and must know what input | |||
| * ports feed which output ports as part of their | |||
| * internal state. Their latency callback will update | |||
| * the ports' latency values appropriately. | |||
| * | |||
| * A pseudo-code example will help. The @a mode argument to the latency | |||
| * callback will determine whether playback or capture | |||
| * latency is being set. The callback will use | |||
| * @ref jack_port_set_latency_range() as follows: | |||
| * | |||
| * \code | |||
| * jack_latency_range_t range; | |||
| * if (mode == JackPlaybackLatency) { | |||
| * foreach input_port in (all self-registered port) { | |||
| * jack_port_get_latency_range (port_feeding_input_port, JackPlaybackLatency, &range); | |||
| * range.min += min_delay_added_as_signal_flows_from port_feeding to input_port; | |||
| * range.max += max_delay_added_as_signal_flows_from port_feeding to input_port; | |||
| * jack_port_set_latency_range (input_port, JackPlaybackLatency, &range); | |||
| * } | |||
| * } else if (mode == JackCaptureLatency) { | |||
| * foreach output_port in (all self-registered port) { | |||
| * jack_port_get_latency_range (port_fed_by_output_port, JackCaptureLatency, &range); | |||
| * range.min += min_delay_added_as_signal_flows_from_output_port_to_fed_by_port; | |||
| * range.max += max_delay_added_as_signal_flows_from_output_port_to_fed_by_port; | |||
| * jack_port_set_latency_range (output_port, JackCaptureLatency, &range); | |||
| * } | |||
| * } | |||
| * \endcode | |||
| * | |||
| * In this relatively simple pseudo-code example, it is assumed that | |||
| * each input port or output is connected to only 1 output or input | |||
| * port respectively. | |||
| * | |||
| * If a port is connected to more than 1 other port, then the | |||
| * range.min and range.max values passed to @ref | |||
| * jack_port_set_latency_range() should reflect the minimum and | |||
| * maximum values across all connected ports. | |||
| * | |||
| * See the description of @ref jack_set_latency_callback for more | |||
| * information. | |||
| */ | |||
| void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) JACK_WEAK_EXPORT; | |||
| /** | |||
| * Request a complete recomputation of all port latencies. This | |||
| * can be called by a client that has just changed the internal | |||
| * latency of its port using jack_port_set_latency | |||
| * and wants to ensure that all signal pathways in the graph | |||
| * are updated with respect to the values that will be returned | |||
| * by jack_port_get_total_latency. It allows a client | |||
| * to change multiple port latencies without triggering a | |||
| * recompute for each change. | |||
| * | |||
| * @return zero for successful execution of the request. non-zero | |||
| * otherwise. | |||
| */ | |||
| int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * @return the time (in frames) between data being available or | |||
| * delivered at/to a port, and the time at which it arrived at or is | |||
| * delivered to the "other side" of the port. E.g. for a physical | |||
| * audio output port, this is the time between writing to the port and | |||
| * when the signal will leave the connector. For a physical audio | |||
| * input port, this is the time between the sound arriving at the | |||
| * connector and the corresponding frames being readable from the | |||
| * port. | |||
| * | |||
| * @deprecated This method will be removed in the next major | |||
| * release of JACK. It should not be used in new code, and should | |||
| * be replaced by jack_port_get_latency_range() in any existing | |||
| * use cases. | |||
| */ | |||
| jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
| /** | |||
| * The maximum of the sum of the latencies in every | |||
| * connection path that can be drawn between the port and other | |||
| * ports with the @ref JackPortIsTerminal flag set. | |||
| * | |||
| * @deprecated This method will be removed in the next major | |||
| * release of JACK. It should not be used in new code, and should | |||
| * be replaced by jack_port_get_latency_range() in any existing | |||
| * use cases. | |||
| */ | |||
| jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
| jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
| /** | |||
| * Request a complete recomputation of a port's total latency. This | |||
| * can be called by a client that has just changed the internal | |||
| * latency of its port using jack_port_set_latency | |||
| * and wants to ensure that all signal pathways in the graph | |||
| * are updated with respect to the values that will be returned | |||
| * by jack_port_get_total_latency. | |||
| * | |||
| * @return zero for successful execution of the request. non-zero | |||
| * otherwise. | |||
| * | |||
| * @deprecated This method will be removed in the next major | |||
| * release of JACK. It should not be used in new code, and should | |||
| * be replaced by jack_recompute_total_latencies() in any existing | |||
| * use cases. | |||
| */ | |||
| int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
| /*@}*/ | |||
| /** | |||
| @@ -989,13 +1205,13 @@ int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT; | |||
| */ | |||
| /** | |||
| * @param port_name_pattern A regular expression used to select | |||
| * ports by name. If NULL or of zero length, no selection based | |||
| * @param port_name_pattern A regular expression used to select | |||
| * ports by name. If NULL or of zero length, no selection based | |||
| * on name will be carried out. | |||
| * @param type_name_pattern A regular expression used to select | |||
| * ports by type. If NULL or of zero length, no selection based | |||
| * @param type_name_pattern A regular expression used to select | |||
| * ports by type. If NULL or of zero length, no selection based | |||
| * on type will be carried out. | |||
| * @param flags A value used to select ports by their flags. | |||
| * @param flags A value used to select ports by their flags. | |||
| * If zero, no selection based on flags will be carried out. | |||
| * | |||
| * @return a NULL-terminated array of ports that match the specified | |||
| @@ -1021,8 +1237,8 @@ jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name) JACK_OP | |||
| */ | |||
| jack_port_t * jack_port_by_id (jack_client_t *client, | |||
| jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /*@}*/ | |||
| /*@}*/ | |||
| /** | |||
| * @defgroup TimeFunctions Handling time | |||
| @@ -1052,7 +1268,7 @@ jack_nframes_t jack_frame_time (const jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT | |||
| * This function may only be used from the process callback, and can | |||
| * be used to interpret timestamps generated by jack_frame_time() in | |||
| * other threads with respect to the current process cycle. | |||
| * | |||
| * | |||
| * This is the only jack time function that returns exact time: | |||
| * when used during the process callback it always returns the same | |||
| * value (until the next process callback, where it will return | |||
| @@ -1075,8 +1291,8 @@ jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t) JAC | |||
| /** | |||
| * @return return JACK's current system time in microseconds, | |||
| * using the JACK clock source. | |||
| * | |||
| * using the JACK clock source. | |||
| * | |||
| * The value returned is guaranteed to be monotonic, but not linear. | |||
| */ | |||
| jack_time_t jack_get_time() JACK_OPTIONAL_WEAK_EXPORT; | |||
| @@ -1129,7 +1345,7 @@ void jack_set_info_function (void (*func)(const char *)) JACK_OPTIONAL_WEAK_EXPO | |||
| /*@}*/ | |||
| /** | |||
| * The free function to be used on memory returned by jack_port_get_connections, | |||
| * The free function to be used on memory returned by jack_port_get_connections, | |||
| * jack_port_get_all_connections and jack_get_ports functions. | |||
| * This is MANDATORY on Windows when otherwise all nasty runtime version related crashes can occur. | |||
| * Developers are strongly encouraged to use this function instead of the standard "free" function in new code. | |||
| @@ -1,18 +1,18 @@ | |||
| /* | |||
| Copyright (C) 2004 Ian Esten | |||
| 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -24,11 +24,12 @@ | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| #include <jack/weakmacros.h> | |||
| #include <jack/types.h> | |||
| #include <stdlib.h> | |||
| #include <jack/weakmacros.h> | |||
| /** Type for raw event data contained in @ref jack_midi_event_t. */ | |||
| typedef unsigned char jack_midi_data_t; | |||
| @@ -43,7 +44,7 @@ typedef struct _jack_midi_event | |||
| /** | |||
| * @defgroup MIDIAPI Reading and writing MIDI data | |||
| * @defgroup MIDIAPI Reading and writing MIDI data | |||
| * @{ | |||
| */ | |||
| @@ -57,7 +58,7 @@ jack_midi_get_event_count(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** Get a MIDI event from an event port buffer. | |||
| * | |||
| * | |||
| * Jack MIDI is normalised, the MIDI event returned by this function is | |||
| * guaranteed to be a complete MIDI event (the status byte will always be | |||
| * present, and no realtime events will interspered with the event). | |||
| @@ -74,7 +75,7 @@ jack_midi_event_get(jack_midi_event_t *event, | |||
| /** Clear an event buffer. | |||
| * | |||
| * | |||
| * This should be called at the beginning of each process cycle before calling | |||
| * @ref jack_midi_event_reserve or @ref jack_midi_event_write. This | |||
| * function may not be called on an input port's buffer. | |||
| @@ -105,10 +106,10 @@ jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; | |||
| * messages interspersed with other messages (realtime messages are fine | |||
| * when they occur on their own, like other messages). | |||
| * | |||
| * Events must be written in order, sorted by their sample offsets. | |||
| * JACK will not sort the events for you, and will refuse to store | |||
| * out-of-order events. | |||
| * | |||
| * Events must be written in order, sorted by their sample offsets. | |||
| * JACK will not sort the events for you, and will refuse to store | |||
| * out-of-order events. | |||
| * | |||
| * @param port_buffer Buffer to write event to. | |||
| * @param time Sample offset of event. | |||
| * @param data_size Length of event's raw data in bytes. | |||
| @@ -117,7 +118,7 @@ jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; | |||
| */ | |||
| jack_midi_data_t* | |||
| jack_midi_event_reserve(void *port_buffer, | |||
| jack_nframes_t time, | |||
| jack_nframes_t time, | |||
| size_t data_size) JACK_OPTIONAL_WEAK_EXPORT; | |||
| @@ -125,18 +126,17 @@ jack_midi_event_reserve(void *port_buffer, | |||
| * | |||
| * This function is simply a wrapper for @ref jack_midi_event_reserve | |||
| * which writes the event data into the space reserved in the buffer. | |||
| * The same restrictions on the MIDI data apply. | |||
| * | |||
| * Clients must not write more than | |||
| * @a data_size bytes into this buffer. Clients must write normalised | |||
| * MIDI data to the port - no running status and no (1-byte) realtime | |||
| * messages interspersed with other messages (realtime messages are fine | |||
| * when they occur on their own, like other messages). | |||
| * | |||
| * Events must be written in order, sorted by their sample offsets. | |||
| * JACK will not sort the events for you, and will refuse to store | |||
| * | |||
| * Clients must not write more than | |||
| * @a data_size bytes into this buffer. Clients must write normalised | |||
| * MIDI data to the port - no running status and no (1-byte) realtime | |||
| * messages interspersed with other messages (realtime messages are fine | |||
| * when they occur on their own, like other messages). | |||
| * | |||
| * Events must be written in order, sorted by their sample offsets. | |||
| * JACK will not sort the events for you, and will refuse to store | |||
| * out-of-order events. | |||
| * | |||
| * | |||
| * @param port_buffer Buffer to write event to. | |||
| * @param time Sample offset of event. | |||
| * @param data Message data to be written. | |||
| @@ -2,21 +2,20 @@ | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004 Jack O'Quin | |||
| Copyright (C) 2010 Torben Hohn | |||
| 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 | |||
| 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_session_h__ | |||
| @@ -36,80 +35,114 @@ extern "C" { | |||
| /** | |||
| * session event types. | |||
| * Session event type. | |||
| * | |||
| * if a client cant save templates, i might just do a normal save. | |||
| * | |||
| * the rationale, why there is no quit without save, is that a client | |||
| * might refuse to quit when it has unsaved data. | |||
| * however some other clients might have already quit. | |||
| * this results in too much confusion, so we just dont support that. | |||
| * the session manager can check, if the saved state is different from a previous | |||
| * save, and just remove the saved stuff. | |||
| * | |||
| * (an inquiry function, whether a quit is ok, followed by a quit event | |||
| * would have a race) | |||
| * There is no "quit without saving" event because a client might refuse to | |||
| * quit when it has unsaved data, but other clients may have already quit. | |||
| * This results in too much confusion, so it is unsupported. | |||
| */ | |||
| enum JackSessionEventType { | |||
| /** | |||
| * Save the session completely. | |||
| * | |||
| * The client may save references to data outside the provided directory, | |||
| * but it must do so by creating a link inside the provided directory and | |||
| * referring to that in any save files. The client must not refer to data | |||
| * files outside the provided directory directly in save files, because | |||
| * this makes it impossible for the session manager to create a session | |||
| * archive for distribution or archival. | |||
| */ | |||
| JackSessionSave = 1, | |||
| /** | |||
| * Save the session completly, then quit. | |||
| * | |||
| * The rules for saving are exactly the same as for JackSessionSave. | |||
| */ | |||
| JackSessionSaveAndQuit = 2, | |||
| /** | |||
| * Save a session template. | |||
| * | |||
| * A session template is a "skeleton" of the session, but without any data. | |||
| * Clients must save a session that, when restored, will create the same | |||
| * ports as a full save would have. However, the actual data contained in | |||
| * the session may not be saved (e.g. a DAW would create the necessary | |||
| * tracks, but not save the actual recorded data). | |||
| */ | |||
| JackSessionSaveTemplate = 3 | |||
| }; | |||
| typedef enum JackSessionEventType jack_session_event_type_t; | |||
| /** | |||
| * @ref jack_session_flags_t bits | |||
| */ | |||
| enum JackSessionFlags { | |||
| /** | |||
| * an error occured while saving. | |||
| * An error occured while saving. | |||
| */ | |||
| JackSessionSaveError = 0x01, | |||
| /** | |||
| * this reply indicates that a client is part of a multiclient application. | |||
| * the command reply is left empty. but the session manager should still | |||
| * consider this client part of a session. it will come up due to invocation of another | |||
| * client. | |||
| * Client needs to be run in a terminal. | |||
| */ | |||
| JackSessionChildClient = 0x02 | |||
| JackSessionNeedTerminal = 0x02 | |||
| }; | |||
| /** | |||
| * Session flags. | |||
| */ | |||
| typedef enum JackSessionFlags jack_session_flags_t; | |||
| struct _jack_session_event { | |||
| /** | |||
| * the actual type of this session event. | |||
| * The type of this session event. | |||
| */ | |||
| jack_session_event_type_t type; | |||
| /** | |||
| * session_directory with trailing separator | |||
| * this is per client. so the client can do whatever it likes in here. | |||
| * Session directory path, with trailing separator. | |||
| * | |||
| * This directory is exclusive to the client; when saving the client may | |||
| * create any files it likes in this directory. | |||
| */ | |||
| const char *session_dir; | |||
| /** | |||
| * client_uuid which must be specified to jack_client_open on session reload. | |||
| * client can specify it in the returned commandline as an option, or just save it | |||
| * with the state file. | |||
| * Client UUID which must be passed to jack_client_open on session load. | |||
| * | |||
| * The client can specify this in the returned command line, or save it | |||
| * in a state file within the session directory. | |||
| */ | |||
| const char *client_uuid; | |||
| /** | |||
| * the command_line is the reply of the client. | |||
| * it specifies in a platform dependent way, how the client must be restarted upon session reload. | |||
| * Reply (set by client): the command line needed to restore the client. | |||
| * | |||
| * probably it should contain ${SESSION_DIR} instead of the actual session dir. | |||
| * this would basically make the session dir moveable. | |||
| * This is a platform dependent command line. It must contain | |||
| * ${SESSION_DIR} instead of the actual session directory path. More | |||
| * generally, just as in session files, clients should not include any | |||
| * paths outside the session directory here as this makes | |||
| * archival/distribution impossible. | |||
| * | |||
| * ownership of the memory is handed to jack. | |||
| * initially set to NULL by jack; | |||
| * This field is set to NULL by Jack when the event is delivered to the | |||
| * client. The client must set to allocated memory that is safe to | |||
| * free(). This memory will be freed by jack_session_event_free. | |||
| */ | |||
| char *command_line; | |||
| /** | |||
| * flags to be set by the client. normally left 0. | |||
| * Reply (set by client): Session flags. | |||
| */ | |||
| jack_session_flags_t flags; | |||
| /** | |||
| * Future flags. Set to zero for now. | |||
| */ | |||
| uint32_t future; | |||
| }; | |||
| typedef struct _jack_session_event jack_session_event_t; | |||
| @@ -118,35 +151,42 @@ typedef struct _jack_session_event jack_session_event_t; | |||
| * Prototype for the client supplied function that is called | |||
| * whenever a session notification is sent via jack_session_notify(). | |||
| * | |||
| * The session_id must be passed to jack_client_open on session reload (this can be | |||
| * done by specifying it somehow on the returned command line). | |||
| * Ownership of the memory of @a event is passed to the application. | |||
| * It must be freed using jack_session_event_free when its not used anymore. | |||
| * | |||
| * The client must promptly call jack_session_reply for this event. | |||
| * | |||
| * @param event the event_structure. | |||
| * @param arg pointer to a client supplied structure | |||
| * @param event The event structure. | |||
| * @param arg Pointer to a client supplied structure. | |||
| */ | |||
| typedef void (*JackSessionCallback)(jack_session_event_t *event, void *arg); | |||
| typedef void (*JackSessionCallback)(jack_session_event_t *event, | |||
| void *arg); | |||
| /** | |||
| * Tell the JACK server to call @a save_callback the session handler wants | |||
| * to save. | |||
| * Tell the JACK server to call @a session_callback when a session event | |||
| * is to be delivered. | |||
| * | |||
| * setting more than one session_callback per process is probably a design | |||
| * error. if you have a multiclient application its more sensible to create | |||
| * a jack_client with only a session callback set. | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| */ | |||
| int jack_set_session_callback(jack_client_t *client, | |||
| JackSessionCallback session_callback, | |||
| void *arg) JACK_WEAK_EXPORT; | |||
| int jack_set_session_callback (jack_client_t *client, | |||
| JackSessionCallback session_callback, | |||
| void *arg) JACK_WEAK_EXPORT; | |||
| /** | |||
| * reply to a session_event | |||
| * Reply to a session event. | |||
| * | |||
| * this can either be called directly from the callback, or later from a different thread. | |||
| * so its possible to just stick the event pointer into a pipe and execute the save code | |||
| * from the gui thread. | |||
| * This can either be called directly from the callback, or later from a | |||
| * different thread. For example, it is possible to push the event through a | |||
| * queue and execute the save code from the GUI thread. | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| */ | |||
| int jack_session_reply( jack_client_t *client, jack_session_event_t *event ) JACK_WEAK_EXPORT; | |||
| int jack_session_reply (jack_client_t *client, | |||
| jack_session_event_t *event) JACK_WEAK_EXPORT; | |||
| /** | |||
| @@ -154,74 +194,90 @@ int jack_session_reply( jack_client_t *client, jack_session_event_t *event ) JAC | |||
| * this also frees the memory used by the command_line pointer. | |||
| * if its non NULL. | |||
| */ | |||
| void jack_session_event_free (jack_session_event_t *event) JACK_WEAK_EXPORT; | |||
| void jack_session_event_free (jack_session_event_t *event); | |||
| /*@}*/ | |||
| /** | |||
| * get the assigned uuid for client. | |||
| * safe to call from callback and all other threads. | |||
| * memory needs to be freed. | |||
| */ | |||
| char *jack_client_get_uuid (jack_client_t *client) JACK_WEAK_EXPORT; | |||
| /** | |||
| * @defgroup JackSessionManagerAPI this API is intended for a sessionmanager. | |||
| * this API could be server specific. if we dont reach consensus here, | |||
| * we can just drop it. | |||
| * i know its a bit clumsy. | |||
| * but this api isnt required to be as stable as the client api. | |||
| * @} | |||
| */ | |||
| /** | |||
| * @defgroup JackSessionManagerAPI API for a session manager. | |||
| * | |||
| * @{ | |||
| */ | |||
| typedef struct { | |||
| const char *uuid; | |||
| const char *client_name; | |||
| const char *command; | |||
| jack_session_flags_t flags; | |||
| const char *uuid; | |||
| const char *client_name; | |||
| const char *command; | |||
| jack_session_flags_t flags; | |||
| } jack_session_command_t; | |||
| /** | |||
| * send a save or quit event, to all clients listening for session | |||
| * callbacks. the returned strings of the clients are accumulated and | |||
| * returned as an array of jack_session_command_t. | |||
| * its terminated by ret[i].uuid == NULL | |||
| * target == NULL means send to all interested clients. otherwise a clientname | |||
| * Send an event to all clients listening for session callbacks. | |||
| * | |||
| * The returned strings of the clients are accumulated and returned as an array | |||
| * of jack_session_command_t. its terminated by ret[i].uuid == NULL target == | |||
| * NULL means send to all interested clients. otherwise a clientname | |||
| */ | |||
| jack_session_command_t *jack_session_notify (jack_client_t* client, | |||
| const char *target, | |||
| jack_session_event_type_t type, | |||
| const char *path ) JACK_WEAK_EXPORT; | |||
| jack_session_command_t *jack_session_notify ( | |||
| jack_client_t* client, | |||
| const char *target, | |||
| jack_session_event_type_t type, | |||
| const char *path) JACK_WEAK_EXPORT; | |||
| /** | |||
| * free the memory allocated by a session command. | |||
| * Free the memory allocated by a session command. | |||
| */ | |||
| void jack_session_commands_free (jack_session_command_t *cmds) JACK_WEAK_EXPORT; | |||
| /** | |||
| * get the sessionid for a client name. | |||
| * the sessionmanager needs this to reassociate a client_name to the session_id. | |||
| * Get the session ID for a client name. | |||
| * The session manager needs this to reassociate a client name to the session_id. | |||
| */ | |||
| char *jack_get_uuid_for_client_name( jack_client_t *client, const char *client_name ) JACK_WEAK_EXPORT; | |||
| char *jack_get_uuid_for_client_name (jack_client_t *client, | |||
| const char *client_name) JACK_WEAK_EXPORT; | |||
| /** | |||
| * get the client name for a session_id. | |||
| * in order to snapshot the graph connections, the sessionmanager needs to map | |||
| * Get the client name for a session_id. | |||
| * | |||
| * In order to snapshot the graph connections, the session manager needs to map | |||
| * session_ids to client names. | |||
| */ | |||
| char *jack_get_client_name_by_uuid( jack_client_t *client, const char *client_uuid ) JACK_WEAK_EXPORT; | |||
| char *jack_get_client_name_by_uuid (jack_client_t *client, | |||
| const char *client_uuid ) JACK_WEAK_EXPORT; | |||
| /** | |||
| * reserve a client name and associate it to a uuid. | |||
| * when a client later call jack_client_open() and specifies the uuid, | |||
| * jackd will assign the reserved name. | |||
| * this allows a session manager to know in advance under which client name | |||
| * its managed clients will appear. | |||
| * Reserve a client name and associate it with a UUID. | |||
| * | |||
| * When a client later calls jack_client_open() and specifies the UUID, jackd | |||
| * will assign the reserved name. This allows a session manager to know in | |||
| * advance under which client name its managed clients will appear. | |||
| * | |||
| * @return 0 on success, otherwise a non-zero error code | |||
| */ | |||
| int | |||
| jack_reserve_client_name (jack_client_t *client, | |||
| const char *name, | |||
| const char *uuid) JACK_WEAK_EXPORT; | |||
| /** | |||
| * Find out whether a client has set up a session callback. | |||
| * | |||
| * @return 0 when the client has no session callback, 1 when it has one. | |||
| * -1 on error. | |||
| */ | |||
| int | |||
| jack_reserve_client_name( jack_client_t *client, const char *name, const char *uuid ) JACK_WEAK_EXPORT; | |||
| jack_client_has_session_callback (jack_client_t *client, const char *client_name) JACK_WEAK_EXPORT; | |||
| #ifdef __cplusplus | |||
| } | |||
| @@ -36,15 +36,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| typedef LONGLONG int64_t; | |||
| typedef ULONGLONG uint64_t; | |||
| #endif | |||
| #ifndef pthread_t | |||
| typedef HANDLE pthread_t; | |||
| #endif | |||
| /** | |||
| * to make jack API independent of different thread implementations, | |||
| * we define jack_native_thread_t to HANDLE here. | |||
| */ | |||
| typedef HANDLE jack_native_thread_t; | |||
| #elif __MINGW32__ /* MINGW */ | |||
| #include <stdint.h> | |||
| #include <sys/types.h> | |||
| #ifndef pthread_t | |||
| typedef HANDLE pthread_t; | |||
| #endif | |||
| /** | |||
| * to make jack API independent of different thread implementations, | |||
| * we define jack_native_thread_t to HANDLE here. | |||
| */ | |||
| typedef HANDLE jack_native_thread_t; | |||
| #else /* other compilers ...*/ | |||
| #include <inttypes.h> | |||
| #include <pthread.h> | |||
| @@ -57,6 +61,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include <inttypes.h> | |||
| #include <pthread.h> | |||
| #include <sys/types.h> | |||
| /** | |||
| * to make jack API independent of different thread implementations, | |||
| * we define jack_native_thread_t to pthread_t here. | |||
| */ | |||
| typedef pthread_t jack_native_thread_t; | |||
| #endif /* __APPLE__ || __linux__ || __sun__ || sun */ | |||
| #endif | |||
| @@ -28,6 +28,10 @@ extern "C" | |||
| #include <jack/systemdeps.h> | |||
| #include <jack/weakmacros.h> | |||
| /* use 512KB stack per thread - the default is way too high to be feasible | |||
| * with mlockall() on many systems */ | |||
| #define THREAD_STACK 524288 | |||
| /** @file thread.h | |||
| * | |||
| * Library functions to standardize thread creation for JACK and its | |||
| @@ -66,7 +70,7 @@ int jack_client_max_real_time_priority (jack_client_t*) JACK_OPTIONAL_WEAK_EXPOR | |||
| * @returns 0, if successful; EPERM, if the calling process lacks | |||
| * required realtime privileges; otherwise some other error number. | |||
| */ | |||
| int jack_acquire_real_time_scheduling (pthread_t thread, int priority) JACK_OPTIONAL_WEAK_EXPORT; | |||
| int jack_acquire_real_time_scheduling (jack_native_thread_t thread, int priority) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Create a thread for JACK or one of its clients. The thread is | |||
| @@ -85,7 +89,7 @@ int jack_acquire_real_time_scheduling (pthread_t thread, int priority) JACK_OPTI | |||
| * @returns 0, if successful; otherwise some error number. | |||
| */ | |||
| int jack_client_create_thread (jack_client_t* client, | |||
| pthread_t *thread, | |||
| jack_native_thread_t *thread, | |||
| int priority, | |||
| int realtime, /* boolean */ | |||
| void *(*start_routine)(void*), | |||
| @@ -98,7 +102,7 @@ int jack_client_create_thread (jack_client_t* client, | |||
| * | |||
| * @returns 0, if successful; otherwise an error number. | |||
| */ | |||
| int jack_drop_real_time_scheduling (pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| int jack_drop_real_time_scheduling (jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Stop the thread, waiting for the thread handler to terminate. | |||
| @@ -107,7 +111,7 @@ int jack_drop_real_time_scheduling (pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| * | |||
| * @returns 0, if successful; otherwise an error number. | |||
| */ | |||
| int jack_client_stop_thread(jack_client_t* client, pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| /** | |||
| * Cancel the thread then waits for the thread handler to terminate. | |||
| @@ -116,7 +120,7 @@ int jack_client_stop_thread(jack_client_t* client, pthread_t thread) JACK_OPTION | |||
| * | |||
| * @returns 0, if successful; otherwise an error number. | |||
| */ | |||
| int jack_client_kill_thread(jack_client_t* client, pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
| #ifndef WIN32 | |||
| @@ -74,6 +74,205 @@ typedef uint32_t jack_port_id_t; | |||
| typedef uint32_t jack_port_type_id_t; | |||
| /** | |||
| * @ref jack_options_t bits | |||
| */ | |||
| enum JackOptions { | |||
| /** | |||
| * Null value to use when no option bits are needed. | |||
| */ | |||
| JackNullOption = 0x00, | |||
| /** | |||
| * Do not automatically start the JACK server when it is not | |||
| * already running. This option is always selected if | |||
| * \$JACK_NO_START_SERVER is defined in the calling process | |||
| * environment. | |||
| */ | |||
| JackNoStartServer = 0x01, | |||
| /** | |||
| * Use the exact client name requested. Otherwise, JACK | |||
| * automatically generates a unique one, if needed. | |||
| */ | |||
| JackUseExactName = 0x02, | |||
| /** | |||
| * Open with optional <em>(char *) server_name</em> parameter. | |||
| */ | |||
| JackServerName = 0x04, | |||
| /** | |||
| * Load internal client from optional <em>(char *) | |||
| * load_name</em>. Otherwise use the @a client_name. | |||
| */ | |||
| JackLoadName = 0x08, | |||
| /** | |||
| * Pass optional <em>(char *) load_init</em> string to the | |||
| * jack_initialize() entry point of an internal client. | |||
| */ | |||
| JackLoadInit = 0x10, | |||
| /** | |||
| * pass a SessionID Token this allows the sessionmanager to identify the client again. | |||
| */ | |||
| JackSessionID = 0x20 | |||
| }; | |||
| /** Valid options for opening an external client. */ | |||
| #define JackOpenOptions (JackSessionID|JackServerName|JackNoStartServer|JackUseExactName) | |||
| /** Valid options for loading an internal client. */ | |||
| #define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName) | |||
| /** | |||
| * Options for several JACK operations, formed by OR-ing together the | |||
| * relevant @ref JackOptions bits. | |||
| */ | |||
| typedef enum JackOptions jack_options_t; | |||
| /** | |||
| * @ref jack_status_t bits | |||
| */ | |||
| enum JackStatus { | |||
| /** | |||
| * Overall operation failed. | |||
| */ | |||
| JackFailure = 0x01, | |||
| /** | |||
| * The operation contained an invalid or unsupported option. | |||
| */ | |||
| JackInvalidOption = 0x02, | |||
| /** | |||
| * The desired client name was not unique. With the @ref | |||
| * JackUseExactName option this situation is fatal. Otherwise, | |||
| * the name was modified by appending a dash and a two-digit | |||
| * number in the range "-01" to "-99". The | |||
| * jack_get_client_name() function will return the exact string | |||
| * that was used. If the specified @a client_name plus these | |||
| * extra characters would be too long, the open fails instead. | |||
| */ | |||
| JackNameNotUnique = 0x04, | |||
| /** | |||
| * The JACK server was started as a result of this operation. | |||
| * Otherwise, it was running already. In either case the caller | |||
| * is now connected to jackd, so there is no race condition. | |||
| * When the server shuts down, the client will find out. | |||
| */ | |||
| JackServerStarted = 0x08, | |||
| /** | |||
| * Unable to connect to the JACK server. | |||
| */ | |||
| JackServerFailed = 0x10, | |||
| /** | |||
| * Communication error with the JACK server. | |||
| */ | |||
| JackServerError = 0x20, | |||
| /** | |||
| * Requested client does not exist. | |||
| */ | |||
| JackNoSuchClient = 0x40, | |||
| /** | |||
| * Unable to load internal client | |||
| */ | |||
| JackLoadFailure = 0x80, | |||
| /** | |||
| * Unable to initialize client | |||
| */ | |||
| JackInitFailure = 0x100, | |||
| /** | |||
| * Unable to access shared memory | |||
| */ | |||
| JackShmFailure = 0x200, | |||
| /** | |||
| * Client's protocol version does not match | |||
| */ | |||
| JackVersionError = 0x400, | |||
| /** | |||
| * Backend error | |||
| */ | |||
| JackBackendError = 0x800, | |||
| /** | |||
| * Client zombified failure | |||
| */ | |||
| JackClientZombie = 0x1000 | |||
| }; | |||
| /** | |||
| * Status word returned from several JACK operations, formed by | |||
| * OR-ing together the relevant @ref JackStatus bits. | |||
| */ | |||
| typedef enum JackStatus jack_status_t; | |||
| /** | |||
| * @ref jack_latency_callback_mode_t | |||
| */ | |||
| enum JackLatencyCallbackMode { | |||
| /** | |||
| * Latency Callback for Capture Latency. | |||
| * Input Ports have their latency value setup. | |||
| * In the Callback the client needs to set the latency of the output ports | |||
| */ | |||
| JackCaptureLatency, | |||
| /** | |||
| * Latency Callback for Playback Latency. | |||
| * Output Ports have their latency value setup. | |||
| * In the Callback the client needs to set the latency of the input ports | |||
| */ | |||
| JackPlaybackLatency | |||
| }; | |||
| /** | |||
| * Type of Latency Callback (Capture or Playback) | |||
| */ | |||
| typedef enum JackLatencyCallbackMode jack_latency_callback_mode_t; | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| * by the engine when port latencies need to be recalculated | |||
| * | |||
| * @param mode playback or capture latency | |||
| * @param arg pointer to a client supplied data | |||
| * | |||
| * @return zero on success, non-zero on error | |||
| */ | |||
| typedef void (*JackLatencyCallback)(jack_latency_callback_mode_t mode, void *arg); | |||
| /** | |||
| * the new latency API operates on Ranges. | |||
| */ | |||
| struct _jack_latency_range | |||
| { | |||
| /** | |||
| * minimum latency | |||
| */ | |||
| jack_nframes_t min; | |||
| /** | |||
| * maximum latency | |||
| */ | |||
| jack_nframes_t max; | |||
| }; | |||
| typedef struct _jack_latency_range jack_latency_range_t; | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| * by the engine anytime there is work to be done. | |||
| @@ -164,9 +363,12 @@ typedef int (*JackSampleRateCallback)(jack_nframes_t nframes, void *arg); | |||
| * Prototype for the client supplied function that is called | |||
| * whenever a port is registered or unregistered. | |||
| * | |||
| * @param arg pointer to a client supplied structure | |||
| * @param port the ID of the port | |||
| * @param arg pointer to a client supplied data | |||
| * @param register non-zero if the port is being registered, | |||
| * zero if the port is being unregistered | |||
| */ | |||
| typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg); | |||
| typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int register, void *arg); | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| @@ -177,7 +379,7 @@ typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg | |||
| * zero if the client is being unregistered | |||
| * @param arg pointer to a client supplied structure | |||
| */ | |||
| typedef void (*JackClientRegistrationCallback)(const char* name, int val, void *arg); | |||
| typedef void (*JackClientRegistrationCallback)(const char* name, int register, void *arg); | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| @@ -214,7 +416,7 @@ typedef void (*JackFreewheelCallback)(int starting, void *arg); | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| * whenever jackd is shutdown. Note that after server shutdown, | |||
| * whenever jackd is shutdown. Note that after server shutdown, | |||
| * the client pointer is *not* deallocated by libjack, | |||
| * the application is responsible to properly use jack_client_close() | |||
| * to release client ressources. Warning: jack_client_close() cannot be | |||
| @@ -225,6 +427,21 @@ typedef void (*JackFreewheelCallback)(int starting, void *arg); | |||
| */ | |||
| typedef void (*JackShutdownCallback)(void *arg); | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| * whenever jackd is shutdown. Note that after server shutdown, | |||
| * the client pointer is *not* deallocated by libjack, | |||
| * the application is responsible to properly use jack_client_close() | |||
| * to release client ressources. Warning: jack_client_close() cannot be | |||
| * safely used inside the shutdown callback and has to be called outside of | |||
| * the callback context. | |||
| * @param code a status word, formed by OR-ing together the relevant @ref JackStatus bits. | |||
| * @param reason a string describing the shutdown reason (backend failure, server crash... etc...) | |||
| * @param arg pointer to a client supplied structure | |||
| */ | |||
| typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg); | |||
| /** | |||
| * Used for the type argument of jack_port_register() for default | |||
| * audio ports and midi ports. | |||
| @@ -295,161 +512,9 @@ enum JackPortFlags { | |||
| * their ports. | |||
| */ | |||
| JackPortIsTerminal = 0x10, | |||
| /** | |||
| * JackPortIsActive means the port has been registered and the | |||
| * client is "active", that is jack_activate has been called | |||
| * | |||
| * JackPortIsActive is on between jack_activate and jack_deactivate. | |||
| */ | |||
| JackPortIsActive = 0x20 | |||
| }; | |||
| /** | |||
| * @ref jack_options_t bits | |||
| */ | |||
| enum JackOptions { | |||
| /** | |||
| * Null value to use when no option bits are needed. | |||
| */ | |||
| JackNullOption = 0x00, | |||
| /** | |||
| * Do not automatically start the JACK server when it is not | |||
| * already running. This option is always selected if | |||
| * \$JACK_NO_START_SERVER is defined in the calling process | |||
| * environment. | |||
| */ | |||
| JackNoStartServer = 0x01, | |||
| /** | |||
| * Use the exact client name requested. Otherwise, JACK | |||
| * automatically generates a unique one, if needed. | |||
| */ | |||
| JackUseExactName = 0x02, | |||
| /** | |||
| * Open with optional <em>(char *) server_name</em> parameter. | |||
| */ | |||
| JackServerName = 0x04, | |||
| /** | |||
| * Load internal client from optional <em>(char *) | |||
| * load_name</em>. Otherwise use the @a client_name. | |||
| */ | |||
| JackLoadName = 0x08, | |||
| /** | |||
| * Pass optional <em>(char *) load_init</em> string to the | |||
| * jack_initialize() entry point of an internal client. | |||
| */ | |||
| JackLoadInit = 0x10, | |||
| /** | |||
| * pass a SessionID Token this allows the sessionmanager to identify the client again. | |||
| */ | |||
| JackSessionID = 0x20 | |||
| }; | |||
| /** Valid options for opening an external client. */ | |||
| #define JackOpenOptions (JackSessionID|JackServerName|JackNoStartServer|JackUseExactName) | |||
| /** Valid options for loading an internal client. */ | |||
| #define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName) | |||
| /** | |||
| * Options for several JACK operations, formed by OR-ing together the | |||
| * relevant @ref JackOptions bits. | |||
| */ | |||
| typedef enum JackOptions jack_options_t; | |||
| /** | |||
| * @ref jack_status_t bits | |||
| */ | |||
| enum JackStatus { | |||
| /** | |||
| * Overall operation failed. | |||
| */ | |||
| JackFailure = 0x01, | |||
| /** | |||
| * The operation contained an invalid or unsupported option. | |||
| */ | |||
| JackInvalidOption = 0x02, | |||
| /** | |||
| * The desired client name was not unique. With the @ref | |||
| * JackUseExactName option this situation is fatal. Otherwise, | |||
| * the name was modified by appending a dash and a two-digit | |||
| * number in the range "-01" to "-99". The | |||
| * jack_get_client_name() function will return the exact string | |||
| * that was used. If the specified @a client_name plus these | |||
| * extra characters would be too long, the open fails instead. | |||
| */ | |||
| JackNameNotUnique = 0x04, | |||
| /** | |||
| * The JACK server was started as a result of this operation. | |||
| * Otherwise, it was running already. In either case the caller | |||
| * is now connected to jackd, so there is no race condition. | |||
| * When the server shuts down, the client will find out. | |||
| */ | |||
| JackServerStarted = 0x08, | |||
| /** | |||
| * Unable to connect to the JACK server. | |||
| */ | |||
| JackServerFailed = 0x10, | |||
| /** | |||
| * Communication error with the JACK server. | |||
| */ | |||
| JackServerError = 0x20, | |||
| /** | |||
| * Requested client does not exist. | |||
| */ | |||
| JackNoSuchClient = 0x40, | |||
| /** | |||
| * Unable to load internal client | |||
| */ | |||
| JackLoadFailure = 0x80, | |||
| /** | |||
| * Unable to initialize client | |||
| */ | |||
| JackInitFailure = 0x100, | |||
| /** | |||
| * Unable to access shared memory | |||
| */ | |||
| JackShmFailure = 0x200, | |||
| /** | |||
| * Client's protocol version does not match | |||
| */ | |||
| JackVersionError = 0x400, | |||
| /** | |||
| * Backend error | |||
| */ | |||
| JackBackendError = 0x800, | |||
| /** | |||
| * Client zombified failure | |||
| */ | |||
| JackClientZombie = 0x1000 | |||
| }; | |||
| /** | |||
| * Status word returned from several JACK operations, formed by | |||
| * OR-ing together the relevant @ref JackStatus bits. | |||
| */ | |||
| typedef enum JackStatus jack_status_t; | |||
| /** | |||
| * Transport states. | |||
| */ | |||
| @@ -476,7 +541,7 @@ typedef enum { | |||
| JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */ | |||
| JackAudioVideoRatio = 0x80, /**< audio frames per video frame */ | |||
| JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */ | |||
| } jack_position_bits_t; | |||
| /** all valid position bits */ | |||
| @@ -666,19 +731,5 @@ typedef struct { | |||
| } jack_transport_info_t; | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| * whenever jackd is shutdown. Note that after server shutdown, | |||
| * the client pointer is *not* deallocated by libjack, | |||
| * the application is responsible to properly use jack_client_close() | |||
| * to release client ressources. Warning: jack_client_close() cannot be | |||
| * safely used inside the shutdown callback and has to be called outside of | |||
| * the callback context. | |||
| * @param code a status word, formed by OR-ing together the relevant @ref JackStatus bits. | |||
| * @param reason a string describing the shutdown reason (backend failure, server crash... etc...) | |||
| * @param arg pointer to a client supplied structure | |||
| */ | |||
| typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg); | |||
| #endif /* __jack_types_h__ */ | |||
| @@ -1,18 +1,18 @@ | |||
| /* | |||
| Copyright (C) 2010 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -20,10 +20,63 @@ | |||
| #ifndef __weakjack_h__ | |||
| #define __weakjack_h__ | |||
| /** | |||
| * @defgroup WeakLinkage managing support for newer/older versions of JACK | |||
| * @{ One challenge faced by developers is that of taking advantage of new features introduced in new versions of [ JACK ] while still | |||
| * supporting older versions of the system. Normally, if an application uses a new feature in a library/API, it is unable to run on | |||
| * earlier versions of the library/API that do not support that feature. Such applications would either fail to launch or crash when | |||
| * an attempt to use the feature was made. This problem cane be solved using weakly-linked symbols. | |||
| * | |||
| * When a symbol in a framework is defined as weakly linked, the symbol does not have to be present at runtime for a process to | |||
| * continue running. The static linker identifies a weakly linked symbol as such in any code module that references the symbol. The | |||
| * dynamic linker uses this same information at runtime to determine whether a process can continue running. If a weakly linked symbol | |||
| * is not present in the framework, the code module can continue to run as long as it does not reference the symbol. However, if the | |||
| * symbol is present, the code can use it normally. | |||
| * | |||
| * (adapted from: http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html) | |||
| * | |||
| * A concrete example will help. Suppose that someone uses a version | |||
| * of a JACK client we'll call "Jill". Jill was linked against a version | |||
| * of JACK that contains a newer part of the API (say, jack_set_latency_callback()) | |||
| * and would like to use it if it is available. | |||
| * | |||
| * When Jill is run on a system that has a suitably "new" version of | |||
| * JACK, this function will be available entirely normally. But if Jill | |||
| * is run on a system with an old version of JACK, the function isn't | |||
| * available. | |||
| * | |||
| * With normal symbol linkage, this would create a startup error whenever | |||
| * someone tries to run Jill with the "old" version of JACK. However, functions | |||
| * added to JACK after version 0.116.2 are all declared to have "weak" linkage | |||
| * which means that their abscence doesn't cause an error during program | |||
| * startup. Instead, Jill can test whether or not the symbol jack_set_latency_callback | |||
| * is null or not. If its null, it means that the JACK installed on this machine | |||
| * is too old to support this function. If its not null, then Jill can use it | |||
| * just like any other function in the API. For example: | |||
| * | |||
| * \code | |||
| * if (jack_set_latency_callback) { | |||
| * jack_set_latency_callback (jill_client, jill_latency_callback, arg); | |||
| * } | |||
| * \endcode | |||
| * | |||
| * However, there are clients that may want to use this approach to parts of the | |||
| * the JACK API that predate 0.116.2. For example, they might want to see if even | |||
| * really old basic parts of the API like jack_client_open() exist at runtime. | |||
| * | |||
| * Such clients should include <jack/weakjack.h> before any other JACK header. | |||
| * This will make the \b entire JACK API be subject to weak linkage, so that any | |||
| * and all functions can be checked for existence at runtime. It is important | |||
| * to understand that very few clients need to do this - if you use this | |||
| * feature you should have a clear reason to do so. | |||
| * | |||
| * | |||
| */ | |||
| #ifndef JACK_OPTIONAL_WEAK_EXPORT | |||
| /* JACK_OPTIONAL_WEAK_EXPORT needs to be a macro which | |||
| expands into a compiler directive. If non-null, the directive | |||
| must tell the compiler to arrange for weak linkage of | |||
| expands into a compiler directive. If non-null, the directive | |||
| must tell the compiler to arrange for weak linkage of | |||
| the symbol it used with. For this to work fully may | |||
| require linker arguments for the client as well. | |||
| */ | |||
| @@ -49,4 +102,6 @@ | |||
| #endif | |||
| #endif | |||
| /*@}*/ | |||
| #endif /* weakjack */ | |||
| @@ -1,18 +1,18 @@ | |||
| /* | |||
| Copyright (C) 2010 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -23,27 +23,31 @@ | |||
| /************************************************************* | |||
| * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | |||
| * added to the JACK API after the 0.116.2 release. | |||
| * | |||
| * Functions that predate this release are marked with | |||
| * | |||
| * Functions that predate this release are marked with | |||
| * JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile | |||
| * time in a variety of ways. The default definition is empty, | |||
| * so that these symbols get normal linkage. If you wish to | |||
| * use all JACK symbols with weak linkage, include | |||
| * use all JACK symbols with weak linkage, include | |||
| * <jack/weakjack.h> before jack.h. | |||
| *************************************************************/ | |||
| #ifndef JACK_WEAK_EXPORT | |||
| #ifdef __GNUC__ | |||
| /* JACK_WEAK_EXPORT needs to be a macro which | |||
| expands into a compiler directive. If non-null, the directive | |||
| must tell the compiler to arrange for weak linkage of | |||
| expands into a compiler directive. If non-null, the directive | |||
| must tell the compiler to arrange for weak linkage of | |||
| the symbol it used with. For this to work full may | |||
| require linker arguments in the client as well. | |||
| */ | |||
| #define JACK_WEAK_EXPORT __attribute__((weak)) | |||
| #else | |||
| /* Add other things here for non-gcc platforms */ | |||
| #define JACK_WEAK_EXPORT | |||
| #ifdef WIN32 | |||
| #define JACK_WEAK_EXPORT | |||
| #endif | |||
| #endif | |||
| #endif | |||
| @@ -54,9 +58,13 @@ | |||
| #ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
| #ifdef __GNUC__ | |||
| #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__)) | |||
| #else | |||
| #else | |||
| /* Add other things here for non-gcc platforms */ | |||
| #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
| #ifdef WIN32 | |||
| #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
| #endif | |||
| #endif /* __GNUC__ */ | |||
| #endif | |||
| @@ -25,7 +25,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
| */ | |||
| #include <math.h> | |||
| #include <stdio.h> | |||
| #include <memory.h> | |||
| @@ -48,8 +47,6 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
| #include <netinet/in.h> | |||
| #endif | |||
| #include "netjack.h" | |||
| #ifdef __linux__ | |||
| #include "config.h" | |||
| #endif | |||
| @@ -58,15 +55,11 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
| #include <samplerate.h> | |||
| #endif | |||
| #if HAVE_CELT | |||
| #include <celt/celt.h> | |||
| #endif | |||
| #include "netjack.h" | |||
| #include "netjack_packet.h" | |||
| // JACK2 | |||
| #include "jack/control.h" | |||
| #include "control.h" | |||
| #define MIN(x,y) ((x)<(y) ? (x) : (y)) | |||
| @@ -105,8 +98,8 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| netj->expected_framecnt += 1; | |||
| } else { | |||
| // starting up.... lets look into the packetcache, and fetch the highest packet. | |||
| packet_cache_drain_socket( global_packcache, netj->sockfd ); | |||
| if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail ) ) { | |||
| packet_cache_drain_socket( netj->packcache, netj->sockfd ); | |||
| if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail ) ) { | |||
| netj->expected_framecnt = next_frame_avail; | |||
| netj->expected_framecnt_valid = 1; | |||
| } else { | |||
| @@ -122,7 +115,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // then poll (have deadline calculated) | |||
| // then drain socket, rinse and repeat. | |||
| while(1) { | |||
| if( packet_cache_get_next_available_framecnt( global_packcache, netj->expected_framecnt, &next_frame_avail) ) { | |||
| if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) { | |||
| if( next_frame_avail == netj->expected_framecnt ) { | |||
| we_have_the_expected_frame = 1; | |||
| if( !netj->always_deadline ) | |||
| @@ -133,13 +126,13 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| break; | |||
| } | |||
| packet_cache_drain_socket( global_packcache, netj->sockfd ); | |||
| packet_cache_drain_socket( netj->packcache, netj->sockfd ); | |||
| } | |||
| // check if we know who to send our packets too. | |||
| if (!netj->srcaddress_valid) | |||
| if( global_packcache->master_address_valid ) { | |||
| memcpy (&(netj->syncsource_address), &(global_packcache->master_address), sizeof( struct sockaddr_in ) ); | |||
| if( netj->packcache->master_address_valid ) { | |||
| memcpy (&(netj->syncsource_address), &(netj->packcache->master_address), sizeof( struct sockaddr_in ) ); | |||
| netj->srcaddress_valid = 1; | |||
| } | |||
| @@ -161,7 +154,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| else | |||
| netj->time_to_deadline = 0; | |||
| packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp); | |||
| packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp); | |||
| pkthdr = (jacknet_packet_header *) netj->rx_buf; | |||
| packet_header_ntoh(pkthdr); | |||
| netj->deadline_goodness = (int)pkthdr->sync_state; | |||
| @@ -203,7 +196,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // lets check if we have the next packets, we will just run a cycle without data. | |||
| // in that case. | |||
| if( packet_cache_get_next_available_framecnt( global_packcache, netj->expected_framecnt, &next_frame_avail) ) | |||
| if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) | |||
| { | |||
| jack_nframes_t offset = next_frame_avail - netj->expected_framecnt; | |||
| @@ -221,7 +214,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // I also found this happening, when the packet queue, is too full. | |||
| // but wtf ? use a smaller latency. this link can handle that ;S | |||
| if( packet_cache_get_fill( global_packcache, netj->expected_framecnt ) > 80.0 ) | |||
| if( packet_cache_get_fill( netj->packcache, netj->expected_framecnt ) > 80.0 ) | |||
| netj->next_deadline -= netj->period_usecs/2; | |||
| @@ -229,7 +222,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // the diff is too high. but we have a packet in the future. | |||
| // lets resync. | |||
| netj->expected_framecnt = next_frame_avail; | |||
| packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
| packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
| pkthdr = (jacknet_packet_header *) netj->rx_buf; | |||
| packet_header_ntoh(pkthdr); | |||
| //netj->deadline_goodness = 0; | |||
| @@ -257,7 +250,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // i will make the packet cache drop redundant packets, | |||
| // that have already been retreived. | |||
| // | |||
| if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) { | |||
| if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) { | |||
| if( next_frame_avail == (netj->expected_framecnt - 1) ) { | |||
| // Ok. the last packet is there now. | |||
| // and it had not been retrieved. | |||
| @@ -277,9 +270,9 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // But now we can check for any new frame available. | |||
| // | |||
| if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) { | |||
| if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) { | |||
| netj->expected_framecnt = next_frame_avail; | |||
| packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
| packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
| pkthdr = (jacknet_packet_header *) netj->rx_buf; | |||
| packet_header_ntoh(pkthdr); | |||
| netj->deadline_goodness = pkthdr->sync_state; | |||
| @@ -300,7 +293,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
| // reply address changes port. | |||
| if (netj->num_lost_packets > 200 ) { | |||
| netj->srcaddress_valid = 0; | |||
| packet_cache_reset_master_address( global_packcache ); | |||
| packet_cache_reset_master_address( netj->packcache ); | |||
| } | |||
| } | |||
| } | |||
| @@ -369,6 +362,21 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
| int port_flags; | |||
| if( netj->bitdepth == CELT_MODE ) | |||
| { | |||
| #if HAVE_CELT | |||
| #if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
| celt_int32 lookahead; | |||
| netj->celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); | |||
| #else | |||
| celt_int32_t lookahead; | |||
| netj->celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL ); | |||
| #endif | |||
| celt_mode_info( netj->celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); | |||
| netj->codec_latency = 2*lookahead; | |||
| #endif | |||
| } | |||
| if (netj->handle_transport_sync) | |||
| jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL); | |||
| @@ -390,17 +398,11 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
| if( netj->bitdepth == CELT_MODE ) { | |||
| #if HAVE_CELT | |||
| #if HAVE_CELT_API_0_7 | |||
| celt_int32 lookahead; | |||
| CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); | |||
| netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); | |||
| #if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
| netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode, 1, NULL ) ); | |||
| #else | |||
| celt_int32_t lookahead; | |||
| CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL ); | |||
| netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode ) ); | |||
| netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode ) ); | |||
| #endif | |||
| celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); | |||
| netj->codec_latency = 2*lookahead; | |||
| #endif | |||
| } else { | |||
| #if HAVE_SAMPLERATE | |||
| @@ -408,6 +410,7 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
| #endif | |||
| } | |||
| } | |||
| for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) { | |||
| snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1); | |||
| @@ -441,7 +444,7 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
| jack_slist_append (netj->playback_ports, port); | |||
| if( netj->bitdepth == CELT_MODE ) { | |||
| #if HAVE_CELT | |||
| #if HAVE_CELT_API_0_7 | |||
| #if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
| CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); | |||
| netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); | |||
| #else | |||
| @@ -479,7 +482,6 @@ void netjack_detach( netjack_driver_state_t *netj ) | |||
| { | |||
| JSList * node; | |||
| for (node = netj->capture_ports; node; node = jack_slist_next (node)) | |||
| jack_port_unregister (netj->client, | |||
| ((jack_port_t *) node->data)); | |||
| @@ -487,12 +489,57 @@ void netjack_detach( netjack_driver_state_t *netj ) | |||
| jack_slist_free (netj->capture_ports); | |||
| netj->capture_ports = NULL; | |||
| for (node = netj->capture_srcs; node; node = jack_slist_next (node)) | |||
| { | |||
| #if HAVE_CELT | |||
| if( netj->bitdepth == CELT_MODE ) | |||
| { | |||
| CELTDecoder * decoder = node->data; | |||
| celt_decoder_destroy(decoder); | |||
| } | |||
| else | |||
| #endif | |||
| { | |||
| #if HAVE_SAMPLERATE | |||
| SRC_STATE * src = node->data; | |||
| src_delete(src); | |||
| #endif | |||
| } | |||
| } | |||
| jack_slist_free (netj->capture_srcs); | |||
| netj->playback_srcs = NULL; | |||
| for (node = netj->playback_ports; node; node = jack_slist_next (node)) | |||
| jack_port_unregister (netj->client, | |||
| ((jack_port_t *) node->data)); | |||
| jack_slist_free (netj->playback_ports); | |||
| netj->playback_ports = NULL; | |||
| for (node = netj->playback_srcs; node; node = jack_slist_next (node)) | |||
| { | |||
| #if HAVE_CELT | |||
| if( netj->bitdepth == CELT_MODE ) | |||
| { | |||
| CELTEncoder * encoder = node->data; | |||
| celt_encoder_destroy(encoder); | |||
| } | |||
| else | |||
| #endif | |||
| { | |||
| #if HAVE_SAMPLERATE | |||
| SRC_STATE * src = node->data; | |||
| src_delete(src); | |||
| #endif | |||
| } | |||
| } | |||
| jack_slist_free (netj->playback_srcs); | |||
| netj->playback_srcs = NULL; | |||
| #if HAVE_CELT | |||
| if( netj->bitdepth == CELT_MODE ) | |||
| celt_mode_destroy(netj->celt_mode); | |||
| #endif | |||
| } | |||
| @@ -574,8 +621,8 @@ void netjack_release( netjack_driver_state_t *netj ) | |||
| close( netj->sockfd ); | |||
| close( netj->outsockfd ); | |||
| packet_cache_free( global_packcache ); | |||
| global_packcache = NULL; | |||
| packet_cache_free( netj->packcache ); | |||
| netj->packcache = NULL; | |||
| } | |||
| int | |||
| @@ -585,13 +632,7 @@ netjack_startup( netjack_driver_state_t *netj ) | |||
| struct sockaddr_in address; | |||
| // Now open the socket, and wait for the first packet to arrive... | |||
| netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); | |||
| #ifdef WIN32 | |||
| u_long parm = 1; | |||
| DWORD bufsize = 262144; | |||
| //ioctlsocket( netj->sockfd, FIONBIO, &parm ); | |||
| setsockopt( netj->sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize) ); | |||
| setsockopt( netj->sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize) ); | |||
| if (netj->sockfd == INVALID_SOCKET) | |||
| #else | |||
| if (netj->sockfd == -1) | |||
| @@ -632,6 +673,10 @@ netjack_startup( netjack_driver_state_t *netj ) | |||
| //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); | |||
| while(1) { | |||
| if( ! netjack_poll( netj->sockfd, 1000 ) ) { | |||
| jack_info ("Waiting aborted"); | |||
| return -1; | |||
| } | |||
| first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); | |||
| #ifdef WIN32 | |||
| if( first_pack_len == -1 ) { | |||
| @@ -735,7 +780,7 @@ netjack_startup( netjack_driver_state_t *netj ) | |||
| } | |||
| netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth); | |||
| global_packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu); | |||
| netj->packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu); | |||
| netj->expected_framecnt_valid = 0; | |||
| netj->num_lost_packets = 0; | |||
| @@ -30,6 +30,10 @@ | |||
| #include "jack/jslist.h" | |||
| #if HAVE_CELT | |||
| #include <celt/celt.h> | |||
| #endif | |||
| //#include <netinet/in.h> | |||
| #ifdef __cplusplus | |||
| @@ -37,6 +41,8 @@ extern "C" | |||
| { | |||
| #endif | |||
| struct _packet_cache; | |||
| typedef struct _netjack_driver_state netjack_driver_state_t; | |||
| struct _netjack_driver_state { | |||
| @@ -106,6 +112,10 @@ struct _netjack_driver_state { | |||
| unsigned int resample_factor; | |||
| unsigned int resample_factor_up; | |||
| int jitter_val; | |||
| struct _packet_cache * packcache; | |||
| #if HAVE_CELT | |||
| CELTMode *celt_mode; | |||
| #endif | |||
| }; | |||
| int netjack_wait( netjack_driver_state_t *netj ); | |||
| @@ -75,7 +75,7 @@ | |||
| #include "netjack_packet.h" | |||
| // JACK2 specific. | |||
| #include "jack/control.h" | |||
| #include "control.h" | |||
| #ifdef NO_JACK_ERROR | |||
| #define jack_error printf | |||
| @@ -83,8 +83,6 @@ | |||
| int fraggo = 0; | |||
| packet_cache *global_packcache = NULL; | |||
| void | |||
| packet_header_hton (jacknet_packet_header *pkthdr) | |||
| { | |||
| @@ -388,7 +386,7 @@ netjack_poll_deadline (int sockfd, jack_time_t deadline) | |||
| #if HAVE_PPOLL | |||
| timeout_spec.tv_nsec = (deadline - now) * 1000; | |||
| #else | |||
| timeout = (deadline - now + 500) / 1000; | |||
| timeout = lrintf( (float)(deadline - now) / 1000.0 ); | |||
| #endif | |||
| @@ -565,7 +563,7 @@ packet_cache_drain_socket( packet_cache *pcache, int sockfd ) | |||
| if( pcache->last_framecnt_retreived_valid && (framecnt <= pcache->last_framecnt_retreived )) | |||
| continue; | |||
| cpack = packet_cache_get_packet (global_packcache, framecnt); | |||
| cpack = packet_cache_get_packet (pcache, framecnt); | |||
| cache_packet_add_fragment (cpack, rx_packet, rcv_len); | |||
| cpack->recv_timestamp = jack_get_time(); | |||
| } | |||
| @@ -774,61 +772,6 @@ packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecn | |||
| return retval; | |||
| } | |||
| // fragmented packet IO | |||
| int | |||
| netjack_recvfrom (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, size_t *addr_size, int mtu) | |||
| { | |||
| int retval; | |||
| socklen_t from_len = *addr_size; | |||
| if (pkt_size <= mtu) { | |||
| retval = recvfrom (sockfd, packet_buf, pkt_size, flags, addr, &from_len); | |||
| *addr_size = from_len; | |||
| return retval; | |||
| } | |||
| char *rx_packet = alloca (mtu); | |||
| jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet; | |||
| int rcv_len; | |||
| jack_nframes_t framecnt; | |||
| cache_packet *cpack; | |||
| do | |||
| { | |||
| rcv_len = recvfrom (sockfd, rx_packet, mtu, 0, addr, &from_len); | |||
| if (rcv_len < 0) | |||
| return rcv_len; | |||
| framecnt = ntohl (pkthdr->framecnt); | |||
| cpack = packet_cache_get_packet (global_packcache, framecnt); | |||
| cache_packet_add_fragment (cpack, rx_packet, rcv_len); | |||
| } while (!cache_packet_is_complete (cpack)); | |||
| memcpy (packet_buf, cpack->packet_buf, pkt_size); | |||
| cache_packet_reset (cpack); | |||
| *addr_size = from_len; | |||
| return pkt_size; | |||
| } | |||
| int | |||
| netjack_recv (int sockfd, char *packet_buf, int pkt_size, int flags, int mtu) | |||
| { | |||
| if (pkt_size <= mtu) | |||
| return recv (sockfd, packet_buf, pkt_size, flags); | |||
| char *rx_packet = alloca (mtu); | |||
| jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet; | |||
| int rcv_len; | |||
| jack_nframes_t framecnt; | |||
| cache_packet *cpack; | |||
| do | |||
| { | |||
| rcv_len = recv (sockfd, rx_packet, mtu, flags); | |||
| if (rcv_len < 0) | |||
| return rcv_len; | |||
| framecnt = ntohl (pkthdr->framecnt); | |||
| cpack = packet_cache_get_packet (global_packcache, framecnt); | |||
| cache_packet_add_fragment (cpack, rx_packet, rcv_len); | |||
| } while (!cache_packet_is_complete (cpack)); | |||
| memcpy (packet_buf, cpack->packet_buf, pkt_size); | |||
| cache_packet_reset (cpack); | |||
| return pkt_size; | |||
| } | |||
| void | |||
| netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu) | |||
| { | |||
| @@ -1427,10 +1370,17 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri | |||
| // audio port, decode celt data. | |||
| CELTDecoder *decoder = src_node->data; | |||
| #if HAVE_CELT_API_0_8 | |||
| if( !packet_payload ) | |||
| celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); | |||
| else | |||
| celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); | |||
| #else | |||
| if( !packet_payload ) | |||
| celt_decode_float( decoder, NULL, net_period_down, buf ); | |||
| else | |||
| celt_decode_float( decoder, packet_bufX, net_period_down, buf ); | |||
| #endif | |||
| src_node = jack_slist_next (src_node); | |||
| } | |||
| @@ -1472,7 +1422,11 @@ render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs | |||
| float *floatbuf = alloca (sizeof(float) * nframes ); | |||
| memcpy( floatbuf, buf, nframes*sizeof(float) ); | |||
| CELTEncoder *encoder = src_node->data; | |||
| #if HAVE_CELT_API_0_8 | |||
| encoded_bytes = celt_encode_float( encoder, floatbuf, nframes, packet_bufX, net_period_up ); | |||
| #else | |||
| encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); | |||
| #endif | |||
| if( encoded_bytes != net_period_up ) | |||
| printf( "something in celt changed. netjack needs to be changed to handle this.\n" ); | |||
| src_node = jack_slist_next( src_node ); | |||
| @@ -107,8 +107,6 @@ struct _packet_cache | |||
| int last_framecnt_retreived_valid; | |||
| }; | |||
| extern packet_cache *global_packcache; | |||
| // fragment cache function prototypes | |||
| // XXX: Some of these are private. | |||
| packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu); | |||
| @@ -152,10 +150,6 @@ void render_jack_ports_to_payload(int bitdepth, JSList *playback_ports, JSList * | |||
| // This one waits forever. an is not using ppoll | |||
| int netjack_poll(int sockfd, int timeout); | |||
| // TODO: these are deprecated. | |||
| //int netjack_recvfrom(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, socklen_t *addr_size, int mtu); | |||
| //int netjack_recv(int sockfd, char *packet_buf, int pkt_size, int flags, int mtu); | |||
| void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); | |||
| void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); | |||
| #ifdef __cplusplus | |||
| @@ -1,24 +1,25 @@ | |||
| /* | |||
| Copyright (C) 2002-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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "timestamps.h" | |||
| #include "JackTime.h" | |||
| @@ -60,7 +61,7 @@ jack_dump_timestamps (FILE *out) | |||
| unsigned long i; | |||
| for (i = 0; i < timestamp_index; ++i) { | |||
| fprintf (out, "%-.32s %" PRIu64 " %" PRIu64, | |||
| fprintf (out, "%-.32s %" PRIu64 " %" PRIu64, | |||
| timestamps[i].what, timestamps[i].when, | |||
| timestamps[i].when - timestamps[0].when); | |||
| if (i > 0) { | |||
| @@ -11,12 +11,11 @@ | |||
| #include <string.h> | |||
| #include <signal.h> | |||
| #include <alloca.h> | |||
| #include <math.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/jslist.h> | |||
| #include <memops.h> | |||
| #include <jack/memops.h> | |||
| #include "alsa/asoundlib.h" | |||
| @@ -77,6 +76,12 @@ 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 { | |||
| @@ -307,8 +312,6 @@ double hann( double x ) | |||
| */ | |||
| int process (jack_nframes_t nframes, void *arg) { | |||
| char *outbuf; | |||
| float *resampbuf; | |||
| int rlen; | |||
| int err; | |||
| snd_pcm_sframes_t delay = target_delay; | |||
| @@ -322,10 +325,15 @@ int process (jack_nframes_t nframes, void *arg) { | |||
| // this is for compensating xruns etc... | |||
| if( delay > (target_delay+max_diff) ) { | |||
| char *tmp = alloca( (delay-target_delay) * formats[format].sample_size * num_channels ); | |||
| snd_pcm_readi( alsa_handle, tmp, delay-target_delay ); | |||
| 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. | |||
| @@ -399,13 +407,6 @@ int process (jack_nframes_t nframes, void *arg) { | |||
| // 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 ) ); | |||
| // get the data... | |||
| again: | |||
| @@ -465,6 +466,32 @@ 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... | |||
| @@ -661,6 +688,8 @@ int main (int argc, char *argv[]) { | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| if (jack_set_latency_callback) | |||
| jack_set_latency_callback (client, latency_cb, 0); | |||
| // get jack sample_rate | |||
| @@ -716,6 +745,17 @@ int main (int argc, char *argv[]) { | |||
| // 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 */ | |||
| @@ -11,12 +11,11 @@ | |||
| #include <string.h> | |||
| #include <signal.h> | |||
| #include <alloca.h> | |||
| #include <math.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/jslist.h> | |||
| #include <memops.h> | |||
| #include <jack/memops.h> | |||
| #include "alsa/asoundlib.h" | |||
| @@ -35,6 +34,7 @@ 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; | |||
| @@ -45,7 +45,6 @@ double *window_array; | |||
| int offset_differential_index = 0; | |||
| double offset_integral = 0; | |||
| int quit = 0; | |||
| // ------------------------------------------------------ commandline parameters | |||
| @@ -77,6 +76,12 @@ 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 { | |||
| @@ -90,6 +95,7 @@ typedef struct alsa_format { | |||
| 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" } | |||
| }; | |||
| @@ -311,8 +317,6 @@ double hann( double x ) | |||
| */ | |||
| int process (jack_nframes_t nframes, void *arg) { | |||
| char *outbuf; | |||
| float *resampbuf; | |||
| int rlen; | |||
| int err; | |||
| snd_pcm_sframes_t delay = target_delay; | |||
| @@ -321,7 +325,6 @@ int process (jack_nframes_t nframes, void *arg) { | |||
| delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; | |||
| delay -= jack_frames_since_cycle_start( client ); | |||
| delay += jack_get_buffer_size( client ) / 2; | |||
| // Do it the hard way. | |||
| // this is for compensating xruns etc... | |||
| @@ -340,12 +343,15 @@ int process (jack_nframes_t nframes, void *arg) { | |||
| offset_array[i] = 0.0; | |||
| } | |||
| if( delay < (target_delay-max_diff) ) { | |||
| char *tmp = alloca( (target_delay-delay) * formats[format].sample_size * num_channels ); | |||
| memset( tmp, 0, formats[format].sample_size * num_channels * (target_delay-delay) ); | |||
| snd_pcm_writei( alsa_handle, tmp, target_delay-delay ); | |||
| output_new_delay = (int) delay; | |||
| while ((target_delay-delay) > 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. | |||
| @@ -463,6 +469,32 @@ 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... | |||
| @@ -659,6 +691,8 @@ int main (int argc, char *argv[]) { | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| if (jack_set_latency_callback) | |||
| jack_set_latency_callback (client, latency_cb, 0); | |||
| // get jack sample_rate | |||
| @@ -714,6 +748,16 @@ int main (int argc, char *argv[]) { | |||
| // 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 */ | |||
| @@ -2,7 +2,7 @@ | |||
| * 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 | |||
| @@ -64,12 +64,23 @@ void parse_arguments(int argc, char *argv[]) | |||
| exit(9); | |||
| } | |||
| if (strspn (argv[1], "0123456789") != strlen (argv[1])) { | |||
| fprintf(stderr, "usage: %s <bufsize>\n", package); | |||
| exit(8); | |||
| } | |||
| nframes = strtoul(argv[1], NULL, 0); | |||
| if (errno == ERANGE) { | |||
| fprintf(stderr, "%s: invalid buffer size: %s\n", | |||
| fprintf(stderr, "%s: invalid buffer size: %s (range is 1-8182)\n", | |||
| package, argv[1]); | |||
| exit(2); | |||
| } | |||
| if (nframes < 1 || nframes > 8182) { | |||
| fprintf(stderr, "%s: invalid buffer size: %s (range is 1-8182)\n", | |||
| package, argv[1]); | |||
| exit(3); | |||
| } | |||
| } | |||
| int main(int argc, char *argv[]) | |||
| @@ -24,7 +24,9 @@ | |||
| #include <string.h> | |||
| #include <stdlib.h> | |||
| #include <math.h> | |||
| #include <getopt.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/session.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| @@ -33,17 +35,84 @@ int done = 0; | |||
| #define TRUE 1 | |||
| #define FALSE 0 | |||
| void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) | |||
| { | |||
| done = 1; | |||
| } | |||
| 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 <name> Connect to the jack server named <name>\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 = NULL; | |||
| 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]; | |||
| @@ -51,90 +120,121 @@ main (int argc, char *argv[]) | |||
| my_name ++; | |||
| } | |||
| printf("name %s\n", my_name); | |||
| if (strstr(my_name, "jack_disconnect")) { | |||
| disconnecting = TRUE; | |||
| } else | |||
| if (strstr(my_name, "jack_connect")) { | |||
| connecting = TRUE; | |||
| 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) { | |||
| fprintf (stderr, "usage: %s <src_port> <dst_port>\n", my_name); | |||
| fprintf(stderr, "The source port must be an output port of the source client.\n"); | |||
| fprintf (stderr, "The destination port must be an input port of the destination client.\n"); | |||
| return 1; | |||
| } | |||
| if (argc < 3) show_usage(my_name); | |||
| /* try to become a client of the JACK server */ | |||
| if ((client = jack_client_open (my_name, JackNullOption, NULL)) == 0) { | |||
| if ((client = jack_client_open (my_name, options, &status, server_name)) == 0) { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| return 1; | |||
| } | |||
| jack_set_port_connect_callback(client, port_connect_callback, NULL); | |||
| /* display the current sample rate. once the client is activated | |||
| (see below), you should rely on your own sample rate | |||
| callback (see above) for this value. | |||
| */ | |||
| /* find the two ports */ | |||
| if ((input_port = jack_port_by_name(client, argv[1])) == 0) { | |||
| fprintf (stderr, "ERROR %s not a valid port\n", argv[1]); | |||
| goto error; | |||
| 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 ((output_port = jack_port_by_name(client, argv[2])) == 0) { | |||
| fprintf (stderr, "ERROR %s not a valid port\n", argv[2]); | |||
| goto error; | |||
| 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; | |||
| } | |||
| } | |||
| /* tell the JACK server that we are ready to roll */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| goto error; | |||
| 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(input_port), jack_port_name(output_port))) { | |||
| fprintf (stderr, "cannot connect ports\n"); | |||
| goto error; | |||
| } | |||
| 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(input_port), jack_port_name(output_port))) { | |||
| fprintf (stderr, "cannot disconnect ports\n"); | |||
| goto error; | |||
| } | |||
| if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) { | |||
| goto exit; | |||
| } | |||
| } | |||
| // Wait for connection/disconnection to be effective | |||
| while(!done) { | |||
| #ifdef WIN32 | |||
| Sleep(10); | |||
| #else | |||
| usleep(10000); | |||
| #endif | |||
| while(!done) { | |||
| #ifdef WIN32 | |||
| Sleep(10); | |||
| #else | |||
| usleep(10000); | |||
| #endif | |||
| } | |||
| jack_deactivate (client); | |||
| jack_client_close (client); | |||
| return 0; | |||
| /* everything was ok, so setting exitcode to 0 */ | |||
| rc = 0; | |||
| error: | |||
| if (client) | |||
| jack_client_close (client); | |||
| return 1; | |||
| exit: | |||
| jack_client_close (client); | |||
| exit (rc); | |||
| } | |||
| @@ -0,0 +1,215 @@ | |||
| /** @file simple_client.c | |||
| * | |||
| * @brief This simple client demonstrates the most basic features of JACK | |||
| * as they would be used by many applications. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <jack/jack.h> | |||
| 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; | |||
| #ifdef WIN32 | |||
| #define jack_sleep(val) Sleep((val)) | |||
| #else | |||
| #define jack_sleep(val) usleep((val) * 1000) | |||
| #endif | |||
| /** | |||
| * 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<nframes; k++) { | |||
| out[k] = delay_line[delay_index]; | |||
| delay_line[delay_index] = in[k]; | |||
| delay_index = (delay_index + 1) % latency; | |||
| } | |||
| return 0; | |||
| } | |||
| void | |||
| latency_cb (jack_latency_callback_mode_t mode, void *arg) | |||
| { | |||
| jack_latency_range_t range; | |||
| if (mode == JackCaptureLatency) { | |||
| jack_port_get_latency_range (input_port, mode, &range); | |||
| range.min += latency; | |||
| range.max += latency; | |||
| jack_port_set_latency_range (output_port, mode, &range); | |||
| } else { | |||
| jack_port_get_latency_range (output_port, mode, &range); | |||
| range.min += latency; | |||
| range.max += latency; | |||
| jack_port_set_latency_range (input_port, mode, &range); | |||
| } | |||
| } | |||
| /** | |||
| * 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 = "latent"; | |||
| const char *server_name = NULL; | |||
| jack_options_t options = JackNullOption; | |||
| jack_status_t status; | |||
| if (argc == 2) | |||
| latency = atoi(argv[1]); | |||
| delay_line = malloc( latency * sizeof(jack_default_audio_sample_t)); | |||
| if (delay_line == NULL) { | |||
| fprintf (stderr, "no memory"); | |||
| exit(1); | |||
| } | |||
| memset (delay_line, 0, latency * sizeof(jack_default_audio_sample_t)); | |||
| /* 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 `latency()' whenever | |||
| the latency needs to be recalculated. | |||
| */ | |||
| if (jack_set_latency_callback) | |||
| jack_set_latency_callback (client, latency_cb, 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 */ | |||
| jack_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); | |||
| } | |||
| @@ -20,7 +20,8 @@ | |||
| #include <unistd.h> | |||
| #endif | |||
| #include <string.h> | |||
| #include <getopt.h> | |||
| #include <getopt.h> | |||
| #include <inttypes.h> | |||
| #include <jack/jack.h> | |||
| char * my_name; | |||
| @@ -39,6 +40,7 @@ show_usage (void) | |||
| 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 <name> Connect to the jack server named <name>\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"); | |||
| @@ -56,6 +58,7 @@ 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; | |||
| @@ -68,9 +71,11 @@ main (int argc, char *argv[]) | |||
| int c; | |||
| int option_index; | |||
| char* aliases[2]; | |||
| char *server_name = NULL; | |||
| jack_port_t *port; | |||
| struct option long_options[] = { | |||
| { "server", 1, 0, 's' }, | |||
| { "aliases", 0, 0, 'A' }, | |||
| { "connections", 0, 0, 'c' }, | |||
| { "port-latency", 0, 0, 'l' }, | |||
| @@ -89,8 +94,13 @@ main (int argc, char *argv[]) | |||
| my_name ++; | |||
| } | |||
| while ((c = getopt_long (argc, argv, "AclLphvt", long_options, &option_index)) >= 0) { | |||
| 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()); | |||
| @@ -131,7 +141,7 @@ main (int argc, char *argv[]) | |||
| * specify JackNoStartServer. */ | |||
| //JOQ: need a new server name option | |||
| client = jack_client_open ("lsp", JackNoStartServer, &status); | |||
| client = jack_client_open ("lsp", options, &status, server_name); | |||
| if (client == NULL) { | |||
| if (status & JackServerFailed) { | |||
| fprintf (stderr, "JACK server not running\n"); | |||
| @@ -143,7 +153,7 @@ main (int argc, char *argv[]) | |||
| } | |||
| ports = jack_get_ports (client, NULL, NULL, 0); | |||
| if (!ports) | |||
| if (!ports) | |||
| goto error; | |||
| for (i = 0; ports && ports[i]; ++i) { | |||
| @@ -168,19 +178,28 @@ main (int argc, char *argv[]) | |||
| 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) { | |||
| printf (" port latency = %d frames\n", | |||
| 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) { | |||
| @@ -208,12 +227,7 @@ main (int argc, char *argv[]) | |||
| if (flags & JackPortIsTerminal) { | |||
| fputs ("terminal,", stdout); | |||
| } | |||
| if (flags & JackPortIsActive) { | |||
| fputs ("active,", stdout); | |||
| } else { | |||
| fputs ("non-active,", stdout); | |||
| } | |||
| putc ('\n', stdout); | |||
| } | |||
| } | |||
| @@ -225,7 +239,7 @@ main (int argc, char *argv[]) | |||
| } | |||
| } | |||
| } | |||
| error: | |||
| if (ports) | |||
| jack_free (ports); | |||
| @@ -0,0 +1,114 @@ | |||
| #include <stdio.h> | |||
| #include <unistd.h> | |||
| #include <assert.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/midiport.h> | |||
| 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; | |||
| } | |||
| @@ -86,6 +86,7 @@ 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; | |||
| @@ -140,7 +141,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int | |||
| } | |||
| if( bitdepth == 1000 ) { | |||
| #if HAVE_CELT | |||
| #if HAVE_CELT_API_0_7 | |||
| #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 | |||
| @@ -183,7 +184,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int | |||
| } | |||
| if( bitdepth == 1000 ) { | |||
| #if HAVE_CELT | |||
| #if HAVE_CELT_API_0_7 | |||
| #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 | |||
| @@ -224,6 +225,9 @@ 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; | |||
| @@ -329,7 +333,7 @@ process (jack_nframes_t nframes, void *arg) | |||
| else if (cont_miss > 50+5*latency) | |||
| { | |||
| state_connected = 0; | |||
| packet_cache_reset_master_address( global_packcache ); | |||
| 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; | |||
| } | |||
| @@ -355,19 +359,19 @@ process (jack_nframes_t nframes, void *arg) | |||
| if ( ! netjack_poll_deadline( input_fd, deadline ) ) | |||
| break; | |||
| packet_cache_drain_socket(global_packcache, input_fd); | |||
| packet_cache_drain_socket(packcache, input_fd); | |||
| if (packet_cache_get_next_available_framecnt( global_packcache, framecnt - latency, &got_frame )) | |||
| 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(global_packcache, input_fd); | |||
| packet_cache_drain_socket(packcache, input_fd); | |||
| } | |||
| size = packet_cache_retreive_packet_pointer( global_packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); | |||
| 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) | |||
| @@ -394,7 +398,7 @@ process (jack_nframes_t nframes, void *arg) | |||
| state_recv_packet_queue_time = recv_time_offset; | |||
| state_connected = 1; | |||
| sync_state = pkthdr_rx->sync_state; | |||
| packet_cache_release_packet( global_packcache, framecnt - latency ); | |||
| 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 | |||
| @@ -402,7 +406,7 @@ process (jack_nframes_t nframes, void *arg) | |||
| else | |||
| { | |||
| jack_nframes_t latency_estimate; | |||
| if( packet_cache_find_latency( global_packcache, framecnt, &latency_estimate ) ) | |||
| if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) | |||
| //if( (state_latency == 0) || (latency_estimate < state_latency) ) | |||
| state_latency = latency_estimate; | |||
| @@ -468,7 +472,7 @@ process (jack_nframes_t nframes, void *arg) | |||
| else if (cont_miss > 50+5*latency) | |||
| { | |||
| state_connected = 0; | |||
| packet_cache_reset_master_address( global_packcache ); | |||
| 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; | |||
| } | |||
| @@ -501,12 +505,11 @@ init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t por | |||
| if (hostinfo == NULL) { | |||
| fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); | |||
| fflush( stderr ); | |||
| return; | |||
| } | |||
| #ifdef WIN32 | |||
| name->sin_addr.s_addr = inet_addr( hostname ); | |||
| name->sin_addr.s_addr = inet_addr( hostname ); | |||
| #else | |||
| name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; | |||
| name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; | |||
| #endif | |||
| } | |||
| else | |||
| @@ -621,15 +624,15 @@ main (int argc, char *argv[]) | |||
| case 'b': | |||
| bitdepth = atoi (optarg); | |||
| break; | |||
| case 'c': | |||
| #if HAVE_CELT | |||
| bitdepth = 1000; | |||
| case 'c': | |||
| #if HAVE_CELT | |||
| bitdepth = 1000; | |||
| factor = atoi (optarg); | |||
| #else | |||
| #else | |||
| printf( "not built with celt supprt\n" ); | |||
| exit(10); | |||
| #endif | |||
| break; | |||
| #endif | |||
| break; | |||
| case 'm': | |||
| mtu = atoi (optarg); | |||
| break; | |||
| @@ -676,17 +679,18 @@ main (int argc, char *argv[]) | |||
| } | |||
| init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); | |||
| if (bind_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" ); | |||
| } | |||
| fprintf (stderr, "bind failure\n" ); | |||
| } | |||
| } | |||
| if (reply_port) { | |||
| if(reply_port) | |||
| { | |||
| init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); | |||
| if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { | |||
| fprintf (stderr, "bind failure\n" ); | |||
| } | |||
| fprintf (stderr, "bind failure\n" ); | |||
| } | |||
| } | |||
| /* try to become a client of the JACK server */ | |||
| @@ -712,7 +716,7 @@ main (int argc, char *argv[]) | |||
| 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); | |||
| global_packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); | |||
| packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); | |||
| /* tell the JACK server that we are ready to roll */ | |||
| if (jack_activate (client)) | |||
| @@ -778,6 +782,6 @@ main (int argc, char *argv[]) | |||
| } | |||
| jack_client_close (client); | |||
| packet_cache_free (global_packcache); | |||
| packet_cache_free (packcache); | |||
| exit (0); | |||
| } | |||
| @@ -25,12 +25,11 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/types.h> | |||
| #include <jack/jslist.h> | |||
| #include <jack/transport.h> | |||
| #include <jack/session.h> | |||
| char *package; /* program name */ | |||
| char *package; /* program name */ | |||
| jack_client_t *client; | |||
| jack_session_event_type_t notify_type; | |||
| @@ -38,147 +37,145 @@ char *save_path = NULL; | |||
| void jack_shutdown(void *arg) | |||
| { | |||
| fprintf(stderr, "JACK shut down, exiting ...\n"); | |||
| exit(1); | |||
| 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); | |||
| 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); | |||
| /* 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]; | |||
| 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 %s", 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 *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); | |||
| 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 ); | |||
| printf( "retval = %p\n", retval ); | |||
| 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; | |||
| 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; | |||
| } | |||
| @@ -27,6 +27,8 @@ example_programs = { | |||
| 'jack_server_control' : 'server_control.cpp', | |||
| 'jack_net_slave' : 'netslave.c', | |||
| 'jack_net_master' : 'netmaster.c', | |||
| 'jack_latent_client' : 'latent_client.c', | |||
| 'jack_midi_dump' : 'midi_dump.c', | |||
| } | |||
| example_libs = { | |||
| @@ -130,12 +132,6 @@ def build(bld): | |||
| prog.includes = os_incdir + ['../common/jack', '../common'] | |||
| prog.source = ['netsource.c', '../common/netjack_packet.c'] | |||
| prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") | |||
| # Seems uneeded here... | |||
| #if bld.env['HAVE_CELT']: | |||
| #if bld.env['HAVE_CELT_API_0_5']: | |||
| # prog.defines = ['HAVE_CELT', 'HAVE_CELT_API_0_5'] | |||
| #elif bld.env['HAVE_CELT_API_0_7']: | |||
| # prog.defines = ['HAVE_CELT', 'HAVE_CELT_API_0_7'] | |||
| prog.uselib = 'CELT SAMPLERATE' | |||
| prog.uselib_local = 'clientlib' | |||
| prog.target = 'jack_netsource' | |||
| @@ -69,12 +69,15 @@ static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* ad | |||
| #endif | |||
| #if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__) | |||
| #warning using builtin gcc (version > 4.1) atomic | |||
| static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) | |||
| { | |||
| return __sync_bool_compare_and_swap (&addr, value, newvalue); | |||
| return __sync_bool_compare_and_swap ((UInt32*)addr, value, newvalue); | |||
| } | |||
| #endif | |||
| @@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include <string.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <inttypes.h> | |||
| static jack_time_t __jack_cpu_mhz = 0; | |||
| jack_time_t (*_jack_get_microseconds)(void) = 0; | |||
| @@ -276,7 +276,7 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
| } else { | |||
| driver->channel_copy = memcpy_fake; | |||
| } | |||
| switch (driver->dither) { | |||
| case Rectangular: | |||
| jack_info("Rectangular dithering at 16 bits"); | |||
| @@ -284,42 +284,42 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
| sample_move_dither_rect_d16_sSs: | |||
| sample_move_dither_rect_d16_sS; | |||
| break; | |||
| case Triangular: | |||
| jack_info("Triangular dithering at 16 bits"); | |||
| driver->write_via_copy = driver->quirk_bswap? | |||
| sample_move_dither_tri_d16_sSs: | |||
| sample_move_dither_tri_d16_sS; | |||
| break; | |||
| case Shaped: | |||
| jack_info("Noise-shaped dithering at 16 bits"); | |||
| driver->write_via_copy = driver->quirk_bswap? | |||
| sample_move_dither_shaped_d16_sSs: | |||
| sample_move_dither_shaped_d16_sS; | |||
| break; | |||
| default: | |||
| driver->write_via_copy = driver->quirk_bswap? | |||
| sample_move_d16_sSs : | |||
| sample_move_d16_sSs : | |||
| sample_move_d16_sS; | |||
| break; | |||
| } | |||
| break; | |||
| case 3: /* NO DITHER */ | |||
| if (driver->playback_interleaved) { | |||
| driver->channel_copy = memcpy_interleave_d24_s24; | |||
| } else { | |||
| driver->channel_copy = memcpy_fake; | |||
| } | |||
| driver->write_via_copy = driver->quirk_bswap? | |||
| sample_move_d24_sSs: | |||
| sample_move_d24_sSs: | |||
| sample_move_d24_sS; | |||
| break; | |||
| case 4: /* NO DITHER */ | |||
| if (driver->playback_interleaved) { | |||
| driver->channel_copy = memcpy_interleave_d32_s32; | |||
| @@ -328,7 +328,7 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
| } | |||
| driver->write_via_copy = driver->quirk_bswap? | |||
| sample_move_d32u24_sSs: | |||
| sample_move_d32u24_sSs: | |||
| sample_move_d32u24_sS; | |||
| break; | |||
| @@ -339,27 +339,27 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
| } | |||
| } | |||
| } | |||
| if (driver->capture_handle) { | |||
| switch (driver->capture_sample_bytes) { | |||
| case 2: | |||
| driver->read_via_copy = driver->quirk_bswap? | |||
| sample_move_dS_s16s: | |||
| sample_move_dS_s16s: | |||
| sample_move_dS_s16; | |||
| break; | |||
| case 3: | |||
| driver->read_via_copy = driver->quirk_bswap? | |||
| sample_move_dS_s24s: | |||
| sample_move_dS_s24s: | |||
| sample_move_dS_s24; | |||
| break; | |||
| case 4: | |||
| driver->read_via_copy = driver->quirk_bswap? | |||
| sample_move_dS_s32u24s: | |||
| sample_move_dS_s32u24s: | |||
| sample_move_dS_s32u24; | |||
| break; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -418,7 +418,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| } | |||
| } | |||
| } | |||
| format = (sample_width == 4) ? 0 : NUMFORMATS - 1; | |||
| while (1) { | |||
| @@ -444,7 +444,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| frame_rate = driver->frame_rate ; | |||
| err = snd_pcm_hw_params_set_rate_near (handle, hw_params, | |||
| @@ -464,7 +464,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| &channels_max); | |||
| *nchns = channels_max ; | |||
| if (*nchns > 1024) { | |||
| if (*nchns > 1024) { | |||
| /* the hapless user is an unwitting victim of | |||
| the "default" ALSA PCM device, which can | |||
| @@ -481,9 +481,9 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| "instead rather than using the plug layer. Usually the name of the\n" | |||
| "hardware device that corresponds to the first sound card is hw:0\n" | |||
| ); | |||
| *nchns = 2; | |||
| *nchns = 2; | |||
| } | |||
| } | |||
| } | |||
| if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, | |||
| *nchns)) < 0) { | |||
| @@ -491,7 +491,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| *nchns, stream_name); | |||
| return -1; | |||
| } | |||
| if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, | |||
| driver->frames_per_cycle, | |||
| 0)) | |||
| @@ -520,7 +520,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| return -1; | |||
| } | |||
| jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); | |||
| #if 0 | |||
| #if 0 | |||
| if (!jack_power_of_two(driver->frames_per_cycle)) { | |||
| jack_error("JACK: frames must be a power of two " | |||
| "(64, 512, 1024, ...)\n"); | |||
| @@ -557,7 +557,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| if (driver->soft_mode) { | |||
| stop_th = (snd_pcm_uframes_t)-1; | |||
| } | |||
| if ((err = snd_pcm_sw_params_set_stop_threshold ( | |||
| handle, sw_params, stop_th)) < 0) { | |||
| jack_error ("ALSA: cannot set stop mode for %s", | |||
| @@ -594,7 +594,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
| else | |||
| err = snd_pcm_sw_params_set_avail_min ( | |||
| handle, sw_params, driver->frames_per_cycle); | |||
| if (err < 0) { | |||
| jack_error ("ALSA: cannot set avail min for %s", stream_name); | |||
| return -1; | |||
| @@ -1158,7 +1158,7 @@ int | |||
| JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) | |||
| { | |||
| int res; | |||
| driver->xrun_recovery = 1; | |||
| if ((res = Stop()) == 0) | |||
| res = Start(); | |||
| @@ -1189,11 +1189,24 @@ JackAlsaDriver::alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed | |||
| } | |||
| } | |||
| if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SUSPENDED) { | |||
| jack_error("**** alsa_pcm: pcm in suspended state, resuming it" ); | |||
| if (driver->capture_handle) { | |||
| if ((res = snd_pcm_prepare(driver->capture_handle)) < 0) { | |||
| jack_error("error preparing after suspend: %s", snd_strerror(res)); | |||
| } | |||
| } else { | |||
| if ((res = snd_pcm_prepare(driver->playback_handle)) < 0) { | |||
| jack_error("error preparing after suspend: %s", snd_strerror(res)); | |||
| } | |||
| } | |||
| } | |||
| if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN | |||
| && driver->process_count > XRUN_REPORT_DELAY) { | |||
| struct timeval now, diff, tstamp; | |||
| driver->xrun_count++; | |||
| snd_pcm_status_get_tstamp(status,&now); | |||
| snd_pcm_status_get_tstamp(status,&now); | |||
| snd_pcm_status_get_trigger_tstamp(status, &tstamp); | |||
| timersub(&now, &tstamp, &diff); | |||
| *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; | |||
| @@ -1253,7 +1266,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| } | |||
| again: | |||
| while (need_playback || need_capture) { | |||
| int poll_result; | |||
| @@ -1269,7 +1282,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| driver->playback_nfds); | |||
| nfds += driver->playback_nfds; | |||
| } | |||
| if (need_capture) { | |||
| snd_pcm_poll_descriptors (driver->capture_handle, | |||
| &driver->pfd[nfds], | |||
| @@ -1279,7 +1292,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| } | |||
| /* ALSA doesn't set POLLERR in some versions of 0.9.X */ | |||
| for (i = 0; i < nfds; i++) { | |||
| driver->pfd[i].events |= POLLERR; | |||
| } | |||
| @@ -1316,12 +1329,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| *status = -2; | |||
| return 0; | |||
| } | |||
| jack_error ("ALSA: poll call failed (%s)", | |||
| strerror (errno)); | |||
| *status = -3; | |||
| return 0; | |||
| } | |||
| poll_ret = jack_get_microseconds (); | |||
| @@ -1332,12 +1345,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| if (extra_fd < 0) { | |||
| if (driver->poll_next && poll_ret > driver->poll_next) { | |||
| *delayed_usecs = poll_ret - driver->poll_next; | |||
| } | |||
| } | |||
| driver->poll_last = poll_ret; | |||
| driver->poll_next = poll_ret + driver->period_usecs; | |||
| // steph | |||
| /* | |||
| driver->engine->transport_cycle_start (driver->engine, | |||
| driver->engine->transport_cycle_start (driver->engine, | |||
| poll_ret); | |||
| */ | |||
| } | |||
| @@ -1358,7 +1371,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| *status = -4; | |||
| return -1; | |||
| } | |||
| } | |||
| /* if POLLIN was the only bit set, we're OK */ | |||
| @@ -1414,14 +1427,14 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| #endif | |||
| } | |||
| } | |||
| if (poll_result == 0) { | |||
| jack_error ("ALSA: poll time out, polled for %" PRIu64 | |||
| " usecs", | |||
| poll_ret - poll_enter); | |||
| *status = -5; | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| @@ -1437,7 +1450,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| } | |||
| } else { | |||
| /* odd, but see min() computation below */ | |||
| capture_avail = INT_MAX; | |||
| capture_avail = INT_MAX; | |||
| } | |||
| if (driver->playback_handle) { | |||
| @@ -1452,7 +1465,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
| } | |||
| } else { | |||
| /* odd, but see min() computation below */ | |||
| playback_avail = INT_MAX; | |||
| playback_avail = INT_MAX; | |||
| } | |||
| if (xrun_detected) { | |||
| @@ -1531,7 +1544,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||
| if (!driver->capture_handle) { | |||
| return 0; | |||
| } | |||
| nread = 0; | |||
| contiguous = 0; | |||
| orig_nframes = nframes; | |||
| @@ -1559,11 +1572,11 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||
| /* // steph | |||
| for (chn = 0, node = driver->capture_ports; node; | |||
| node = jack_slist_next (node), chn++) { | |||
| port = (jack_port_t *) node->data; | |||
| if (!jack_port_connected (port)) { | |||
| // no-copy optimization | |||
| // no-copy optimization | |||
| continue; | |||
| } | |||
| buf = jack_port_get_buffer (port, orig_nframes); | |||
| @@ -1574,7 +1587,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||
| if ((err = snd_pcm_mmap_commit (driver->capture_handle, | |||
| offset, contiguous)) < 0) { | |||
| jack_error ("ALSA: could not complete read of %" | |||
| PRIu32 " frames: error = %d\n", contiguous, err); | |||
| return -1; | |||
| @@ -1702,7 +1715,7 @@ JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes | |||
| } | |||
| monbuf = jack_port_get_buffer (port, orig_nframes); | |||
| memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); | |||
| mon_node = jack_slist_next (mon_node); | |||
| mon_node = jack_slist_next (mon_node); | |||
| } | |||
| } | |||
| */ | |||
| @@ -1716,7 +1729,7 @@ JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes | |||
| offset, contiguous)) < 0) { | |||
| jack_error ("ALSA: could not complete playback of %" | |||
| PRIu32 " frames: error = %d", contiguous, err); | |||
| if (err != EPIPE && err != ESTRPIPE) | |||
| if (err != -EPIPE && err != -ESTRPIPE) | |||
| return -1; | |||
| } | |||
| @@ -1739,11 +1752,11 @@ JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver) | |||
| free (node->data); | |||
| } | |||
| jack_slist_free (driver->clock_sync_listeners); | |||
| if (driver->ctl_handle) { | |||
| snd_ctl_close (driver->ctl_handle); | |||
| driver->ctl_handle = 0; | |||
| } | |||
| } | |||
| if (driver->capture_handle) { | |||
| snd_pcm_close (driver->capture_handle); | |||
| @@ -1821,14 +1834,14 @@ JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device, | |||
| jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 | |||
| "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", | |||
| playing ? playback_alsa_device : "-", | |||
| capturing ? capture_alsa_device : "-", | |||
| capturing ? capture_alsa_device : "-", | |||
| frames_per_cycle, user_nperiods, rate, | |||
| user_capture_nchnls,user_playback_nchnls, | |||
| hw_monitoring ? "hwmon": "nomon", | |||
| hw_metering ? "hwmeter":"swmeter", | |||
| soft_mode ? "soft-mode":"-", | |||
| shorts_first ? "16bit":"32bit"); | |||
| driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); | |||
| jack_driver_nt_init ((jack_driver_nt_t *) driver); | |||
| @@ -1862,8 +1875,8 @@ JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device, | |||
| driver->playback_addr = 0; | |||
| driver->capture_addr = 0; | |||
| driver->playback_interleave_skip = NULL; | |||
| driver->capture_interleave_skip = NULL; | |||
| driver->playback_interleave_skip = NULL; | |||
| driver->capture_interleave_skip = NULL; | |||
| driver->silent = 0; | |||
| driver->all_monitor_in = FALSE; | |||
| @@ -2071,6 +2084,7 @@ int JackAlsaDriver::Attach() | |||
| unsigned long port_flags; | |||
| char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| jack_latency_range_t range; | |||
| assert(fCaptureChannels < DRIVER_PORT_NUM); | |||
| assert(fPlaybackChannels < DRIVER_PORT_NUM); | |||
| @@ -2097,7 +2111,8 @@ int JackAlsaDriver::Attach() | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| port->SetLatency(alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency); | |||
| range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fCapturePortList[i] = port_index; | |||
| jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index); | |||
| } | |||
| @@ -2114,8 +2129,10 @@ int JackAlsaDriver::Attach() | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| // Add one buffer more latency if "async" mode is used... | |||
| port->SetLatency((alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + | |||
| ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency); | |||
| range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + | |||
| ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency; | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| fPlaybackPortList[i] = port_index; | |||
| jack_log("JackAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
| @@ -2127,7 +2144,8 @@ int JackAlsaDriver::Attach() | |||
| jack_error ("ALSA: cannot register monitor port for %s", name); | |||
| } else { | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetLatency(alsa_driver->frames_per_cycle); | |||
| range.min = range.max = alsa_driver->frames_per_cycle; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fMonitorPortList[i] = port_index; | |||
| } | |||
| } | |||
| @@ -2151,7 +2169,7 @@ int JackAlsaDriver::Detach() | |||
| return JackAudioDriver::Detach(); | |||
| } | |||
| static int card_to_num(const char* device) | |||
| static int card_to_num(const char* device) | |||
| { | |||
| int err; | |||
| char* ctl_name; | |||
| @@ -2316,13 +2334,13 @@ int JackAlsaDriver::Read() | |||
| retry: | |||
| nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | |||
| if (wait_status < 0) | |||
| return -1; /* driver failed */ | |||
| if (nframes == 0) { | |||
| /* we detected an xrun and restarted: notify | |||
| * clients about the delay. | |||
| * clients about the delay. | |||
| */ | |||
| jack_log("ALSA XRun wait_status = %d", wait_status); | |||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
| @@ -2331,7 +2349,7 @@ retry: | |||
| if (nframes != fEngineControl->fBufferSize) | |||
| jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes); | |||
| // Has to be done before read | |||
| JackDriver::CycleIncTime(); | |||
| @@ -2619,7 +2637,7 @@ get_dither_constraint() | |||
| } | |||
| static int | |||
| dither_opt (char c, DitherAlgorithm* dither) | |||
| dither_opt (char c, DitherAlgorithm* dither) | |||
| { | |||
| switch (c) { | |||
| case '-': | |||
| @@ -2646,17 +2664,17 @@ dither_opt (char c, DitherAlgorithm* dither) | |||
| return 0; | |||
| } | |||
| SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
| SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
| { | |||
| jack_driver_desc_t * desc; | |||
| jack_driver_param_desc_t * params; | |||
| unsigned int i; | |||
| desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); | |||
| strcpy(desc->name, "alsa"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
| strcpy(desc->desc, "Linux ALSA API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
| desc->nparams = 18; | |||
| params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | |||
| @@ -2825,7 +2843,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
| return desc; | |||
| } | |||
| SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) | |||
| SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) | |||
| { | |||
| jack_nframes_t srate = 48000; | |||
| jack_nframes_t frames_per_interrupt = 1024; | |||
| @@ -104,7 +104,7 @@ typedef struct input_port_t { | |||
| // jack | |||
| midi_unpack_t unpack; | |||
| // midi | |||
| int overruns; | |||
| } input_port_t; | |||
| @@ -114,7 +114,7 @@ typedef struct output_port_t { | |||
| // jack | |||
| midi_pack_t packer; | |||
| // midi | |||
| event_head_t next_event; | |||
| int todo; | |||
| @@ -425,16 +425,16 @@ static | |||
| inline int midi_port_open_jack(alsa_rawmidi_t *midi, midi_port_t *port, int type, const char *alias) | |||
| { | |||
| char name[128]; | |||
| if (type & JackPortIsOutput) | |||
| snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++midi->midi_in_cnt); | |||
| else | |||
| else | |||
| snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++midi->midi_out_cnt); | |||
| port->jack = jack_port_register(midi->client, name, JACK_DEFAULT_MIDI_TYPE, | |||
| type | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive, 0); | |||
| if (port->jack) | |||
| type | JackPortIsPhysical | JackPortIsTerminal, 0); | |||
| if (port->jack) | |||
| jack_port_set_alias(port->jack, alias); | |||
| return port->jack == NULL; | |||
| } | |||
| @@ -455,7 +455,7 @@ int midi_port_open(alsa_rawmidi_t *midi, midi_port_t *port) | |||
| out = &port->rawmidi; | |||
| type = JackPortIsInput; | |||
| } | |||
| if ((err = snd_rawmidi_open(in, out, port->dev, SND_RAWMIDI_NONBLOCK))<0) | |||
| return err; | |||
| @@ -749,7 +749,7 @@ void* scan_thread(void *arg) | |||
| return NULL; | |||
| } | |||
| /* | |||
| /* | |||
| * ------------------------------- Input/Output ------------------------------ | |||
| */ | |||
| @@ -836,7 +836,7 @@ void *midi_thread(void *arg) | |||
| npfds = 1; | |||
| if (jack_is_realtime(midi->client)) | |||
| set_threaded_log_function(); | |||
| set_threaded_log_function(); | |||
| //debug_log("midi_thread(%s): enter", str->name); | |||
| @@ -978,7 +978,7 @@ int midi_update_pfds(process_midi_t *proc) | |||
| return 1; | |||
| } | |||
| /* | |||
| /* | |||
| * ------------------------------------ Input ------------------------------ | |||
| */ | |||
| @@ -1083,7 +1083,7 @@ int do_midi_input(process_midi_t *proc) | |||
| return 1; | |||
| } | |||
| /* | |||
| /* | |||
| * ------------------------------------ Output ------------------------------ | |||
| */ | |||
| @@ -1149,7 +1149,7 @@ int do_midi_output(process_midi_t *proc) | |||
| } else | |||
| debug_log("midi_out: at %ld got %d bytes for %ld", (long)proc->cur_time, (int)port->next_event.size, (long)port->next_event.time); | |||
| } | |||
| if (port->todo) | |||
| debug_log("midi_out: todo = %d at %ld", (int)port->todo, (long)proc->cur_time); | |||
| @@ -285,7 +285,7 @@ int alsa_seqmidi_attach(alsa_midi_t *m) | |||
| self->client_id = snd_seq_client_id(self->seq); | |||
| self->queue = snd_seq_alloc_queue(self->seq); | |||
| snd_seq_start_queue(self->seq, self->queue, 0); | |||
| snd_seq_start_queue(self->seq, self->queue, 0); | |||
| stream_attach(self, PORT_INPUT); | |||
| stream_attach(self, PORT_OUTPUT); | |||
| @@ -488,14 +488,14 @@ port_t* port_create(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, const s | |||
| /* mark anything that looks like a hardware port as physical&terminal */ | |||
| if (snd_seq_port_info_get_type (info) & (SND_SEQ_PORT_TYPE_HARDWARE|SND_SEQ_PORT_TYPE_PORT|SND_SEQ_PORT_TYPE_SPECIFIC)) { | |||
| jack_caps |= (JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive); | |||
| jack_caps |= (JackPortIsPhysical | JackPortIsTerminal); | |||
| } | |||
| if (jack_caps & JackPortIsOutput) | |||
| snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt); | |||
| else | |||
| else | |||
| snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt); | |||
| port->jack_port = jack_port_register(self->jack, | |||
| name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0); | |||
| if (!port->jack_port) | |||
| @@ -588,7 +588,7 @@ void update_ports(alsa_seqmidi_t *self) | |||
| snd_seq_port_info_alloca(&info); | |||
| while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) { | |||
| int err; | |||
| assert (size == sizeof(addr)); | |||
| @@ -666,7 +666,7 @@ void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, | |||
| info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec; | |||
| if (info->period_start + info->nframes < info->cur_frames) { | |||
| int periods_lost = (info->cur_frames - info->period_start) / info->nframes; | |||
| int periods_lost = (info->cur_frames - info->period_start) / info->nframes; | |||
| info->period_start += periods_lost * info->nframes; | |||
| debug_log("xrun detected: %d periods lost\n", periods_lost); | |||
| } | |||
| @@ -805,7 +805,7 @@ void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct proce | |||
| ev.size = size; | |||
| jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); | |||
| jack_ringbuffer_write(port->early_events, (char*)data, size); | |||
| debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes)); | |||
| debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes)); | |||
| return; | |||
| } | |||
| @@ -829,7 +829,7 @@ void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes) | |||
| return; | |||
| set_process_info(&info, self, PORT_INPUT, nframes); | |||
| jack_process(self, &info); | |||
| jack_process(self, &info); | |||
| while ((res = snd_seq_event_input(self->seq, &event))>0) { | |||
| if (event->source.client == SND_SEQ_CLIENT_SYSTEM) | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2005 Karsten Wiese, Rui Nuno Capela | |||
| This program is free software; you can redistribute it and/or modify | |||
| @@ -33,14 +33,14 @@ | |||
| int dbg_offset; | |||
| char dbg_buffer[8096]; | |||
| #endif | |||
| static | |||
| static | |||
| int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | |||
| { | |||
| return -1; | |||
| } | |||
| static | |||
| int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||
| int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||
| { | |||
| return -1; | |||
| } | |||
| @@ -52,7 +52,7 @@ usx2y_release (jack_hardware_t *hw) | |||
| if (h == 0) | |||
| return; | |||
| if (h->hwdep_handle) | |||
| snd_hwdep_close(h->hwdep_handle); | |||
| @@ -622,7 +622,7 @@ usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) | |||
| offset, nframes_)) < 0) { | |||
| jack_error ("ALSA/USX2Y: could not complete playback of %" | |||
| PRIu32 " frames: error = %d", nframes_, err); | |||
| if (err != EPIPE && err != ESTRPIPE) | |||
| if (err != -EPIPE && err != -ESTRPIPE) | |||
| return -1; | |||
| } | |||
| @@ -37,8 +37,6 @@ | |||
| * regardless of how fast the machine is. | |||
| */ | |||
| #ifdef __linux__ | |||
| #ifdef __x86_64__ | |||
| typedef unsigned long cycles_t; | |||
| @@ -127,21 +125,5 @@ static inline cycles_t get_cycles(void) | |||
| #endif /* everything else but x86, amd64, sparcv9 or ppc */ | |||
| #endif /* __linux__ */ | |||
| #if defined(__FreeBSD_kernel__) | |||
| #warning No suitable get_cycles() implementation. Returning 0 instead | |||
| typedef unsigned long long cycles_t; | |||
| static inline cycles_t get_cycles(void) | |||
| { | |||
| return 0; | |||
| } | |||
| #endif /* __FreeBSD_kernel__ */ | |||
| #endif /* __jack_cycles_h__ */ | |||
| @@ -272,7 +272,7 @@ JackFFADODriver::SetBufferSize (jack_nframes_t nframes) | |||
| printError("Buffer size change requested but not supported!!!"); | |||
| /* | |||
| driver->period_size = nframes; | |||
| driver->period_size = nframes; | |||
| driver->period_usecs = | |||
| (jack_time_t) floor ((((float) nframes) / driver->sample_rate) | |||
| * 1000000.0f); | |||
| @@ -362,6 +362,7 @@ int JackFFADODriver::Attach() | |||
| int port_index; | |||
| char buf[JACK_PORT_NAME_SIZE]; | |||
| char portname[JACK_PORT_NAME_SIZE]; | |||
| jack_latency_range_t range; | |||
| ffado_driver_t* driver = (ffado_driver_t*)fDriver; | |||
| @@ -447,7 +448,8 @@ int JackFFADODriver::Attach() | |||
| ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetLatency(driver->period_size + driver->capture_frame_latency); | |||
| range.min = range.max = driver->period_size + driver->capture_frame_latency; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| // capture port aliases (jackd1 style port names) | |||
| snprintf(buf, sizeof(buf) - 1, "%s:capture_%i", fClientControl.fName, (int) chn + 1); | |||
| port->SetAlias(buf); | |||
| @@ -479,7 +481,8 @@ int JackFFADODriver::Attach() | |||
| driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetLatency(driver->period_size + driver->capture_frame_latency); | |||
| range.min = range.max = driver->period_size + driver->capture_frame_latency; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fCapturePortList[chn] = port_index; | |||
| jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); | |||
| fCaptureChannels++; | |||
| @@ -523,7 +526,8 @@ int JackFFADODriver::Attach() | |||
| port = fGraphManager->GetPort(port_index); | |||
| // Add one buffer more latency if "async" mode is used... | |||
| port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency); | |||
| range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| // playback port aliases (jackd1 style port names) | |||
| snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1); | |||
| port->SetAlias(buf); | |||
| @@ -549,7 +553,7 @@ int JackFFADODriver::Attach() | |||
| printError(" cannot enable port %s", buf); | |||
| } | |||
| // setup the midi buffer | |||
| // This constructor optionally accepts arguments for the | |||
| // non-realtime buffer size and the realtime buffer size. Ideally, | |||
| // these would become command-line options for the FFADO driver. | |||
| @@ -558,7 +562,8 @@ int JackFFADODriver::Attach() | |||
| driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency); | |||
| range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency; | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| fPlaybackPortList[chn] = port_index; | |||
| jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
| fPlaybackChannels++; | |||
| @@ -676,7 +681,7 @@ retry: | |||
| if (nframes == 0) { | |||
| /* we detected an xrun and restarted: notify | |||
| * clients about the delay. | |||
| * clients about the delay. | |||
| */ | |||
| jack_log("FFADO XRun"); | |||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
| @@ -685,7 +690,7 @@ retry: | |||
| if (nframes != fEngineControl->fBufferSize) | |||
| jack_log("JackFFADODriver::Read warning nframes = %ld", nframes); | |||
| // Has to be done before read | |||
| JackDriver::CycleIncTime(); | |||
| @@ -755,7 +760,7 @@ extern "C" | |||
| strcpy (desc->name, "firewire"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
| strcpy(desc->desc, "Linux FFADO API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
| desc->nparams = 13; | |||
| params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | |||
| @@ -260,7 +260,7 @@ JackFreebobDriver::SetBufferSize (jack_nframes_t nframes) | |||
| printError("Buffer size change requested but not supported!!!"); | |||
| /* | |||
| driver->period_size = nframes; | |||
| driver->period_size = nframes; | |||
| driver->period_usecs = | |||
| (jack_time_t) floor ((((float) nframes) / driver->sample_rate) | |||
| * 1000000.0f); | |||
| @@ -667,9 +667,10 @@ int JackFreebobDriver::Attach() | |||
| { | |||
| JackPort* port; | |||
| int port_index; | |||
| char buf[JACK_PORT_NAME_SIZE]; | |||
| char portname[JACK_PORT_NAME_SIZE]; | |||
| jack_latency_range_t range; | |||
| freebob_driver_t* driver = (freebob_driver_t*)fDriver; | |||
| @@ -737,7 +738,8 @@ int JackFreebobDriver::Attach() | |||
| return -1; | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetLatency(driver->period_size + driver->capture_frame_latency); | |||
| range.min = range.max = driver->period_size + driver->capture_frame_latency; | |||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||
| fCapturePortList[i] = port_index; | |||
| jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index); | |||
| driver->capture_nchannels_audio++; | |||
| @@ -766,7 +768,8 @@ int JackFreebobDriver::Attach() | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| // Add one buffer more latency if "async" mode is used... | |||
| port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency); | |||
| range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency); | |||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||
| fPlaybackPortList[i] = port_index; | |||
| jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
| driver->playback_nchannels_audio++; | |||
| @@ -866,7 +869,7 @@ retry: | |||
| if (nframes == 0) { | |||
| /* we detected an xrun and restarted: notify | |||
| * clients about the delay. | |||
| * clients about the delay. | |||
| */ | |||
| jack_log("FreeBoB XRun"); | |||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
| @@ -878,7 +881,7 @@ retry: | |||
| // Has to be done before read | |||
| JackDriver::CycleIncTime(); | |||
| printExit(); | |||
| return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize); | |||
| } | |||
| @@ -944,7 +947,7 @@ extern "C" | |||
| strcpy (desc->name, "freebob"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
| strcpy(desc->desc, "Linux FreeBob API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
| desc->nparams = 11; | |||
| params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | |||
| @@ -7,7 +7,7 @@ | |||
| <key>CFBundleExecutable</key> | |||
| <string>Jackservermp</string> | |||
| <key>CFBundleGetInfoString</key> | |||
| <string>Jackdmp 1.9.7, @03-10 Paul Davis, Grame</string> | |||
| <string>Jackdmp 1.9.7, @03-11 Paul Davis, Grame</string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.grame.Jackmp</string> | |||
| <key>CFBundleInfoDictionaryVersion</key> | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| namespace Jack | |||
| { | |||
| int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| int JackMachThread::SetThreadToPriority(jack_native_thread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| { | |||
| if (inPriority == 96) { | |||
| // REAL-TIME / TIME-CONSTRAINT THREAD | |||
| @@ -73,18 +73,18 @@ int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boo | |||
| } | |||
| // returns the thread's priority as it was last set by the API | |||
| UInt32 JackMachThread::GetThreadSetPriority(pthread_t thread) | |||
| UInt32 JackMachThread::GetThreadSetPriority(jack_native_thread_t thread) | |||
| { | |||
| return GetThreadPriority(thread, THREAD_SET_PRIORITY); | |||
| } | |||
| // returns the thread's priority as it was last scheduled by the Kernel | |||
| UInt32 JackMachThread::GetThreadScheduledPriority(pthread_t thread) | |||
| UInt32 JackMachThread::GetThreadScheduledPriority(jack_native_thread_t thread) | |||
| { | |||
| return GetThreadPriority(thread, THREAD_SCHEDULED_PRIORITY); | |||
| } | |||
| UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority) | |||
| UInt32 JackMachThread::GetThreadPriority(jack_native_thread_t thread, int inWhichPriority) | |||
| { | |||
| thread_basic_info_data_t threadInfo; | |||
| policy_info_data_t thePolicyInfo; | |||
| @@ -127,7 +127,7 @@ UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority) | |||
| return 0; | |||
| } | |||
| int JackMachThread::GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint) | |||
| int JackMachThread::GetParams(jack_native_thread_t thread, UInt64* period, UInt64* computation, UInt64* constraint) | |||
| { | |||
| thread_time_constraint_policy_data_t theTCPolicy; | |||
| mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT; | |||
| @@ -160,11 +160,11 @@ int JackMachThread::Kill() | |||
| { | |||
| // pthread_cancel still not yet implemented in Darwin (TO CHECK ON TIGER) | |||
| jack_log("JackMachThread::Kill"); | |||
| if (fThread != (pthread_t)NULL) { // If thread has been started | |||
| if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| mach_port_t machThread = pthread_mach_thread_np(fThread); | |||
| int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1; | |||
| fThread = (pthread_t)NULL; | |||
| fThread = (jack_native_thread_t)NULL; | |||
| return res; | |||
| } else { | |||
| return -1; | |||
| @@ -175,7 +175,7 @@ int JackMachThread::AcquireRealTime() | |||
| { | |||
| jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld", | |||
| long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000)); | |||
| return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1; | |||
| return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1; | |||
| } | |||
| int JackMachThread::AcquireSelfRealTime() | |||
| @@ -197,7 +197,7 @@ int JackMachThread::AcquireSelfRealTime(int priority) | |||
| return AcquireSelfRealTime(); | |||
| } | |||
| int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| int JackMachThread::AcquireRealTimeImp(jack_native_thread_t thread, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| { | |||
| SetThreadToPriority(thread, 96, true, period, computation, constraint); | |||
| return 0; | |||
| @@ -205,7 +205,7 @@ int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 c | |||
| int JackMachThread::DropRealTime() | |||
| { | |||
| return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
| return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
| } | |||
| int JackMachThread::DropSelfRealTime() | |||
| @@ -213,7 +213,7 @@ int JackMachThread::DropSelfRealTime() | |||
| return DropRealTimeImp(pthread_self()); | |||
| } | |||
| int JackMachThread::DropRealTimeImp(pthread_t thread) | |||
| int JackMachThread::DropRealTimeImp(jack_native_thread_t thread) | |||
| { | |||
| SetThreadToPriority(thread, 63, false, 0, 0, 0); | |||
| return 0; | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -98,9 +98,9 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread | |||
| UInt64 fComputation; | |||
| UInt64 fConstraint; | |||
| static UInt32 GetThreadSetPriority(pthread_t thread); | |||
| static UInt32 GetThreadScheduledPriority(pthread_t thread); | |||
| static UInt32 GetThreadPriority(pthread_t thread, int inWhichPriority); | |||
| static UInt32 GetThreadSetPriority(jack_native_thread_t thread); | |||
| static UInt32 GetThreadScheduledPriority(jack_native_thread_t thread); | |||
| static UInt32 GetThreadPriority(jack_native_thread_t thread, int inWhichPriority); | |||
| public: | |||
| @@ -116,23 +116,23 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread | |||
| int AcquireRealTime(); // Used when called from another thread | |||
| int AcquireSelfRealTime(); // Used when called from thread itself | |||
| int AcquireRealTime(int priority); // Used when called from another thread | |||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
| int DropRealTime(); // Used when called from another thread | |||
| int DropSelfRealTime(); // Used when called from thread itself | |||
| void SetParams(UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint); | |||
| static int SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int GetParams(jack_native_thread_t thread, UInt64* period, UInt64* computation, UInt64* constraint); | |||
| static int SetThreadToPriority(jack_native_thread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| { | |||
| return JackMachThread::AcquireRealTimeImp(thread, period, computation, constraint); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, UInt64 period, UInt64 computation, UInt64 constraint); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| { | |||
| return JackMachThread::AcquireRealTimeImp(thread, period, computation, constraint); | |||
| } | |||
| static int DropRealTimeImp(pthread_t thread); | |||
| static int DropRealTimeImp(jack_native_thread_t thread); | |||
| }; | |||
| } // end of namespace | |||
| @@ -184,9 +184,9 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice | |||
| AudioDevicePropertyID inPropertyID, | |||
| void* inClientData) | |||
| { | |||
| switch (inPropertyID) { | |||
| case kAudioDeviceProcessorOverload: { | |||
| jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload"); | |||
| break; | |||
| @@ -196,12 +196,12 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice | |||
| jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration"); | |||
| return kAudioHardwareUnsupportedOperationError; | |||
| } | |||
| case kAudioDevicePropertyNominalSampleRate: { | |||
| jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate"); | |||
| return kAudioHardwareUnsupportedOperationError; | |||
| } | |||
| } | |||
| return noErr; | |||
| } | |||
| @@ -217,7 +217,7 @@ int JackCoreAudioAdapter::AddListeners() | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); | |||
| if (err != noErr) { | |||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); | |||
| @@ -275,17 +275,17 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon, | |||
| { | |||
| JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon); | |||
| AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); | |||
| float* inputBuffer[adapter->fCaptureChannels]; | |||
| float* outputBuffer[adapter->fPlaybackChannels]; | |||
| for (int i = 0; i < adapter->fCaptureChannels; i++) { | |||
| inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData; | |||
| } | |||
| for (int i = 0; i < adapter->fPlaybackChannels; i++) { | |||
| outputBuffer[i] = (float*)ioData->mBuffers[i].mData; | |||
| } | |||
| adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames); | |||
| return noErr; | |||
| } | |||
| @@ -302,16 +302,16 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
| fCaptureUID[0] = 0; | |||
| fPlaybackUID[0] = 0; | |||
| fClockDriftCompensate = false; | |||
| // Default values | |||
| fCaptureChannels = -1; | |||
| fPlaybackChannels = -1; | |||
| SInt32 major; | |||
| SInt32 minor; | |||
| Gestalt(gestaltSystemVersionMajor, &major); | |||
| Gestalt(gestaltSystemVersionMinor, &minor); | |||
| // Starting with 10.6 systems, the HAL notification thread is created internally | |||
| if (major == 10 && minor >= 6) { | |||
| CFRunLoopRef theRunLoop = NULL; | |||
| @@ -321,7 +321,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
| jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error"); | |||
| } | |||
| } | |||
| for (node = params; node; node = jack_slist_next(node)) { | |||
| param = (const jack_driver_param_t*) node->data; | |||
| @@ -348,7 +348,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
| fPlaying = true; | |||
| strncpy(fPlaybackUID, param->value.str, 256); | |||
| break; | |||
| case 'd': | |||
| strncpy(fCaptureUID, param->value.str, 256); | |||
| strncpy(fPlaybackUID, param->value.str, 256); | |||
| @@ -365,51 +365,51 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
| case 'p': | |||
| SetAdaptedBufferSize(param->value.ui); | |||
| break; | |||
| case 'l': | |||
| DisplayDeviceNames(); | |||
| break; | |||
| case 'q': | |||
| fQuality = param->value.ui; | |||
| break; | |||
| case 'g': | |||
| fRingbufferCurSize = param->value.ui; | |||
| fAdaptative = false; | |||
| break; | |||
| case 's': | |||
| fClockDriftCompensate = true; | |||
| break; | |||
| } | |||
| } | |||
| /* duplex is the default */ | |||
| if (!fCapturing && !fPlaying) { | |||
| fCapturing = true; | |||
| fPlaying = true; | |||
| } | |||
| if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) | |||
| throw -1; | |||
| if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) | |||
| throw -1; | |||
| if (SetupBufferSize(fAdaptedBufferSize) < 0) | |||
| throw -1; | |||
| if (SetupSampleRate(fAdaptedSampleRate) < 0) | |||
| throw -1; | |||
| if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0) | |||
| if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0) | |||
| throw -1; | |||
| if (fCapturing && fCaptureChannels > 0) | |||
| if (SetupBuffers(fCaptureChannels) < 0) | |||
| throw -1; | |||
| if (AddListeners() < 0) | |||
| throw -1; | |||
| } | |||
| @@ -488,6 +488,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID* id) | |||
| if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) | |||
| return res; | |||
| if (inDefault == 0) { | |||
| jack_error("Error : input device is 0, please select a correct one !!"); | |||
| return -1; | |||
| } | |||
| jack_log("GetDefaultInputDevice: input = %ld ", inDefault); | |||
| *id = inDefault; | |||
| return noErr; | |||
| @@ -502,6 +506,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID* id) | |||
| if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) | |||
| return res; | |||
| if (outDefault == 0) { | |||
| jack_error("Error : output device is 0, please select a correct one !!"); | |||
| return -1; | |||
| } | |||
| jack_log("GetDefaultOutputDevice: output = %ld", outDefault); | |||
| *id = outDefault; | |||
| return noErr; | |||
| @@ -525,10 +533,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| // Duplex | |||
| if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | |||
| // Same device for capture and playback... | |||
| if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { | |||
| if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | |||
| jack_log("Will take default in/out"); | |||
| if (GetDefaultDevice(&fDeviceID) != noErr) { | |||
| @@ -540,12 +548,12 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| jack_error("Cannot get device name from device ID"); | |||
| return -1; | |||
| } | |||
| } else { | |||
| // Creates aggregate device | |||
| AudioDeviceID captureID, playbackID; | |||
| if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | |||
| jack_log("Will take default input"); | |||
| if (GetDefaultInputDevice(&captureID) != noErr) { | |||
| @@ -553,7 +561,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| return -1; | |||
| } | |||
| } | |||
| if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | |||
| jack_log("Will take default output"); | |||
| if (GetDefaultOutputDevice(&playbackID) != noErr) { | |||
| @@ -561,7 +569,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| return -1; | |||
| } | |||
| } | |||
| if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | |||
| return -1; | |||
| } | |||
| @@ -599,10 +607,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| jack_log("JackCoreAudioDriver::Open default driver"); | |||
| if (GetDefaultDevice(&fDeviceID) != noErr) { | |||
| jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); | |||
| // Creates aggregate device | |||
| AudioDeviceID captureID, playbackID; | |||
| if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | |||
| jack_log("Will take default input"); | |||
| if (GetDefaultInputDevice(&captureID) != noErr) { | |||
| @@ -610,7 +618,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| return -1; | |||
| } | |||
| } | |||
| if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | |||
| jack_log("Will take default output"); | |||
| if (GetDefaultOutputDevice(&playbackID) != noErr) { | |||
| @@ -618,7 +626,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| return -1; | |||
| } | |||
| } | |||
| if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | |||
| return -1; | |||
| } | |||
| @@ -680,7 +688,7 @@ int JackCoreAudioAdapter::SetupChannels(bool capturing, | |||
| jack_log("Setup max out channels = %ld", out_nChannels); | |||
| outchannels = out_nChannels; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -694,7 +702,7 @@ int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size) | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -708,7 +716,7 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||
| OSStatus err = noErr; | |||
| UInt32 outSize; | |||
| Float64 sampleRate; | |||
| // Get sample rate | |||
| outSize = sizeof(Float64); | |||
| err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); | |||
| @@ -716,12 +724,14 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||
| jack_error("Cannot get current sample rate"); | |||
| printError(err); | |||
| return -1; | |||
| } else { | |||
| jack_log("Current sample rate = %f", sampleRate); | |||
| } | |||
| // If needed, set new sample rate | |||
| if (samplerate != (jack_nframes_t)sampleRate) { | |||
| sampleRate = (Float64)samplerate; | |||
| // To get SR change notification | |||
| err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); | |||
| if (err != noErr) { | |||
| @@ -735,18 +745,18 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| // Waiting for SR change notification | |||
| int count = 0; | |||
| while (!fState && count++ < WAIT_COUNTER) { | |||
| usleep(100000); | |||
| jack_log("Wait count = %d", count); | |||
| } | |||
| // Remove SR change notification | |||
| AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -796,7 +806,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| jack_error("No input and output channels..."); | |||
| return -1; | |||
| } | |||
| // AUHAL | |||
| ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; | |||
| Component HALOutput = FindNextComponent(NULL, &cd); | |||
| @@ -823,7 +833,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| enableIO = 0; | |||
| jack_log("Setup AUHAL input off"); | |||
| } | |||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); | |||
| @@ -838,14 +848,14 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| enableIO = 0; | |||
| jack_log("Setup AUHAL output off"); | |||
| } | |||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); | |||
| printError(err1); | |||
| goto error; | |||
| } | |||
| size = sizeof(AudioDeviceID); | |||
| err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); | |||
| if (err1 != noErr) { | |||
| @@ -863,7 +873,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| printError(err1); | |||
| goto error; | |||
| } | |||
| // Set buffer size | |||
| if (capturing && inchannels > 0) { | |||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32)); | |||
| @@ -918,7 +928,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| // Setup stream converters | |||
| if (capturing && inchannels > 0) { | |||
| size = sizeof(AudioStreamBasicDescription); | |||
| err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size); | |||
| if (err1 != noErr) { | |||
| @@ -927,7 +937,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| goto error; | |||
| } | |||
| PrintStreamDesc(&srcFormat); | |||
| jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); | |||
| srcFormat.mSampleRate = samplerate; | |||
| srcFormat.mFormatID = kAudioFormatLinearPCM; | |||
| @@ -938,9 +948,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| srcFormat.mChannelsPerFrame = inchannels; | |||
| srcFormat.mBitsPerChannel = 32; | |||
| PrintStreamDesc(&srcFormat); | |||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); | |||
| printError(err1); | |||
| @@ -949,7 +959,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| } | |||
| if (playing && outchannels > 0) { | |||
| size = sizeof(AudioStreamBasicDescription); | |||
| err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size); | |||
| if (err1 != noErr) { | |||
| @@ -958,7 +968,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| goto error; | |||
| } | |||
| PrintStreamDesc(&dstFormat); | |||
| jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); | |||
| dstFormat.mSampleRate = samplerate; | |||
| dstFormat.mFormatID = kAudioFormatLinearPCM; | |||
| @@ -969,9 +979,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| dstFormat.mChannelsPerFrame = outchannels; | |||
| dstFormat.mBitsPerChannel = 32; | |||
| PrintStreamDesc(&dstFormat); | |||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); | |||
| if (err1 != noErr) { | |||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); | |||
| printError(err1); | |||
| @@ -1003,13 +1013,13 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
| } | |||
| return 0; | |||
| error: | |||
| CloseAUHAL(); | |||
| return -1; | |||
| } | |||
| OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||
| OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||
| { | |||
| OSStatus osErr = noErr; | |||
| AudioObjectPropertyAddress pluginAOPA; | |||
| @@ -1017,21 +1027,21 @@ OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||
| pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||
| pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||
| UInt32 outDataSize; | |||
| osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); | |||
| printError(osErr); | |||
| return osErr; | |||
| } | |||
| osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); | |||
| printError(osErr); | |||
| return osErr; | |||
| } | |||
| return noErr; | |||
| } | |||
| @@ -1043,15 +1053,15 @@ static CFStringRef GetDeviceName(AudioDeviceID id) | |||
| return (err == noErr) ? UIname : NULL; | |||
| } | |||
| OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
| OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
| { | |||
| OSStatus err = noErr; | |||
| AudioObjectID sub_device[32]; | |||
| UInt32 outSize = sizeof(sub_device); | |||
| err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
| vector<AudioDeviceID> captureDeviceIDArray; | |||
| if (err != noErr) { | |||
| jack_log("Input device does not have subdevices"); | |||
| captureDeviceIDArray.push_back(captureDeviceID); | |||
| @@ -1062,10 +1072,10 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice | |||
| captureDeviceIDArray.push_back(sub_device[i]); | |||
| } | |||
| } | |||
| err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
| err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
| vector<AudioDeviceID> playbackDeviceIDArray; | |||
| if (err != noErr) { | |||
| jack_log("Output device does not have subdevices"); | |||
| playbackDeviceIDArray.push_back(playbackDeviceID); | |||
| @@ -1076,16 +1086,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice | |||
| playbackDeviceIDArray.push_back(sub_device[i]); | |||
| } | |||
| } | |||
| return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice); | |||
| } | |||
| OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
| OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
| { | |||
| OSStatus osErr = noErr; | |||
| UInt32 outSize; | |||
| Boolean outWritable; | |||
| // Prepare sub-devices for clock drift compensation | |||
| // Workaround for bug in the HAL : until 10.6.2 | |||
| AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; | |||
| @@ -1094,7 +1104,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| AudioClassID inClass = kAudioSubDeviceClassID; | |||
| void* theQualifierData = &inClass; | |||
| UInt32 subDevicesNum = 0; | |||
| //--------------------------------------------------------------------------- | |||
| // Setup SR of both devices otherwise creating AD may fail... | |||
| //--------------------------------------------------------------------------- | |||
| @@ -1102,18 +1112,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| UInt32 clockdomain = 0; | |||
| outSize = sizeof(UInt32); | |||
| bool need_clock_drift_compensation = false; | |||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
| if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); | |||
| } else { | |||
| // Check clock domain | |||
| osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
| osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
| if (osErr != 0) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | |||
| printError(osErr); | |||
| } else { | |||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); | |||
| if (clockdomain != 0 && clockdomain != keptclockdomain) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); | |||
| @@ -1122,18 +1132,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| } | |||
| } | |||
| } | |||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
| if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); | |||
| } else { | |||
| // Check clock domain | |||
| osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
| osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
| if (osErr != 0) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | |||
| printError(osErr); | |||
| } else { | |||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); | |||
| if (clockdomain != 0 && clockdomain != keptclockdomain) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); | |||
| @@ -1142,74 +1152,74 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| } | |||
| } | |||
| } | |||
| // If no valid clock domain was found, then assume we have to compensate... | |||
| if (keptclockdomain == 0) { | |||
| need_clock_drift_compensation = true; | |||
| } | |||
| //--------------------------------------------------------------------------- | |||
| // Start to create a new aggregate by getting the base audio hardware plugin | |||
| //--------------------------------------------------------------------------- | |||
| char device_name[256]; | |||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
| GetDeviceNameFromID(captureDeviceID[i], device_name); | |||
| jack_info("Separated input = '%s' ", device_name); | |||
| } | |||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
| GetDeviceNameFromID(playbackDeviceID[i], device_name); | |||
| jack_info("Separated output = '%s' ", device_name); | |||
| } | |||
| osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); | |||
| printError(osErr); | |||
| return osErr; | |||
| } | |||
| AudioValueTranslation pluginAVT; | |||
| CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); | |||
| pluginAVT.mInputData = &inBundleRef; | |||
| pluginAVT.mInputDataSize = sizeof(inBundleRef); | |||
| pluginAVT.mOutputData = &fPluginID; | |||
| pluginAVT.mOutputDataSize = sizeof(fPluginID); | |||
| osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); | |||
| printError(osErr); | |||
| return osErr; | |||
| } | |||
| //------------------------------------------------- | |||
| // Create a CFDictionary for our aggregate device | |||
| //------------------------------------------------- | |||
| CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |||
| CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); | |||
| CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); | |||
| // add the name of the device to the dictionary | |||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); | |||
| // add our choice of UID for the aggregate device to the dictionary | |||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); | |||
| // add a "private aggregate key" to the dictionary | |||
| int value = 1; | |||
| CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); | |||
| SInt32 system; | |||
| Gestalt(gestaltSystemVersion, &system); | |||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); | |||
| // Starting with 10.5.4 systems, the AD can be internal... (better) | |||
| if (system < 0x00001054) { | |||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); | |||
| @@ -1217,16 +1227,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); | |||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); | |||
| } | |||
| // Prepare sub-devices for clock drift compensation | |||
| CFMutableArrayRef subDevicesArrayClock = NULL; | |||
| /* | |||
| if (fClockDriftCompensate) { | |||
| if (need_clock_drift_compensation) { | |||
| jack_info("Clock drift compensation activated..."); | |||
| subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
| CFStringRef UID = GetDeviceName(captureDeviceID[i]); | |||
| if (UID) { | |||
| @@ -1237,7 +1247,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | |||
| } | |||
| } | |||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
| CFStringRef UID = GetDeviceName(playbackDeviceID[i]); | |||
| if (UID) { | |||
| @@ -1248,7 +1258,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | |||
| } | |||
| } | |||
| // add sub-device clock array for the aggregate device to the dictionary | |||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); | |||
| } else { | |||
| @@ -1256,14 +1266,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| } | |||
| } | |||
| */ | |||
| //------------------------------------------------- | |||
| // Create a CFMutableArray for our sub-device list | |||
| //------------------------------------------------- | |||
| // we need to append the UID for each device to a CFMutableArray, so create one here | |||
| CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |||
| vector<CFStringRef> captureDeviceUID; | |||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
| CFStringRef ref = GetDeviceName(captureDeviceID[i]); | |||
| @@ -1273,7 +1283,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| // input sub-devices in this example, so append the sub-device's UID to the CFArray | |||
| CFArrayAppendValue(subDevicesArray, ref); | |||
| } | |||
| vector<CFStringRef> playbackDeviceUID; | |||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
| CFStringRef ref = GetDeviceName(playbackDeviceID[i]); | |||
| @@ -1283,39 +1293,39 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| // output sub-devices in this example, so append the sub-device's UID to the CFArray | |||
| CFArrayAppendValue(subDevicesArray, ref); | |||
| } | |||
| //----------------------------------------------------------------------- | |||
| // Feed the dictionary to the plugin, to create a blank aggregate device | |||
| //----------------------------------------------------------------------- | |||
| AudioObjectPropertyAddress pluginAOPA; | |||
| pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; | |||
| pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||
| pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||
| UInt32 outDataSize; | |||
| osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); | |||
| printError(osErr); | |||
| goto error; | |||
| } | |||
| osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); | |||
| printError(osErr); | |||
| goto error; | |||
| } | |||
| // pause for a bit to make sure that everything completed correctly | |||
| // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created | |||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
| //------------------------- | |||
| // Set the sub-device list | |||
| //------------------------- | |||
| pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; | |||
| pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||
| pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||
| @@ -1326,14 +1336,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| printError(osErr); | |||
| goto error; | |||
| } | |||
| // pause again to give the changes time to take effect | |||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
| //----------------------- | |||
| // Set the master device | |||
| //----------------------- | |||
| // set the master device manually (this is the device which will act as the master clock for the aggregate device) | |||
| // pass in the UID of the device you want to use | |||
| pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; | |||
| @@ -1346,36 +1356,36 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| printError(osErr); | |||
| goto error; | |||
| } | |||
| // pause again to give the changes time to take effect | |||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
| // Prepare sub-devices for clock drift compensation | |||
| // Workaround for bug in the HAL : until 10.6.2 | |||
| if (fClockDriftCompensate) { | |||
| if (need_clock_drift_compensation) { | |||
| jack_info("Clock drift compensation activated..."); | |||
| // Get the property data size | |||
| osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | |||
| printError(osErr); | |||
| } | |||
| // Calculate the number of object IDs | |||
| subDevicesNum = outSize / sizeof(AudioObjectID); | |||
| jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); | |||
| AudioObjectID subDevices[subDevicesNum]; | |||
| outSize = sizeof(subDevices); | |||
| osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); | |||
| if (osErr != noErr) { | |||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | |||
| printError(osErr); | |||
| } | |||
| // Set kAudioSubDevicePropertyDriftCompensation property... | |||
| for (UInt32 index = 0; index < subDevicesNum; ++index) { | |||
| UInt32 theDriftCompensationValue = 1; | |||
| @@ -1388,50 +1398,50 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
| } else { | |||
| jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); | |||
| } | |||
| } | |||
| } | |||
| // pause again to give the changes time to take effect | |||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
| //---------- | |||
| // Clean up | |||
| //---------- | |||
| // release the private AD key | |||
| CFRelease(AggregateDeviceNumberRef); | |||
| // release the CF objects we have created - we don't need them any more | |||
| CFRelease(aggDeviceDict); | |||
| CFRelease(subDevicesArray); | |||
| if (subDevicesArrayClock) | |||
| CFRelease(subDevicesArrayClock); | |||
| // release the device UID | |||
| for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { | |||
| CFRelease(captureDeviceUID[i]); | |||
| } | |||
| for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { | |||
| CFRelease(playbackDeviceUID[i]); | |||
| } | |||
| jack_log("New aggregate device %ld", *outAggregateDevice); | |||
| return noErr; | |||
| error: | |||
| DestroyAggregateDevice(); | |||
| return -1; | |||
| } | |||
| bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device) | |||
| { | |||
| OSStatus err = noErr; | |||
| AudioObjectID sub_device[32]; | |||
| UInt32 outSize = sizeof(sub_device); | |||
| err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
| if (err != noErr) { | |||
| jack_log("Device does not have subdevices"); | |||
| return false; | |||
| @@ -1494,7 +1504,7 @@ extern "C" | |||
| strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
| strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
| desc->nparams = 13; | |||
| desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); | |||
| @@ -1574,7 +1584,7 @@ extern "C" | |||
| desc->params[i].value.i = TRUE; | |||
| strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "quality"); | |||
| desc->params[i].character = 'q'; | |||
| @@ -1582,7 +1592,7 @@ extern "C" | |||
| desc->params[i].value.ui = 0; | |||
| strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "ring-buffer"); | |||
| desc->params[i].character = 'g'; | |||
| @@ -1590,7 +1600,7 @@ extern "C" | |||
| desc->params[i].value.ui = 32768; | |||
| strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
| strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); | |||
| i++; | |||
| strcpy(desc->params[i].name, "clock-drift"); | |||
| desc->params[i].character = 's'; | |||
| @@ -1598,7 +1608,7 @@ extern "C" | |||
| desc->params[i].value.i = FALSE; | |||
| strcpy(desc->params[i].short_desc, "Clock drift compensation"); | |||
| strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device"); | |||
| return desc; | |||
| } | |||
| @@ -6,12 +6,6 @@ def create_jack_driver_obj(bld, target, sources, uselib = None): | |||
| driver.features.append('cc') | |||
| driver.env['shlib_PATTERN'] = 'jack_%s.so' | |||
| driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
| # Seems uneeded here... | |||
| #if bld.env['HAVE_CELT']: | |||
| #if bld.env['HAVE_CELT_API_0_5']: | |||
| # driver.defines += ['HAVE_CELT', 'HAVE_CELT_API_0_5'] | |||
| #elif bld.env['HAVE_CELT_API_0_7']: | |||
| # driver.defines += ['HAVE_CELT', 'HAVE_CELT_API_0_7'] | |||
| driver.includes = ['.', '../macosx', '../posix', '../common', '../common/jack'] | |||
| driver.target = target | |||
| driver.source = sources | |||
| @@ -0,0 +1,53 @@ | |||
| .TH JACK_IODELAY "1" "!DATE!" "!VERSION!" | |||
| .SH NAME | |||
| jack_iodelay \- JACK toolkit client to measure roundtrip latency | |||
| .SH SYNOPSIS | |||
| .B jack_iodelay | |||
| .SH DESCRIPTION | |||
| .B jack_iodelay | |||
| will create one input and one output port, and then | |||
| measures the latency (signal delay) between them. For this to work, | |||
| the output port must be connected to its input port. The measurement | |||
| is accurate to a resolution of greater than 1 sample. | |||
| .PP | |||
| The expected use is to connect jack_iodelay's output port to a | |||
| hardware playback port, then use a physical loopback cable from the | |||
| corresponding hardware output connector to an input connector, and to | |||
| connect that corresponding hardware capture port to jack_iodelay's | |||
| input port. This creates a roundtrip that goes through any | |||
| analog-to-digital or digital-converters that are present in the audio | |||
| hardware. | |||
| .PP | |||
| Although the hardware loopback latency is the expected use, it is also | |||
| possible to use jack_iodelay to measure the latency along any fully | |||
| connected signal path, such as those involving other JACK clients. | |||
| .PP | |||
| Once jack_iodelay completes its measurement it will print the total | |||
| latency it has detected. This will include the JACK period length in | |||
| addition to any other latency in the signal path. It will continue to | |||
| print the value every 0.5 seconds or so so that if you wish you can | |||
| vary aspects of the signal path to see their effect on the measured | |||
| latency. | |||
| .PP | |||
| If no incoming signal is detected from the input port, jack_iodelay | |||
| will print | |||
| .PP | |||
| \fT Signal below threshold... .\fR | |||
| .PP | |||
| every second until this changes (e.g. until you establish the correct connections). | |||
| .PP | |||
| To use the value measured by jack_iodelay with the -I and -O arguments | |||
| of a JACK backend (also called Input Latency and Output Latency in the | |||
| setup dialog of qjackctl), you must subtract the JACK period size from | |||
| the result. Then, if you believe that the latency is equally | |||
| distributed between the input and output parts of your audio hardware | |||
| (extremely likely), divide the result by two and use that for input | |||
| and/or output latency value. Doing this measurement will enable JACK | |||
| clients that use the JACK latency API to accurately position/delay | |||
| audio to keep signals synchronized even when there are inherent delays | |||
| in the end-to-end signal pathways. | |||
| .SH AUTHOR | |||
| Originally written in C++ by Fons Adriensen, ported to C by Torben Hohn. | |||
| @@ -33,47 +33,47 @@ namespace Jack | |||
| \brief Mutex abstraction. | |||
| */ | |||
| class JackBasePosixMutex | |||
| { | |||
| protected: | |||
| pthread_mutex_t fMutex; | |||
| public: | |||
| JackBasePosixMutex() | |||
| { | |||
| pthread_mutex_init(&fMutex, NULL); | |||
| pthread_mutex_init(&fMutex, NULL); | |||
| } | |||
| virtual ~JackBasePosixMutex() | |||
| { | |||
| pthread_mutex_destroy(&fMutex); | |||
| } | |||
| void Lock() | |||
| { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| if (res != 0) | |||
| jack_error("JackBasePosixMutex::Lock res = %d", res); | |||
| jack_log("JackBasePosixMutex::Lock res = %d", res); | |||
| } | |||
| bool Trylock() | |||
| { | |||
| return (pthread_mutex_trylock(&fMutex) == 0); | |||
| } | |||
| void Unlock() | |||
| { | |||
| int res = pthread_mutex_unlock(&fMutex); | |||
| if (res != 0) | |||
| jack_error("JackBasePosixMutex::Unlock res = %d", res); | |||
| jack_log("JackBasePosixMutex::Unlock res = %d", res); | |||
| } | |||
| }; | |||
| class JackPosixMutex | |||
| { | |||
| @@ -97,7 +97,7 @@ class JackPosixMutex | |||
| res = pthread_mutexattr_destroy(&mutex_attr); | |||
| assert(res == 0); | |||
| } | |||
| virtual ~JackPosixMutex() | |||
| { | |||
| pthread_mutex_destroy(&fMutex); | |||
| @@ -107,7 +107,7 @@ class JackPosixMutex | |||
| { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| if (res != 0) | |||
| jack_error("JackPosixMutex::Lock res = %d", res); | |||
| jack_log("JackPosixMutex::Lock res = %d", res); | |||
| return (res == 0); | |||
| } | |||
| @@ -120,7 +120,7 @@ class JackPosixMutex | |||
| { | |||
| int res = pthread_mutex_unlock(&fMutex); | |||
| if (res != 0) | |||
| jack_error("JackPosixMutex::Unlock res = %d", res); | |||
| jack_log("JackPosixMutex::Unlock res = %d", res); | |||
| return (res == 0); | |||
| } | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -40,19 +40,19 @@ void* JackPosixThread::ThreadHandler(void* arg) | |||
| if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) { | |||
| jack_error("pthread_setcanceltype err = %s", strerror(err)); | |||
| } | |||
| // Signal creation thread when started with StartSync | |||
| jack_log("ThreadHandler: start"); | |||
| obj->fStatus = kIniting; | |||
| // Call Init method | |||
| if (!runnable->Init()) { | |||
| jack_error("Thread init fails: thread quits"); | |||
| return 0; | |||
| } | |||
| obj->fStatus = kRunning; | |||
| // If Init succeed, start the thread loop | |||
| bool res = true; | |||
| while (obj->fStatus == kRunning && res) { | |||
| @@ -76,11 +76,11 @@ int JackPosixThread::Start() | |||
| return 0; | |||
| } | |||
| } | |||
| int JackPosixThread::StartSync() | |||
| { | |||
| fStatus = kStarting; | |||
| if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { | |||
| fStatus = kIdle; | |||
| return -1; | |||
| @@ -90,10 +90,10 @@ int JackPosixThread::StartSync() | |||
| JackSleep(1000); | |||
| } | |||
| return (count == 1000) ? -1 : 0; | |||
| } | |||
| } | |||
| } | |||
| int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg) | |||
| int JackPosixThread::StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg) | |||
| { | |||
| pthread_attr_t attributes; | |||
| struct sched_param rt_param; | |||
| @@ -111,19 +111,19 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi | |||
| } | |||
| if (realtime) { | |||
| jack_log("Create RT thread"); | |||
| if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) { | |||
| jack_error("Cannot request explicit scheduling for RT thread res = %d", res); | |||
| return -1; | |||
| } | |||
| if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { | |||
| jack_error("Cannot set RR scheduling class for RT thread res = %d", res); | |||
| return -1; | |||
| } | |||
| memset(&rt_param, 0, sizeof(rt_param)); | |||
| rt_param.sched_priority = priority; | |||
| @@ -152,13 +152,13 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi | |||
| int JackPosixThread::Kill() | |||
| { | |||
| if (fThread != (pthread_t)NULL) { // If thread has been started | |||
| if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackPosixThread::Kill"); | |||
| void* status; | |||
| pthread_cancel(fThread); | |||
| pthread_join(fThread, &status); | |||
| fStatus = kIdle; | |||
| fThread = (pthread_t)NULL; | |||
| fThread = (jack_native_thread_t)NULL; | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| @@ -167,21 +167,21 @@ int JackPosixThread::Kill() | |||
| int JackPosixThread::Stop() | |||
| { | |||
| if (fThread != (pthread_t)NULL) { // If thread has been started | |||
| if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackPosixThread::Stop"); | |||
| void* status; | |||
| fStatus = kIdle; // Request for the thread to stop | |||
| pthread_join(fThread, &status); | |||
| fThread = (pthread_t)NULL; | |||
| fThread = (jack_native_thread_t)NULL; | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| } | |||
| } | |||
| int JackPosixThread::KillImp(pthread_t thread) | |||
| int JackPosixThread::KillImp(jack_native_thread_t thread) | |||
| { | |||
| if (thread != (pthread_t)NULL) { // If thread has been started | |||
| if (thread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackPosixThread::Kill"); | |||
| void* status; | |||
| pthread_cancel(thread); | |||
| @@ -192,9 +192,9 @@ int JackPosixThread::KillImp(pthread_t thread) | |||
| } | |||
| } | |||
| int JackPosixThread::StopImp(pthread_t thread) | |||
| int JackPosixThread::StopImp(jack_native_thread_t thread) | |||
| { | |||
| if (thread != (pthread_t)NULL) { // If thread has been started | |||
| if (thread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackPosixThread::Stop"); | |||
| void* status; | |||
| pthread_join(thread, &status); | |||
| @@ -206,7 +206,7 @@ int JackPosixThread::StopImp(pthread_t thread) | |||
| int JackPosixThread::AcquireRealTime() | |||
| { | |||
| return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1; | |||
| return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1; | |||
| } | |||
| int JackPosixThread::AcquireSelfRealTime() | |||
| @@ -225,7 +225,7 @@ int JackPosixThread::AcquireSelfRealTime(int priority) | |||
| fPriority = priority; | |||
| return AcquireSelfRealTime(); | |||
| } | |||
| int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) | |||
| int JackPosixThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority) | |||
| { | |||
| struct sched_param rtparam; | |||
| int res; | |||
| @@ -243,7 +243,7 @@ int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) | |||
| int JackPosixThread::DropRealTime() | |||
| { | |||
| return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
| return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
| } | |||
| int JackPosixThread::DropSelfRealTime() | |||
| @@ -251,7 +251,7 @@ int JackPosixThread::DropSelfRealTime() | |||
| return DropRealTimeImp(pthread_self()); | |||
| } | |||
| int JackPosixThread::DropRealTimeImp(pthread_t thread) | |||
| int JackPosixThread::DropRealTimeImp(jack_native_thread_t thread) | |||
| { | |||
| struct sched_param rtparam; | |||
| int res; | |||
| @@ -265,7 +265,7 @@ int JackPosixThread::DropRealTimeImp(pthread_t thread) | |||
| return 0; | |||
| } | |||
| pthread_t JackPosixThread::GetThreadID() | |||
| jack_native_thread_t JackPosixThread::GetThreadID() | |||
| { | |||
| return fThread; | |||
| } | |||
| @@ -320,42 +320,42 @@ bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr) | |||
| bool jack_tls_allocate_key(jack_tls_key *key_ptr) | |||
| { | |||
| int ret; | |||
| ret = pthread_key_create(key_ptr, NULL); | |||
| if (ret != 0) | |||
| { | |||
| jack_error("pthread_key_create() failed with error %d", ret); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool jack_tls_free_key(jack_tls_key key) | |||
| { | |||
| int ret; | |||
| ret = pthread_key_delete(key); | |||
| if (ret != 0) | |||
| { | |||
| jack_error("pthread_key_delete() failed with error %d", ret); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool jack_tls_set(jack_tls_key key, void *data_ptr) | |||
| { | |||
| int ret; | |||
| ret = pthread_setspecific(key, (const void *)data_ptr); | |||
| if (ret != 0) | |||
| { | |||
| jack_error("pthread_setspecific() failed with error %d", ret); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| @@ -13,7 +13,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -40,16 +40,16 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface | |||
| protected: | |||
| pthread_t fThread; | |||
| jack_native_thread_t fThread; | |||
| static void* ThreadHandler(void* arg); | |||
| public: | |||
| JackPosixThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation) | |||
| : JackThreadInterface(runnable, priority, real_time, cancellation), fThread((pthread_t)NULL) | |||
| : JackThreadInterface(runnable, priority, real_time, cancellation), fThread((jack_native_thread_t)NULL) | |||
| {} | |||
| JackPosixThread(JackRunnableInterface* runnable, int cancellation = PTHREAD_CANCEL_ASYNCHRONOUS) | |||
| : JackThreadInterface(runnable, 0, false, cancellation), fThread((pthread_t)NULL) | |||
| : JackThreadInterface(runnable, 0, false, cancellation), fThread((jack_native_thread_t)NULL) | |||
| {} | |||
| int Start(); | |||
| @@ -60,23 +60,23 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface | |||
| int AcquireRealTime(); // Used when called from another thread | |||
| int AcquireSelfRealTime(); // Used when called from thread itself | |||
| int AcquireRealTime(int priority); // Used when called from another thread | |||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
| int DropRealTime(); // Used when called from another thread | |||
| int DropSelfRealTime(); // Used when called from thread itself | |||
| pthread_t GetThreadID(); | |||
| jack_native_thread_t GetThreadID(); | |||
| bool IsThread(); | |||
| static int AcquireRealTimeImp(pthread_t thread, int priority); | |||
| static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| { return JackPosixThread::AcquireRealTimeImp(thread, priority); } | |||
| static int DropRealTimeImp(pthread_t thread); | |||
| static int StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
| static int StopImp(pthread_t thread); | |||
| static int KillImp(pthread_t thread); | |||
| static int DropRealTimeImp(jack_native_thread_t thread); | |||
| static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
| static int StopImp(jack_native_thread_t thread); | |||
| static int KillImp(jack_native_thread_t thread); | |||
| }; | |||
| SERVER_EXPORT void ThreadExit(); | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -45,12 +45,12 @@ void JackClientSocket::SetReadTimeOut(long sec) | |||
| { | |||
| int flags; | |||
| fTimeOut = sec; | |||
| if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | |||
| jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL"); | |||
| return; | |||
| } | |||
| flags |= O_NONBLOCK; | |||
| if (fcntl(fSocket, F_SETFL, flags) < 0) { | |||
| jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL"); | |||
| @@ -62,12 +62,12 @@ void JackClientSocket::SetWriteTimeOut(long sec) | |||
| { | |||
| int flags; | |||
| fTimeOut = sec; | |||
| if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | |||
| jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL"); | |||
| return; | |||
| } | |||
| flags |= O_NONBLOCK; | |||
| if (fcntl(fSocket, F_SETFL, flags) < 0) { | |||
| jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL"); | |||
| @@ -100,7 +100,7 @@ void JackClientSocket::SetWriteTimeOut(long sec) | |||
| #endif | |||
| void JackClientSocket::SetNonBlocking(bool onoff) | |||
| { | |||
| { | |||
| if (onoff) { | |||
| long flags = 0; | |||
| if (fcntl(fSocket, F_SETFL, flags | O_NONBLOCK) < 0) { | |||
| @@ -140,7 +140,7 @@ int JackClientSocket::Connect(const char* dir, const char* name, int which) // A | |||
| int JackClientSocket::Close() | |||
| { | |||
| jack_log("JackClientSocket::Close"); | |||
| jack_log("JackClientSocket::Close"); | |||
| if (fSocket > 0) { | |||
| shutdown(fSocket, SHUT_RDWR); | |||
| close(fSocket); | |||
| @@ -161,17 +161,17 @@ int JackClientSocket::Read(void* data, int len) | |||
| struct timeval tv; | |||
| fd_set fdset; | |||
| ssize_t res; | |||
| tv.tv_sec = fTimeOut; | |||
| tv.tv_usec = 0; | |||
| FD_ZERO(&fdset); | |||
| FD_SET(fSocket, &fdset); | |||
| do { | |||
| res = select(fSocket + 1, &fdset, NULL, NULL, &tv); | |||
| } while (res < 0 && errno == EINTR); | |||
| if (res < 0) { | |||
| return res; | |||
| } else if (res == 0) { | |||
| @@ -179,9 +179,9 @@ int JackClientSocket::Read(void* data, int len) | |||
| } | |||
| } | |||
| #endif | |||
| if ((res = read(fSocket, data, len)) != len) { | |||
| if (errno == EWOULDBLOCK) { | |||
| if (errno == EWOULDBLOCK || errno == EAGAIN) { | |||
| jack_error("JackClientSocket::Read time out"); | |||
| return 0; // For a non blocking socket, a read failure is not considered as an error | |||
| } else if (res != 0) { | |||
| @@ -201,21 +201,21 @@ int JackClientSocket::Write(void* data, int len) | |||
| #if defined(__sun__) || defined(sun) | |||
| if (fTimeOut > 0) { | |||
| struct timeval tv; | |||
| fd_set fdset; | |||
| ssize_t res; | |||
| tv.tv_sec = fTimeOut; | |||
| tv.tv_usec = 0; | |||
| FD_ZERO(&fdset); | |||
| FD_SET(fSocket, &fdset); | |||
| do { | |||
| res = select(fSocket + 1, NULL, &fdset, NULL, &tv); | |||
| } while (res < 0 && errno == EINTR); | |||
| if (res < 0) { | |||
| return res; | |||
| } else if (res == 0) { | |||
| @@ -225,7 +225,7 @@ int JackClientSocket::Write(void* data, int len) | |||
| #endif | |||
| if ((res = write(fSocket, data, len)) != len) { | |||
| if (errno == EWOULDBLOCK) { | |||
| if (errno == EWOULDBLOCK || errno == EAGAIN) { | |||
| jack_log("JackClientSocket::Write time out"); | |||
| return 0; // For a non blocking socket, a write failure is not considered as an error | |||
| } else if (res != 0) { | |||
| @@ -251,7 +251,7 @@ int JackServerSocket::Bind(const char* dir, const char* name, int which) // A re | |||
| addr.sun_family = AF_UNIX; | |||
| BuildName(name, fName, dir, which); | |||
| strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1); | |||
| jack_log("Bind: addr.sun_path %s", addr.sun_path); | |||
| unlink(fName); // Security... | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -108,7 +108,6 @@ int JackSocketClientChannel::Start() | |||
| } | |||
| } | |||
| void JackSocketClientChannel::Stop() | |||
| { | |||
| jack_log("JackSocketClientChannel::Stop"); | |||
| @@ -246,61 +245,73 @@ void JackSocketClientChannel::SetFreewheel(int onoff, int* result) | |||
| ServerSyncCall(&req, &res, result); | |||
| } | |||
| void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t ** result) | |||
| void JackSocketClientChannel::ComputeTotalLatencies(int* result) | |||
| { | |||
| JackComputeTotalLatenciesRequest req; | |||
| JackResult res; | |||
| ServerSyncCall(&req, &res, result); | |||
| } | |||
| void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result) | |||
| { | |||
| JackSessionNotifyRequest req(refnum, path, type, target); | |||
| JackSessionNotifyResult res; | |||
| JackSessionNotifyResult res; | |||
| int intresult; | |||
| ServerSyncCall(&req, &res, &intresult); | |||
| jack_session_command_t *session_command = (jack_session_command_t *)malloc( sizeof(jack_session_command_t) * (res.fCommandList.size()+1) ); | |||
| int i=0; | |||
| jack_session_command_t* session_command = (jack_session_command_t *)malloc(sizeof(jack_session_command_t) * (res.fCommandList.size() + 1)); | |||
| int i = 0; | |||
| for (std::list<JackSessionCommand>::iterator ci=res.fCommandList.begin(); ci!=res.fCommandList.end(); ci++) { | |||
| session_command[i].uuid = strdup( ci->fUUID ); | |||
| session_command[i].client_name = strdup( ci->fClientName ); | |||
| session_command[i].command = strdup( ci->fCommand ); | |||
| session_command[i].flags = ci->fFlags; | |||
| i+=1; | |||
| } | |||
| session_command[i].uuid = strdup( ci->fUUID ); | |||
| session_command[i].client_name = strdup( ci->fClientName ); | |||
| session_command[i].command = strdup( ci->fCommand ); | |||
| session_command[i].flags = ci->fFlags; | |||
| i += 1; | |||
| } | |||
| session_command[i].uuid = NULL; | |||
| session_command[i].client_name = NULL; | |||
| session_command[i].command = NULL; | |||
| session_command[i].flags = (jack_session_flags_t)0; | |||
| *result = session_command; | |||
| } | |||
| void JackSocketClientChannel::SessionReply(int refnum, int* result) | |||
| { | |||
| JackSessionReplyRequest req(refnum); | |||
| JackResult res; | |||
| JackResult res; | |||
| ServerSyncCall(&req, &res, result); | |||
| } | |||
| void JackSocketClientChannel::GetUUIDForClientName( int refnum, const char *client_name, char *uuid_res, int *result ) | |||
| void JackSocketClientChannel::GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result) | |||
| { | |||
| JackGetUUIDRequest req(client_name); | |||
| JackUUIDResult res; | |||
| JackUUIDResult res; | |||
| ServerSyncCall(&req, &res, result); | |||
| strncpy( uuid_res, res.fUUID, JACK_UUID_SIZE ); | |||
| strncpy(uuid_res, res.fUUID, JACK_UUID_SIZE); | |||
| } | |||
| void JackSocketClientChannel::GetClientNameForUUID( int refnum, const char *uuid, char *name_res, int *result ) | |||
| void JackSocketClientChannel::GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result) | |||
| { | |||
| JackGetClientNameRequest req(uuid); | |||
| JackClientNameResult res; | |||
| JackClientNameResult res; | |||
| ServerSyncCall(&req, &res, result); | |||
| strncpy(name_res, res.fName, JACK_CLIENT_NAME_SIZE); | |||
| } | |||
| void JackSocketClientChannel::ClientHasSessionCallback(const char* client_name, int* result) | |||
| { | |||
| JackClientHasSessionCallbackRequest req(client_name); | |||
| JackResult res; | |||
| ServerSyncCall(&req, &res, result); | |||
| strncpy( name_res, res.fName, JACK_CLIENT_NAME_SIZE ); | |||
| } | |||
| void JackSocketClientChannel::ReserveClientName( int refnum, const char *client_name, const char *uuid, int *result ) | |||
| void JackSocketClientChannel::ReserveClientName(int refnum, const char* client_name, const char* uuid, int* result) | |||
| { | |||
| JackReserveNameRequest req(refnum, client_name, uuid); | |||
| JackResult res; | |||
| JackResult res; | |||
| ServerSyncCall(&req, &res, result); | |||
| } | |||
| @@ -363,7 +374,7 @@ bool JackSocketClientChannel::Init() | |||
| jack_error("JackSocketClientChannel: cannot establish notication socket"); | |||
| return false; | |||
| } else { | |||
| return fClient->Init(); | |||
| return true; | |||
| } | |||
| } | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -38,11 +38,11 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||
| private: | |||
| JackClientSocket fRequestSocket; // Socket to communicate with the server | |||
| JackServerSocket fNotificationListenSocket; // Socket listener for server notification | |||
| JackClientSocket* fNotificationSocket; // Socket for server notification | |||
| JackClientSocket fRequestSocket; // Socket to communicate with the server | |||
| JackServerSocket fNotificationListenSocket; // Socket listener for server notification | |||
| JackClientSocket* fNotificationSocket; // Socket for server notification | |||
| JackThread fThread; // Thread to execute the event loop | |||
| JackClient* fClient; | |||
| JackClient* fClient; | |||
| void ServerSyncCall(JackRequest* req, JackResult* res, int* result); | |||
| void ServerAsyncCall(JackRequest* req, JackResult* res, int* result); | |||
| @@ -77,12 +77,14 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||
| void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); | |||
| void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); | |||
| void PortRename(int refnum, jack_port_id_t port, const char* name, int* result); | |||
| void SetBufferSize(jack_nframes_t buffer_size, int* result); | |||
| void SetFreewheel(int onoff, int* result); | |||
| void ComputeTotalLatencies(int* result); | |||
| void ReleaseTimebase(int refnum, int* result); | |||
| void SetTimebaseCallback(int refnum, int conditional, int* result); | |||
| @@ -91,18 +93,18 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||
| void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result); | |||
| void InternalClientUnload(int refnum, int int_ref, int* status, int* result); | |||
| // Session Stuff | |||
| // Session API | |||
| void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result); | |||
| void SessionReply(int refnum, int* result); | |||
| void GetUUIDForClientName( int refnum, const char *client_name, char *uuid_res, int *result ); | |||
| void GetClientNameForUUID( int refnum, const char *uuid, char *name_res, int *result ); | |||
| void ReserveClientName( int refnum, const char *client_name, const char *uuid, int *result ); | |||
| void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result); | |||
| void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result); | |||
| void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result); | |||
| void ClientHasSessionCallback(const char* client_name, int* result); | |||
| // JackRunnableInterface interface | |||
| bool Init(); | |||
| bool Execute(); | |||
| bool IsChannelThread() { return fThread.IsThread(); } | |||
| }; | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -51,7 +51,7 @@ JackSocketServerChannel::~JackSocketServerChannel() | |||
| int JackSocketServerChannel::Open(const char* server_name, JackServer* server) | |||
| { | |||
| jack_log("JackSocketServerChannel::Open"); | |||
| // Prepare request socket | |||
| if (fRequestListenSocket.Bind(jack_server_dir, server_name, 0) < 0) { | |||
| jack_log("JackSocketServerChannel::Open : cannot create result listen socket"); | |||
| @@ -79,14 +79,14 @@ void JackSocketServerChannel::Close() | |||
| delete socket; | |||
| } | |||
| } | |||
| int JackSocketServerChannel::Start() | |||
| { | |||
| if (fThread.Start() != 0) { | |||
| jack_error("Cannot start Jack server listener"); | |||
| return -1; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -168,6 +168,12 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
| return false; | |||
| } | |||
| if (fd == JackServerGlobals::fRTNotificationSocket && header.fType != JackRequest::kNotification) { | |||
| jack_error("fRTNotificationSocket = %d", JackServerGlobals::fRTNotificationSocket); | |||
| jack_error("JackSocketServerChannel::HandleRequest : incorrect notification !!"); | |||
| return true; | |||
| } | |||
| // Read data | |||
| switch (header.fType) { | |||
| @@ -292,7 +298,7 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
| jack_error("JackRequest::DisconnectPorts write error ref = %d", req.fRefNum); | |||
| break; | |||
| } | |||
| case JackRequest::kPortRename: { | |||
| jack_log("JackRequest::PortRename"); | |||
| JackPortRenameRequest req; | |||
| @@ -326,6 +332,17 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
| break; | |||
| } | |||
| case JackRequest::kComputeTotalLatencies: { | |||
| jack_log("JackRequest::ComputeTotalLatencies"); | |||
| JackComputeTotalLatenciesRequest req; | |||
| JackResult res; | |||
| if (req.Read(socket) == 0) | |||
| res.fResult = fServer->GetEngine()->ComputeTotalLatencies(); | |||
| if (res.Write(socket) < 0) | |||
| jack_error("JackRequest::ComputeTotalLatencies write error"); | |||
| break; | |||
| } | |||
| case JackRequest::kReleaseTimebase: { | |||
| jack_log("JackRequest::ReleaseTimebase"); | |||
| JackReleaseTimebaseRequest req; | |||
| @@ -430,27 +447,26 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
| } | |||
| case JackRequest::kGetClientByUUID: { | |||
| jack_log("JackRequest::GetClientNameForUUID"); | |||
| jack_log("JackRequest::GetClientByUUID"); | |||
| JackGetClientNameRequest req; | |||
| JackClientNameResult res; | |||
| if (req.Read(socket) == 0) { | |||
| fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult); | |||
| } | |||
| if (res.Write(socket) < 0) | |||
| jack_error("JackRequest::GetClientNameForUUID write error"); | |||
| jack_error("JackRequest::GetClientByUUID write error"); | |||
| break; | |||
| } | |||
| case JackRequest::kGetUUIDByClient: { | |||
| jack_log("JackRequest::GetUUIDForClientName"); | |||
| jack_log("JackRequest::GetUUIDByClient"); | |||
| JackGetUUIDRequest req; | |||
| JackUUIDResult res; | |||
| if (req.Read(socket) == 0) { | |||
| fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult); | |||
| res.fResult = 0; | |||
| } | |||
| if (res.Write(socket) < 0) | |||
| jack_error("JackRequest::GetUUIDForClientName write error"); | |||
| jack_error("JackRequest::GetUUIDByClient write error"); | |||
| break; | |||
| } | |||
| @@ -466,11 +482,23 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
| break; | |||
| } | |||
| case JackRequest::kClientHasSessionCallback: { | |||
| jack_log("JackRequest::ClientHasSessionCallback"); | |||
| JackClientHasSessionCallbackRequest req; | |||
| JackResult res; | |||
| if (req.Read(socket) == 0) { | |||
| fServer->GetEngine()->ClientHasSessionCallbackRequest(req.fName, &res.fResult); | |||
| } | |||
| if (res.Write(socket) < 0) | |||
| jack_error("JackRequest::ClientHasSessionCallback write error"); | |||
| break; | |||
| } | |||
| default: | |||
| jack_error("Unknown request %ld", header.fType); | |||
| break; | |||
| } | |||
| return true; | |||
| } | |||
| @@ -511,7 +539,7 @@ bool JackSocketServerChannel::Init() | |||
| bool JackSocketServerChannel::Execute() | |||
| { | |||
| try { | |||
| // Global poll | |||
| if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) { | |||
| jack_error("Engine poll failed err = %s request thread quits...", strerror(errno)); | |||
| @@ -526,22 +554,22 @@ bool JackSocketServerChannel::Execute() | |||
| jack_log("Poll client error err = %s", strerror(errno)); | |||
| ClientKill(fd); | |||
| } else if (fPollTable[i].revents & POLLIN) { | |||
| if (!HandleRequest(fd)) | |||
| if (!HandleRequest(fd)) | |||
| jack_log("Could not handle external client request"); | |||
| } | |||
| } | |||
| // Check the server request socket */ | |||
| if (fPollTable[0].revents & POLLERR) | |||
| if (fPollTable[0].revents & POLLERR) | |||
| jack_error("Error on server request socket err = %s", strerror(errno)); | |||
| if (fPollTable[0].revents & POLLIN) | |||
| if (fPollTable[0].revents & POLLIN) | |||
| ClientCreate(); | |||
| } | |||
| BuildPoolTable(); | |||
| return true; | |||
| } catch (JackQuitException& e) { | |||
| jack_log("JackMachServerChannel::Execute JackQuitException"); | |||
| return false; | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -41,7 +41,7 @@ class JackSocketServerChannel : public JackRunnableInterface | |||
| JackServerSocket fRequestListenSocket; // Socket to create request socket for the client | |||
| JackThread fThread; // Thread to execute the event loop | |||
| JackServer* fServer; | |||
| JackServer* fServer; | |||
| pollfd* fPollTable; | |||
| bool fRebuild; | |||
| std::map<int, std::pair<int, JackClientSocket*> > fSocketTable; | |||
| @@ -61,7 +61,7 @@ class JackSocketServerChannel : public JackRunnableInterface | |||
| int Open(const char* server_name, JackServer* server); // Open the Server/Client connection | |||
| void Close(); // Close the Server/Client connection | |||
| int Start(); | |||
| // JackRunnableInterface interface | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackRequest.h" | |||
| #include "JackConstants.h" | |||
| #include "JackNotification.h" | |||
| #include "JackServerGlobals.h" | |||
| namespace Jack | |||
| { | |||
| @@ -33,6 +34,7 @@ int JackSocketServerNotifyChannel::Open(const char* server_name) | |||
| return -1; | |||
| } else { | |||
| fRequestSocket.SetNonBlocking(true); | |||
| JackServerGlobals::fRTNotificationSocket = fRequestSocket.GetFd(); | |||
| return 0; | |||
| } | |||
| } | |||
| @@ -63,7 +65,7 @@ void JackSocketServerNotifyChannel::NotifyQuit() | |||
| jack_error("Could not write request ref = %d notify = %d", -1, kQUIT); | |||
| } | |||
| } | |||
| } // end of namespace | |||
| @@ -12,7 +12,7 @@ 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 | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -25,6 +25,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include <signal.h> | |||
| #include <dlfcn.h> | |||
| #define UINT32_MAX 4294967295U | |||
| #define DRIVER_HANDLE void* | |||
| #define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) | |||
| #define UnloadDriverModule(handle) dlclose((handle)) | |||
| @@ -26,6 +26,8 @@ | |||
| typedef unsigned long long UInt64; | |||
| typedef pthread_key_t jack_tls_key; | |||
| typedef pthread_t jack_native_thread_t; | |||
| typedef int (*jack_thread_creator_t)(pthread_t*, const pthread_attr_t*, void* (*function)(void*), void* arg); | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net> | |||
| 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 | |||
| @@ -95,14 +95,14 @@ int MTDM::process (size_t len, float *ip, float *op) | |||
| vip = *ip++; | |||
| for (i = 0, F = _freq; i < 5; i++, F++) | |||
| { | |||
| a = 2 * (float) M_PI * (F->p & 65535) / 65536.0; | |||
| a = 2 * (float) M_PI * (F->p & 65535) / 65536.0; | |||
| F->p += F->f; | |||
| c = cosf (a); | |||
| s = -sinf (a); | |||
| c = cosf (a); | |||
| s = -sinf (a); | |||
| vop += F->a * s; | |||
| F->xa += s * vip; | |||
| F->ya += c * vip; | |||
| } | |||
| } | |||
| *op++ = vop; | |||
| if (++_cnt == 16) | |||
| { | |||
| @@ -142,10 +142,10 @@ int MTDM::resolve (void) | |||
| k = (int)(floor (p + 0.5)); | |||
| e = fabs (p - k); | |||
| if (e > _err) _err = e; | |||
| if (e > 0.4) return 1; | |||
| if (e > 0.4) return 1; | |||
| d += m * (k & 7); | |||
| m *= 8; | |||
| } | |||
| } | |||
| _del = 16 * d; | |||
| return 0; | |||
| @@ -158,6 +158,34 @@ 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; | |||
| @@ -182,14 +210,12 @@ int main (int ac, char *av []) | |||
| 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); | |||
| printf ("capture latency = %d\n", | |||
| jack_port_get_latency (jack_port_by_name (jack_handle, "system:capture_1"))); | |||
| printf ("playback_latency = %d\n", | |||
| jack_port_get_latency (jack_port_by_name (jack_handle, "system:playback_1"))); | |||
| t = 1000.0f / jack_get_sample_rate (jack_handle); | |||
| if (jack_activate (jack_handle)) | |||
| @@ -200,16 +226,16 @@ int main (int ac, char *av []) | |||
| while (1) | |||
| { | |||
| #ifdef WIN32 | |||
| Sleep (250); | |||
| #else | |||
| usleep (250000); | |||
| #endif | |||
| #ifdef WIN32 | |||
| Sleep (250); | |||
| #else | |||
| usleep (250000); | |||
| #endif | |||
| if (mtdm.resolve () < 0) printf ("Signal below threshold...\n"); | |||
| else | |||
| else | |||
| { | |||
| if (mtdm.err () > 0.3) | |||
| if (mtdm.err () > 0.3) | |||
| { | |||
| mtdm.invert (); | |||
| mtdm.resolve (); | |||
| @@ -9,7 +9,7 @@ test_programs = { | |||
| #'testSem': ['testSem.cpp'], | |||
| 'jack_test': ['test.cpp'], | |||
| 'jack_cpu': ['cpu.c'], | |||
| 'jack_delay': ['jdelay.cpp'], | |||
| 'jack_iodelay': ['iodelay.cpp'], | |||
| 'jack_multiple_metro' : ['external_metro.cpp'], | |||
| } | |||
| @@ -43,7 +43,7 @@ RSC=rc.exe | |||
| # PROP Ignore_Export_Lib 0 | |||
| # PROP Target_Dir "" | |||
| # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | |||
| # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | |||
| # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c | |||
| # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | |||
| # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | |||
| # ADD BASE RSC /l 0x409 /d "NDEBUG" | |||