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 | Arnold Krille | ||||
| Jan Engelhardt | Jan Engelhardt | ||||
| Adrian Knoth | Adrian Knoth | ||||
| David Garcia Garzon | |||||
| David Garcia Garzon | |||||
| Valerio Pilo | |||||
| --------------------------- | --------------------------- | ||||
| Jackdmp changes log | 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> | 2010-11-05 Stephane Letz <letz@grame.fr> | ||||
| * In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. | * 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> | 2010-11-03 Stephane Letz <letz@grame.fr> | ||||
| @@ -41,7 +41,7 @@ extern "C" | |||||
| { | { | ||||
| #endif | #endif | ||||
| typedef void (*print_function)(const char *); | |||||
| typedef void (*print_function)(const char*); | |||||
| typedef void *(*thread_routine)(void*); | typedef void *(*thread_routine)(void*); | ||||
| EXPORT | EXPORT | ||||
| @@ -53,198 +53,219 @@ extern "C" | |||||
| int *proto_ptr); | int *proto_ptr); | ||||
| EXPORT | EXPORT | ||||
| const char * | |||||
| const char* | |||||
| jack_get_version_string(); | 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_options_t options, | ||||
| jack_status_t *status); | 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_options_t options, | ||||
| jack_status_t *status, ...); | 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); | 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); | 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, | JackProcessCallback process_callback, | ||||
| void *arg); | void *arg); | ||||
| EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status); | EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status); | ||||
| // new | // 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_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, | JackThreadInitCallback thread_init_callback, | ||||
| void *arg); | 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, | JackFreewheelCallback freewheel_callback, | ||||
| void *arg); | void *arg); | ||||
| EXPORT int jack_set_freewheel(jack_client_t* client, int onoff); | 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, | JackBufferSizeCallback bufsize_callback, | ||||
| void *arg); | 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, | JackSampleRateCallback srate_callback, | ||||
| void *arg); | void *arg); | ||||
| EXPORT int jack_set_client_registration_callback (jack_client_t *, | |||||
| EXPORT int jack_set_client_registration_callback(jack_client_t *, | |||||
| JackClientRegistrationCallback | JackClientRegistrationCallback | ||||
| registration_callback, void *arg); | 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 | JackPortRegistrationCallback | ||||
| registration_callback, void *arg); | 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 | JackPortConnectCallback | ||||
| connect_callback, void *arg); | 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 | JackPortRenameCallback | ||||
| rename_callback, void *arg); | 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, | JackGraphOrderCallback graph_callback, | ||||
| void *); | void *); | ||||
| EXPORT int jack_set_xrun_callback (jack_client_t *, | |||||
| EXPORT int jack_set_xrun_callback(jack_client_t *, | |||||
| JackXRunCallback xrun_callback, void *arg); | 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 flags, | ||||
| unsigned long buffer_size); | 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); | 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); | 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_name_size(void); | ||||
| EXPORT int jack_port_type_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); | 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); | 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_time_t jack_get_time(); | ||||
| EXPORT jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t 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_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, | JackSyncCallback sync_callback, | ||||
| void *arg); | 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); | 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, | int conditional, | ||||
| JackTimebaseCallback timebase_callback, | JackTimebaseCallback timebase_callback, | ||||
| void *arg); | void *arg); | ||||
| EXPORT int jack_transport_locate (jack_client_t *client, | |||||
| EXPORT int jack_transport_locate(jack_client_t *client, | |||||
| jack_nframes_t frame); | 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); | 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); | 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); | 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); | 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 priority, | ||||
| int realtime, // boolean | int realtime, // boolean | ||||
| thread_routine routine, | thread_routine routine, | ||||
| void *arg); | 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 | #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 | #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); | 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); | 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_options_t options, | ||||
| jack_status_t *status, ...); | 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_options_t options, | ||||
| jack_status_t *status, va_list ap); | 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); | jack_intclient_t intclient); | ||||
| EXPORT void jack_free(void* ptr); | 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 | #ifdef __cplusplus | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -256,7 +277,7 @@ static inline bool CheckPort(jack_port_id_t port_index) | |||||
| static inline bool CheckBufferSize(jack_nframes_t buffer_size) | 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() | 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; | 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; | 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) | EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* port) | ||||
| { | { | ||||
| #ifdef __CLIENTDEBUG__ | #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; | uintptr_t port_aux = (uintptr_t)port; | ||||
| jack_port_id_t myport = (jack_port_id_t)port_aux; | jack_port_id_t myport = (jack_port_id_t)port_aux; | ||||
| if (client == NULL) { | 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; | return -1; | ||||
| } else if (!CheckPort(myport)) { | } 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; | return -1; | ||||
| } else { | } else { | ||||
| WaitGraphChange(); | 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"); | jack_error("jack_recompute_total_latencies called with a NULL client"); | ||||
| return -1; | return -1; | ||||
| } else { | } 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) | EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback init_callback, void *arg) | ||||
| { | { | ||||
| #ifdef __CLIENTDEBUG__ | #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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_client_thread_id"); | 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; | JackClient* client = (JackClient*)ext_client; | ||||
| if (client == NULL) { | if (client == NULL) { | ||||
| jack_error("jack_client_thread_id called with a NULL client"); | jack_error("jack_client_thread_id called with a NULL client"); | ||||
| return (pthread_t)NULL; | |||||
| return (jack_native_thread_t)NULL; | |||||
| } else { | } else { | ||||
| return client->GetThreadID(); | return client->GetThreadID(); | ||||
| } | } | ||||
| @@ -1439,6 +1506,26 @@ EXPORT int jack_port_type_size(void) | |||||
| return JACK_PORT_TYPE_SIZE; | 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 | // transport.h | ||||
| EXPORT int jack_release_timebase(jack_client_t* ext_client) | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_set_transport_info"); | JackGlobals::CheckContext("jack_set_transport_info"); | ||||
| #endif | |||||
| #endif | |||||
| jack_error("jack_set_transport_info: deprecated"); | jack_error("jack_set_transport_info: deprecated"); | ||||
| if (tinfo) | if (tinfo) | ||||
| memset(tinfo, 0, sizeof(jack_transport_info_t)); | 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(); | JackEngineControl* control = GetEngineControl(); | ||||
| return (control ? JackThread::AcquireRealTimeImp(thread, priority, GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint) : -1); | return (control ? JackThread::AcquireRealTimeImp(thread, priority, GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint) : -1); | ||||
| } | } | ||||
| EXPORT int jack_client_create_thread(jack_client_t* client, | EXPORT int jack_client_create_thread(jack_client_t* client, | ||||
| pthread_t *thread, | |||||
| jack_native_thread_t *thread, | |||||
| int priority, | int priority, | ||||
| int realtime, /* boolean */ | int realtime, /* boolean */ | ||||
| thread_routine routine, | thread_routine routine, | ||||
| @@ -1692,28 +1779,28 @@ EXPORT int jack_client_create_thread(jack_client_t* client, | |||||
| { | { | ||||
| #ifdef __CLIENTDEBUG__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_client_create_thread"); | JackGlobals::CheckContext("jack_client_create_thread"); | ||||
| #endif | |||||
| #endif | |||||
| return JackThread::StartImp(thread, priority, realtime, routine, arg); | 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); | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_client_stop_thread"); | JackGlobals::CheckContext("jack_client_stop_thread"); | ||||
| #endif | |||||
| #endif | |||||
| return JackThread::StopImp(thread); | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_client_kill_thread"); | JackGlobals::CheckContext("jack_client_kill_thread"); | ||||
| #endif | |||||
| #endif | |||||
| return JackThread::KillImp(thread); | return JackThread::KillImp(thread); | ||||
| } | } | ||||
| @@ -1725,15 +1812,15 @@ EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc) | |||||
| #endif | #endif | ||||
| // intclient.h | // 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"); | jack_error("jack_internal_client_new: deprecated"); | ||||
| return -1; | 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"); | 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_list ap; | ||||
| va_start(ap, status); | va_start(ap, status); | ||||
| @@ -1847,7 +1934,7 @@ jack_get_version( | |||||
| } | } | ||||
| EXPORT | EXPORT | ||||
| const char * | |||||
| const char* | |||||
| jack_get_version_string() | jack_get_version_string() | ||||
| { | { | ||||
| return VERSION; | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_session_notify"); | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_session_reply"); | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_get_uuid_for_client_name"); | 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_get_client_name_by_uuid"); | 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"); | jack_error("jack_get_client_name_by_uuid called with a NULL client"); | ||||
| return NULL; | return NULL; | ||||
| } else { | } 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__ | #ifdef __CLIENTDEBUG__ | ||||
| JackGlobals::CheckContext("jack_reserve_client_name"); | 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"); | jack_error("jack_reserve_client_name called with a NULL client"); | ||||
| return -1; | return -1; | ||||
| } else { | } 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) | if (!cmds) | ||||
| return; | return; | ||||
| int i=0; | |||||
| while(1) { | |||||
| int i = 0; | |||||
| while (1) { | |||||
| if (cmds[i].client_name) | if (cmds[i].client_name) | ||||
| free ((char *)cmds[i].client_name); | free ((char *)cmds[i].client_name); | ||||
| if (cmds[i].command) | if (cmds[i].command) | ||||
| @@ -1985,3 +2072,18 @@ EXPORT void jack_session_commands_free( jack_session_command_t *cmds ) | |||||
| free(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; | jack_port_id_t port_index; | ||||
| char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | ||||
| char alias[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; | int i; | ||||
| jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); | 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 = fGraphManager->GetPort(port_index); | ||||
| port->SetAlias(alias); | port->SetAlias(alias); | ||||
| port->SetLatency(fEngineControl->fBufferSize + fCaptureLatency); | |||||
| range.min = range.max = fEngineControl->fBufferSize + fCaptureLatency; | |||||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||||
| fCapturePortList[i] = port_index; | fCapturePortList[i] = port_index; | ||||
| jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", 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 = fGraphManager->GetPort(port_index); | ||||
| port->SetAlias(alias); | port->SetAlias(alias); | ||||
| // Add more latency if "async" mode is used... | // 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; | fPlaybackPortList[i] = port_index; | ||||
| jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); | jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); | ||||
| @@ -143,7 +146,8 @@ int JackAudioDriver::Attach() | |||||
| } else { | } else { | ||||
| port = fGraphManager->GetPort(port_index); | port = fGraphManager->GetPort(port_index); | ||||
| port->SetAlias(alias); | port->SetAlias(alias); | ||||
| port->SetLatency(fEngineControl->fBufferSize); | |||||
| range.min = range.max = fEngineControl->fBufferSize; | |||||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||||
| fMonitorPortList[i] = port_index; | fMonitorPortList[i] = port_index; | ||||
| } | } | ||||
| } | } | ||||
| @@ -188,13 +192,13 @@ int JackAudioDriver::ProcessNull() | |||||
| { | { | ||||
| // Keep begin cycle time | // Keep begin cycle time | ||||
| JackDriver::CycleTakeBeginTime(); | JackDriver::CycleTakeBeginTime(); | ||||
| if (fEngineControl->fSyncMode) { | if (fEngineControl->fSyncMode) { | ||||
| ProcessGraphSync(); | ProcessGraphSync(); | ||||
| } else { | } else { | ||||
| ProcessGraphAsync(); | ProcessGraphAsync(); | ||||
| } | } | ||||
| // Keep end cycle time | // Keep end cycle time | ||||
| JackDriver::CycleTakeEndTime(); | JackDriver::CycleTakeEndTime(); | ||||
| WaitUntilNextCycle(); | WaitUntilNextCycle(); | ||||
| @@ -214,23 +218,24 @@ synchronize to the end of client graph execution. | |||||
| int JackAudioDriver::ProcessAsync() | int JackAudioDriver::ProcessAsync() | ||||
| { | { | ||||
| // Read input buffers for the current cycle | // Read input buffers for the current cycle | ||||
| if (Read() < 0) { | |||||
| if (Read() < 0) { | |||||
| jack_error("JackAudioDriver::ProcessAsync: read error, stopping..."); | jack_error("JackAudioDriver::ProcessAsync: read error, stopping..."); | ||||
| return -1; | |||||
| return -1; | |||||
| } | } | ||||
| // Write output buffers from the previous cycle | // Write output buffers from the previous cycle | ||||
| if (Write() < 0) { | if (Write() < 0) { | ||||
| jack_error("JackAudioDriver::ProcessAsync: write error, stopping..."); | jack_error("JackAudioDriver::ProcessAsync: write error, stopping..."); | ||||
| return -1; | |||||
| return -1; | |||||
| } | } | ||||
| // Process graph | |||||
| if (fIsMaster) { | if (fIsMaster) { | ||||
| ProcessGraphAsync(); | ProcessGraphAsync(); | ||||
| } else { | } else { | ||||
| fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | ||||
| } | } | ||||
| // Keep end cycle time | // Keep end cycle time | ||||
| JackDriver::CycleTakeEndTime(); | JackDriver::CycleTakeEndTime(); | ||||
| return 0; | return 0; | ||||
| @@ -238,29 +243,38 @@ int JackAudioDriver::ProcessAsync() | |||||
| /* | /* | ||||
| The driver SYNC mode: the server does synchronize to the end of client graph execution, | 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() | int JackAudioDriver::ProcessSync() | ||||
| { | { | ||||
| // Read input buffers for the current cycle | // Read input buffers for the current cycle | ||||
| if (Read() < 0) { | |||||
| if (Read() < 0) { | |||||
| jack_error("JackAudioDriver::ProcessSync: read error, stopping..."); | jack_error("JackAudioDriver::ProcessSync: read error, stopping..."); | ||||
| return -1; | |||||
| return -1; | |||||
| } | } | ||||
| // Process graph | |||||
| if (fIsMaster) { | if (fIsMaster) { | ||||
| ProcessGraphSync(); | |||||
| if (ProcessGraphSync() < 0) { | |||||
| jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); | |||||
| goto end; | |||||
| } | |||||
| } else { | } 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 | // Write output buffers from the current cycle | ||||
| if (Write() < 0) { | if (Write() < 0) { | ||||
| jack_error("JackAudioDriver::ProcessSync: write error, stopping..."); | jack_error("JackAudioDriver::ProcessSync: write error, stopping..."); | ||||
| return -1; | |||||
| return -1; | |||||
| } | } | ||||
| end: | |||||
| // Keep end cycle time | // Keep end cycle time | ||||
| JackDriver::CycleTakeEndTime(); | JackDriver::CycleTakeEndTime(); | ||||
| return 0; | return 0; | ||||
| @@ -269,25 +283,34 @@ int JackAudioDriver::ProcessSync() | |||||
| void JackAudioDriver::ProcessGraphAsync() | void JackAudioDriver::ProcessGraphAsync() | ||||
| { | { | ||||
| // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | // 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"); | jack_error("JackAudioDriver::ProcessGraphAsync: Process error"); | ||||
| fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | ||||
| if (ProcessSlaves() < 0) | if (ProcessSlaves() < 0) | ||||
| jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error"); | 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 | // 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); | fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | ||||
| if (ProcessSlaves() < 0) | |||||
| if (ProcessSlaves() < 0) { | |||||
| jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!"); | 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!!"); | jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!"); | ||||
| res = -1; | |||||
| } | |||||
| } else { // Graph not finished: do not activate it | } else { // Graph not finished: do not activate it | ||||
| jack_error("JackAudioDriver::ProcessGraphSync: Process error"); | jack_error("JackAudioDriver::ProcessGraphSync: Process error"); | ||||
| res = -1; | |||||
| } | } | ||||
| return res; | |||||
| } | } | ||||
| void JackAudioDriver::WaitUntilNextCycle() | 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); | 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 | } // end of namespace | ||||
| @@ -36,12 +36,12 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||||
| protected: | protected: | ||||
| void ProcessGraphAsync(); | void ProcessGraphAsync(); | ||||
| void ProcessGraphSync(); | |||||
| int ProcessGraphSync(); | |||||
| void WaitUntilNextCycle(); | void WaitUntilNextCycle(); | ||||
| virtual int ProcessAsync(); | virtual int ProcessAsync(); | ||||
| virtual int ProcessSync(); | virtual int ProcessSync(); | ||||
| int fCaptureChannels; | int fCaptureChannels; | ||||
| int fPlaybackChannels; | 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* GetOutputBuffer(int port_index); | ||||
| jack_default_audio_sample_t* GetMonitorBuffer(int port_index); | jack_default_audio_sample_t* GetMonitorBuffer(int port_index); | ||||
| void HandleLatencyCallback(int status); | |||||
| public: | public: | ||||
| JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | 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, | const char* playback_driver_name, | ||||
| jack_nframes_t capture_latency, | jack_nframes_t capture_latency, | ||||
| jack_nframes_t playback_latency); | jack_nframes_t playback_latency); | ||||
| virtual int Open(bool capturing, | virtual int Open(bool capturing, | ||||
| bool playing, | bool playing, | ||||
| int inchannels, | int inchannels, | ||||
| @@ -83,18 +85,20 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||||
| const char* playback_driver_name, | const char* playback_driver_name, | ||||
| jack_nframes_t capture_latency, | jack_nframes_t capture_latency, | ||||
| jack_nframes_t playback_latency); | jack_nframes_t playback_latency); | ||||
| virtual int Process(); | virtual int Process(); | ||||
| virtual int ProcessNull(); | virtual int ProcessNull(); | ||||
| virtual int Attach(); | virtual int Attach(); | ||||
| virtual int Detach(); | virtual int Detach(); | ||||
| virtual int Write(); | virtual int Write(); | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | virtual int SetBufferSize(jack_nframes_t buffer_size); | ||||
| virtual int SetSampleRate(jack_nframes_t sample_rate); | 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 | } // 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 "JackPortType.h" | ||||
| #include <string.h> | #include <string.h> | ||||
| #if defined (__APPLE__) | #if defined (__APPLE__) | ||||
| @@ -46,7 +49,7 @@ static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_ | |||||
| frames = frames % 4; | frames = frames % 4; | ||||
| while (frames_group > 0) { | 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)); | __m128 vec = _mm_add_ps(_mm_load_ps(mixbuffer), _mm_load_ps(buffer)); | ||||
| _mm_store_ps(mixbuffer, vec); | _mm_store_ps(mixbuffer, vec); | ||||
| @@ -97,7 +100,7 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun | |||||
| void* buffer; | void* buffer; | ||||
| // Copy first buffer | // Copy first buffer | ||||
| #if defined (__SSE__) && !defined (__sun__) | |||||
| #if defined (__SSE__) && !defined (__sun__) | |||||
| jack_nframes_t frames_group = nframes / 4; | jack_nframes_t frames_group = nframes / 4; | ||||
| jack_nframes_t remaining_frames = 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 = | const JackPortType gAudioPortType = | ||||
| { | |||||
| JACK_DEFAULT_AUDIO_TYPE, | |||||
| AudioBufferInit, | |||||
| AudioBufferMixdown | |||||
| }; | |||||
| { | |||||
| JACK_DEFAULT_AUDIO_TYPE, | |||||
| AudioBufferSize, | |||||
| AudioBufferInit, | |||||
| AudioBufferMixdown | |||||
| }; | |||||
| } // namespace Jack | } // namespace Jack | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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__ | #ifndef __JackChannel__ | ||||
| #define __JackChannel__ | #define __JackChannel__ | ||||
| #include "types.h" | |||||
| #include "session.h" | #include "session.h" | ||||
| namespace Jack | namespace Jack | ||||
| @@ -108,43 +107,39 @@ class JackClientChannelInterface | |||||
| {} | {} | ||||
| virtual void SetFreewheel(int onoff, int* result) | virtual void SetFreewheel(int onoff, int* result) | ||||
| {} | {} | ||||
| virtual void ComputeTotalLatencies(int* result) | |||||
| {} | |||||
| virtual void ReleaseTimebase(int refnum, int* result) | virtual void ReleaseTimebase(int refnum, int* result) | ||||
| {} | {} | ||||
| virtual void SetTimebaseCallback(int refnum, int conditional, 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 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 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 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 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() | 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| #include "JackClient.h" | |||||
| #include "JackSystemDeps.h" | |||||
| #include "JackGraphManager.h" | #include "JackGraphManager.h" | ||||
| #include "JackClientControl.h" | #include "JackClientControl.h" | ||||
| #include "JackEngineControl.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 "driver_interface.h" | ||||
| #include "JackLibGlobals.h" | #include "JackLibGlobals.h" | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <string> | #include <string> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| @@ -60,6 +61,9 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||||
| fTimebase = NULL; | fTimebase = NULL; | ||||
| fSync = NULL; | fSync = NULL; | ||||
| fThreadFun = NULL; | fThreadFun = NULL; | ||||
| fSession = NULL; | |||||
| fLatency = NULL; | |||||
| fProcessArg = NULL; | fProcessArg = NULL; | ||||
| fGraphOrderArg = NULL; | fGraphOrderArg = NULL; | ||||
| fXrunArg = NULL; | fXrunArg = NULL; | ||||
| @@ -75,6 +79,8 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||||
| fSyncArg = NULL; | fSyncArg = NULL; | ||||
| fTimebaseArg = NULL; | fTimebaseArg = NULL; | ||||
| fThreadFunArg = NULL; | fThreadFunArg = NULL; | ||||
| fSessionArg = NULL; | |||||
| fLatencyArg = NULL; | |||||
| } | } | ||||
| JackClient::~JackClient() | JackClient::~JackClient() | ||||
| @@ -84,17 +90,17 @@ int JackClient::Close() | |||||
| { | { | ||||
| jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); | jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); | ||||
| int result = 0; | int result = 0; | ||||
| Deactivate(); | Deactivate(); | ||||
| fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing | fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing | ||||
| // Request close only if server is still running | // Request close only if server is still running | ||||
| if (JackGlobals::fServerRunning) { | if (JackGlobals::fServerRunning) { | ||||
| fChannel->ClientClose(GetClientControl()->fRefNum, &result); | fChannel->ClientClose(GetClientControl()->fRefNum, &result); | ||||
| } else { | } else { | ||||
| jack_log("JackClient::Close server is shutdown"); | |||||
| jack_log("JackClient::Close server is shutdown"); | |||||
| } | } | ||||
| fChannel->Close(); | fChannel->Close(); | ||||
| fSynchroTable[GetClientControl()->fRefNum].Disconnect(); | fSynchroTable[GetClientControl()->fRefNum].Disconnect(); | ||||
| JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; | JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; | ||||
| @@ -106,7 +112,7 @@ bool JackClient::IsActive() | |||||
| return (GetClientControl()) ? GetClientControl()->fActive : false; | return (GetClientControl()) ? GetClientControl()->fActive : false; | ||||
| } | } | ||||
| pthread_t JackClient::GetThreadID() | |||||
| jack_native_thread_t JackClient::GetThreadID() | |||||
| { | { | ||||
| return fThread.GetThreadID(); | return fThread.GetThreadID(); | ||||
| } | } | ||||
| @@ -156,7 +162,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| case kActivateClient: | case kActivateClient: | ||||
| jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); | jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); | ||||
| Init(); | |||||
| InitAux(); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -188,7 +194,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| res = fBufferSize(value1, fBufferSizeArg); | res = fBufferSize(value1, fBufferSizeArg); | ||||
| } | } | ||||
| break; | break; | ||||
| case kSampleRateCallback: | case kSampleRateCallback: | ||||
| jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); | jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); | ||||
| if (fSampleRate) { | if (fSampleRate) { | ||||
| @@ -219,7 +225,9 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| fFreewheel(0, fFreewheelArg); | fFreewheel(0, fFreewheelArg); | ||||
| } | } | ||||
| if (GetEngineControl()->fRealTime) { | if (GetEngineControl()->fRealTime) { | ||||
| fThread.AcquireRealTime(); | |||||
| if (fThread.AcquireRealTime() < 0) { | |||||
| jack_error("JackClient::AcquireRealTime error"); | |||||
| } | |||||
| } | } | ||||
| break; | break; | ||||
| @@ -250,7 +258,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| fPortConnect(value1, value2, 0, fPortConnectArg); | fPortConnect(value1, value2, 0, fPortConnectArg); | ||||
| } | } | ||||
| break; | break; | ||||
| case kPortRenameCallback: | case kPortRenameCallback: | ||||
| jack_log("JackClient::kPortRenameCallback port = %ld", value1); | jack_log("JackClient::kPortRenameCallback port = %ld", value1); | ||||
| if (fPortRename) { | if (fPortRename) { | ||||
| @@ -264,7 +272,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| res = fXrun(fXrunArg); | res = fXrun(fXrunArg); | ||||
| } | } | ||||
| break; | break; | ||||
| case kShutDownCallback: | case kShutDownCallback: | ||||
| jack_log("JackClient::kShutDownCallback"); | jack_log("JackClient::kShutDownCallback"); | ||||
| if (fInfoShutdown) { | if (fInfoShutdown) { | ||||
| @@ -289,15 +297,109 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| res = (fImmediateSessionReply) ? 1 : 2; | res = (fImmediateSessionReply) ? 1 : 2; | ||||
| } | } | ||||
| break; | break; | ||||
| case kLatencyCallback: | |||||
| res = HandleLatencyCallback(value1); | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| return res; | 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 | \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() | int JackClient::Activate() | ||||
| { | { | ||||
| @@ -310,13 +412,13 @@ int JackClient::Activate() | |||||
| if (StartThread() < 0) | if (StartThread() < 0) | ||||
| return -1; | 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. | to be delivered by the server, the client wants to receive it. | ||||
| */ | */ | ||||
| GetClientControl()->fActive = true; | GetClientControl()->fActive = true; | ||||
| // Transport related callback become "active" | // Transport related callback become "active" | ||||
| GetClientControl()->fTransportSync = true; | GetClientControl()->fTransportSync = true; | ||||
| GetClientControl()->fTransportTimebase = true; | GetClientControl()->fTransportTimebase = true; | ||||
| @@ -337,18 +439,18 @@ int JackClient::Deactivate() | |||||
| return 0; | return 0; | ||||
| GetClientControl()->fActive = false; | GetClientControl()->fActive = false; | ||||
| // Transport related callback become "unactive" | // Transport related callback become "unactive" | ||||
| GetClientControl()->fTransportSync = false; | GetClientControl()->fTransportSync = false; | ||||
| GetClientControl()->fTransportTimebase = false; | GetClientControl()->fTransportTimebase = false; | ||||
| // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate | // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate | ||||
| int result = -1; | int result = -1; | ||||
| fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | ||||
| jack_log("JackClient::Deactivate res = %ld", result); | jack_log("JackClient::Deactivate res = %ld", result); | ||||
| // RT thread is stopped only when needed... | // RT thread is stopped only when needed... | ||||
| if (IsRealTime()) | |||||
| if (IsRealTime()) | |||||
| fThread.Kill(); | fThread.Kill(); | ||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -357,15 +459,48 @@ int JackClient::Deactivate() | |||||
| // RT thread management | // 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. | \brief Called once when the thread starts. | ||||
| */ | */ | ||||
| bool JackClient::Init() | 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; | return true; | ||||
| } | } | ||||
| @@ -384,12 +519,6 @@ int JackClient::StartThread() | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| if (GetEngineControl()->fRealTime) { | |||||
| if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { | |||||
| jack_error("AcquireRealTime error"); | |||||
| } | |||||
| } | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -399,21 +528,15 @@ int JackClient::StartThread() | |||||
| bool JackClient::Execute() | 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 | // Execute a dummy cycle to be sure thread has the correct properties | ||||
| DummyCycle(); | DummyCycle(); | ||||
| if (fThreadFun) { | if (fThreadFun) { | ||||
| fThreadFun(fThreadFunArg); | fThreadFun(fThreadFunArg); | ||||
| } else { | } else { | ||||
| ExecuteThread(); | ExecuteThread(); | ||||
| } | } | ||||
| return false; | |||||
| return false; | |||||
| } | } | ||||
| void JackClient::DummyCycle() | void JackClient::DummyCycle() | ||||
| @@ -424,15 +547,15 @@ void JackClient::DummyCycle() | |||||
| inline void JackClient::ExecuteThread() | inline void JackClient::ExecuteThread() | ||||
| { | { | ||||
| while (true) { | |||||
| while (true) { | |||||
| CycleWaitAux(); | CycleWaitAux(); | ||||
| CycleSignalAux(CallProcessCallback()); | |||||
| } | |||||
| CycleSignalAux(CallProcessCallback()); | |||||
| } | |||||
| } | } | ||||
| inline jack_nframes_t JackClient::CycleWaitAux() | inline jack_nframes_t JackClient::CycleWaitAux() | ||||
| { | { | ||||
| if (!WaitSync()) | |||||
| if (!WaitSync()) | |||||
| Error(); // Terminates the thread | Error(); // Terminates the thread | ||||
| CallSyncCallbackAux(); | CallSyncCallbackAux(); | ||||
| return GetEngineControl()->fBufferSize; | return GetEngineControl()->fBufferSize; | ||||
| @@ -443,7 +566,7 @@ inline void JackClient::CycleSignalAux(int status) | |||||
| if (status == 0) | if (status == 0) | ||||
| CallTimebaseCallbackAux(); | CallTimebaseCallbackAux(); | ||||
| SignalSync(); | SignalSync(); | ||||
| if (status != 0) | |||||
| if (status != 0) | |||||
| End(); // Terminates the thread | End(); // Terminates the thread | ||||
| } | } | ||||
| @@ -531,7 +654,7 @@ int JackClient::PortRegister(const char* port_name, const char* port_type, unsig | |||||
| int result = -1; | int result = -1; | ||||
| jack_port_id_t port_index = NO_PORT; | jack_port_id_t port_index = NO_PORT; | ||||
| fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); | fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); | ||||
| if (result == 0) { | 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); | 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); | fPortList.push_back(port_index); | ||||
| @@ -612,6 +735,13 @@ int JackClient::SetFreeWheel(int onoff) | |||||
| return result; | return result; | ||||
| } | } | ||||
| int JackClient::ComputeTotalLatencies() | |||||
| { | |||||
| int result = -1; | |||||
| fChannel->ComputeTotalLatencies(&result); | |||||
| return result; | |||||
| } | |||||
| /* | /* | ||||
| ShutDown is called: | ShutDown is called: | ||||
| - from the RT thread when Execute method fails | - from the RT thread when Execute method fails | ||||
| @@ -621,9 +751,9 @@ ShutDown is called: | |||||
| void JackClient::ShutDown() | void JackClient::ShutDown() | ||||
| { | { | ||||
| jack_log("ShutDown"); | |||||
| jack_log("JackClient::ShutDown"); | |||||
| JackGlobals::fServerRunning = false; | JackGlobals::fServerRunning = false; | ||||
| if (fInfoShutdown) { | if (fInfoShutdown) { | ||||
| fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); | fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); | ||||
| fInfoShutdown = NULL; | fInfoShutdown = NULL; | ||||
| @@ -641,18 +771,18 @@ inline int JackClient::ActivateAux() | |||||
| { | { | ||||
| // If activated without RT thread... | // If activated without RT thread... | ||||
| if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { | if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { | ||||
| jack_log("ActivateAux"); | |||||
| jack_log("JackClient::ActivateAux"); | |||||
| // RT thread is started | // RT thread is started | ||||
| if (StartThread() < 0) | if (StartThread() < 0) | ||||
| return -1; | return -1; | ||||
| int result = -1; | int result = -1; | ||||
| GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); | GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); | ||||
| fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); | fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); | ||||
| return result; | return result; | ||||
| } else { | } else { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -683,7 +813,7 @@ int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timeba | |||||
| { | { | ||||
| int result = -1; | int result = -1; | ||||
| fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | ||||
| if (result == 0) { | if (result == 0) { | ||||
| GetClientControl()->fTransportTimebase = true; | GetClientControl()->fTransportTimebase = true; | ||||
| fTimebase = timebase_callback; | fTimebase = timebase_callback; | ||||
| @@ -709,14 +839,14 @@ void JackClient::TransportLocate(jack_nframes_t frame) | |||||
| jack_position_t pos; | jack_position_t pos; | ||||
| pos.frame = frame; | pos.frame = frame; | ||||
| pos.valid = (jack_position_bits_t)0; | 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); | GetEngineControl()->fTransport.RequestNewPos(&pos); | ||||
| } | } | ||||
| int JackClient::TransportReposition(jack_position_t* pos) | int JackClient::TransportReposition(jack_position_t* pos) | ||||
| { | { | ||||
| jack_position_t tmp = *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) { | if (tmp.valid & ~JACK_POSITION_MASK) { | ||||
| return EINVAL; | return EINVAL; | ||||
| } else { | } else { | ||||
| @@ -758,11 +888,11 @@ void JackClient::CallSyncCallback() | |||||
| inline void JackClient::CallSyncCallbackAux() | inline void JackClient::CallSyncCallbackAux() | ||||
| { | { | ||||
| if (GetClientControl()->fTransportSync) { | if (GetClientControl()->fTransportSync) { | ||||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | JackTransportEngine& transport = GetEngineControl()->fTransport; | ||||
| jack_position_t* cur_pos = transport.ReadCurrentState(); | jack_position_t* cur_pos = transport.ReadCurrentState(); | ||||
| jack_transport_state_t transport_state = transport.GetState(); | jack_transport_state_t transport_state = transport.GetState(); | ||||
| if (fSync != NULL) { | if (fSync != NULL) { | ||||
| if (fSync(transport_state, cur_pos, fSyncArg)) { | if (fSync(transport_state, cur_pos, fSyncArg)) { | ||||
| GetClientControl()->fTransportState = JackTransportRolling; | GetClientControl()->fTransportState = JackTransportRolling; | ||||
| @@ -785,21 +915,21 @@ inline void JackClient::CallTimebaseCallbackAux() | |||||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | JackTransportEngine& transport = GetEngineControl()->fTransport; | ||||
| int master; | int master; | ||||
| bool unused; | bool unused; | ||||
| transport.GetTimebaseMaster(master, unused); | transport.GetTimebaseMaster(master, unused); | ||||
| if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... | if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... | ||||
| jack_transport_state_t transport_state = transport.GetState(); | jack_transport_state_t transport_state = transport.GetState(); | ||||
| jack_position_t* cur_pos = transport.WriteNextStateStart(1); | jack_position_t* cur_pos = transport.WriteNextStateStart(1); | ||||
| if (GetClientControl()->fTransportTimebase) { | 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) { | } else if (transport_state == JackTransportRolling) { | ||||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); | fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); | ||||
| } | |||||
| } | |||||
| transport.WriteNextStateStop(1); | transport.WriteNextStateStop(1); | ||||
| } | } | ||||
| } | } | ||||
| @@ -817,7 +947,7 @@ void JackClient::OnShutdown(JackShutdownCallback callback, void *arg) | |||||
| fShutdown = callback; | fShutdown = callback; | ||||
| } | } | ||||
| } | } | ||||
| void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) | void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) | ||||
| { | { | ||||
| if (IsActive()) { | if (IsActive()) { | ||||
| @@ -873,8 +1003,6 @@ int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||||
| int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) | int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) | ||||
| { | { | ||||
| jack_log("SetGraphOrderCallback "); | |||||
| if (IsActive()) { | if (IsActive()) { | ||||
| jack_error("You cannot set callbacks on an active client"); | jack_error("You cannot set callbacks on an active client"); | ||||
| return -1; | return -1; | ||||
| @@ -908,8 +1036,8 @@ int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg | |||||
| GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); | GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); | ||||
| fSampleRateArg = arg; | fSampleRateArg = arg; | ||||
| fSampleRate = callback; | fSampleRate = callback; | ||||
| // Now invoke it | |||||
| if (callback) | |||||
| // Now invoke it | |||||
| if (callback) | |||||
| callback(GetEngineControl()->fSampleRate, arg); | callback(GetEngineControl()->fSampleRate, arg); | ||||
| return 0; | 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 | // Internal clients | ||||
| //------------------ | //------------------ | ||||
| @@ -1072,65 +1213,64 @@ void JackClient::InternalClientUnload(int ref, jack_status_t* status) | |||||
| // Session API | // 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; | return res; | ||||
| } | } | ||||
| int JackClient::SessionReply( jack_session_event_t *ev ) | |||||
| int JackClient::SessionReply(jack_session_event_t* ev) | |||||
| { | { | ||||
| if (ev->command_line) { | if (ev->command_line) { | ||||
| strncpy( GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand) ); | |||||
| strncpy(GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand)); | |||||
| } else { | } else { | ||||
| GetClientControl()->fSessionCommand[0] = '\0'; | GetClientControl()->fSessionCommand[0] = '\0'; | ||||
| } | } | ||||
| GetClientControl()->fSessionFlags = ev->flags; | GetClientControl()->fSessionFlags = ev->flags; | ||||
| jack_log( "JackClient::SessionReply... we are here" ); | |||||
| jack_log("JackClient::SessionReply... we are here"); | |||||
| if (fChannel->IsChannelThread()) { | if (fChannel->IsChannelThread()) { | ||||
| jack_log( "JackClient::SessionReply... in callback reply" ); | |||||
| jack_log( "JackClient::SessionReply... in callback reply"); | |||||
| fImmediateSessionReply = true; | fImmediateSessionReply = true; | ||||
| return 0; | 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* JackClient::GetUUIDForClientName(const char* client_name) | ||||
| { | { | ||||
| char uuid_res[JACK_UUID_SIZE]; | char uuid_res[JACK_UUID_SIZE]; | ||||
| int result = -1; | 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]; | char name_res[JACK_CLIENT_NAME_SIZE + 1]; | ||||
| int result = -1; | int result = -1; | ||||
| fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result); | 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; | int result = -1; | ||||
| fChannel->ReserveClientName( GetClientControl()->fRefNum, name, uuid, &result); | |||||
| fChannel->ClientHasSessionCallback(client_name, &result); | |||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 "JackSynchro.h" | ||||
| #include "JackPlatformPlug.h" | #include "JackPlatformPlug.h" | ||||
| #include "JackChannel.h" | #include "JackChannel.h" | ||||
| #include "types.h" | |||||
| #include "session.h" | #include "session.h" | ||||
| #include "varargs.h" | #include "varargs.h" | ||||
| #include <list> | #include <list> | ||||
| @@ -68,6 +67,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||||
| JackSyncCallback fSync; | JackSyncCallback fSync; | ||||
| JackThreadCallback fThreadFun; | JackThreadCallback fThreadFun; | ||||
| JackSessionCallback fSession; | JackSessionCallback fSession; | ||||
| JackLatencyCallback fLatency; | |||||
| void* fProcessArg; | void* fProcessArg; | ||||
| void* fGraphOrderArg; | void* fGraphOrderArg; | ||||
| @@ -86,6 +86,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||||
| void* fSyncArg; | void* fSyncArg; | ||||
| void* fThreadFunArg; | void* fThreadFunArg; | ||||
| void* fSessionArg; | void* fSessionArg; | ||||
| void* fLatencyArg; | |||||
| char fServerName[64]; | char fServerName[64]; | ||||
| JackThread fThread; /*! Thread to execute the Process function */ | 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; | std::list<jack_port_id_t> fPortList; | ||||
| bool fImmediateSessionReply; | bool fImmediateSessionReply; | ||||
| int StartThread(); | int StartThread(); | ||||
| void SetupDriverSync(bool freewheel); | void SetupDriverSync(bool freewheel); | ||||
| bool IsActive(); | bool IsActive(); | ||||
| void CallSyncCallback(); | void CallSyncCallback(); | ||||
| void CallTimebaseCallback(); | void CallTimebaseCallback(); | ||||
| virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value); | virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value); | ||||
| inline void DummyCycle(); | inline void DummyCycle(); | ||||
| @@ -116,7 +117,10 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||||
| inline void CallSyncCallbackAux(); | inline void CallSyncCallbackAux(); | ||||
| inline void CallTimebaseCallbackAux(); | inline void CallTimebaseCallbackAux(); | ||||
| inline int ActivateAux(); | inline int ActivateAux(); | ||||
| inline void InitAux(); | |||||
| int HandleLatencyCallback(int status); | |||||
| public: | public: | ||||
| JackClient(); | JackClient(); | ||||
| @@ -138,8 +142,9 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||||
| // Context | // Context | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | virtual int SetBufferSize(jack_nframes_t buffer_size); | ||||
| virtual int SetFreeWheel(int onoff); | virtual int SetFreeWheel(int onoff); | ||||
| virtual int ComputeTotalLatencies(); | |||||
| virtual void ShutDown(); | virtual void ShutDown(); | ||||
| virtual pthread_t GetThreadID(); | |||||
| virtual jack_native_thread_t GetThreadID(); | |||||
| // Port management | // Port management | ||||
| virtual int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); | 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 SetPortConnectCallback(JackPortConnectCallback callback, void *arg); | ||||
| virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg); | virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg); | ||||
| virtual int SetSessionCallback(JackSessionCallback callback, void *arg); | virtual int SetSessionCallback(JackSessionCallback callback, void *arg); | ||||
| virtual int SetLatencyCallback(JackLatencyCallback callback, void *arg); | |||||
| // Internal clients | // Internal clients | ||||
| virtual char* GetInternalClientName(int ref); | 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 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); | virtual void InternalClientUnload(int ref, jack_status_t* status); | ||||
| // RT Thread | |||||
| jack_nframes_t CycleWait(); | jack_nframes_t CycleWait(); | ||||
| void CycleSignal(int status); | void CycleSignal(int status); | ||||
| int SetProcessThread(JackThreadCallback fun, void *arg); | 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 | // JackRunnableInterface interface | ||||
| bool Init(); | bool Init(); | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 "JackPort.h" | ||||
| #include "JackSynchro.h" | #include "JackSynchro.h" | ||||
| #include "JackNotification.h" | #include "JackNotification.h" | ||||
| #include "jack/session.h" | |||||
| #include "session.h" | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| @@ -74,6 +73,7 @@ struct JackClientControl : public JackShmMemAble | |||||
| fCallback[kAddClient] = true; | fCallback[kAddClient] = true; | ||||
| fCallback[kRemoveClient] = true; | fCallback[kRemoveClient] = true; | ||||
| fCallback[kActivateClient] = true; | fCallback[kActivateClient] = true; | ||||
| fCallback[kLatencyCallback] = true; | |||||
| // So that driver synchro are correctly setup in "flush" or "normal" mode | // So that driver synchro are correctly setup in "flush" or "normal" mode | ||||
| fCallback[kStartFreewheelCallback] = true; | fCallback[kStartFreewheelCallback] = true; | ||||
| fCallback[kStopFreewheelCallback] = 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 "JackEngineControl.h" | ||||
| #include "JackGlobals.h" | #include "JackGlobals.h" | ||||
| #include "JackError.h" | #include "JackError.h" | ||||
| #include <set> | |||||
| #include <iostream> | #include <iostream> | ||||
| #include <assert.h> | #include <assert.h> | ||||
| @@ -246,7 +247,7 @@ int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro | |||||
| int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) | int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) | ||||
| { | { | ||||
| jack_time_t current_date = GetMicroSeconds(); | 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; | int res = 0; | ||||
| // Update state and timestamp of current client | // 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++) { | for (int i = 0; i < CLIENT_NUM; i++) { | ||||
| // Signal connected clients or drivers | // Signal connected clients or drivers | ||||
| if (outputRef[i] > 0) { | |||||
| if (output_ref[i] > 0) { | |||||
| // Update state and timestamp of destination clients | // Update state and timestamp of destination clients | ||||
| timing[i].fStatus = Triggered; | timing[i].fStatus = Triggered; | ||||
| @@ -272,6 +273,44 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* | |||||
| return res; | 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. | \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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 "JackActivationCount.h" | ||||
| #include "JackError.h" | #include "JackError.h" | ||||
| #include "JackCompilerDeps.h" | #include "JackCompilerDeps.h" | ||||
| #include <vector> | |||||
| #include <assert.h> | #include <assert.h> | ||||
| namespace Jack | namespace Jack | ||||
| @@ -151,7 +151,7 @@ class JackFixedArray1 : public JackFixedArray<SIZE> | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } POST_PACKED_STRUCTURE; | } POST_PACKED_STRUCTURE; | ||||
| /*! | /*! | ||||
| @@ -200,6 +200,11 @@ class JackFixedMatrix | |||||
| return fTable[index1][index2]; | 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. | \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 | bool IsInsideTable(jack_int_t index, jack_int_t* output) const | ||||
| { | { | ||||
| for (int i = 0; i < SIZE && output[i] != EMPTY; i++) { | for (int i = 0; i < SIZE && output[i] != EMPTY; i++) { | ||||
| @@ -227,6 +239,14 @@ class JackFixedMatrix | |||||
| return false; | 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; | } POST_PACKED_STRUCTURE; | ||||
| /*! | /*! | ||||
| @@ -359,7 +379,7 @@ struct JackClientTiming | |||||
| } | } | ||||
| ~JackClientTiming() | ~JackClientTiming() | ||||
| {} | {} | ||||
| void Init() | void Init() | ||||
| { | { | ||||
| fSignaledAt = 0; | fSignaledAt = 0; | ||||
| @@ -367,7 +387,7 @@ struct JackClientTiming | |||||
| fFinishedAt = 0; | fFinishedAt = 0; | ||||
| fStatus = NotTriggered; | fStatus = NotTriggered; | ||||
| } | } | ||||
| } POST_PACKED_STRUCTURE; | } POST_PACKED_STRUCTURE; | ||||
| /*! | /*! | ||||
| @@ -375,11 +395,9 @@ struct JackClientTiming | |||||
| <UL> | <UL> | ||||
| <LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port. | <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>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>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>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. | <LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose. | ||||
| </UL> | </UL> | ||||
| */ | */ | ||||
| @@ -461,7 +479,8 @@ class SERVER_EXPORT JackConnectionManager | |||||
| void ResetGraph(JackClientTiming* timing); | void ResetGraph(JackClientTiming* timing); | ||||
| int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing); | int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing); | ||||
| int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec); | int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec); | ||||
| void TopologicalSort(std::vector<jack_int_t>& sorted); | |||||
| } POST_PACKED_STRUCTURE; | } POST_PACKED_STRUCTURE; | ||||
| } // end of namespace | } // end of namespace | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 | void JackDebugClient::CheckClient(const char* function_name) const | ||||
| { | { | ||||
| *fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl; | *fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl; | ||||
| if (fIsClosed > 0) { | 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; | *fStream << "This is likely to cause crash !'" << endl; | ||||
| #ifdef __APPLE__ | #ifdef __APPLE__ | ||||
| // Debugger(); | // Debugger(); | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| } | } | ||||
| pthread_t JackDebugClient::GetThreadID() | |||||
| jack_native_thread_t JackDebugClient::GetThreadID() | |||||
| { | { | ||||
| CheckClient("GetThreadID"); | CheckClient("GetThreadID"); | ||||
| return fClient->GetThreadID(); | return fClient->GetThreadID(); | ||||
| @@ -428,7 +428,7 @@ void JackDebugClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *ar | |||||
| CheckClient("OnInfoShutdown"); | CheckClient("OnInfoShutdown"); | ||||
| fClient->OnInfoShutdown(callback, arg); | fClient->OnInfoShutdown(callback, arg); | ||||
| } | } | ||||
| int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) | int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) | ||||
| { | { | ||||
| JackDebugClient* client = (JackDebugClient*)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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 SetBufferSize(jack_nframes_t buffer_size); | ||||
| int SetFreeWheel(int onoff); | int SetFreeWheel(int onoff); | ||||
| void ShutDown(); | void ShutDown(); | ||||
| pthread_t GetThreadID(); | |||||
| jack_native_thread_t GetThreadID(); | |||||
| // Port management | // Port management | ||||
| int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); | 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() | int JackDriver::Close() | ||||
| { | { | ||||
| if (fClientControl.fRefNum >= 0) { | |||||
| if (fClientControl.fRefNum >= 0) { | |||||
| jack_log("JackDriver::Close"); | jack_log("JackDriver::Close"); | ||||
| fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync | fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync | ||||
| fClientControl.fActive = false; | fClientControl.fActive = false; | ||||
| @@ -207,7 +207,7 @@ int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync, | |||||
| jack_log("JackDriver::kStopFreewheel"); | jack_log("JackDriver::kStopFreewheel"); | ||||
| SetupDriverSync(fClientControl.fRefNum, false); | SetupDriverSync(fClientControl.fRefNum, false); | ||||
| break; | break; | ||||
| } | |||||
| } | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -223,13 +223,13 @@ void JackDriver::CycleIncTime() | |||||
| } | } | ||||
| void JackDriver::CycleTakeBeginTime() | void JackDriver::CycleTakeBeginTime() | ||||
| { | |||||
| { | |||||
| fBeginDateUst = GetMicroSeconds(); // Take callback date here | fBeginDateUst = GetMicroSeconds(); // Take callback date here | ||||
| fEngineControl->CycleIncTime(fBeginDateUst); | fEngineControl->CycleIncTime(fBeginDateUst); | ||||
| } | } | ||||
| void JackDriver::CycleTakeEndTime() | void JackDriver::CycleTakeEndTime() | ||||
| { | |||||
| { | |||||
| fEndDateUst = GetMicroSeconds(); // Take end date here | fEndDateUst = GetMicroSeconds(); // Take end date here | ||||
| } | } | ||||
| @@ -254,7 +254,7 @@ void JackDriver::NotifySampleRate(jack_nframes_t sample_rate) | |||||
| fEngine->NotifySampleRate(sample_rate); | fEngine->NotifySampleRate(sample_rate); | ||||
| fEngineControl->InitFrameTime(); | fEngineControl->InitFrameTime(); | ||||
| } | } | ||||
| void JackDriver::NotifyFailure(int code, const char* reason) | void JackDriver::NotifyFailure(int code, const char* reason) | ||||
| { | { | ||||
| fEngine->NotifyFailure(code, reason); | fEngine->NotifyFailure(code, reason); | ||||
| @@ -1,21 +1,21 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2001 Paul Davis | Copyright (C) 2001 Paul Davis | ||||
| Copyright (C) 2004-2008 Grame | Copyright (C) 2004-2008 Grame | ||||
| This program is free software; you can redistribute it and/or modify | 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 | it under the terms of the GNU General Public License as published by | ||||
| the Free Software Foundation; either version 2 of the License, or | the Free Software Foundation; either version 2 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU General Public License for more details. | GNU General Public License for more details. | ||||
| You should have received a copy of the GNU General Public License | You should have received a copy of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| */ | */ | ||||
| #ifndef __JackDriver__ | #ifndef __JackDriver__ | ||||
| @@ -30,27 +30,27 @@ | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| class JackLockedEngine; | class JackLockedEngine; | ||||
| class JackGraphManager; | class JackGraphManager; | ||||
| struct JackEngineControl; | struct JackEngineControl; | ||||
| /*! | /*! | ||||
| \brief The base interface for drivers. | \brief The base interface for drivers. | ||||
| */ | */ | ||||
| class SERVER_EXPORT JackDriverInterface | class SERVER_EXPORT JackDriverInterface | ||||
| { | { | ||||
| public: | public: | ||||
| JackDriverInterface() | JackDriverInterface() | ||||
| {} | {} | ||||
| virtual ~JackDriverInterface() | virtual ~JackDriverInterface() | ||||
| {} | {} | ||||
| virtual int Open() = 0; | virtual int Open() = 0; | ||||
| virtual int Open (bool capturing, | virtual int Open (bool capturing, | ||||
| bool playing, | bool playing, | ||||
| int inchannels, | int inchannels, | ||||
| @@ -60,7 +60,7 @@ class SERVER_EXPORT JackDriverInterface | |||||
| const char* playback_driver_name, | const char* playback_driver_name, | ||||
| jack_nframes_t capture_latency, | jack_nframes_t capture_latency, | ||||
| jack_nframes_t playback_latency) = 0; | jack_nframes_t playback_latency) = 0; | ||||
| virtual int Open(jack_nframes_t buffer_size, | virtual int Open(jack_nframes_t buffer_size, | ||||
| jack_nframes_t samplerate, | jack_nframes_t samplerate, | ||||
| bool capturing, | bool capturing, | ||||
| @@ -72,30 +72,30 @@ class SERVER_EXPORT JackDriverInterface | |||||
| const char* playback_driver_name, | const char* playback_driver_name, | ||||
| jack_nframes_t capture_latency, | jack_nframes_t capture_latency, | ||||
| jack_nframes_t playback_latency) = 0; | jack_nframes_t playback_latency) = 0; | ||||
| virtual int Attach() = 0; | virtual int Attach() = 0; | ||||
| virtual int Detach() = 0; | virtual int Detach() = 0; | ||||
| virtual int Read() = 0; | virtual int Read() = 0; | ||||
| virtual int Write() = 0; | virtual int Write() = 0; | ||||
| virtual int Start() = 0; | virtual int Start() = 0; | ||||
| virtual int Stop() = 0; | virtual int Stop() = 0; | ||||
| virtual bool IsFixedBufferSize() = 0; | virtual bool IsFixedBufferSize() = 0; | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; | virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; | ||||
| virtual int SetSampleRate(jack_nframes_t sample_rate) = 0; | virtual int SetSampleRate(jack_nframes_t sample_rate) = 0; | ||||
| virtual int Process() = 0; | virtual int Process() = 0; | ||||
| virtual int ProcessNull() = 0; | virtual int ProcessNull() = 0; | ||||
| virtual void SetMaster(bool onoff) = 0; | virtual void SetMaster(bool onoff) = 0; | ||||
| virtual bool GetMaster() = 0; | virtual bool GetMaster() = 0; | ||||
| virtual void AddSlave(JackDriverInterface* slave) = 0; | virtual void AddSlave(JackDriverInterface* slave) = 0; | ||||
| virtual void RemoveSlave(JackDriverInterface* slave) = 0; | virtual void RemoveSlave(JackDriverInterface* slave) = 0; | ||||
| virtual std::list<JackDriverInterface*> GetSlaves() = 0; | virtual std::list<JackDriverInterface*> GetSlaves() = 0; | ||||
| virtual int ProcessSlaves() = 0; | virtual int ProcessSlaves() = 0; | ||||
| virtual bool IsRealTime() const = 0; | virtual bool IsRealTime() const = 0; | ||||
| }; | }; | ||||
| @@ -109,16 +109,16 @@ class SERVER_EXPORT JackDriverClientInterface : public JackDriverInterface, publ | |||||
| /*! | /*! | ||||
| \brief The base class for drivers. | \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 | class SERVER_EXPORT JackDriver : public JackDriverClientInterface | ||||
| { | { | ||||
| protected: | protected: | ||||
| char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1]; | char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1]; | ||||
| char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1]; | char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1]; | ||||
| char fAliasName[JACK_CLIENT_NAME_SIZE + 1]; | char fAliasName[JACK_CLIENT_NAME_SIZE + 1]; | ||||
| @@ -134,27 +134,27 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||||
| JackClientControl fClientControl; | JackClientControl fClientControl; | ||||
| std::list<JackDriverInterface*> fSlaveList; | std::list<JackDriverInterface*> fSlaveList; | ||||
| bool fIsMaster; | bool fIsMaster; | ||||
| void CycleIncTime(); | void CycleIncTime(); | ||||
| void CycleTakeBeginTime(); | void CycleTakeBeginTime(); | ||||
| void CycleTakeEndTime(); | void CycleTakeEndTime(); | ||||
| void SetupDriverSync(int ref, bool freewheel); | void SetupDriverSync(int ref, bool freewheel); | ||||
| void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver | 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 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 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 | void NotifyFailure(int code, const char* reason); // Failure notification sent by the driver | ||||
| public: | public: | ||||
| JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | ||||
| JackDriver(); | JackDriver(); | ||||
| virtual ~JackDriver(); | virtual ~JackDriver(); | ||||
| void SetMaster(bool onoff); | void SetMaster(bool onoff); | ||||
| bool GetMaster(); | bool GetMaster(); | ||||
| void AddSlave(JackDriverInterface* slave); | void AddSlave(JackDriverInterface* slave); | ||||
| void RemoveSlave(JackDriverInterface* slave); | void RemoveSlave(JackDriverInterface* slave); | ||||
| std::list<JackDriverInterface*> GetSlaves() | std::list<JackDriverInterface*> GetSlaves() | ||||
| @@ -162,9 +162,9 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||||
| return fSlaveList; | return fSlaveList; | ||||
| } | } | ||||
| int ProcessSlaves(); | int ProcessSlaves(); | ||||
| virtual int Open(); | virtual int Open(); | ||||
| virtual int Open (bool capturing, | virtual int Open (bool capturing, | ||||
| bool playing, | bool playing, | ||||
| int inchannels, | int inchannels, | ||||
| @@ -174,7 +174,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||||
| const char* playback_driver_name, | const char* playback_driver_name, | ||||
| jack_nframes_t capture_latency, | jack_nframes_t capture_latency, | ||||
| jack_nframes_t playback_latency); | jack_nframes_t playback_latency); | ||||
| virtual int Open(jack_nframes_t buffer_size, | virtual int Open(jack_nframes_t buffer_size, | ||||
| jack_nframes_t samplerate, | jack_nframes_t samplerate, | ||||
| bool capturing, | bool capturing, | ||||
| @@ -187,31 +187,31 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||||
| jack_nframes_t capture_latency, | jack_nframes_t capture_latency, | ||||
| jack_nframes_t playback_latency); | jack_nframes_t playback_latency); | ||||
| virtual int Close(); | virtual int Close(); | ||||
| virtual int Process(); | virtual int Process(); | ||||
| virtual int ProcessNull(); | virtual int ProcessNull(); | ||||
| virtual int Attach(); | virtual int Attach(); | ||||
| virtual int Detach(); | virtual int Detach(); | ||||
| virtual int Read(); | virtual int Read(); | ||||
| virtual int Write(); | virtual int Write(); | ||||
| virtual int Start(); | virtual int Start(); | ||||
| virtual int Stop(); | virtual int Stop(); | ||||
| virtual bool IsFixedBufferSize(); | virtual bool IsFixedBufferSize(); | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | virtual int SetBufferSize(jack_nframes_t buffer_size); | ||||
| virtual int SetSampleRate(jack_nframes_t sample_rate); | 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 int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | ||||
| virtual JackClientControl* GetClientControl() const; | virtual JackClientControl* GetClientControl() const; | ||||
| virtual bool IsRealTime() 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 | } // end of namespace | ||||
| #endif | #endif | ||||
| @@ -56,6 +56,12 @@ int JackDummyDriver::Open(jack_nframes_t buffer_size, | |||||
| fEngineControl->fPeriod = 0; | fEngineControl->fPeriod = 0; | ||||
| fEngineControl->fComputation = 500 * 1000; | fEngineControl->fComputation = 500 * 1000; | ||||
| fEngineControl->fConstraint = 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; | return 0; | ||||
| } else { | } else { | ||||
| return -1; | return -1; | ||||
| @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #include <iostream> | #include <iostream> | ||||
| #include <fstream> | #include <fstream> | ||||
| #include <set> | |||||
| #include <assert.h> | #include <assert.h> | ||||
| #include "JackSystemDeps.h" | #include "JackSystemDeps.h" | ||||
| @@ -90,7 +91,7 @@ int JackEngine::Close() | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| void JackEngine::NotifyQuit() | void JackEngine::NotifyQuit() | ||||
| { | { | ||||
| fChannel.NotifyQuit(); | fChannel.NotifyQuit(); | ||||
| @@ -137,8 +138,10 @@ void JackEngine::ReleaseRefnum(int ref) | |||||
| void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) | void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) | ||||
| { | { | ||||
| fLastSwitchUsecs = 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); | fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0); | ||||
| //NotifyGraphReorder(); | |||||
| } | |||||
| fSignal.Signal(); // Signal for threads waiting for next cycle | 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) { | if (status != NotTriggered && status != Finished) { | ||||
| jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status); | jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status); | ||||
| fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | ||||
| //NotifyXRun(ALL_CLIENTS); | |||||
| } | } | ||||
| if (status == Finished && (long)(finished_date - callback_usecs) > 0) { | if (status == Finished && (long)(finished_date - callback_usecs) > 0) { | ||||
| jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName); | jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName); | ||||
| fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | 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 | // 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 | // The client may be notified by the RT thread while closing | ||||
| if (client) { | if (client) { | ||||
| if (client && client->GetClientControl()->fCallback[event]) { | |||||
| if (client->GetClientControl()->fCallback[event]) { | |||||
| /* | /* | ||||
| Important for internal clients : unlock before calling the notification callbacks. | 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); | jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2); | ||||
| if (res) | if (res) | ||||
| fMutex.Lock(); | fMutex.Lock(); | ||||
| } else { | } else { | ||||
| jack_log("JackEngine::NotifyClient: no callback for event = %ld", event); | 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 | // Use the audio thread => request thread communication channel | ||||
| fEngineControl->NotifyXRun(callback_usecs, delayed_usecs); | fEngineControl->NotifyXRun(callback_usecs, delayed_usecs); | ||||
| fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); | fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); | ||||
| //NotifyXRun(ALL_CLIENTS); | |||||
| } | } | ||||
| void JackEngine::NotifyXRun(int refnum) | void JackEngine::NotifyXRun(int refnum) | ||||
| @@ -290,6 +322,7 @@ void JackEngine::NotifyXRun(int refnum) | |||||
| void JackEngine::NotifyGraphReorder() | void JackEngine::NotifyGraphReorder() | ||||
| { | { | ||||
| ComputeTotalLatencies(); | |||||
| NotifyClients(kGraphOrderCallback, false, "", 0, 0); | NotifyClients(kGraphOrderCallback, false, "", 0, 0); | ||||
| } | } | ||||
| @@ -307,7 +340,7 @@ void JackEngine::NotifyFailure(int code, const char* reason) | |||||
| { | { | ||||
| NotifyClients(kShutDownCallback, false, reason, code, 0); | NotifyClients(kShutDownCallback, false, reason, code, 0); | ||||
| } | } | ||||
| void JackEngine::NotifyFreewheel(bool onoff) | void JackEngine::NotifyFreewheel(bool onoff) | ||||
| { | { | ||||
| if (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); | std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | ||||
| if (res != fReservationMap.end()) { | 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)) { | } else if (ClientCheckName(name)) { | ||||
| *status |= JackNameNotUnique; | *status |= JackNameNotUnique; | ||||
| @@ -467,7 +500,7 @@ bool JackEngine::ClientCheckName(const char* name) | |||||
| return true; | 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) | if (i->second == name) | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -522,14 +555,14 @@ int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref | |||||
| if (uuid < 0) { | if (uuid < 0) { | ||||
| uuid = GetNewUUID(); | uuid = GetNewUUID(); | ||||
| strncpy( real_name, name, JACK_CLIENT_NAME_SIZE ); | |||||
| strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); | |||||
| } else { | } else { | ||||
| std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | ||||
| if (res != fReservationMap.end()) { | 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); | fReservationMap.erase(uuid); | ||||
| } else { | } else { | ||||
| strncpy( real_name, name, JACK_CLIENT_NAME_SIZE ); | |||||
| strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); | |||||
| } | } | ||||
| EnsureUUID(uuid); | EnsureUUID(uuid); | ||||
| @@ -689,7 +722,7 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time) | |||||
| { | { | ||||
| JackClientInterface* client = fClientTable[refnum]; | JackClientInterface* client = fClientTable[refnum]; | ||||
| jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); | jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); | ||||
| if (is_real_time) | if (is_real_time) | ||||
| fGraphManager->Activate(refnum); | 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]; | jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; | ||||
| fGraphManager->GetInputPorts(refnum, input_ports); | fGraphManager->GetInputPorts(refnum, input_ports); | ||||
| fGraphManager->GetOutputPorts(refnum, output_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 | // Notify client | ||||
| NotifyActivate(refnum); | NotifyActivate(refnum); | ||||
| // Then issue port registration notification | // Then issue port registration notification | ||||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | ||||
| NotifyPortRegistation(input_ports[i], true); | NotifyPortRegistation(input_ports[i], true); | ||||
| @@ -740,13 +765,11 @@ int JackEngine::ClientDeactivate(int refnum) | |||||
| // First disconnect all ports and remove their JackPortIsActive state | // First disconnect all ports and remove their JackPortIsActive state | ||||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | ||||
| PortDisconnect(refnum, input_ports[i], ALL_PORTS); | 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++) { | for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { | ||||
| PortDisconnect(refnum, output_ports[i], ALL_PORTS); | PortDisconnect(refnum, output_ports[i], ALL_PORTS); | ||||
| fGraphManager->DeactivatePort(output_ports[i]); | |||||
| } | } | ||||
| // Then issue port registration notification | // Then issue port registration notification | ||||
| for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | ||||
| NotifyPortRegistation(input_ports[i], false); | 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) | 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); | jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst); | ||||
| if (dst == ALL_PORTS) { | if (dst == ALL_PORTS) { | ||||
| jack_int_t connections[CONNECTION_NUM_FOR_PORT]; | 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; | return 0; | ||||
| } | } | ||||
| //-------------------- | |||||
| // Session management | |||||
| //-------------------- | |||||
| void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket) | void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket) | ||||
| { | { | ||||
| if (fSessionPendingReplies != 0) { | 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]; | char path_buf[JACK_PORT_NAME_SIZE]; | ||||
| snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR ); | snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR ); | ||||
| int res = JackTools::MkDir(path_buf); | int res = JackTools::MkDir(path_buf); | ||||
| if (res) | |||||
| if (res) | |||||
| jack_error( "JackEngine::SessionNotify: can not create session directory '%s'", path_buf ); | 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); | int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int) type, 0); | ||||
| if (result == 2) { | if (result == 2) { | ||||
| @@ -952,9 +979,9 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||||
| } else if (result == 1) { | } else if (result == 1) { | ||||
| char uuid_buf[JACK_UUID_SIZE]; | char uuid_buf[JACK_UUID_SIZE]; | ||||
| snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID ); | 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()->fName, | ||||
| client->GetClientControl()->fSessionCommand, | |||||
| client->GetClientControl()->fSessionCommand, | |||||
| client->GetClientControl()->fSessionFlags )); | client->GetClientControl()->fSessionFlags )); | ||||
| } | } | ||||
| } | } | ||||
| @@ -973,11 +1000,11 @@ void JackEngine::SessionReply(int refnum) | |||||
| { | { | ||||
| JackClientInterface* client = fClientTable[refnum]; | JackClientInterface* client = fClientTable[refnum]; | ||||
| char uuid_buf[JACK_UUID_SIZE]; | 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; | fSessionPendingReplies -= 1; | ||||
| if (fSessionPendingReplies == 0) { | if (fSessionPendingReplies == 0) { | ||||
| @@ -998,9 +1025,8 @@ void JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res, i | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| // did not find name. | |||||
| // Did not find name. | |||||
| *result = -1; | *result = -1; | ||||
| return; | |||||
| } | } | ||||
| void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *result) | 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; | return; | ||||
| } | } | ||||
| } | } | ||||
| // did not find uuid. | |||||
| // Did not find uuid. | |||||
| *result = -1; | *result = -1; | ||||
| return; | |||||
| } | } | ||||
| void JackEngine::ReserveClientName(const char *name, const char *uuid, int *result) | 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)) { | if (ClientCheckName(name)) { | ||||
| *result = -1; | *result = -1; | ||||
| jack_log( "name already taken" ); | |||||
| jack_log("name already taken"); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -1040,5 +1065,21 @@ void JackEngine::ReserveClientName(const char *name, const char *uuid, int *resu | |||||
| *result = 0; | *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 | } // 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 PortRename(int refnum, jack_port_id_t port, const char* name); | ||||
| int ComputeTotalLatencies(); | |||||
| // Graph | // Graph | ||||
| bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | 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 NotifyFreewheel(bool onoff); | ||||
| void NotifyQuit(); | 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 GetUUIDForClientName(const char *client_name, char *uuid_res, int *result); | ||||
| void GetClientNameForUUID(const char *uuid, char *name_res, int *result); | void GetClientNameForUUID(const char *uuid, char *name_res, int *result); | ||||
| void ReserveClientName(const char *name, const char *uuid, 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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; | 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) | jack_time_t prev_cycle_end) | ||||
| { | { | ||||
| fPrevCycleTime = fCurCycleTime; | fPrevCycleTime = fCurCycleTime; | ||||
| fCurCycleTime = cur_cycle_begin; | fCurCycleTime = cur_cycle_begin; | ||||
| jack_time_t last_cycle_end = prev_cycle_end; | jack_time_t last_cycle_end = prev_cycle_end; | ||||
| // In Asynchronous mode, last cycle end is the max of client end dates | // In Asynchronous mode, last cycle end is the max of client end dates | ||||
| if (!fSyncMode) { | if (!fSyncMode) { | ||||
| for (int i = fDriverNum; i < CLIENT_NUM; i++) { | for (int i = fDriverNum; i < CLIENT_NUM; i++) { | ||||
| JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
| JackClientTiming* timing = manager->GetClientTiming(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); | 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; | fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime; | ||||
| if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||||
| if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||||
| fRollingClientUsecsIndex = 0; | fRollingClientUsecsIndex = 0; | ||||
| // Every so often, recompute the current maximum use over the | // Every so often, recompute the current maximum use over the | ||||
| // last JACK_ENGINE_ROLLING_COUNT client iterations. | // last JACK_ENGINE_ROLLING_COUNT client iterations. | ||||
| if (++fRollingClientUsecsCnt % fRollingInterval == 0) { | if (++fRollingClientUsecsCnt % fRollingInterval == 0) { | ||||
| jack_time_t max_usecs = 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); | max_usecs = JACK_MAX(fRollingClientUsecs[i], max_usecs); | ||||
| fMaxUsecs = JACK_MAX(fMaxUsecs, max_usecs); | fMaxUsecs = JACK_MAX(fMaxUsecs, max_usecs); | ||||
| fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0); | fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0); | ||||
| fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f)); | fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f)); | ||||
| @@ -80,7 +80,7 @@ void JackEngineControl::ResetRollingUsecs() | |||||
| fSpareUsecs = 0; | fSpareUsecs = 0; | ||||
| fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs)); | fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs)); | ||||
| } | } | ||||
| void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | ||||
| { | { | ||||
| ResetFrameTime(callback_usecs); | ResetFrameTime(callback_usecs); | ||||
| @@ -88,5 +88,5 @@ void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_use | |||||
| if (delayed_usecs > fMaxDelayedUsecs) | if (delayed_usecs > fMaxDelayedUsecs) | ||||
| fMaxDelayedUsecs = delayed_usecs; | fMaxDelayedUsecs = delayed_usecs; | ||||
| } | } | ||||
| } // end of namespace | } // end of namespace | ||||
| @@ -7,12 +7,12 @@ | |||||
| it under the terms of the GNU Lesser General Public License as published by | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| @@ -25,7 +25,6 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include "JackCompilerDeps.h" | #include "JackCompilerDeps.h" | ||||
| #include "types.h" | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| extern "C" | extern "C" | ||||
| @@ -44,17 +43,17 @@ extern "C" | |||||
| EXPORT extern void (*jack_error_callback)(const char *desc); | EXPORT extern void (*jack_error_callback)(const char *desc); | ||||
| EXPORT extern void (*jack_info_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_error_callback(const char *desc); | ||||
| EXPORT extern void default_jack_info_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_error_callback(const char *desc); | ||||
| EXPORT extern void silent_jack_info_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); | typedef void (* jack_log_function_t)(int level, const char *message); | ||||
| void jack_log_function(int level, const char *message); | void jack_log_function(int level, const char *message); | ||||
| EXPORT int set_threaded_log_function(); | EXPORT int set_threaded_log_function(); | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -36,9 +36,9 @@ class SERVER_EXPORT JackTimer | |||||
| { | { | ||||
| friend class JackFrameTimer; | friend class JackFrameTimer; | ||||
| private: | |||||
| private: | |||||
| jack_nframes_t fFrames; | jack_nframes_t fFrames; | ||||
| jack_time_t fCurrentWakeup; | jack_time_t fCurrentWakeup; | ||||
| jack_time_t fCurrentCallback; | jack_time_t fCurrentCallback; | ||||
| @@ -47,21 +47,21 @@ class SERVER_EXPORT JackTimer | |||||
| float fFilterCoefficient; /* set once, never altered */ | float fFilterCoefficient; /* set once, never altered */ | ||||
| bool fInitialized; | bool fInitialized; | ||||
| public: | |||||
| public: | |||||
| JackTimer(); | JackTimer(); | ||||
| ~JackTimer() | ~JackTimer() | ||||
| {} | {} | ||||
| jack_nframes_t Time2Frames(jack_time_t time, jack_nframes_t buffer_size); | 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_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 FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate); | ||||
| jack_nframes_t CurFrame() | jack_nframes_t CurFrame() | ||||
| { | { | ||||
| return fFrames; | return fFrames; | ||||
| } | } | ||||
| jack_time_t CurTime() | jack_time_t CurTime() | ||||
| { | { | ||||
| return fCurrentWakeup; | return fCurrentWakeup; | ||||
| @@ -75,7 +75,7 @@ class SERVER_EXPORT JackTimer | |||||
| class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | ||||
| { | { | ||||
| private: | private: | ||||
| bool fFirstWakeUp; | 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 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 IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs); | ||||
| void ReadFrameTime(JackTimer* timer); | void ReadFrameTime(JackTimer* timer); | ||||
| } POST_PACKED_STRUCTURE; | } POST_PACKED_STRUCTURE; | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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); | assert(buffer_size <= BUFFER_SIZE_MAX); | ||||
| } | } | ||||
| } | } | ||||
| void JackGraphManager::AssertPort(jack_port_id_t port_index) | void JackGraphManager::AssertPort(jack_port_id_t port_index) | ||||
| { | { | ||||
| if (port_index >= fPortMax) { | if (port_index >= fPortMax) { | ||||
| @@ -45,7 +45,7 @@ void JackGraphManager::AssertPort(jack_port_id_t port_index) | |||||
| assert(port_index < fPortMax); | assert(port_index < fPortMax); | ||||
| } | } | ||||
| } | } | ||||
| JackGraphManager* JackGraphManager::Allocate(int port_max) | JackGraphManager* JackGraphManager::Allocate(int port_max) | ||||
| { | { | ||||
| // Using "Placement" new | // Using "Placement" new | ||||
| @@ -59,18 +59,18 @@ void JackGraphManager::Destroy(JackGraphManager* manager) | |||||
| manager->~JackGraphManager(); | manager->~JackGraphManager(); | ||||
| JackShmMem::operator delete(manager); | JackShmMem::operator delete(manager); | ||||
| } | } | ||||
| JackGraphManager::JackGraphManager(int port_max) | |||||
| JackGraphManager::JackGraphManager(int port_max) | |||||
| { | { | ||||
| assert(port_max <= PORT_NUM_MAX); | assert(port_max <= PORT_NUM_MAX); | ||||
| for (int i = 0; i < port_max; i++) { | for (int i = 0; i < port_max; i++) { | ||||
| fPortArray[i].Release(); | fPortArray[i].Release(); | ||||
| } | } | ||||
| fPortMax = port_max; | fPortMax = port_max; | ||||
| } | } | ||||
| JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) | JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) | ||||
| { | { | ||||
| AssertPort(port_index); | AssertPort(port_index); | ||||
| @@ -127,6 +127,19 @@ int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* tab | |||||
| return manager->SuspendRefNum(control, table, fClientTiming, usec); | 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 | // Server | ||||
| void JackGraphManager::DirectConnect(int ref1, int ref2) | 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); | jack_int_t len = manager->Connections(port_index); | ||||
| // No connections : return a zero-filled buffer | // No connections : return a zero-filled buffer | ||||
| if (len == 0) { | |||||
| if (len == 0) { | |||||
| port->ClearBuffer(buffer_size); | port->ClearBuffer(buffer_size); | ||||
| return port->GetBuffer(); | return port->GetBuffer(); | ||||
| // One connection | // One connection | ||||
| } else if (len == 1) { | |||||
| } else if (len == 1) { | |||||
| jack_port_id_t src_index = manager->GetPort(port_index, 0); | jack_port_id_t src_index = manager->GetPort(port_index, 0); | ||||
| // Ports in same client : copy the buffer | // Ports in same client : copy the buffer | ||||
| if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) { | if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) { | ||||
| void* buffers[1]; | void* buffers[1]; | ||||
| @@ -194,10 +207,10 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff | |||||
| } else { | } else { | ||||
| return GetBuffer(src_index, buffer_size); | return GetBuffer(src_index, buffer_size); | ||||
| } | } | ||||
| // Multiple connections : mix all buffers | // Multiple connections : mix all buffers | ||||
| } else { | |||||
| } else { | |||||
| const jack_int_t* connections = manager->GetConnections(port_index); | const jack_int_t* connections = manager->GetConnections(port_index); | ||||
| void* buffers[CONNECTION_NUM_FOR_PORT]; | void* buffers[CONNECTION_NUM_FOR_PORT]; | ||||
| jack_port_id_t src_index; | 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); | JackPort* port = GetPort(port_index); | ||||
| /** | /** | ||||
| jackd.h | |||||
| jackd.h | |||||
| * If @ref JackPortCanMonitor is set for this @a port, turn input | * If @ref JackPortCanMonitor is set for this @a port, turn input | ||||
| * monitoring on or off. Otherwise, do nothing. | * monitoring on or off. Otherwise, do nothing. | ||||
| if (!(fFlags & JackPortCanMonitor)) | if (!(fFlags & JackPortCanMonitor)) | ||||
| return -1; | return -1; | ||||
| */ | */ | ||||
| @@ -245,7 +258,7 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C | |||||
| // Client | // Client | ||||
| jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count) | 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_nframes_t max_latency = 0; | ||||
| jack_port_id_t dst_index; | jack_port_id_t dst_index; | ||||
| @@ -296,6 +309,46 @@ int JackGraphManager::ComputeTotalLatencies() | |||||
| return 0; | 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 | // Server | ||||
| void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size) | 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; | 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) | void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res) | ||||
| { | { | ||||
| JackConnectionManager* manager = WriteNextStateStart(); | 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); | jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index); | ||||
| assert(true); | assert(true); | ||||
| break; | break; | ||||
| } | |||||
| } | |||||
| } | } | ||||
| WriteNextStateStop(); | WriteNextStateStop(); | ||||
| @@ -717,7 +758,7 @@ void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const c | |||||
| const jack_int_t* connections = manager->GetConnections(port_index); | const jack_int_t* connections = manager->GetConnections(port_index); | ||||
| jack_int_t index; | jack_int_t index; | ||||
| int i; | int i; | ||||
| // Cleanup connection array | // Cleanup connection array | ||||
| memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT); | 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); | const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT); | ||||
| UInt16 cur_index, next_index; | UInt16 cur_index, next_index; | ||||
| if (!res) | if (!res) | ||||
| return NULL; | return NULL; | ||||
| @@ -763,7 +804,7 @@ void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port | |||||
| { | { | ||||
| int match_cnt = 0; | int match_cnt = 0; | ||||
| regex_t port_regex, type_regex; | regex_t port_regex, type_regex; | ||||
| if (port_name_pattern && port_name_pattern[0]) { | if (port_name_pattern && port_name_pattern[0]) { | ||||
| regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB); | 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); | const char** res = (const char**)malloc(sizeof(char*) * fPortMax); | ||||
| UInt16 cur_index, next_index; | UInt16 cur_index, next_index; | ||||
| if (!res) | if (!res) | ||||
| return NULL; | return NULL; | ||||
| do { | do { | ||||
| cur_index = GetCurrentIndex(); | cur_index = GetCurrentIndex(); | ||||
| GetPortsAux(res, port_name_pattern, type_name_pattern, flags); | GetPortsAux(res, port_name_pattern, type_name_pattern, flags); | ||||
| next_index = GetCurrentIndex(); | 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 | if (res[0]) { // at least one port | ||||
| return res; | return res; | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 "JackPlatformPlug.h" | ||||
| #include "JackSystemDeps.h" | #include "JackSystemDeps.h" | ||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| /*! | /*! | ||||
| \brief Graph manager: contains the connection manager and the port array. | \brief Graph manager: contains the connection manager and the port array. | ||||
| */ | */ | ||||
| class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState<JackConnectionManager> | 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); | float* GetBuffer(jack_port_id_t port_index); | ||||
| void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames); | 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); | 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: | public: | ||||
| @@ -65,8 +65,6 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||||
| // Ports management | // Ports management | ||||
| jack_port_id_t AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size); | 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); | 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 GetInputPorts(int refnum, jack_int_t* res); | ||||
| void GetOutputPorts(int refnum, jack_int_t* res); | void GetOutputPorts(int refnum, jack_int_t* res); | ||||
| void RemoveAllPorts(int refnum); | void RemoveAllPorts(int refnum); | ||||
| @@ -74,10 +72,13 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||||
| JackPort* GetPort(jack_port_id_t index); | JackPort* GetPort(jack_port_id_t index); | ||||
| jack_port_id_t GetPort(const char* name); | jack_port_id_t GetPort(const char* name); | ||||
| int ComputeTotalLatency(jack_port_id_t port_index); | int ComputeTotalLatency(jack_port_id_t port_index); | ||||
| int ComputeTotalLatencies(); | 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); | int RequestMonitor(jack_port_id_t port_index, bool onoff); | ||||
| // Connections management | // Connections management | ||||
| int Connect(jack_port_id_t src_index, jack_port_id_t dst_index); | 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); | 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); | void InitRefNum(int refnum); | ||||
| int ResumeRefNum(JackClientControl* control, JackSynchro* table); | int ResumeRefNum(JackClientControl* control, JackSynchro* table); | ||||
| int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs); | int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs); | ||||
| void TopologicalSort(std::vector<jack_int_t>& sorted); | |||||
| JackClientTiming* GetClientTiming(int refnum) | JackClientTiming* GetClientTiming(int refnum) | ||||
| { | { | ||||
| @@ -130,7 +132,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||||
| void Save(JackConnectionManager* dst); | void Save(JackConnectionManager* dst); | ||||
| void Restore(JackConnectionManager* src); | void Restore(JackConnectionManager* src); | ||||
| static JackGraphManager* Allocate(int port_max); | static JackGraphManager* Allocate(int port_max); | ||||
| static void Destroy(JackGraphManager* manager); | static void Destroy(JackGraphManager* manager); | ||||
| @@ -80,7 +80,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||||
| { | { | ||||
| *result = fEngine->PortUnRegister(refnum, port_index); | *result = fEngine->PortUnRegister(refnum, port_index); | ||||
| } | } | ||||
| void PortConnect(int refnum, const char* src, const char* dst, int* result) | void PortConnect(int refnum, const char* src, const char* dst, int* result) | ||||
| { | { | ||||
| *result = fEngine->PortConnect(refnum, src, dst); | *result = fEngine->PortConnect(refnum, src, dst); | ||||
| @@ -89,7 +88,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||||
| { | { | ||||
| *result = fEngine->PortDisconnect(refnum, src, dst); | *result = fEngine->PortDisconnect(refnum, src, dst); | ||||
| } | } | ||||
| void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) | void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) | ||||
| { | { | ||||
| *result = fEngine->PortConnect(refnum, src, dst); | *result = fEngine->PortConnect(refnum, src, dst); | ||||
| @@ -111,10 +109,9 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||||
| { | { | ||||
| *result = fServer->SetFreewheel(onoff); | *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) | void ReleaseTimebase(int refnum, int* result) | ||||
| @@ -126,7 +123,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||||
| { | { | ||||
| *result = fServer->SetTimebaseCallback(refnum, conditional); | *result = fServer->SetTimebaseCallback(refnum, conditional); | ||||
| } | } | ||||
| void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | ||||
| { | { | ||||
| *result = fEngine->GetInternalClientName(int_ref, name_res); | *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) | 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) | 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); | *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 | } // end of namespace | ||||
| @@ -66,7 +66,7 @@ catch (...) { | |||||
| \brief Locked Engine, access to methods is serialized using a mutex. | \brief Locked Engine, access to methods is serialized using a mutex. | ||||
| */ | */ | ||||
| class SERVER_EXPORT JackLockedEngine | |||||
| class SERVER_EXPORT JackLockedEngine | |||||
| { | { | ||||
| private: | private: | ||||
| @@ -94,7 +94,7 @@ class SERVER_EXPORT JackLockedEngine | |||||
| return fEngine.Close(); | return fEngine.Close(); | ||||
| CATCH_EXCEPTION_RETURN | CATCH_EXCEPTION_RETURN | ||||
| } | } | ||||
| // Client management | // Client management | ||||
| int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status) | 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 | CATCH_EXCEPTION_RETURN | ||||
| } | } | ||||
| int ComputeTotalLatencies() | |||||
| { | |||||
| TRY_CALL | |||||
| JackLock lock(&fEngine); | |||||
| return fEngine.ComputeTotalLatencies(); | |||||
| CATCH_EXCEPTION_RETURN | |||||
| } | |||||
| // Graph | // Graph | ||||
| bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) | 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 | // RT : no lock | ||||
| fEngine.NotifyXRun(refnum); | fEngine.NotifyXRun(refnum); | ||||
| } | } | ||||
| void NotifyGraphReorder() | void NotifyGraphReorder() | ||||
| { | { | ||||
| TRY_CALL | TRY_CALL | ||||
| @@ -298,7 +306,7 @@ class SERVER_EXPORT JackLockedEngine | |||||
| return fEngine.GetClientRefNum(name); | return fEngine.GetClientRefNum(name); | ||||
| CATCH_EXCEPTION_RETURN | CATCH_EXCEPTION_RETURN | ||||
| } | } | ||||
| void NotifyQuit() | void NotifyQuit() | ||||
| { | { | ||||
| TRY_CALL | TRY_CALL | ||||
| @@ -314,7 +322,7 @@ class SERVER_EXPORT JackLockedEngine | |||||
| fEngine.SessionNotify(refnum, target, type, path, socket); | fEngine.SessionNotify(refnum, target, type, path, socket); | ||||
| CATCH_EXCEPTION | CATCH_EXCEPTION | ||||
| } | } | ||||
| void SessionReply(int refnum) | void SessionReply(int refnum) | ||||
| { | { | ||||
| TRY_CALL | TRY_CALL | ||||
| @@ -322,7 +330,7 @@ class SERVER_EXPORT JackLockedEngine | |||||
| fEngine.SessionReply(refnum); | fEngine.SessionReply(refnum); | ||||
| CATCH_EXCEPTION | CATCH_EXCEPTION | ||||
| } | } | ||||
| void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) | void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) | ||||
| { | { | ||||
| TRY_CALL | TRY_CALL | ||||
| @@ -344,6 +352,14 @@ class SERVER_EXPORT JackLockedEngine | |||||
| fEngine.ReserveClientName(name, uuid, result); | fEngine.ReserveClientName(name, uuid, result); | ||||
| CATCH_EXCEPTION | CATCH_EXCEPTION | ||||
| } | } | ||||
| void ClientHasSessionCallbackRequest(const char *name, int *result) | |||||
| { | |||||
| TRY_CALL | |||||
| JackLock lock(&fEngine); | |||||
| fEngine.ClientHasSessionCallbackRequest(name, result); | |||||
| CATCH_EXCEPTION | |||||
| } | |||||
| }; | }; | ||||
| } // end of namespace | } // end of namespace | ||||
| @@ -2,19 +2,19 @@ | |||||
| * Copyright (C) 2004 Rui Nuno Capela, Steve Harris | * Copyright (C) 2004 Rui Nuno Capela, Steve Harris | ||||
| * Copyright (C) 2008 Nedko Arnaudov | * Copyright (C) 2008 Nedko Arnaudov | ||||
| * Copyright (C) 2008 Grame | * Copyright (C) 2008 Grame | ||||
| * | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or modify | * 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 | * 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 | * the Free Software Foundation; either version 2.1 of the License, or | ||||
| * (at your option) any later version. | * (at your option) any later version. | ||||
| * | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | * This program is distributed in the hope that it will be useful, | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| * GNU Lesser General Public License for more details. | * GNU Lesser General Public License for more details. | ||||
| * | |||||
| * | |||||
| * You should have received a copy of the GNU Lesser General Public License | * 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. | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| * | * | ||||
| */ | */ | ||||
| @@ -34,7 +34,7 @@ JackMessageBuffer::JackMessageBuffer() | |||||
| JackMessageBuffer::~JackMessageBuffer() | JackMessageBuffer::~JackMessageBuffer() | ||||
| {} | {} | ||||
| void JackMessageBuffer::Start() | void JackMessageBuffer::Start() | ||||
| { | { | ||||
| fRunning = true; | fRunning = true; | ||||
| @@ -44,9 +44,9 @@ void JackMessageBuffer::Start() | |||||
| void JackMessageBuffer::Stop() | void JackMessageBuffer::Stop() | ||||
| { | { | ||||
| if (fOverruns > 0) { | if (fOverruns > 0) { | ||||
| jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||||
| jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||||
| } else { | } else { | ||||
| jack_log("no message buffer overruns"); | |||||
| jack_log("no message buffer overruns"); | |||||
| } | } | ||||
| fGuard.Lock(); | fGuard.Lock(); | ||||
| fRunning = false; | fRunning = false; | ||||
| @@ -55,7 +55,7 @@ void JackMessageBuffer::Stop() | |||||
| fThread.Stop(); | fThread.Stop(); | ||||
| Flush(); | Flush(); | ||||
| } | } | ||||
| void JackMessageBuffer::Flush() | void JackMessageBuffer::Flush() | ||||
| { | { | ||||
| while (fOutBuffer != fInBuffer) { | while (fOutBuffer != fInBuffer) { | ||||
| @@ -76,7 +76,7 @@ void JackMessageBuffer::AddMessage(int level, const char *message) | |||||
| INC_ATOMIC(&fOverruns); | INC_ATOMIC(&fOverruns); | ||||
| } | } | ||||
| } | } | ||||
| bool JackMessageBuffer::Execute() | bool JackMessageBuffer::Execute() | ||||
| { | { | ||||
| while (fRunning) { | while (fRunning) { | ||||
| @@ -94,10 +94,10 @@ bool JackMessageBuffer::Execute() | |||||
| Flush(); | Flush(); | ||||
| fGuard.Unlock(); | fGuard.Unlock(); | ||||
| } | } | ||||
| return false; | |||||
| return false; | |||||
| } | } | ||||
| void JackMessageBuffer::Create() | |||||
| void JackMessageBuffer::Create() | |||||
| { | { | ||||
| if (fInstance == NULL) { | if (fInstance == NULL) { | ||||
| fInstance = new JackMessageBuffer(); | fInstance = new JackMessageBuffer(); | ||||
| @@ -105,7 +105,7 @@ void JackMessageBuffer::Create() | |||||
| } | } | ||||
| } | } | ||||
| void JackMessageBuffer::Destroy() | |||||
| void JackMessageBuffer::Destroy() | |||||
| { | { | ||||
| if (fInstance != NULL) { | if (fInstance != NULL) { | ||||
| fInstance->Stop(); | 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) { | if (Jack::JackMessageBuffer::fInstance == NULL) { | ||||
| /* Unable to print message with realtime safety. Complain and print it anyway. */ | /* 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 */ | /* and we're done */ | ||||
| fGuard.Unlock(); | fGuard.Unlock(); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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; | mix->lost_events += event_count - events_done; | ||||
| } | } | ||||
| static size_t MidiBufferSize() | |||||
| { | |||||
| return BUFFER_SIZE_MAX * sizeof(float); | |||||
| } | |||||
| const JackPortType gMidiPortType = | const JackPortType gMidiPortType = | ||||
| { | |||||
| JACK_DEFAULT_MIDI_TYPE, | |||||
| MidiBufferInit, | |||||
| MidiBufferMixdown | |||||
| }; | |||||
| { | |||||
| JACK_DEFAULT_MIDI_TYPE, | |||||
| MidiBufferSize, | |||||
| MidiBufferInit, | |||||
| MidiBufferMixdown | |||||
| }; | |||||
| } // namespace Jack | } // namespace Jack | ||||
| @@ -118,10 +118,10 @@ namespace Jack | |||||
| //init and restart-------------------------------------------------------------------- | //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. | as a "dummy driver, until Init method returns. | ||||
| */ | */ | ||||
| bool JackNetDriver::Initialize() | bool JackNetDriver::Initialize() | ||||
| { | { | ||||
| jack_log("JackNetDriver::Initialize()"); | jack_log("JackNetDriver::Initialize()"); | ||||
| @@ -221,7 +221,7 @@ namespace Jack | |||||
| void JackNetDriver::FreeAll() | void JackNetDriver::FreeAll() | ||||
| { | { | ||||
| FreePorts(); | FreePorts(); | ||||
| delete[] fTxBuffer; | delete[] fTxBuffer; | ||||
| delete[] fRxBuffer; | delete[] fRxBuffer; | ||||
| delete fNetAudioCaptureBuffer; | delete fNetAudioCaptureBuffer; | ||||
| @@ -230,7 +230,7 @@ namespace Jack | |||||
| delete fNetMidiPlaybackBuffer; | delete fNetMidiPlaybackBuffer; | ||||
| delete[] fMidiCapturePortList; | delete[] fMidiCapturePortList; | ||||
| delete[] fMidiPlaybackPortList; | delete[] fMidiPlaybackPortList; | ||||
| fTxBuffer = NULL; | fTxBuffer = NULL; | ||||
| fRxBuffer = NULL; | fRxBuffer = NULL; | ||||
| fNetAudioCaptureBuffer = NULL; | fNetAudioCaptureBuffer = NULL; | ||||
| @@ -239,7 +239,7 @@ namespace Jack | |||||
| fNetMidiPlaybackBuffer = NULL; | fNetMidiPlaybackBuffer = NULL; | ||||
| fMidiCapturePortList = NULL; | fMidiCapturePortList = NULL; | ||||
| fMidiPlaybackPortList = NULL; | fMidiPlaybackPortList = NULL; | ||||
| #ifdef JACK_MONITOR | #ifdef JACK_MONITOR | ||||
| delete fNetTimeMon; | delete fNetTimeMon; | ||||
| fNetTimeMon = NULL; | fNetTimeMon = NULL; | ||||
| @@ -258,6 +258,7 @@ namespace Jack | |||||
| unsigned long port_flags; | unsigned long port_flags; | ||||
| int audio_port_index; | int audio_port_index; | ||||
| uint midi_port_index; | uint midi_port_index; | ||||
| jack_latency_range_t range; | |||||
| //audio | //audio | ||||
| port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; | port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; | ||||
| @@ -274,7 +275,8 @@ namespace Jack | |||||
| port = fGraphManager->GetPort ( port_id ); | port = fGraphManager->GetPort ( port_id ); | ||||
| port->SetAlias ( alias ); | port->SetAlias ( alias ); | ||||
| //port latency | //port latency | ||||
| port->SetLatency ( fEngineControl->fBufferSize ); | |||||
| range.min = range.max = fEngineControl->fBufferSize; | |||||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||||
| fCapturePortList[audio_port_index] = port_id; | 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() ); | 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 ) | switch ( fParams.fNetworkMode ) | ||||
| { | { | ||||
| case 'f' : | case 'f' : | ||||
| port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||||
| range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize; | |||||
| break; | break; | ||||
| case 'n' : | case 'n' : | ||||
| port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||||
| range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||||
| break; | break; | ||||
| case 's' : | 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; | break; | ||||
| } | } | ||||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||||
| fPlaybackPortList[audio_port_index] = port_id; | 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() ); | 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 = fGraphManager->GetPort ( port_id ); | ||||
| //port latency | //port latency | ||||
| port->SetLatency ( fEngineControl->fBufferSize ); | |||||
| range.min = range.max = fEngineControl->fBufferSize; | |||||
| port->SetLatencyRange(JackCaptureLatency, &range); | |||||
| fMidiCapturePortList[midi_port_index] = port_id; | 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() ); | 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 ) | switch ( fParams.fNetworkMode ) | ||||
| { | { | ||||
| case 'f' : | case 'f' : | ||||
| port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||||
| range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize; | |||||
| break; | break; | ||||
| case 'n' : | case 'n' : | ||||
| port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ; | |||||
| range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||||
| break; | break; | ||||
| case 's' : | 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; | break; | ||||
| } | } | ||||
| port->SetLatencyRange(JackPlaybackLatency, &range); | |||||
| fMidiPlaybackPortList[midi_port_index] = port_id; | 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() ); | 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 ? | //is there a transport state change to handle ? | ||||
| if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) ) | if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) ) | ||||
| { | { | ||||
| switch ( fSendTransportData.fState ) | switch ( fSendTransportData.fState ) | ||||
| { | { | ||||
| case JackTransportStopped : | case JackTransportStopped : | ||||
| @@ -458,13 +463,13 @@ namespace Jack | |||||
| else | else | ||||
| fReturnTransportData.fTimebaseMaster = NO_CHANGE; | fReturnTransportData.fTimebaseMaster = NO_CHANGE; | ||||
| */ | */ | ||||
| //update transport state and position | //update transport state and position | ||||
| fReturnTransportData.fState = fEngineControl->fTransport.Query ( &fReturnTransportData.fPosition ); | fReturnTransportData.fState = fEngineControl->fTransport.Query ( &fReturnTransportData.fPosition ); | ||||
| //is it a new state (that the master need to know...) ? | //is it a new state (that the master need to know...) ? | ||||
| fReturnTransportData.fNewState = (( fReturnTransportData.fState == JackTransportNetStarting) && | fReturnTransportData.fNewState = (( fReturnTransportData.fState == JackTransportNetStarting) && | ||||
| ( fReturnTransportData.fState != fLastTransportState ) && | |||||
| ( fReturnTransportData.fState != fLastTransportState ) && | |||||
| ( fReturnTransportData.fState != fSendTransportData.fState ) ); | ( fReturnTransportData.fState != fSendTransportData.fState ) ); | ||||
| if ( fReturnTransportData.fNewState ) | if ( fReturnTransportData.fNewState ) | ||||
| jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) ); | jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) ); | ||||
| @@ -492,14 +497,14 @@ namespace Jack | |||||
| return 0; | return 0; | ||||
| #ifdef JACK_MONITOR | #ifdef JACK_MONITOR | ||||
| // For timing | |||||
| // For timing | |||||
| fRcvSyncUst = GetMicroSeconds(); | fRcvSyncUst = GetMicroSeconds(); | ||||
| #endif | #endif | ||||
| //decode sync | //decode sync | ||||
| //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified | //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified | ||||
| DecodeSyncPacket(); | DecodeSyncPacket(); | ||||
| #ifdef JACK_MONITOR | #ifdef JACK_MONITOR | ||||
| fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - fRcvSyncUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f ); | fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - fRcvSyncUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f ); | ||||
| #endif | #endif | ||||
| @@ -534,7 +539,7 @@ namespace Jack | |||||
| //sync | //sync | ||||
| EncodeSyncPacket(); | EncodeSyncPacket(); | ||||
| //send sync | //send sync | ||||
| if ( SyncSend() == SOCKET_ERROR ) | if ( SyncSend() == SOCKET_ERROR ) | ||||
| return SOCKET_ERROR; | return SOCKET_ERROR; | ||||
| @@ -134,7 +134,7 @@ namespace Jack | |||||
| if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0) | if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0) | ||||
| goto fail; | goto fail; | ||||
| if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) | if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) | ||||
| goto fail; | goto fail; | ||||
| @@ -153,7 +153,7 @@ namespace Jack | |||||
| jack_error ( "Can't activate jack client." ); | jack_error ( "Can't activate jack client." ); | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| if (auto_connect) | if (auto_connect) | ||||
| ConnectPorts(); | ConnectPorts(); | ||||
| jack_info ( "New NetMaster started." ); | jack_info ( "New NetMaster started." ); | ||||
| @@ -172,7 +172,8 @@ namespace Jack | |||||
| uint i; | uint i; | ||||
| char name[24]; | char name[24]; | ||||
| jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); | jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); | ||||
| jack_latency_range_t range; | |||||
| jack_log ( "JackNetMaster::AllocPorts" ); | jack_log ( "JackNetMaster::AllocPorts" ); | ||||
| //audio | //audio | ||||
| @@ -182,9 +183,10 @@ namespace Jack | |||||
| if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | ||||
| return -1; | return -1; | ||||
| //port latency | //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++ ) | for ( i = 0; i < fParams.fReturnAudioChannels; i++ ) | ||||
| { | { | ||||
| sprintf ( name, "from_slave_%d", i+1 ); | sprintf ( name, "from_slave_%d", i+1 ); | ||||
| @@ -194,17 +196,20 @@ namespace Jack | |||||
| switch ( fParams.fNetworkMode ) | switch ( fParams.fNetworkMode ) | ||||
| { | { | ||||
| case 'f' : | 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; | break; | ||||
| case 'n' : | 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; | break; | ||||
| case 's' : | 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; | break; | ||||
| } | } | ||||
| } | } | ||||
| //midi | //midi | ||||
| for ( i = 0; i < fParams.fSendMidiChannels; i++ ) | 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 ) | if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | ||||
| return -1; | return -1; | ||||
| //port latency | //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++ ) | for ( i = 0; i < fParams.fReturnMidiChannels; i++ ) | ||||
| { | { | ||||
| @@ -223,23 +229,26 @@ namespace Jack | |||||
| switch ( fParams.fNetworkMode ) | switch ( fParams.fNetworkMode ) | ||||
| { | { | ||||
| case 'f' : | 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; | break; | ||||
| case 'n' : | 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; | break; | ||||
| case 's' : | 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; | break; | ||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| void JackNetMaster::ConnectPorts() | void JackNetMaster::ConnectPorts() | ||||
| { | { | ||||
| const char **ports; | const char **ports; | ||||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | ||||
| if (ports != NULL) { | if (ports != NULL) { | ||||
| for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { | for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { | ||||
| @@ -247,7 +256,7 @@ namespace Jack | |||||
| } | } | ||||
| free(ports); | free(ports); | ||||
| } | } | ||||
| ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | ||||
| if (ports != NULL) { | if (ports != NULL) { | ||||
| for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { | for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { | ||||
| @@ -309,7 +318,7 @@ namespace Jack | |||||
| else | else | ||||
| jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName ); | jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName ); | ||||
| break; | break; | ||||
| case TIMEBASEMASTER : | case TIMEBASEMASTER : | ||||
| timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this ); | timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this ); | ||||
| if ( timebase < 0 ) | if ( timebase < 0 ) | ||||
| @@ -317,7 +326,7 @@ namespace Jack | |||||
| else | else | ||||
| jack_info ( "'%s' is the new timebase master.", fParams.fName ); | jack_info ( "'%s' is the new timebase master.", fParams.fName ); | ||||
| break; | break; | ||||
| case CONDITIONAL_TIMEBASEMASTER : | case CONDITIONAL_TIMEBASEMASTER : | ||||
| timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this ); | timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this ); | ||||
| if ( timebase != EBUSY ) | if ( timebase != EBUSY ) | ||||
| @@ -340,18 +349,18 @@ namespace Jack | |||||
| jack_transport_stop ( fJackClient ); | jack_transport_stop ( fJackClient ); | ||||
| jack_info ( "'%s' stops transport.", fParams.fName ); | jack_info ( "'%s' stops transport.", fParams.fName ); | ||||
| break; | break; | ||||
| case JackTransportStarting : | case JackTransportStarting : | ||||
| if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL ) | if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL ) | ||||
| jack_error ( "Can't set new position." ); | jack_error ( "Can't set new position." ); | ||||
| jack_transport_start ( fJackClient ); | jack_transport_start ( fJackClient ); | ||||
| jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); | jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); | ||||
| break; | break; | ||||
| case JackTransportNetStarting : | case JackTransportNetStarting : | ||||
| jack_info ( "'%s' is ready to roll..", fParams.fName ); | jack_info ( "'%s' is ready to roll..", fParams.fName ); | ||||
| break; | break; | ||||
| case JackTransportRolling : | case JackTransportRolling : | ||||
| jack_info ( "'%s' is rolling.", fParams.fName ); | jack_info ( "'%s' is rolling.", fParams.fName ); | ||||
| break; | break; | ||||
| @@ -377,16 +386,19 @@ namespace Jack | |||||
| } | } | ||||
| //sync-------------------------------------------------------------------------------- | //sync-------------------------------------------------------------------------------- | ||||
| bool JackNetMaster::IsSlaveReadyToRoll() | bool JackNetMaster::IsSlaveReadyToRoll() | ||||
| { | { | ||||
| return ( fReturnTransportData.fState == JackTransportNetStarting ); | 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; | return 0; | ||||
| } | } | ||||
| @@ -424,10 +436,10 @@ namespace Jack | |||||
| fParams.fPeriodSize ) ) ); | fParams.fPeriodSize ) ) ); | ||||
| if (IsSynched()) { // only send if connection is "synched" | if (IsSynched()) { // only send if connection is "synched" | ||||
| //encode the first packet | //encode the first packet | ||||
| EncodeSyncPacket(); | EncodeSyncPacket(); | ||||
| //send sync | //send sync | ||||
| if ( SyncSend() == SOCKET_ERROR ) | if ( SyncSend() == SOCKET_ERROR ) | ||||
| return SOCKET_ERROR; | return SOCKET_ERROR; | ||||
| @@ -443,7 +455,7 @@ namespace Jack | |||||
| #ifdef JACK_MONITOR | #ifdef JACK_MONITOR | ||||
| fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f ); | fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f ); | ||||
| #endif | #endif | ||||
| } else { | } else { | ||||
| jack_error("Connection is not synched, skip cycle..."); | jack_error("Connection is not synched, skip cycle..."); | ||||
| } | } | ||||
| @@ -459,7 +471,7 @@ namespace Jack | |||||
| //decode sync | //decode sync | ||||
| DecodeSyncPacket(); | DecodeSyncPacket(); | ||||
| //receive data | //receive data | ||||
| res = DataRecv(); | res = DataRecv(); | ||||
| if ( ( res == 0 ) || ( res == SOCKET_ERROR ) ) | if ( ( res == 0 ) || ( res == SOCKET_ERROR ) ) | ||||
| @@ -498,11 +510,11 @@ namespace Jack | |||||
| else | else | ||||
| jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP); | jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP); | ||||
| break; | break; | ||||
| case 'p': | case 'p': | ||||
| fSocket.SetPort ( param->value.ui ); | fSocket.SetPort ( param->value.ui ); | ||||
| break; | break; | ||||
| case 'c': | case 'c': | ||||
| fAutoConnect = param->value.i; | fAutoConnect = param->value.i; | ||||
| break; | break; | ||||
| @@ -646,7 +658,7 @@ namespace Jack | |||||
| JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params ) | JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params ) | ||||
| { | { | ||||
| jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName ); | jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName ); | ||||
| //check MASTER <<==> SLAVE network protocol coherency | //check MASTER <<==> SLAVE network protocol coherency | ||||
| if (params.fProtocolVersion != MASTER_PROTOCOL) { | if (params.fProtocolVersion != MASTER_PROTOCOL) { | ||||
| jack_error ( "Error : slave is running with a different protocol %s", params.fName ); | 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; | desc->params[i].value.i = DEFAULT_PORT; | ||||
| strcpy ( desc->params[i].short_desc, "UDP port" ); | strcpy ( desc->params[i].short_desc, "UDP port" ); | ||||
| strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | ||||
| i++; | i++; | ||||
| strcpy ( desc->params[i].name, "auto_connect" ); | strcpy ( desc->params[i].name, "auto_connect" ); | ||||
| desc->params[i].character = 'c'; | desc->params[i].character = 'c'; | ||||
| @@ -54,7 +54,7 @@ namespace Jack | |||||
| //sync and transport | //sync and transport | ||||
| int fLastTransportState; | int fLastTransportState; | ||||
| //monitoring | //monitoring | ||||
| #ifdef JACK_MONITOR | #ifdef JACK_MONITOR | ||||
| jack_time_t fPeriodUsecs; | jack_time_t fPeriodUsecs; | ||||
| @@ -64,7 +64,7 @@ namespace Jack | |||||
| bool Init(bool auto_connect); | bool Init(bool auto_connect); | ||||
| int AllocPorts(); | int AllocPorts(); | ||||
| void FreePorts(); | void FreePorts(); | ||||
| //transport | //transport | ||||
| void EncodeTransportData(); | void EncodeTransportData(); | ||||
| void DecodeTransportData(); | void DecodeTransportData(); | ||||
| @@ -98,7 +98,7 @@ namespace Jack | |||||
| const char* fManagerName; | const char* fManagerName; | ||||
| char fMulticastIP[32]; | char fMulticastIP[32]; | ||||
| JackNetSocket fSocket; | JackNetSocket fSocket; | ||||
| pthread_t fManagerThread; | |||||
| jack_native_thread_t fManagerThread; | |||||
| master_list_t fMasterList; | master_list_t fMasterList; | ||||
| uint32_t fGlobalID; | uint32_t fGlobalID; | ||||
| bool fRunning; | bool fRunning; | ||||
| @@ -34,45 +34,47 @@ namespace Jack | |||||
| class JackNetOneDriver : public JackAudioDriver | class JackNetOneDriver : public JackAudioDriver | ||||
| { | { | ||||
| private: | 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: | 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 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, | 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 ); | const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency ); | ||||
| int Close(); | |||||
| int Close(); | |||||
| int Attach(); | int Attach(); | ||||
| int Detach(); | int Detach(); | ||||
| int Read(); | int Read(); | ||||
| int Write(); | int Write(); | ||||
| bool Initialize(); | |||||
| int AllocPorts(); | |||||
| void FreePorts(); | |||||
| bool Initialize(); | |||||
| int AllocPorts(); | |||||
| void FreePorts(); | |||||
| // BufferSize can't be changed | // BufferSize can't be changed | ||||
| bool IsFixedBufferSize() | bool IsFixedBufferSize() | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -46,6 +46,7 @@ enum NotificationType { | |||||
| kShutDownCallback = 15, | kShutDownCallback = 15, | ||||
| kQUIT = 16, | kQUIT = 16, | ||||
| kSessionCallback = 17, | kSessionCallback = 17, | ||||
| kLatencyCallback = 18, | |||||
| kMaxNotification | kMaxNotification | ||||
| }; | }; | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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; | fInUse = true; | ||||
| fLatency = 0; | fLatency = 0; | ||||
| fTotalLatency = 0; | fTotalLatency = 0; | ||||
| fPlaybackLatency.min = fPlaybackLatency.max = 0; | |||||
| fCaptureLatency.min = fCaptureLatency.max = 0; | |||||
| fTied = NO_PORT; | fTied = NO_PORT; | ||||
| // DB: At this point we do not know current buffer size in frames, | // DB: At this point we do not know current buffer size in frames, | ||||
| // but every time buffer will be returned to any user, | // 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) | void JackPort::SetLatency(jack_nframes_t nframes) | ||||
| { | { | ||||
| fLatency = 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) | int JackPort::Tie(jack_port_id_t port_index) | ||||
| @@ -103,10 +147,10 @@ int JackPort::UnTie() | |||||
| int JackPort::RequestMonitor(bool onoff) | int JackPort::RequestMonitor(bool onoff) | ||||
| { | { | ||||
| /** | /** | ||||
| jackd.h | |||||
| jackd.h | |||||
| * If @ref JackPortCanMonitor is set for this @a port, turn input | * If @ref JackPortCanMonitor is set for this @a port, turn input | ||||
| * monitoring on or off. Otherwise, do nothing. | * monitoring on or off. Otherwise, do nothing. | ||||
| if (!(fFlags & JackPortCanMonitor)) | if (!(fFlags & JackPortCanMonitor)) | ||||
| return -1; | return -1; | ||||
| */ | */ | ||||
| @@ -123,10 +167,10 @@ int JackPort::RequestMonitor(bool onoff) | |||||
| int JackPort::EnsureMonitor(bool onoff) | int JackPort::EnsureMonitor(bool onoff) | ||||
| { | { | ||||
| /** | /** | ||||
| jackd.h | |||||
| jackd.h | |||||
| * If @ref JackPortCanMonitor is set for this @a port, turn input | * If @ref JackPortCanMonitor is set for this @a port, turn input | ||||
| * monitoring on or off. Otherwise, do nothing. | * monitoring on or off. Otherwise, do nothing. | ||||
| if (!(fFlags & JackPortCanMonitor)) | if (!(fFlags & JackPortCanMonitor)) | ||||
| return -1; | return -1; | ||||
| */ | */ | ||||
| @@ -165,7 +209,7 @@ int JackPort::GetFlags() const | |||||
| const char* JackPort::GetType() const | const char* JackPort::GetType() const | ||||
| { | { | ||||
| const JackPortType* type = GetPortType(fTypeId); | const JackPortType* type = GetPortType(fTypeId); | ||||
| return type->name; | |||||
| return type->fName; | |||||
| } | } | ||||
| void JackPort::SetName(const char* new_name) | 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 fLatency; | ||||
| jack_nframes_t fTotalLatency; | jack_nframes_t fTotalLatency; | ||||
| jack_latency_range_t fPlaybackLatency; | |||||
| jack_latency_range_t fCaptureLatency; | |||||
| uint8_t fMonitorRequests; | uint8_t fMonitorRequests; | ||||
| bool fInUse; | bool fInUse; | ||||
| jack_port_id_t fTied; // Locally tied source port | jack_port_id_t fTied; // Locally tied source port | ||||
| float fBuffer[BUFFER_SIZE_MAX + 4]; | float fBuffer[BUFFER_SIZE_MAX + 4]; | ||||
| bool IsUsed() const | bool IsUsed() const | ||||
| { | { | ||||
| return fInUse; | return fInUse; | ||||
| @@ -88,9 +90,13 @@ class SERVER_EXPORT JackPort | |||||
| int UnTie(); | int UnTie(); | ||||
| jack_nframes_t GetLatency() const; | jack_nframes_t GetLatency() const; | ||||
| jack_nframes_t GetTotalLatency() const; | |||||
| void SetLatency(jack_nframes_t latency); | 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 RequestMonitor(bool onoff); | ||||
| int EnsureMonitor(bool onoff); | int EnsureMonitor(bool onoff); | ||||
| bool MonitoringInput() | bool MonitoringInput() | ||||
| @@ -105,7 +111,7 @@ class SERVER_EXPORT JackPort | |||||
| } | } | ||||
| int GetRefNum() const; | int GetRefNum() const; | ||||
| } POST_PACKED_STRUCTURE; | } POST_PACKED_STRUCTURE; | ||||
| } // end of namespace | } // end of namespace | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 | namespace Jack | ||||
| { | { | ||||
| static const JackPortType* port_types[] = | |||||
| static const JackPortType* gPortTypes[] = | |||||
| { | { | ||||
| &gAudioPortType, | &gAudioPortType, | ||||
| &gMidiPortType, | &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) | jack_port_type_id_t GetPortTypeId(const char* port_type) | ||||
| { | { | ||||
| for (jack_port_type_id_t i = 0; i < PORT_TYPES_MAX; ++i) { | 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); | assert(type != 0); | ||||
| if (strcmp(port_type, type->name) == 0) | |||||
| if (strcmp(port_type, type->fName) == 0) | |||||
| return i; | return i; | ||||
| } | } | ||||
| return PORT_TYPES_MAX; | 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) | const JackPortType* GetPortType(jack_port_type_id_t type_id) | ||||
| { | { | ||||
| assert(type_id >= 0 && type_id <= PORT_TYPES_MAX); | 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); | assert(type != 0); | ||||
| return type; | return type; | ||||
| } | } | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 | struct JackPortType | ||||
| { | { | ||||
| const char* name; | |||||
| const char* fName; | |||||
| size_t (*size)(); | |||||
| void (*init)(void* buffer, size_t buffer_size, jack_nframes_t nframes); | 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); | 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -71,7 +71,9 @@ struct JackRequest | |||||
| kSessionReply = 34, | kSessionReply = 34, | ||||
| kGetClientByUUID = 35, | kGetClientByUUID = 35, | ||||
| kReserveClientName = 36, | kReserveClientName = 36, | ||||
| kGetUUIDByClient = 37 | |||||
| kGetUUIDByClient = 37, | |||||
| kClientHasSessionCallback = 38, | |||||
| kComputeTotalLatencies = 39 | |||||
| }; | }; | ||||
| RequestType fType; | RequestType fType; | ||||
| @@ -122,7 +124,7 @@ struct JackResult | |||||
| { | { | ||||
| return trans->Write(&fResult, sizeof(int)); | return trans->Write(&fResult, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -161,7 +163,7 @@ struct JackClientCheckRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fOptions, sizeof(int))); | CheckRes(trans->Write(&fOptions, sizeof(int))); | ||||
| return trans->Write(&fUUID, sizeof(int)); | return trans->Write(&fUUID, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -197,7 +199,7 @@ struct JackClientCheckResult : public JackResult | |||||
| CheckRes(trans->Write(&fStatus, sizeof(int))); | CheckRes(trans->Write(&fStatus, sizeof(int))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -210,7 +212,7 @@ struct JackClientOpenRequest : public JackRequest | |||||
| int fPID; | int fPID; | ||||
| int fUUID; | int fUUID; | ||||
| char fName[JACK_CLIENT_NAME_SIZE + 1]; | char fName[JACK_CLIENT_NAME_SIZE + 1]; | ||||
| JackClientOpenRequest() | JackClientOpenRequest() | ||||
| {} | {} | ||||
| JackClientOpenRequest(const char* name, int pid, int uuid): JackRequest(JackRequest::kClientOpen) | 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))); | CheckRes(trans->Write(&fUUID, sizeof(int))); | ||||
| return trans->Write(&fName, sizeof(fName)); | return trans->Write(&fName, sizeof(fName)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -247,7 +249,7 @@ struct JackClientOpenResult : public JackResult | |||||
| int fSharedEngine; | int fSharedEngine; | ||||
| int fSharedClient; | int fSharedClient; | ||||
| int fSharedGraph; | int fSharedGraph; | ||||
| JackClientOpenResult() | JackClientOpenResult() | ||||
| : JackResult(), fSharedEngine(-1), fSharedClient(-1), fSharedGraph(-1) | : JackResult(), fSharedEngine(-1), fSharedClient(-1), fSharedGraph(-1) | ||||
| {} | {} | ||||
| @@ -272,7 +274,7 @@ struct JackClientOpenResult : public JackResult | |||||
| CheckRes(trans->Write(&fSharedGraph, sizeof(int))); | CheckRes(trans->Write(&fSharedGraph, sizeof(int))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -299,7 +301,7 @@ struct JackClientCloseRequest : public JackRequest | |||||
| CheckRes(JackRequest::Write(trans)); | CheckRes(JackRequest::Write(trans)); | ||||
| return trans->Write(&fRefNum, sizeof(int)); | return trans->Write(&fRefNum, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -402,7 +404,7 @@ struct JackPortRegisterRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int))); | CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -428,7 +430,7 @@ struct JackPortRegisterResult : public JackResult | |||||
| CheckRes(JackResult::Write(trans)); | CheckRes(JackResult::Write(trans)); | ||||
| return trans->Write(&fPortIndex, sizeof(jack_port_id_t)); | 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))); | CheckRes(trans->Write(&fPortIndex, sizeof(jack_port_id_t))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -501,7 +503,7 @@ struct JackPortConnectNameRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fDst, sizeof(fDst))); | CheckRes(trans->Write(&fDst, sizeof(fDst))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -540,7 +542,7 @@ struct JackPortDisconnectNameRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fDst, sizeof(fDst))); | CheckRes(trans->Write(&fDst, sizeof(fDst))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -576,7 +578,7 @@ struct JackPortConnectRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -612,7 +614,7 @@ struct JackPortDisconnectRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -651,7 +653,7 @@ struct JackPortRenameRequest : public JackRequest | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -679,7 +681,7 @@ struct JackSetBufferSizeRequest : public JackRequest | |||||
| CheckRes(JackRequest::Write(trans)); | CheckRes(JackRequest::Write(trans)); | ||||
| return trans->Write(&fBufferSize, sizeof(jack_nframes_t)); | return trans->Write(&fBufferSize, sizeof(jack_nframes_t)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -707,7 +709,31 @@ struct JackSetFreeWheelRequest : public JackRequest | |||||
| CheckRes(JackRequest::Write(trans)); | CheckRes(JackRequest::Write(trans)); | ||||
| return trans->Write(&fOnOff, sizeof(int)); | 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)); | CheckRes(JackRequest::Write(trans)); | ||||
| return trans->Write(&fRefNum, sizeof(int)); | return trans->Write(&fRefNum, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -766,7 +792,7 @@ struct JackSetTimebaseCallbackRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fRefNum, sizeof(int))); | CheckRes(trans->Write(&fRefNum, sizeof(int))); | ||||
| return trans->Write(&fConditionnal, sizeof(int)); | return trans->Write(&fConditionnal, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -797,7 +823,7 @@ struct JackGetInternalClientNameRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fRefNum, sizeof(int))); | CheckRes(trans->Write(&fRefNum, sizeof(int))); | ||||
| return trans->Write(&fIntRefNum, sizeof(int)); | return trans->Write(&fIntRefNum, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -830,7 +856,7 @@ struct JackGetInternalClientNameResult : public JackResult | |||||
| CheckRes(trans->Write(&fName, sizeof(fName))); | CheckRes(trans->Write(&fName, sizeof(fName))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -863,7 +889,7 @@ struct JackInternalClientHandleRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fRefNum, sizeof(int))); | CheckRes(trans->Write(&fRefNum, sizeof(int))); | ||||
| return trans->Write(&fName, sizeof(fName)); | return trans->Write(&fName, sizeof(fName)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -897,7 +923,7 @@ struct JackInternalClientHandleResult : public JackResult | |||||
| CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -949,7 +975,7 @@ struct JackInternalClientLoadRequest : public JackRequest | |||||
| CheckRes(trans->Write(&fUUID, sizeof(int))); | CheckRes(trans->Write(&fUUID, sizeof(int))); | ||||
| return trans->Write(&fOptions, sizeof(int)); | return trans->Write(&fOptions, sizeof(int)); | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -983,7 +1009,7 @@ struct JackInternalClientLoadResult : public JackResult | |||||
| CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -1044,7 +1070,7 @@ struct JackInternalClientUnloadResult : public JackResult | |||||
| CheckRes(trans->Write(&fStatus, sizeof(int))); | CheckRes(trans->Write(&fStatus, sizeof(int))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -1147,7 +1173,7 @@ struct JackSessionNotifyResult : public JackResult | |||||
| CheckRes(trans->Write(terminator, sizeof(terminator))); | CheckRes(trans->Write(terminator, sizeof(terminator))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /*! | /*! | ||||
| @@ -1245,7 +1271,7 @@ struct JackClientNameResult : public JackResult | |||||
| CheckRes(trans->Write(&fName, sizeof(fName))); | CheckRes(trans->Write(&fName, sizeof(fName))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| struct JackUUIDResult : public JackResult | struct JackUUIDResult : public JackResult | ||||
| @@ -1274,7 +1300,7 @@ struct JackUUIDResult : public JackResult | |||||
| CheckRes(trans->Write(&fUUID, sizeof(fUUID))); | CheckRes(trans->Write(&fUUID, sizeof(fUUID))); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| }; | }; | ||||
| struct JackGetUUIDRequest : public JackRequest | 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. | \brief ClientNotification. | ||||
| */ | */ | ||||
| @@ -45,7 +45,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio | |||||
| } else { | } else { | ||||
| jack_info("JACK server starting in non-realtime mode"); | jack_info("JACK server starting in non-realtime mode"); | ||||
| } | } | ||||
| fGraphManager = JackGraphManager::Allocate(port_max); | fGraphManager = JackGraphManager::Allocate(port_max); | ||||
| fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); | fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); | ||||
| fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); | 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() | // TODO: move that in reworked JackServerGlobals::Init() | ||||
| JackMessageBuffer::Create(); | JackMessageBuffer::Create(); | ||||
| if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | ||||
| jack_error("Cannot initialize driver"); | jack_error("Cannot initialize driver"); | ||||
| goto fail_close1; | goto fail_close1; | ||||
| } | } | ||||
| if (fChannel.Open(fEngineControl->fServerName, this) < 0) { | if (fChannel.Open(fEngineControl->fServerName, this) < 0) { | ||||
| jack_error("Server channel open error"); | jack_error("Server channel open error"); | ||||
| goto fail_close2; | goto fail_close2; | ||||
| } | } | ||||
| if (fEngine->Open() < 0) { | if (fEngine->Open() < 0) { | ||||
| jack_error("Cannot open engine"); | jack_error("Cannot open engine"); | ||||
| goto fail_close3; | goto fail_close3; | ||||
| @@ -92,12 +92,12 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||||
| jack_error("Cannot open driver"); | jack_error("Cannot open driver"); | ||||
| goto fail_close4; | goto fail_close4; | ||||
| } | } | ||||
| if (fAudioDriver->Attach() < 0) { | if (fAudioDriver->Attach() < 0) { | ||||
| jack_error("Cannot attach audio driver"); | jack_error("Cannot attach audio driver"); | ||||
| goto fail_close5; | goto fail_close5; | ||||
| } | } | ||||
| fFreewheelDriver->SetMaster(false); | fFreewheelDriver->SetMaster(false); | ||||
| fAudioDriver->SetMaster(true); | fAudioDriver->SetMaster(true); | ||||
| fAudioDriver->AddSlave(fFreewheelDriver); // After ??? | fAudioDriver->AddSlave(fFreewheelDriver); // After ??? | ||||
| @@ -113,11 +113,11 @@ fail_close4: | |||||
| fail_close3: | fail_close3: | ||||
| fChannel.Close(); | fChannel.Close(); | ||||
| fail_close2: | |||||
| fail_close2: | |||||
| fAudioDriver->Close(); | fAudioDriver->Close(); | ||||
| fail_close1: | |||||
| fail_close1: | |||||
| JackMessageBuffer::Destroy(); | JackMessageBuffer::Destroy(); | ||||
| return -1; | 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"); | jack_log("SetBufferSize: requirement for new buffer size equals current value"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (fAudioDriver->IsFixedBufferSize()) { | if (fAudioDriver->IsFixedBufferSize()) { | ||||
| jack_log("SetBufferSize: driver only supports a fixed buffer size"); | jack_log("SetBufferSize: driver only supports a fixed buffer size"); | ||||
| return -1; | return -1; | ||||
| @@ -316,37 +316,37 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par | |||||
| fAudioDriver->Stop(); | fAudioDriver->Stop(); | ||||
| fAudioDriver->Detach(); | fAudioDriver->Detach(); | ||||
| fAudioDriver->Close(); | fAudioDriver->Close(); | ||||
| // Open new master | // Open new master | ||||
| JackDriverInfo* info = new JackDriverInfo(); | JackDriverInfo* info = new JackDriverInfo(); | ||||
| JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | ||||
| if (master == NULL || info == NULL) { | if (master == NULL || info == NULL) { | ||||
| delete info; | delete info; | ||||
| delete master; | delete master; | ||||
| return -1; | return -1; | ||||
| } else { | } else { | ||||
| // Get slaves list | // Get slaves list | ||||
| std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); | std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); | ||||
| std::list<JackDriverInterface*>::const_iterator it; | std::list<JackDriverInterface*>::const_iterator it; | ||||
| // Move slaves in new master | // Move slaves in new master | ||||
| for (it = slave_list.begin(); it != slave_list.end(); it++) { | for (it = slave_list.begin(); it != slave_list.end(); it++) { | ||||
| JackDriverInterface* slave = *it; | JackDriverInterface* slave = *it; | ||||
| master->AddSlave(slave); | master->AddSlave(slave); | ||||
| } | } | ||||
| // Delete old master | // Delete old master | ||||
| delete fAudioDriver; | delete fAudioDriver; | ||||
| delete fDriverInfo; | delete fDriverInfo; | ||||
| // Activate master | // Activate master | ||||
| fAudioDriver = master; | fAudioDriver = master; | ||||
| fDriverInfo = info; | fDriverInfo = info; | ||||
| fAudioDriver->Attach(); | fAudioDriver->Attach(); | ||||
| fAudioDriver->SetMaster(true); | fAudioDriver->SetMaster(true); | ||||
| return fAudioDriver->Start(); | |||||
| return fAudioDriver->Start(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -28,8 +28,10 @@ static char* server_name = NULL; | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| JackServer* JackServerGlobals::fInstance; | |||||
| JackServer* JackServerGlobals::fInstance; | |||||
| unsigned int JackServerGlobals::fUserCount; | unsigned int JackServerGlobals::fUserCount; | ||||
| int JackServerGlobals::fRTNotificationSocket; | |||||
| bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; | bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; | ||||
| void (* JackServerGlobals::on_device_release)(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; | int argc = 0; | ||||
| char* argv[32]; | char* argv[32]; | ||||
| jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; | jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; | ||||
| // First user starts the server | // First user starts the server | ||||
| if (fUserCount++ == 0) { | if (fUserCount++ == 0) { | ||||
| @@ -158,7 +160,7 @@ bool JackServerGlobals::Init() | |||||
| (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { | (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { | ||||
| switch (opt) { | switch (opt) { | ||||
| case 'c': | case 'c': | ||||
| if (tolower (optarg[0]) == 'h') { | if (tolower (optarg[0]) == 'h') { | ||||
| clock_source = JACK_TIMER_HPET; | clock_source = JACK_TIMER_HPET; | ||||
| @@ -168,7 +170,7 @@ bool JackServerGlobals::Init() | |||||
| clock_source = JACK_TIMER_SYSTEM_CLOCK; | clock_source = JACK_TIMER_SYSTEM_CLOCK; | ||||
| } else { | } else { | ||||
| jack_error("unknown option character %c", optopt); | jack_error("unknown option character %c", optopt); | ||||
| } | |||||
| } | |||||
| break; | break; | ||||
| case 'd': | case 'd': | ||||
| @@ -38,9 +38,10 @@ struct SERVER_EXPORT JackServerGlobals | |||||
| { | { | ||||
| static JackServer* fInstance; | static JackServer* fInstance; | ||||
| static unsigned int fUserCount; | 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(); | ||||
| ~JackServerGlobals(); | ~JackServerGlobals(); | ||||
| @@ -1,21 +1,21 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2001 Paul Davis | Copyright (C) 2001 Paul Davis | ||||
| Copyright (C) 2004-2008 Grame | Copyright (C) 2004-2008 Grame | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| #ifndef __JackThread__ | #ifndef __JackThread__ | ||||
| @@ -26,23 +26,23 @@ | |||||
| namespace Jack | 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. | \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 | class JackRunnableInterface | ||||
| { | { | ||||
| protected: | protected: | ||||
| JackRunnableInterface() | JackRunnableInterface() | ||||
| {} | {} | ||||
| virtual ~JackRunnableInterface() | virtual ~JackRunnableInterface() | ||||
| {} | {} | ||||
| public: | public: | ||||
| virtual bool Init() /*! Called once when the thread is started */ | virtual bool Init() /*! Called once when the thread is started */ | ||||
| { | { | ||||
| return true; | return true; | ||||
| @@ -61,23 +61,23 @@ class SERVER_EXPORT JackThreadInterface | |||||
| { | { | ||||
| public: | public: | ||||
| enum kThreadState {kIdle, kStarting, kIniting, kRunning}; | enum kThreadState {kIdle, kStarting, kIniting, kRunning}; | ||||
| protected: | protected: | ||||
| JackRunnableInterface* fRunnable; | JackRunnableInterface* fRunnable; | ||||
| int fPriority; | int fPriority; | ||||
| bool fRealTime; | bool fRealTime; | ||||
| volatile kThreadState fStatus; | volatile kThreadState fStatus; | ||||
| int fCancellation; | int fCancellation; | ||||
| public: | public: | ||||
| JackThreadInterface(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation): | JackThreadInterface(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation): | ||||
| fRunnable(runnable), fPriority(priority), fRealTime(real_time), fStatus(kIdle), fCancellation(cancellation) | fRunnable(runnable), fPriority(priority), fRealTime(real_time), fStatus(kIdle), fCancellation(cancellation) | ||||
| {} | {} | ||||
| kThreadState GetStatus() | kThreadState GetStatus() | ||||
| { | { | ||||
| return fStatus; | return fStatus; | ||||
| @@ -86,10 +86,10 @@ class SERVER_EXPORT JackThreadInterface | |||||
| { | { | ||||
| fStatus = status; | fStatus = status; | ||||
| } | } | ||||
| void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX... | void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX... | ||||
| {} | {} | ||||
| int Start(); | int Start(); | ||||
| int StartSync(); | int StartSync(); | ||||
| int Kill(); | int Kill(); | ||||
| @@ -98,24 +98,24 @@ class SERVER_EXPORT JackThreadInterface | |||||
| int AcquireRealTime(); // Used when called from another thread | int AcquireRealTime(); // Used when called from another thread | ||||
| int AcquireSelfRealTime(); // Used when called from thread itself | int AcquireSelfRealTime(); // Used when called from thread itself | ||||
| int AcquireRealTime(int priority); // Used when called from another thread | int AcquireRealTime(int priority); // Used when called from another thread | ||||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | int AcquireSelfRealTime(int priority); // Used when called from thread itself | ||||
| int DropRealTime(); // Used when called from another thread | int DropRealTime(); // Used when called from another thread | ||||
| int DropSelfRealTime(); // Used when called from thread itself | int DropSelfRealTime(); // Used when called from thread itself | ||||
| pthread_t GetThreadID(); | |||||
| jack_native_thread_t GetThreadID(); | |||||
| bool IsThread(); | 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 | } // end of namespace | ||||
| @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
| #ifndef __JackTime__ | #ifndef __JackTime__ | ||||
| #define __JackTime__ | #define __JackTime__ | ||||
| #include "types.h" | |||||
| #include "JackCompilerDeps.h" | #include "JackCompilerDeps.h" | ||||
| #include "JackTypes.h" | #include "JackTypes.h" | ||||
| @@ -34,6 +34,12 @@ typedef signed long SInt32; | |||||
| #include "JackTypes_os.h" | #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 uint16_t jack_int_t; // Internal type for ports and refnum | ||||
| typedef enum { | typedef enum { | ||||
| @@ -33,7 +33,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #include "JackDriverLoader.h" | #include "JackDriverLoader.h" | ||||
| #if defined(JACK_DBUS) && defined(__linux__) | #if defined(JACK_DBUS) && defined(__linux__) | ||||
| #include <dbus/dbus.h> | |||||
| #include <dbus/dbus.h> | |||||
| #include "audio_reserve.h" | #include "audio_reserve.h" | ||||
| #endif | #endif | ||||
| @@ -85,7 +85,7 @@ static void copyright(FILE* file) | |||||
| { | { | ||||
| fprintf(file, "jackdmp " VERSION "\n" | fprintf(file, "jackdmp " VERSION "\n" | ||||
| "Copyright 2001-2005 Paul Davis and others.\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" | "jackdmp comes with ABSOLUTELY NO WARRANTY\n" | ||||
| "This is free software, and you are welcome to redistribute it\n" | "This is free software, and you are welcome to redistribute it\n" | ||||
| "under certain conditions; see the file COPYING for details\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" | " -d backend [ ... backend args ... ]\n" | ||||
| #ifdef __APPLE__ | #ifdef __APPLE__ | ||||
| " Available backends may include: coreaudio, dummy or net.\n\n" | " Available backends may include: coreaudio, dummy or net.\n\n" | ||||
| #endif | |||||
| #endif | |||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| " Available backends may include: portaudio, dummy or net.\n\n" | " Available backends may include: portaudio, dummy or net.\n\n" | ||||
| #endif | |||||
| #endif | |||||
| #ifdef __linux__ | #ifdef __linux__ | ||||
| " Available backends may include: alsa, dummy, freebob, firewire or net\n\n" | " Available backends may include: alsa, dummy, freebob, firewire or net\n\n" | ||||
| #endif | #endif | ||||
| @@ -178,13 +178,13 @@ int main(int argc, char* argv[]) | |||||
| jackctl_driver_t * midi_driver_ctl; | jackctl_driver_t * midi_driver_ctl; | ||||
| jackctl_driver_t * loopback_driver_ctl; | jackctl_driver_t * loopback_driver_ctl; | ||||
| int replace_registry = 0; | int replace_registry = 0; | ||||
| const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" | const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" | ||||
| #ifdef __linux__ | #ifdef __linux__ | ||||
| "c:" | "c:" | ||||
| #endif | #endif | ||||
| ; | ; | ||||
| struct option long_options[] = { | struct option long_options[] = { | ||||
| #ifdef __linux__ | #ifdef __linux__ | ||||
| { "clock-source", 1, 0, 'c' }, | { "clock-source", 1, 0, 'c' }, | ||||
| @@ -199,7 +199,7 @@ int main(int argc, char* argv[]) | |||||
| { "name", 1, 0, 'n' }, | { "name", 1, 0, 'n' }, | ||||
| { "unlock", 0, 0, 'u' }, | { "unlock", 0, 0, 'u' }, | ||||
| { "realtime", 0, 0, 'R' }, | { "realtime", 0, 0, 'R' }, | ||||
| { "no-realtime", 0, 0, 'r' }, | |||||
| { "no-realtime", 0, 0, 'r' }, | |||||
| { "replace-registry", 0, &replace_registry, 0 }, | { "replace-registry", 0, &replace_registry, 0 }, | ||||
| { "loopback", 0, 0, 'L' }, | { "loopback", 0, 0, 'L' }, | ||||
| { "realtime-priority", 1, 0, 'P' }, | { "realtime-priority", 1, 0, 'P' }, | ||||
| @@ -239,23 +239,23 @@ int main(int argc, char* argv[]) | |||||
| fprintf(stderr, "Failed to create server object\n"); | fprintf(stderr, "Failed to create server object\n"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| server_parameters = jackctl_server_get_parameters(server_ctl); | server_parameters = jackctl_server_get_parameters(server_ctl); | ||||
| // Default setting | // Default setting | ||||
| param = jackctl_get_parameter(server_parameters, "realtime"); | param = jackctl_get_parameter(server_parameters, "realtime"); | ||||
| if (param != NULL) { | if (param != NULL) { | ||||
| value.b = true; | value.b = true; | ||||
| jackctl_parameter_set_value(param, &value); | jackctl_parameter_set_value(param, &value); | ||||
| } | } | ||||
| opterr = 0; | opterr = 0; | ||||
| while (!seen_audio_driver && | while (!seen_audio_driver && | ||||
| (opt = getopt_long(argc, argv, options, | (opt = getopt_long(argc, argv, options, | ||||
| long_options, &option_index)) != EOF) { | long_options, &option_index)) != EOF) { | ||||
| switch (opt) { | switch (opt) { | ||||
| #ifdef __linux__ | |||||
| #ifdef __linux__ | |||||
| case 'c': | case 'c': | ||||
| param = jackctl_get_parameter(server_parameters, "clock-source"); | param = jackctl_get_parameter(server_parameters, "clock-source"); | ||||
| if (param != NULL) { | if (param != NULL) { | ||||
| @@ -280,7 +280,7 @@ int main(int argc, char* argv[]) | |||||
| seen_audio_driver = true; | seen_audio_driver = true; | ||||
| audio_driver_name = optarg; | audio_driver_name = optarg; | ||||
| break; | break; | ||||
| case 'L': | case 'L': | ||||
| loopback = atoi(optarg); | loopback = atoi(optarg); | ||||
| break; | break; | ||||
| @@ -342,7 +342,7 @@ int main(int argc, char* argv[]) | |||||
| jackctl_parameter_set_value(param, &value); | jackctl_parameter_set_value(param, &value); | ||||
| } | } | ||||
| break; | break; | ||||
| case 'r': | case 'r': | ||||
| param = jackctl_get_parameter(server_parameters, "realtime"); | param = jackctl_get_parameter(server_parameters, "realtime"); | ||||
| if (param != NULL) { | if (param != NULL) { | ||||
| @@ -388,14 +388,14 @@ int main(int argc, char* argv[]) | |||||
| goto fail_free1; | goto fail_free1; | ||||
| } | } | ||||
| } | } | ||||
| // Long option with no letter so treated separately | // Long option with no letter so treated separately | ||||
| param = jackctl_get_parameter(server_parameters, "replace-registry"); | param = jackctl_get_parameter(server_parameters, "replace-registry"); | ||||
| if (param != NULL) { | if (param != NULL) { | ||||
| value.b = replace_registry; | value.b = replace_registry; | ||||
| jackctl_parameter_set_value(param, &value); | jackctl_parameter_set_value(param, &value); | ||||
| } | } | ||||
| if (show_version) { | if (show_version) { | ||||
| printf( "jackdmp version " VERSION | printf( "jackdmp version " VERSION | ||||
| " tmpdir " jack_server_dir | " tmpdir " jack_server_dir | ||||
| @@ -441,7 +441,7 @@ int main(int argc, char* argv[]) | |||||
| // Setup signals then start server | // Setup signals then start server | ||||
| signals = jackctl_setup_signals(0); | signals = jackctl_setup_signals(0); | ||||
| if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { | if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { | ||||
| fprintf(stderr, "Failed to start server\n"); | fprintf(stderr, "Failed to start server\n"); | ||||
| goto fail_free1; | goto fail_free1; | ||||
| @@ -458,7 +458,7 @@ int main(int argc, char* argv[]) | |||||
| jackctl_server_add_slave(server_ctl, midi_driver_ctl); | jackctl_server_add_slave(server_ctl, midi_driver_ctl); | ||||
| } | } | ||||
| // Loopback driver | // Loopback driver | ||||
| if (loopback > 0) { | if (loopback > 0) { | ||||
| loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); | 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)) | if (!jackctl_server_stop(server_ctl)) | ||||
| fprintf(stderr, "Cannot stop server...\n"); | fprintf(stderr, "Cannot stop server...\n"); | ||||
| jackctl_server_destroy(server_ctl); | jackctl_server_destroy(server_ctl); | ||||
| notify_server_stop(server_name); | notify_server_stop(server_name); | ||||
| return 0; | return 0; | ||||
| @@ -488,7 +488,7 @@ int main(int argc, char* argv[]) | |||||
| fail_free1: | fail_free1: | ||||
| jackctl_server_destroy(server_ctl); | jackctl_server_destroy(server_ctl); | ||||
| return -1; | return -1; | ||||
| fail_free2: | fail_free2: | ||||
| jackctl_server_stop(server_ctl); | jackctl_server_stop(server_ctl); | ||||
| jackctl_server_destroy(server_ctl); | jackctl_server_destroy(server_ctl); | ||||
| @@ -1,19 +1,19 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2001 Paul Davis | Copyright (C) 2001 Paul Davis | ||||
| Copyright (C) 2004 Jack O'Quin | Copyright (C) 2004 Jack O'Quin | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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: More documentation can be found in jack/types.h. | ||||
| */ | */ | ||||
| /************************************************************* | /************************************************************* | ||||
| * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | ||||
| * added to the JACK API after the 0.116.2 release. | * 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 | * JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile | ||||
| * time in a variety of ways. The default definition is empty, | * time in a variety of ways. The default definition is empty, | ||||
| * so that these symbols get normal linkage. If you wish to | * 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. | * <jack/weakjack.h> before jack.h. | ||||
| *************************************************************/ | *************************************************************/ | ||||
| #include <jack/weakmacros.h> | #include <jack/weakmacros.h> | ||||
| /** | /** | ||||
| * Call this function to get version of the JACK, in form of several numbers | * 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 | * @return the pthread ID of the thread running the JACK client side | ||||
| * code. | * 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. | * Wait until this JACK client should process data. | ||||
| * | |||||
| * | |||||
| * @param client - pointer to a JACK client structure | * @param client - pointer to a JACK client structure | ||||
| * | * | ||||
| * @return the number of frames of data to process | * @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. | * Signal next clients in the graph. | ||||
| * | |||||
| * | |||||
| * @param client - pointer to a JACK client structure | * @param client - pointer to a JACK client structure | ||||
| * @param status - if non-zero, calling thread should exit | * @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 | * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 | ||||
| * for more information. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code. | * @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 | * 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. | * will be handled. | ||||
| * | * | ||||
| * The code in the supplied function does not need to be | * The code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code, causing JACK | * @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, | void jack_on_info_shutdown (jack_client_t *client, | ||||
| JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | ||||
| /** | /** | ||||
| * Tell the Jack server to call @a process_callback whenever there is | * Tell the Jack server to call @a process_callback whenever there is | ||||
| * work be done, passing @a arg as the second argument. | * 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 | * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 | ||||
| * for more information. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code. | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code. | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @param client pointer to JACK client structure. | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @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 *, | int jack_set_port_registration_callback (jack_client_t *, | ||||
| JackPortRegistrationCallback | JackPortRegistrationCallback | ||||
| registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | ||||
| /** | /** | ||||
| * Tell the JACK server to call @a connect_callback whenever a | * Tell the JACK server to call @a connect_callback whenever a | ||||
| * port is connected or disconnected, passing @a arg as a parameter. | * 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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @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 | * the code in the supplied function does not need to be | ||||
| * suitable for real-time execution. | * 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.) | * (after jack_activate has been called.) | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code | * @return 0 on success, otherwise a non-zero error code | ||||
| */ | */ | ||||
| int jack_set_xrun_callback (jack_client_t *, | int jack_set_xrun_callback (jack_client_t *, | ||||
| JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | 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 | * @defgroup ServerClientControl Controlling & querying JACK server operation | ||||
| * @{ | * @{ | ||||
| */ | */ | ||||
| /** | /** | ||||
| * Start/Stop JACK's "freewheel" mode. | * Start/Stop JACK's "freewheel" mode. | ||||
| * | * | ||||
| * When in "freewheel" mode, JACK no longer waits for | * When in "freewheel" mode, JACK no longer waits for | ||||
| * any external event to begin the start of the next process | * any external event to begin the start of the next process | ||||
| * cycle. | |||||
| * cycle. | |||||
| * | * | ||||
| * As a result, freewheel mode causes "faster than realtime" | * As a result, freewheel mode causes "faster than realtime" | ||||
| * execution of a JACK graph. If possessed, real-time | * execution of a JACK graph. If possessed, real-time | ||||
| * scheduling is dropped when entering freewheel mode, and | * scheduling is dropped when entering freewheel mode, and | ||||
| * if appropriate it is reacquired when stopping. | * if appropriate it is reacquired when stopping. | ||||
| * | |||||
| * | |||||
| * IMPORTANT: on systems using capabilities to provide real-time | * IMPORTANT: on systems using capabilities to provide real-time | ||||
| * scheduling (i.e. Linux kernel 2.4), if onoff is zero, this function | * 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). | * or OS X). | ||||
| * | |||||
| * | |||||
| * @param client pointer to JACK client structure | * @param client pointer to JACK client structure | ||||
| * @param onoff if non-zero, freewheel mode starts. Otherwise | * @param onoff if non-zero, freewheel mode starts. Otherwise | ||||
| * freewheel mode ends. | * 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 | * @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; | 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 | * @return the sample rate of the jack system, as set by the user when | ||||
| * jackd was started. | * jackd was started. | ||||
| @@ -613,7 +671,7 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||||
| * @defgroup PortFunctions Creating & manipulating ports | * @defgroup PortFunctions Creating & manipulating ports | ||||
| * @{ | * @{ | ||||
| */ | */ | ||||
| /** | /** | ||||
| * Create a new port for the client. This is an object used for moving | * 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 | * 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 | * name. Exceeding that will cause the port registration to fail and | ||||
| * return NULL. | * 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 | * 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 | * length string, passed as an argument. Some port types are built | ||||
| * into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE. | * into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE. | ||||
| * | * | ||||
| * @param client pointer to JACK client structure. | * @param client pointer to JACK client structure. | ||||
| * @param port_name non-empty short name for the new port (not | * @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 | * @param port_type port type name. If longer than | ||||
| * jack_port_type_size(), only that many characters are significant. | * jack_port_type_size(), only that many characters are significant. | ||||
| * @param flags @ref JackPortFlags bit mask. | * @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 | * that can be written to; for an input port, it will be an area | ||||
| * containing the data from the port's connection(s), or | * containing the data from the port's connection(s), or | ||||
| * zero-filled. if there are multiple inbound connections, the data | * 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 !! | * 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 | * either never cache the return value or ensure you have | ||||
| * a "blocksize" callback and be sure to invalidate the cached | * a "blocksize" callback and be sure to invalidate the cached | ||||
| * address from there. | * address from there. | ||||
| * | |||||
| * | |||||
| * Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). | * 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; | 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. | * you cannot use it in a GraphReordered handler. | ||||
| * | * | ||||
| * 2) You need not be the owner of the port to get information | * 2) You need not be the owner of the port to get information | ||||
| * about its connections. | |||||
| * about its connections. | |||||
| * | * | ||||
| * @see jack_port_name_size() | * @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 | * turned out to serve essentially no purpose in real-life | ||||
| * JACK clients. | * 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 | * turned out to serve essentially no purpose in real-life | ||||
| * JACK clients. | * JACK clients. | ||||
| */ | */ | ||||
| int jack_port_untie (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | 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 | * Modify a port's short name. May be called at any time. If the | ||||
| * resulting full name (including the @a "client_name:" prefix) is | * 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. | * 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. | * If the alias is longer than jack_port_name_size(), it will be truncated. | ||||
| * | |||||
| * | |||||
| * After a successful call, and until JACK exits or | * After a successful call, and until JACK exits or | ||||
| * @function jack_port_unset_alias() is called, @alias may be | * @function jack_port_unset_alias() is called, @alias may be | ||||
| * used as a alternate name for the port. | * 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. | * set, this function will return an error. | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code. | * @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. | * 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. | * used as a alternate name for the port. | ||||
| * | * | ||||
| * @return 0 on success, otherwise a non-zero error code. | * @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; | 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. | * 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. | * 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. | * If zero, no selection based on flags will be carried out. | ||||
| * | * | ||||
| * @return a NULL-terminated array of ports that match the specified | * @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_t * jack_port_by_id (jack_client_t *client, | ||||
| jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT; | jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT; | ||||
| /*@}*/ | |||||
| /*@}*/ | |||||
| /** | /** | ||||
| * @defgroup TimeFunctions Handling time | * @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 | * This function may only be used from the process callback, and can | ||||
| * be used to interpret timestamps generated by jack_frame_time() in | * be used to interpret timestamps generated by jack_frame_time() in | ||||
| * other threads with respect to the current process cycle. | * other threads with respect to the current process cycle. | ||||
| * | |||||
| * | |||||
| * This is the only jack time function that returns exact time: | * This is the only jack time function that returns exact time: | ||||
| * when used during the process callback it always returns the same | * when used during the process callback it always returns the same | ||||
| * value (until the next process callback, where it will return | * 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, | * @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. | * The value returned is guaranteed to be monotonic, but not linear. | ||||
| */ | */ | ||||
| jack_time_t jack_get_time() JACK_OPTIONAL_WEAK_EXPORT; | 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. | * 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. | * 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. | * 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 | Copyright (C) 2004 Ian Esten | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -24,11 +24,12 @@ | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| extern "C" { | extern "C" { | ||||
| #endif | #endif | ||||
| #include <jack/weakmacros.h> | |||||
| #include <jack/types.h> | #include <jack/types.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <jack/weakmacros.h> | |||||
| /** Type for raw event data contained in @ref jack_midi_event_t. */ | /** Type for raw event data contained in @ref jack_midi_event_t. */ | ||||
| typedef unsigned char jack_midi_data_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. | /** Get a MIDI event from an event port buffer. | ||||
| * | |||||
| * | |||||
| * Jack MIDI is normalised, the MIDI event returned by this function is | * 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 | * guaranteed to be a complete MIDI event (the status byte will always be | ||||
| * present, and no realtime events will interspered with the event). | * 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. | /** Clear an event buffer. | ||||
| * | |||||
| * | |||||
| * This should be called at the beginning of each process cycle before calling | * 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 | * @ref jack_midi_event_reserve or @ref jack_midi_event_write. This | ||||
| * function may not be called on an input port's buffer. | * 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 | * messages interspersed with other messages (realtime messages are fine | ||||
| * when they occur on their own, like other messages). | * 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 port_buffer Buffer to write event to. | ||||
| * @param time Sample offset of event. | * @param time Sample offset of event. | ||||
| * @param data_size Length of event's raw data in bytes. | * @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_data_t* | ||||
| jack_midi_event_reserve(void *port_buffer, | jack_midi_event_reserve(void *port_buffer, | ||||
| jack_nframes_t time, | |||||
| jack_nframes_t time, | |||||
| size_t data_size) JACK_OPTIONAL_WEAK_EXPORT; | 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 | * This function is simply a wrapper for @ref jack_midi_event_reserve | ||||
| * which writes the event data into the space reserved in the buffer. | * 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. | * out-of-order events. | ||||
| * | |||||
| * | |||||
| * @param port_buffer Buffer to write event to. | * @param port_buffer Buffer to write event to. | ||||
| * @param time Sample offset of event. | * @param time Sample offset of event. | ||||
| * @param data Message data to be written. | * @param data Message data to be written. | ||||
| @@ -2,21 +2,20 @@ | |||||
| Copyright (C) 2001 Paul Davis | Copyright (C) 2001 Paul Davis | ||||
| Copyright (C) 2004 Jack O'Quin | Copyright (C) 2004 Jack O'Quin | ||||
| Copyright (C) 2010 Torben Hohn | Copyright (C) 2010 Torben Hohn | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| #ifndef __jack_session_h__ | #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. | * 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 { | 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, | JackSessionSave = 1, | ||||
| /** | |||||
| * Save the session completly, then quit. | |||||
| * | |||||
| * The rules for saving are exactly the same as for JackSessionSave. | |||||
| */ | |||||
| JackSessionSaveAndQuit = 2, | 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 | JackSessionSaveTemplate = 3 | ||||
| }; | }; | ||||
| typedef enum JackSessionEventType jack_session_event_type_t; | typedef enum JackSessionEventType jack_session_event_type_t; | ||||
| /** | |||||
| * @ref jack_session_flags_t bits | |||||
| */ | |||||
| enum JackSessionFlags { | enum JackSessionFlags { | ||||
| /** | /** | ||||
| * an error occured while saving. | |||||
| * An error occured while saving. | |||||
| */ | */ | ||||
| JackSessionSaveError = 0x01, | 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; | typedef enum JackSessionFlags jack_session_flags_t; | ||||
| struct _jack_session_event { | struct _jack_session_event { | ||||
| /** | /** | ||||
| * the actual type of this session event. | |||||
| * The type of this session event. | |||||
| */ | */ | ||||
| jack_session_event_type_t type; | 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; | 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; | 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; | char *command_line; | ||||
| /** | /** | ||||
| * flags to be set by the client. normally left 0. | |||||
| * Reply (set by client): Session flags. | |||||
| */ | */ | ||||
| jack_session_flags_t 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; | 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 | * Prototype for the client supplied function that is called | ||||
| * whenever a session notification is sent via jack_session_notify(). | * 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 | * @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 | * @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. | * this also frees the memory used by the command_line pointer. | ||||
| * if its non NULL. | * 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 { | 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; | } 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; | 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. | * 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 | * @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 | 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 | #ifdef __cplusplus | ||||
| } | } | ||||
| @@ -36,15 +36,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| typedef LONGLONG int64_t; | typedef LONGLONG int64_t; | ||||
| typedef ULONGLONG uint64_t; | typedef ULONGLONG uint64_t; | ||||
| #endif | #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 */ | #elif __MINGW32__ /* MINGW */ | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <sys/types.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 ...*/ | #else /* other compilers ...*/ | ||||
| #include <inttypes.h> | #include <inttypes.h> | ||||
| #include <pthread.h> | #include <pthread.h> | ||||
| @@ -57,6 +61,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #include <inttypes.h> | #include <inttypes.h> | ||||
| #include <pthread.h> | #include <pthread.h> | ||||
| #include <sys/types.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 /* __APPLE__ || __linux__ || __sun__ || sun */ | ||||
| #endif | #endif | ||||
| @@ -28,6 +28,10 @@ extern "C" | |||||
| #include <jack/systemdeps.h> | #include <jack/systemdeps.h> | ||||
| #include <jack/weakmacros.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 | /** @file thread.h | ||||
| * | * | ||||
| * Library functions to standardize thread creation for JACK and its | * 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 | * @returns 0, if successful; EPERM, if the calling process lacks | ||||
| * required realtime privileges; otherwise some other error number. | * 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 | * 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. | * @returns 0, if successful; otherwise some error number. | ||||
| */ | */ | ||||
| int jack_client_create_thread (jack_client_t* client, | int jack_client_create_thread (jack_client_t* client, | ||||
| pthread_t *thread, | |||||
| jack_native_thread_t *thread, | |||||
| int priority, | int priority, | ||||
| int realtime, /* boolean */ | int realtime, /* boolean */ | ||||
| void *(*start_routine)(void*), | 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. | * @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. | * 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. | * @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. | * 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. | * @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 | #ifndef WIN32 | ||||
| @@ -74,6 +74,205 @@ typedef uint32_t jack_port_id_t; | |||||
| typedef uint32_t jack_port_type_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 | * Prototype for the client supplied function that is called | ||||
| * by the engine anytime there is work to be done. | * 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 | * Prototype for the client supplied function that is called | ||||
| * whenever a port is registered or unregistered. | * 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 | * 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 | * zero if the client is being unregistered | ||||
| * @param arg pointer to a client supplied structure | * @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 | * 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 | * 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 client pointer is *not* deallocated by libjack, | ||||
| * the application is responsible to properly use jack_client_close() | * the application is responsible to properly use jack_client_close() | ||||
| * to release client ressources. Warning: jack_client_close() cannot be | * 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); | 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 | * Used for the type argument of jack_port_register() for default | ||||
| * audio ports and midi ports. | * audio ports and midi ports. | ||||
| @@ -295,161 +512,9 @@ enum JackPortFlags { | |||||
| * their ports. | * their ports. | ||||
| */ | */ | ||||
| JackPortIsTerminal = 0x10, | 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. | * Transport states. | ||||
| */ | */ | ||||
| @@ -476,7 +541,7 @@ typedef enum { | |||||
| JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */ | JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */ | ||||
| JackAudioVideoRatio = 0x80, /**< audio frames per video frame */ | JackAudioVideoRatio = 0x80, /**< audio frames per video frame */ | ||||
| JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */ | JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */ | ||||
| } jack_position_bits_t; | } jack_position_bits_t; | ||||
| /** all valid position bits */ | /** all valid position bits */ | ||||
| @@ -666,19 +731,5 @@ typedef struct { | |||||
| } jack_transport_info_t; | } 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__ */ | #endif /* __jack_types_h__ */ | ||||
| @@ -1,18 +1,18 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2010 Paul Davis | Copyright (C) 2010 Paul Davis | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -20,10 +20,63 @@ | |||||
| #ifndef __weakjack_h__ | #ifndef __weakjack_h__ | ||||
| #define __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 | #ifndef JACK_OPTIONAL_WEAK_EXPORT | ||||
| /* JACK_OPTIONAL_WEAK_EXPORT needs to be a macro which | /* 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 | the symbol it used with. For this to work fully may | ||||
| require linker arguments for the client as well. | require linker arguments for the client as well. | ||||
| */ | */ | ||||
| @@ -49,4 +102,6 @@ | |||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| /*@}*/ | |||||
| #endif /* weakjack */ | #endif /* weakjack */ | ||||
| @@ -1,18 +1,18 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2010 Paul Davis | Copyright (C) 2010 Paul Davis | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 | * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | ||||
| * added to the JACK API after the 0.116.2 release. | * 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 | * JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile | ||||
| * time in a variety of ways. The default definition is empty, | * time in a variety of ways. The default definition is empty, | ||||
| * so that these symbols get normal linkage. If you wish to | * 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. | * <jack/weakjack.h> before jack.h. | ||||
| *************************************************************/ | *************************************************************/ | ||||
| #ifndef JACK_WEAK_EXPORT | #ifndef JACK_WEAK_EXPORT | ||||
| #ifdef __GNUC__ | #ifdef __GNUC__ | ||||
| /* JACK_WEAK_EXPORT needs to be a macro which | /* 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 | the symbol it used with. For this to work full may | ||||
| require linker arguments in the client as well. | require linker arguments in the client as well. | ||||
| */ | */ | ||||
| #define JACK_WEAK_EXPORT __attribute__((weak)) | #define JACK_WEAK_EXPORT __attribute__((weak)) | ||||
| #else | #else | ||||
| /* Add other things here for non-gcc platforms */ | /* Add other things here for non-gcc platforms */ | ||||
| #define JACK_WEAK_EXPORT | |||||
| #ifdef WIN32 | |||||
| #define JACK_WEAK_EXPORT | |||||
| #endif | |||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| @@ -54,9 +58,13 @@ | |||||
| #ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | #ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | ||||
| #ifdef __GNUC__ | #ifdef __GNUC__ | ||||
| #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__)) | #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__)) | ||||
| #else | |||||
| #else | |||||
| /* Add other things here for non-gcc platforms */ | /* 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 /* __GNUC__ */ | ||||
| #endif | #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 $ | $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | ||||
| */ | */ | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <memory.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> | #include <netinet/in.h> | ||||
| #endif | #endif | ||||
| #include "netjack.h" | |||||
| #ifdef __linux__ | #ifdef __linux__ | ||||
| #include "config.h" | #include "config.h" | ||||
| #endif | #endif | ||||
| @@ -58,15 +55,11 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||||
| #include <samplerate.h> | #include <samplerate.h> | ||||
| #endif | #endif | ||||
| #if HAVE_CELT | |||||
| #include <celt/celt.h> | |||||
| #endif | |||||
| #include "netjack.h" | #include "netjack.h" | ||||
| #include "netjack_packet.h" | #include "netjack_packet.h" | ||||
| // JACK2 | // JACK2 | ||||
| #include "jack/control.h" | |||||
| #include "control.h" | |||||
| #define MIN(x,y) ((x)<(y) ? (x) : (y)) | #define MIN(x,y) ((x)<(y) ? (x) : (y)) | ||||
| @@ -105,8 +98,8 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||||
| netj->expected_framecnt += 1; | netj->expected_framecnt += 1; | ||||
| } else { | } else { | ||||
| // starting up.... lets look into the packetcache, and fetch the highest packet. | // 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 = next_frame_avail; | ||||
| netj->expected_framecnt_valid = 1; | netj->expected_framecnt_valid = 1; | ||||
| } else { | } else { | ||||
| @@ -122,7 +115,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||||
| // then poll (have deadline calculated) | // then poll (have deadline calculated) | ||||
| // then drain socket, rinse and repeat. | // then drain socket, rinse and repeat. | ||||
| while(1) { | 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 ) { | if( next_frame_avail == netj->expected_framecnt ) { | ||||
| we_have_the_expected_frame = 1; | we_have_the_expected_frame = 1; | ||||
| if( !netj->always_deadline ) | if( !netj->always_deadline ) | ||||
| @@ -133,13 +126,13 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||||
| break; | 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. | // check if we know who to send our packets too. | ||||
| if (!netj->srcaddress_valid) | 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; | netj->srcaddress_valid = 1; | ||||
| } | } | ||||
| @@ -161,7 +154,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||||
| else | else | ||||
| netj->time_to_deadline = 0; | 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; | pkthdr = (jacknet_packet_header *) netj->rx_buf; | ||||
| packet_header_ntoh(pkthdr); | packet_header_ntoh(pkthdr); | ||||
| netj->deadline_goodness = (int)pkthdr->sync_state; | 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. | // lets check if we have the next packets, we will just run a cycle without data. | ||||
| // in that case. | // 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; | 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. | // I also found this happening, when the packet queue, is too full. | ||||
| // but wtf ? use a smaller latency. this link can handle that ;S | // 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; | 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. | // the diff is too high. but we have a packet in the future. | ||||
| // lets resync. | // lets resync. | ||||
| netj->expected_framecnt = 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; | pkthdr = (jacknet_packet_header *) netj->rx_buf; | ||||
| packet_header_ntoh(pkthdr); | packet_header_ntoh(pkthdr); | ||||
| //netj->deadline_goodness = 0; | //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, | // i will make the packet cache drop redundant packets, | ||||
| // that have already been retreived. | // 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) ) { | if( next_frame_avail == (netj->expected_framecnt - 1) ) { | ||||
| // Ok. the last packet is there now. | // Ok. the last packet is there now. | ||||
| // and it had not been retrieved. | // 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. | // 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; | 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; | pkthdr = (jacknet_packet_header *) netj->rx_buf; | ||||
| packet_header_ntoh(pkthdr); | packet_header_ntoh(pkthdr); | ||||
| netj->deadline_goodness = pkthdr->sync_state; | netj->deadline_goodness = pkthdr->sync_state; | ||||
| @@ -300,7 +293,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||||
| // reply address changes port. | // reply address changes port. | ||||
| if (netj->num_lost_packets > 200 ) { | if (netj->num_lost_packets > 200 ) { | ||||
| netj->srcaddress_valid = 0; | 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; | 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) | if (netj->handle_transport_sync) | ||||
| jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL); | 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( netj->bitdepth == CELT_MODE ) { | ||||
| #if HAVE_CELT | #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 | #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 | #endif | ||||
| celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); | |||||
| netj->codec_latency = 2*lookahead; | |||||
| #endif | #endif | ||||
| } else { | } else { | ||||
| #if HAVE_SAMPLERATE | #if HAVE_SAMPLERATE | ||||
| @@ -408,6 +410,7 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||||
| #endif | #endif | ||||
| } | } | ||||
| } | } | ||||
| for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) { | for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) { | ||||
| snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1); | 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); | jack_slist_append (netj->playback_ports, port); | ||||
| if( netj->bitdepth == CELT_MODE ) { | if( netj->bitdepth == CELT_MODE ) { | ||||
| #if HAVE_CELT | #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 ); | 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 ) ); | netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); | ||||
| #else | #else | ||||
| @@ -479,7 +482,6 @@ void netjack_detach( netjack_driver_state_t *netj ) | |||||
| { | { | ||||
| JSList * node; | JSList * node; | ||||
| for (node = netj->capture_ports; node; node = jack_slist_next (node)) | for (node = netj->capture_ports; node; node = jack_slist_next (node)) | ||||
| jack_port_unregister (netj->client, | jack_port_unregister (netj->client, | ||||
| ((jack_port_t *) node->data)); | ((jack_port_t *) node->data)); | ||||
| @@ -487,12 +489,57 @@ void netjack_detach( netjack_driver_state_t *netj ) | |||||
| jack_slist_free (netj->capture_ports); | jack_slist_free (netj->capture_ports); | ||||
| netj->capture_ports = NULL; | 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)) | for (node = netj->playback_ports; node; node = jack_slist_next (node)) | ||||
| jack_port_unregister (netj->client, | jack_port_unregister (netj->client, | ||||
| ((jack_port_t *) node->data)); | ((jack_port_t *) node->data)); | ||||
| jack_slist_free (netj->playback_ports); | jack_slist_free (netj->playback_ports); | ||||
| netj->playback_ports = NULL; | 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->sockfd ); | ||||
| close( netj->outsockfd ); | close( netj->outsockfd ); | ||||
| packet_cache_free( global_packcache ); | |||||
| global_packcache = NULL; | |||||
| packet_cache_free( netj->packcache ); | |||||
| netj->packcache = NULL; | |||||
| } | } | ||||
| int | int | ||||
| @@ -585,13 +632,7 @@ netjack_startup( netjack_driver_state_t *netj ) | |||||
| struct sockaddr_in address; | struct sockaddr_in address; | ||||
| // Now open the socket, and wait for the first packet to arrive... | // Now open the socket, and wait for the first packet to arrive... | ||||
| netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); | netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); | ||||
| #ifdef WIN32 | #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) | if (netj->sockfd == INVALID_SOCKET) | ||||
| #else | #else | ||||
| if (netj->sockfd == -1) | 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 !!!"); | //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); | ||||
| while(1) { | 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); | first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); | ||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| if( first_pack_len == -1 ) { | 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); | 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->expected_framecnt_valid = 0; | ||||
| netj->num_lost_packets = 0; | netj->num_lost_packets = 0; | ||||
| @@ -30,6 +30,10 @@ | |||||
| #include "jack/jslist.h" | #include "jack/jslist.h" | ||||
| #if HAVE_CELT | |||||
| #include <celt/celt.h> | |||||
| #endif | |||||
| //#include <netinet/in.h> | //#include <netinet/in.h> | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| @@ -37,6 +41,8 @@ extern "C" | |||||
| { | { | ||||
| #endif | #endif | ||||
| struct _packet_cache; | |||||
| typedef struct _netjack_driver_state netjack_driver_state_t; | typedef struct _netjack_driver_state netjack_driver_state_t; | ||||
| struct _netjack_driver_state { | struct _netjack_driver_state { | ||||
| @@ -106,6 +112,10 @@ struct _netjack_driver_state { | |||||
| unsigned int resample_factor; | unsigned int resample_factor; | ||||
| unsigned int resample_factor_up; | unsigned int resample_factor_up; | ||||
| int jitter_val; | int jitter_val; | ||||
| struct _packet_cache * packcache; | |||||
| #if HAVE_CELT | |||||
| CELTMode *celt_mode; | |||||
| #endif | |||||
| }; | }; | ||||
| int netjack_wait( netjack_driver_state_t *netj ); | int netjack_wait( netjack_driver_state_t *netj ); | ||||
| @@ -75,7 +75,7 @@ | |||||
| #include "netjack_packet.h" | #include "netjack_packet.h" | ||||
| // JACK2 specific. | // JACK2 specific. | ||||
| #include "jack/control.h" | |||||
| #include "control.h" | |||||
| #ifdef NO_JACK_ERROR | #ifdef NO_JACK_ERROR | ||||
| #define jack_error printf | #define jack_error printf | ||||
| @@ -83,8 +83,6 @@ | |||||
| int fraggo = 0; | int fraggo = 0; | ||||
| packet_cache *global_packcache = NULL; | |||||
| void | void | ||||
| packet_header_hton (jacknet_packet_header *pkthdr) | packet_header_hton (jacknet_packet_header *pkthdr) | ||||
| { | { | ||||
| @@ -388,7 +386,7 @@ netjack_poll_deadline (int sockfd, jack_time_t deadline) | |||||
| #if HAVE_PPOLL | #if HAVE_PPOLL | ||||
| timeout_spec.tv_nsec = (deadline - now) * 1000; | timeout_spec.tv_nsec = (deadline - now) * 1000; | ||||
| #else | #else | ||||
| timeout = (deadline - now + 500) / 1000; | |||||
| timeout = lrintf( (float)(deadline - now) / 1000.0 ); | |||||
| #endif | #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 )) | if( pcache->last_framecnt_retreived_valid && (framecnt <= pcache->last_framecnt_retreived )) | ||||
| continue; | 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); | cache_packet_add_fragment (cpack, rx_packet, rcv_len); | ||||
| cpack->recv_timestamp = jack_get_time(); | cpack->recv_timestamp = jack_get_time(); | ||||
| } | } | ||||
| @@ -774,61 +772,6 @@ packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecn | |||||
| return retval; | return retval; | ||||
| } | } | ||||
| // fragmented packet IO | // 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 | void | ||||
| netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu) | 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. | // audio port, decode celt data. | ||||
| CELTDecoder *decoder = src_node->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 ) | if( !packet_payload ) | ||||
| celt_decode_float( decoder, NULL, net_period_down, buf ); | celt_decode_float( decoder, NULL, net_period_down, buf ); | ||||
| else | else | ||||
| celt_decode_float( decoder, packet_bufX, net_period_down, buf ); | celt_decode_float( decoder, packet_bufX, net_period_down, buf ); | ||||
| #endif | |||||
| src_node = jack_slist_next (src_node); | 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 ); | float *floatbuf = alloca (sizeof(float) * nframes ); | ||||
| memcpy( floatbuf, buf, nframes*sizeof(float) ); | memcpy( floatbuf, buf, nframes*sizeof(float) ); | ||||
| CELTEncoder *encoder = src_node->data; | 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 ); | encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); | ||||
| #endif | |||||
| if( encoded_bytes != net_period_up ) | if( encoded_bytes != net_period_up ) | ||||
| printf( "something in celt changed. netjack needs to be changed to handle this.\n" ); | printf( "something in celt changed. netjack needs to be changed to handle this.\n" ); | ||||
| src_node = jack_slist_next( src_node ); | src_node = jack_slist_next( src_node ); | ||||
| @@ -107,8 +107,6 @@ struct _packet_cache | |||||
| int last_framecnt_retreived_valid; | int last_framecnt_retreived_valid; | ||||
| }; | }; | ||||
| extern packet_cache *global_packcache; | |||||
| // fragment cache function prototypes | // fragment cache function prototypes | ||||
| // XXX: Some of these are private. | // XXX: Some of these are private. | ||||
| packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu); | 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 | // This one waits forever. an is not using ppoll | ||||
| int netjack_poll(int sockfd, int timeout); | 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 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); | void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| @@ -1,24 +1,25 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2002-2003 Paul Davis | Copyright (C) 2002-2003 Paul Davis | ||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 | the Free Software Foundation; either version 2.1 of the License, or | ||||
| (at your option) any later version. | (at your option) any later version. | ||||
| This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <inttypes.h> | |||||
| #include "timestamps.h" | #include "timestamps.h" | ||||
| #include "JackTime.h" | #include "JackTime.h" | ||||
| @@ -60,7 +61,7 @@ jack_dump_timestamps (FILE *out) | |||||
| unsigned long i; | unsigned long i; | ||||
| for (i = 0; i < timestamp_index; ++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].what, timestamps[i].when, | ||||
| timestamps[i].when - timestamps[0].when); | timestamps[i].when - timestamps[0].when); | ||||
| if (i > 0) { | if (i > 0) { | ||||
| @@ -11,12 +11,11 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <alloca.h> | |||||
| #include <math.h> | #include <math.h> | ||||
| #include <jack/jack.h> | #include <jack/jack.h> | ||||
| #include <jack/jslist.h> | #include <jack/jslist.h> | ||||
| #include <memops.h> | |||||
| #include <jack/memops.h> | |||||
| #include "alsa/asoundlib.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_buffer_size; | ||||
| snd_pcm_uframes_t real_period_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. | // format selection, and corresponding functions from memops in a nice set of structs. | ||||
| typedef struct alsa_format { | typedef struct alsa_format { | ||||
| @@ -307,8 +312,6 @@ double hann( double x ) | |||||
| */ | */ | ||||
| int process (jack_nframes_t nframes, void *arg) { | int process (jack_nframes_t nframes, void *arg) { | ||||
| char *outbuf; | |||||
| float *resampbuf; | |||||
| int rlen; | int rlen; | ||||
| int err; | int err; | ||||
| snd_pcm_sframes_t delay = target_delay; | 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... | // this is for compensating xruns etc... | ||||
| if( delay > (target_delay+max_diff) ) { | 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; | 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; | delay = target_delay; | ||||
| // Set the resample_rate... we need to adjust the offset integral, to do this. | // 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. | // Calculate resample_mean so we can init ourselves to saner values. | ||||
| resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; | 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... | // get the data... | ||||
| again: | again: | ||||
| @@ -465,6 +466,32 @@ again: | |||||
| return 0; | 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... | * Allocate the necessary jack ports... | ||||
| @@ -661,6 +688,8 @@ int main (int argc, char *argv[]) { | |||||
| jack_on_shutdown (client, jack_shutdown, 0); | jack_on_shutdown (client, jack_shutdown, 0); | ||||
| if (jack_set_latency_callback) | |||||
| jack_set_latency_callback (client, latency_cb, 0); | |||||
| // get jack sample_rate | // get jack sample_rate | ||||
| @@ -716,6 +745,17 @@ int main (int argc, char *argv[]) { | |||||
| // alloc input ports, which are blasted out to alsa... | // alloc input ports, which are blasted out to alsa... | ||||
| alloc_ports( num_channels, 0 ); | 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 */ | /* tell the JACK server that we are ready to roll */ | ||||
| @@ -11,12 +11,11 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <alloca.h> | |||||
| #include <math.h> | #include <math.h> | ||||
| #include <jack/jack.h> | #include <jack/jack.h> | ||||
| #include <jack/jslist.h> | #include <jack/jslist.h> | ||||
| #include <memops.h> | |||||
| #include <jack/memops.h> | |||||
| #include "alsa/asoundlib.h" | #include "alsa/asoundlib.h" | ||||
| @@ -35,6 +34,7 @@ snd_pcm_t *alsa_handle; | |||||
| int jack_sample_rate; | int jack_sample_rate; | ||||
| int jack_buffer_size; | int jack_buffer_size; | ||||
| int quit = 0; | |||||
| double resample_mean = 1.0; | double resample_mean = 1.0; | ||||
| double static_resample_factor = 1.0; | double static_resample_factor = 1.0; | ||||
| double resample_lower_limit = 0.25; | double resample_lower_limit = 0.25; | ||||
| @@ -45,7 +45,6 @@ double *window_array; | |||||
| int offset_differential_index = 0; | int offset_differential_index = 0; | ||||
| double offset_integral = 0; | double offset_integral = 0; | ||||
| int quit = 0; | |||||
| // ------------------------------------------------------ commandline parameters | // ------------------------------------------------------ commandline parameters | ||||
| @@ -77,6 +76,12 @@ volatile float output_diff = 0.0; | |||||
| snd_pcm_uframes_t real_buffer_size; | snd_pcm_uframes_t real_buffer_size; | ||||
| snd_pcm_uframes_t real_period_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. | // format selection, and corresponding functions from memops in a nice set of structs. | ||||
| typedef struct alsa_format { | typedef struct alsa_format { | ||||
| @@ -90,6 +95,7 @@ typedef struct alsa_format { | |||||
| alsa_format_t formats[] = { | alsa_format_t formats[] = { | ||||
| { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, | { 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_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_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" } | { 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) { | int process (jack_nframes_t nframes, void *arg) { | ||||
| char *outbuf; | |||||
| float *resampbuf; | |||||
| int rlen; | int rlen; | ||||
| int err; | int err; | ||||
| snd_pcm_sframes_t delay = target_delay; | 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 = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; | ||||
| delay -= jack_frames_since_cycle_start( client ); | delay -= jack_frames_since_cycle_start( client ); | ||||
| delay += jack_get_buffer_size( client ) / 2; | |||||
| // Do it the hard way. | // Do it the hard way. | ||||
| // this is for compensating xruns etc... | // this is for compensating xruns etc... | ||||
| @@ -340,12 +343,15 @@ int process (jack_nframes_t nframes, void *arg) { | |||||
| offset_array[i] = 0.0; | offset_array[i] = 0.0; | ||||
| } | } | ||||
| if( delay < (target_delay-max_diff) ) { | 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; | 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; | delay = target_delay; | ||||
| // Set the resample_rate... we need to adjust the offset integral, to do this. | // Set the resample_rate... we need to adjust the offset integral, to do this. | ||||
| @@ -463,6 +469,32 @@ again: | |||||
| return 0; | 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... | * Allocate the necessary jack ports... | ||||
| @@ -659,6 +691,8 @@ int main (int argc, char *argv[]) { | |||||
| jack_on_shutdown (client, jack_shutdown, 0); | jack_on_shutdown (client, jack_shutdown, 0); | ||||
| if (jack_set_latency_callback) | |||||
| jack_set_latency_callback (client, latency_cb, 0); | |||||
| // get jack sample_rate | // get jack sample_rate | ||||
| @@ -714,6 +748,16 @@ int main (int argc, char *argv[]) { | |||||
| // alloc input ports, which are blasted out to alsa... | // alloc input ports, which are blasted out to alsa... | ||||
| alloc_ports( 0, num_channels ); | 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 */ | /* tell the JACK server that we are ready to roll */ | ||||
| @@ -2,7 +2,7 @@ | |||||
| * bufsize.c -- change JACK buffer size. | * bufsize.c -- change JACK buffer size. | ||||
| * | * | ||||
| * Copyright (C) 2003 Jack O'Quin. | * Copyright (C) 2003 Jack O'Quin. | ||||
| * | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or modify | * 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 | * it under the terms of the GNU General Public License as published by | ||||
| * the Free Software Foundation; either version 2 of the License, or | * the Free Software Foundation; either version 2 of the License, or | ||||
| @@ -64,12 +64,23 @@ void parse_arguments(int argc, char *argv[]) | |||||
| exit(9); | 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); | nframes = strtoul(argv[1], NULL, 0); | ||||
| if (errno == ERANGE) { | 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]); | package, argv[1]); | ||||
| exit(2); | 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[]) | int main(int argc, char *argv[]) | ||||
| @@ -24,7 +24,9 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <getopt.h> | |||||
| #include <jack/jack.h> | #include <jack/jack.h> | ||||
| #include <jack/session.h> | |||||
| jack_port_t *input_port; | jack_port_t *input_port; | ||||
| jack_port_t *output_port; | jack_port_t *output_port; | ||||
| @@ -33,17 +35,84 @@ int done = 0; | |||||
| #define TRUE 1 | #define TRUE 1 | ||||
| #define FALSE 0 | #define FALSE 0 | ||||
| void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) | void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) | ||||
| { | { | ||||
| done = 1; | 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 | int | ||||
| main (int argc, char *argv[]) | 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], '/'); | 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; | connecting = disconnecting = FALSE; | ||||
| if (my_name == 0) { | if (my_name == 0) { | ||||
| my_name = argv[0]; | my_name = argv[0]; | ||||
| @@ -51,90 +120,121 @@ main (int argc, char *argv[]) | |||||
| my_name ++; | 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 { | } else { | ||||
| fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); | fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); | ||||
| return 1; | 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 */ | /* 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"); | fprintf (stderr, "jack server not running?\n"); | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| jack_set_port_connect_callback(client, port_connect_callback, NULL); | 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 */ | /* 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 | /* connect the ports. Note: you can't do this before | ||||
| the client is activated (this may change in the future). | 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 (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 | // 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> | #include <unistd.h> | ||||
| #endif | #endif | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <getopt.h> | |||||
| #include <getopt.h> | |||||
| #include <inttypes.h> | |||||
| #include <jack/jack.h> | #include <jack/jack.h> | ||||
| char * my_name; | char * my_name; | ||||
| @@ -39,6 +40,7 @@ show_usage (void) | |||||
| fprintf (stderr, "List active Jack ports, and optionally display extra information.\n"); | 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, "Optionally filter ports which match ALL strings provided after any options.\n\n"); | ||||
| fprintf (stderr, "Display options:\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, " -A, --aliases List aliases for each port\n"); | ||||
| fprintf (stderr, " -c, --connections List connections to/from 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"); | 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_client_t *client; | ||||
| jack_status_t status; | jack_status_t status; | ||||
| jack_options_t options = JackNoStartServer; | |||||
| const char **ports, **connections; | const char **ports, **connections; | ||||
| unsigned int i, j, k; | unsigned int i, j, k; | ||||
| int skip_port; | int skip_port; | ||||
| @@ -68,9 +71,11 @@ main (int argc, char *argv[]) | |||||
| int c; | int c; | ||||
| int option_index; | int option_index; | ||||
| char* aliases[2]; | char* aliases[2]; | ||||
| char *server_name = NULL; | |||||
| jack_port_t *port; | jack_port_t *port; | ||||
| struct option long_options[] = { | struct option long_options[] = { | ||||
| { "server", 1, 0, 's' }, | |||||
| { "aliases", 0, 0, 'A' }, | { "aliases", 0, 0, 'A' }, | ||||
| { "connections", 0, 0, 'c' }, | { "connections", 0, 0, 'c' }, | ||||
| { "port-latency", 0, 0, 'l' }, | { "port-latency", 0, 0, 'l' }, | ||||
| @@ -89,8 +94,13 @@ main (int argc, char *argv[]) | |||||
| my_name ++; | 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) { | switch (c) { | ||||
| case 's': | |||||
| server_name = (char *) malloc (sizeof (char) * strlen(optarg)); | |||||
| strcpy (server_name, optarg); | |||||
| options |= JackServerName; | |||||
| break; | |||||
| case 'A': | case 'A': | ||||
| aliases[0] = (char *) malloc (jack_port_name_size()); | aliases[0] = (char *) malloc (jack_port_name_size()); | ||||
| aliases[1] = (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. */ | * specify JackNoStartServer. */ | ||||
| //JOQ: need a new server name option | //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 (client == NULL) { | ||||
| if (status & JackServerFailed) { | if (status & JackServerFailed) { | ||||
| fprintf (stderr, "JACK server not running\n"); | fprintf (stderr, "JACK server not running\n"); | ||||
| @@ -143,7 +153,7 @@ main (int argc, char *argv[]) | |||||
| } | } | ||||
| ports = jack_get_ports (client, NULL, NULL, 0); | ports = jack_get_ports (client, NULL, NULL, 0); | ||||
| if (!ports) | |||||
| if (!ports) | |||||
| goto error; | goto error; | ||||
| for (i = 0; ports && ports[i]; ++i) { | for (i = 0; ports && ports[i]; ++i) { | ||||
| @@ -168,19 +178,28 @@ main (int argc, char *argv[]) | |||||
| printf (" %s\n", aliases[i]); | printf (" %s\n", aliases[i]); | ||||
| } | } | ||||
| } | } | ||||
| if (show_con) { | if (show_con) { | ||||
| if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { | if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { | ||||
| for (j = 0; connections[j]; j++) { | for (j = 0; connections[j]; j++) { | ||||
| printf (" %s\n", connections[j]); | printf (" %s\n", connections[j]); | ||||
| } | } | ||||
| free (connections); | free (connections); | ||||
| } | |||||
| } | |||||
| } | } | ||||
| if (show_port_latency) { | if (show_port_latency) { | ||||
| if (port) { | 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 (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) { | if (show_total_latency) { | ||||
| @@ -208,12 +227,7 @@ main (int argc, char *argv[]) | |||||
| if (flags & JackPortIsTerminal) { | if (flags & JackPortIsTerminal) { | ||||
| fputs ("terminal,", stdout); | fputs ("terminal,", stdout); | ||||
| } | } | ||||
| if (flags & JackPortIsActive) { | |||||
| fputs ("active,", stdout); | |||||
| } else { | |||||
| fputs ("non-active,", stdout); | |||||
| } | |||||
| putc ('\n', stdout); | putc ('\n', stdout); | ||||
| } | } | ||||
| } | } | ||||
| @@ -225,7 +239,7 @@ main (int argc, char *argv[]) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| error: | error: | ||||
| if (ports) | if (ports) | ||||
| jack_free (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 bind_port = 0; | ||||
| int redundancy = 1; | int redundancy = 1; | ||||
| jack_client_t *client; | jack_client_t *client; | ||||
| packet_cache * packcache = 0; | |||||
| int state_connected = 0; | int state_connected = 0; | ||||
| int state_latency = 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( bitdepth == 1000 ) { | ||||
| #if HAVE_CELT | #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 ); | 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 ) ); | capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); | ||||
| #else | #else | ||||
| @@ -183,7 +184,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int | |||||
| } | } | ||||
| if( bitdepth == 1000 ) { | if( bitdepth == 1000 ) { | ||||
| #if HAVE_CELT | #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 ); | 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 ) ); | playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); | ||||
| #else | #else | ||||
| @@ -224,6 +225,9 @@ sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg) | |||||
| static int latency_count = 0; | static int latency_count = 0; | ||||
| int retval = sync_state; | int retval = sync_state; | ||||
| if (! state_connected) { | |||||
| return 1; | |||||
| } | |||||
| if (latency_count) { | if (latency_count) { | ||||
| latency_count--; | latency_count--; | ||||
| retval = 0; | retval = 0; | ||||
| @@ -329,7 +333,7 @@ process (jack_nframes_t nframes, void *arg) | |||||
| else if (cont_miss > 50+5*latency) | else if (cont_miss > 50+5*latency) | ||||
| { | { | ||||
| state_connected = 0; | 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); | //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); | ||||
| cont_miss = 0; | cont_miss = 0; | ||||
| } | } | ||||
| @@ -355,19 +359,19 @@ process (jack_nframes_t nframes, void *arg) | |||||
| if ( ! netjack_poll_deadline( input_fd, deadline ) ) | if ( ! netjack_poll_deadline( input_fd, deadline ) ) | ||||
| break; | 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) ) | if( got_frame == (framecnt - latency) ) | ||||
| break; | break; | ||||
| } | } | ||||
| } else { | } else { | ||||
| // normally: | // normally: | ||||
| // only drain socket. | // 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 | /* First alternative : we received what we expected. Render the data | ||||
| * to the JACK ports so it can be played. */ | * to the JACK ports so it can be played. */ | ||||
| if (size == rx_bufsize) | if (size == rx_bufsize) | ||||
| @@ -394,7 +398,7 @@ process (jack_nframes_t nframes, void *arg) | |||||
| state_recv_packet_queue_time = recv_time_offset; | state_recv_packet_queue_time = recv_time_offset; | ||||
| state_connected = 1; | state_connected = 1; | ||||
| sync_state = pkthdr_rx->sync_state; | 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 | /* Second alternative : we've received something that's not | ||||
| * as big as expected or we missed a packet. We render silence | * as big as expected or we missed a packet. We render silence | ||||
| @@ -402,7 +406,7 @@ process (jack_nframes_t nframes, void *arg) | |||||
| else | else | ||||
| { | { | ||||
| jack_nframes_t latency_estimate; | 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) ) | //if( (state_latency == 0) || (latency_estimate < state_latency) ) | ||||
| state_latency = latency_estimate; | state_latency = latency_estimate; | ||||
| @@ -468,7 +472,7 @@ process (jack_nframes_t nframes, void *arg) | |||||
| else if (cont_miss > 50+5*latency) | else if (cont_miss > 50+5*latency) | ||||
| { | { | ||||
| state_connected = 0; | 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); | //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); | ||||
| cont_miss = 0; | cont_miss = 0; | ||||
| } | } | ||||
| @@ -501,12 +505,11 @@ init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t por | |||||
| if (hostinfo == NULL) { | if (hostinfo == NULL) { | ||||
| fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); | fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); | ||||
| fflush( stderr ); | fflush( stderr ); | ||||
| return; | |||||
| } | } | ||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| name->sin_addr.s_addr = inet_addr( hostname ); | |||||
| name->sin_addr.s_addr = inet_addr( hostname ); | |||||
| #else | #else | ||||
| name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; | |||||
| name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; | |||||
| #endif | #endif | ||||
| } | } | ||||
| else | else | ||||
| @@ -621,15 +624,15 @@ main (int argc, char *argv[]) | |||||
| case 'b': | case 'b': | ||||
| bitdepth = atoi (optarg); | bitdepth = atoi (optarg); | ||||
| break; | break; | ||||
| case 'c': | |||||
| #if HAVE_CELT | |||||
| bitdepth = 1000; | |||||
| case 'c': | |||||
| #if HAVE_CELT | |||||
| bitdepth = 1000; | |||||
| factor = atoi (optarg); | factor = atoi (optarg); | ||||
| #else | |||||
| #else | |||||
| printf( "not built with celt supprt\n" ); | printf( "not built with celt supprt\n" ); | ||||
| exit(10); | exit(10); | ||||
| #endif | |||||
| break; | |||||
| #endif | |||||
| break; | |||||
| case 'm': | case 'm': | ||||
| mtu = atoi (optarg); | mtu = atoi (optarg); | ||||
| break; | break; | ||||
| @@ -676,17 +679,18 @@ main (int argc, char *argv[]) | |||||
| } | } | ||||
| init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); | 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); | init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); | ||||
| if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { | 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); | init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); | ||||
| if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { | 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 */ | /* 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); | 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); | 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 */ | /* tell the JACK server that we are ready to roll */ | ||||
| if (jack_activate (client)) | if (jack_activate (client)) | ||||
| @@ -778,6 +782,6 @@ main (int argc, char *argv[]) | |||||
| } | } | ||||
| jack_client_close (client); | jack_client_close (client); | ||||
| packet_cache_free (global_packcache); | |||||
| packet_cache_free (packcache); | |||||
| exit (0); | exit (0); | ||||
| } | } | ||||
| @@ -25,12 +25,11 @@ | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <jack/jack.h> | #include <jack/jack.h> | ||||
| #include <jack/types.h> | |||||
| #include <jack/jslist.h> | #include <jack/jslist.h> | ||||
| #include <jack/transport.h> | #include <jack/transport.h> | ||||
| #include <jack/session.h> | #include <jack/session.h> | ||||
| char *package; /* program name */ | |||||
| char *package; /* program name */ | |||||
| jack_client_t *client; | jack_client_t *client; | ||||
| jack_session_event_type_t notify_type; | jack_session_event_type_t notify_type; | ||||
| @@ -38,147 +37,145 @@ char *save_path = NULL; | |||||
| void jack_shutdown(void *arg) | 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) | 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[]) | 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 { | typedef struct { | ||||
| char name[32]; | |||||
| char uuid[16]; | |||||
| char name[32]; | |||||
| char uuid[16]; | |||||
| } uuid_map_t; | } uuid_map_t; | ||||
| JSList *uuid_map = NULL; | JSList *uuid_map = NULL; | ||||
| void add_uuid_mapping( const char *uuid ) { | 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 ) | 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[]) | 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_server_control' : 'server_control.cpp', | ||||
| 'jack_net_slave' : 'netslave.c', | 'jack_net_slave' : 'netslave.c', | ||||
| 'jack_net_master' : 'netmaster.c', | 'jack_net_master' : 'netmaster.c', | ||||
| 'jack_latent_client' : 'latent_client.c', | |||||
| 'jack_midi_dump' : 'midi_dump.c', | |||||
| } | } | ||||
| example_libs = { | example_libs = { | ||||
| @@ -130,12 +132,6 @@ def build(bld): | |||||
| prog.includes = os_incdir + ['../common/jack', '../common'] | prog.includes = os_incdir + ['../common/jack', '../common'] | ||||
| prog.source = ['netsource.c', '../common/netjack_packet.c'] | prog.source = ['netsource.c', '../common/netjack_packet.c'] | ||||
| prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") | 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 = 'CELT SAMPLERATE' | ||||
| prog.uselib_local = 'clientlib' | prog.uselib_local = 'clientlib' | ||||
| prog.target = 'jack_netsource' | prog.target = 'jack_netsource' | ||||
| @@ -69,12 +69,15 @@ static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* ad | |||||
| #endif | #endif | ||||
| #if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__) | #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) | 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 | #endif | ||||
| @@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <inttypes.h> | |||||
| static jack_time_t __jack_cpu_mhz = 0; | static jack_time_t __jack_cpu_mhz = 0; | ||||
| jack_time_t (*_jack_get_microseconds)(void) = 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 { | } else { | ||||
| driver->channel_copy = memcpy_fake; | driver->channel_copy = memcpy_fake; | ||||
| } | } | ||||
| switch (driver->dither) { | switch (driver->dither) { | ||||
| case Rectangular: | case Rectangular: | ||||
| jack_info("Rectangular dithering at 16 bits"); | 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_sSs: | ||||
| sample_move_dither_rect_d16_sS; | sample_move_dither_rect_d16_sS; | ||||
| break; | break; | ||||
| case Triangular: | case Triangular: | ||||
| jack_info("Triangular dithering at 16 bits"); | jack_info("Triangular dithering at 16 bits"); | ||||
| driver->write_via_copy = driver->quirk_bswap? | driver->write_via_copy = driver->quirk_bswap? | ||||
| sample_move_dither_tri_d16_sSs: | sample_move_dither_tri_d16_sSs: | ||||
| sample_move_dither_tri_d16_sS; | sample_move_dither_tri_d16_sS; | ||||
| break; | break; | ||||
| case Shaped: | case Shaped: | ||||
| jack_info("Noise-shaped dithering at 16 bits"); | jack_info("Noise-shaped dithering at 16 bits"); | ||||
| driver->write_via_copy = driver->quirk_bswap? | driver->write_via_copy = driver->quirk_bswap? | ||||
| sample_move_dither_shaped_d16_sSs: | sample_move_dither_shaped_d16_sSs: | ||||
| sample_move_dither_shaped_d16_sS; | sample_move_dither_shaped_d16_sS; | ||||
| break; | break; | ||||
| default: | default: | ||||
| driver->write_via_copy = driver->quirk_bswap? | driver->write_via_copy = driver->quirk_bswap? | ||||
| sample_move_d16_sSs : | |||||
| sample_move_d16_sSs : | |||||
| sample_move_d16_sS; | sample_move_d16_sS; | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| case 3: /* NO DITHER */ | case 3: /* NO DITHER */ | ||||
| if (driver->playback_interleaved) { | if (driver->playback_interleaved) { | ||||
| driver->channel_copy = memcpy_interleave_d24_s24; | driver->channel_copy = memcpy_interleave_d24_s24; | ||||
| } else { | } else { | ||||
| driver->channel_copy = memcpy_fake; | driver->channel_copy = memcpy_fake; | ||||
| } | } | ||||
| driver->write_via_copy = driver->quirk_bswap? | driver->write_via_copy = driver->quirk_bswap? | ||||
| sample_move_d24_sSs: | |||||
| sample_move_d24_sSs: | |||||
| sample_move_d24_sS; | sample_move_d24_sS; | ||||
| break; | break; | ||||
| case 4: /* NO DITHER */ | case 4: /* NO DITHER */ | ||||
| if (driver->playback_interleaved) { | if (driver->playback_interleaved) { | ||||
| driver->channel_copy = memcpy_interleave_d32_s32; | 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? | driver->write_via_copy = driver->quirk_bswap? | ||||
| sample_move_d32u24_sSs: | |||||
| sample_move_d32u24_sSs: | |||||
| sample_move_d32u24_sS; | sample_move_d32u24_sS; | ||||
| break; | break; | ||||
| @@ -339,27 +339,27 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (driver->capture_handle) { | if (driver->capture_handle) { | ||||
| switch (driver->capture_sample_bytes) { | switch (driver->capture_sample_bytes) { | ||||
| case 2: | case 2: | ||||
| driver->read_via_copy = driver->quirk_bswap? | driver->read_via_copy = driver->quirk_bswap? | ||||
| sample_move_dS_s16s: | |||||
| sample_move_dS_s16s: | |||||
| sample_move_dS_s16; | sample_move_dS_s16; | ||||
| break; | break; | ||||
| case 3: | case 3: | ||||
| driver->read_via_copy = driver->quirk_bswap? | driver->read_via_copy = driver->quirk_bswap? | ||||
| sample_move_dS_s24s: | |||||
| sample_move_dS_s24s: | |||||
| sample_move_dS_s24; | sample_move_dS_s24; | ||||
| break; | break; | ||||
| case 4: | case 4: | ||||
| driver->read_via_copy = driver->quirk_bswap? | driver->read_via_copy = driver->quirk_bswap? | ||||
| sample_move_dS_s32u24s: | |||||
| sample_move_dS_s32u24s: | |||||
| sample_move_dS_s32u24; | sample_move_dS_s32u24; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -418,7 +418,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| format = (sample_width == 4) ? 0 : NUMFORMATS - 1; | format = (sample_width == 4) ? 0 : NUMFORMATS - 1; | ||||
| while (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); | jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); | ||||
| break; | break; | ||||
| } | } | ||||
| } | |||||
| } | |||||
| frame_rate = driver->frame_rate ; | frame_rate = driver->frame_rate ; | ||||
| err = snd_pcm_hw_params_set_rate_near (handle, hw_params, | 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); | &channels_max); | ||||
| *nchns = channels_max ; | *nchns = channels_max ; | ||||
| if (*nchns > 1024) { | |||||
| if (*nchns > 1024) { | |||||
| /* the hapless user is an unwitting victim of | /* the hapless user is an unwitting victim of | ||||
| the "default" ALSA PCM device, which can | 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" | "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" | "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, | if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, | ||||
| *nchns)) < 0) { | *nchns)) < 0) { | ||||
| @@ -491,7 +491,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||||
| *nchns, stream_name); | *nchns, stream_name); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, | if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, | ||||
| driver->frames_per_cycle, | driver->frames_per_cycle, | ||||
| 0)) | 0)) | ||||
| @@ -520,7 +520,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); | jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); | ||||
| #if 0 | |||||
| #if 0 | |||||
| if (!jack_power_of_two(driver->frames_per_cycle)) { | if (!jack_power_of_two(driver->frames_per_cycle)) { | ||||
| jack_error("JACK: frames must be a power of two " | jack_error("JACK: frames must be a power of two " | ||||
| "(64, 512, 1024, ...)\n"); | "(64, 512, 1024, ...)\n"); | ||||
| @@ -557,7 +557,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||||
| if (driver->soft_mode) { | if (driver->soft_mode) { | ||||
| stop_th = (snd_pcm_uframes_t)-1; | stop_th = (snd_pcm_uframes_t)-1; | ||||
| } | } | ||||
| if ((err = snd_pcm_sw_params_set_stop_threshold ( | if ((err = snd_pcm_sw_params_set_stop_threshold ( | ||||
| handle, sw_params, stop_th)) < 0) { | handle, sw_params, stop_th)) < 0) { | ||||
| jack_error ("ALSA: cannot set stop mode for %s", | 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 | else | ||||
| err = snd_pcm_sw_params_set_avail_min ( | err = snd_pcm_sw_params_set_avail_min ( | ||||
| handle, sw_params, driver->frames_per_cycle); | handle, sw_params, driver->frames_per_cycle); | ||||
| if (err < 0) { | if (err < 0) { | ||||
| jack_error ("ALSA: cannot set avail min for %s", stream_name); | jack_error ("ALSA: cannot set avail min for %s", stream_name); | ||||
| return -1; | return -1; | ||||
| @@ -1158,7 +1158,7 @@ int | |||||
| JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) | JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) | ||||
| { | { | ||||
| int res; | int res; | ||||
| driver->xrun_recovery = 1; | driver->xrun_recovery = 1; | ||||
| if ((res = Stop()) == 0) | if ((res = Stop()) == 0) | ||||
| res = Start(); | 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 | if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN | ||||
| && driver->process_count > XRUN_REPORT_DELAY) { | && driver->process_count > XRUN_REPORT_DELAY) { | ||||
| struct timeval now, diff, tstamp; | struct timeval now, diff, tstamp; | ||||
| driver->xrun_count++; | 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); | snd_pcm_status_get_trigger_tstamp(status, &tstamp); | ||||
| timersub(&now, &tstamp, &diff); | timersub(&now, &tstamp, &diff); | ||||
| *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; | *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: | again: | ||||
| while (need_playback || need_capture) { | while (need_playback || need_capture) { | ||||
| int poll_result; | int poll_result; | ||||
| @@ -1269,7 +1282,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||||
| driver->playback_nfds); | driver->playback_nfds); | ||||
| nfds += driver->playback_nfds; | nfds += driver->playback_nfds; | ||||
| } | } | ||||
| if (need_capture) { | if (need_capture) { | ||||
| snd_pcm_poll_descriptors (driver->capture_handle, | snd_pcm_poll_descriptors (driver->capture_handle, | ||||
| &driver->pfd[nfds], | &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 */ | /* ALSA doesn't set POLLERR in some versions of 0.9.X */ | ||||
| for (i = 0; i < nfds; i++) { | for (i = 0; i < nfds; i++) { | ||||
| driver->pfd[i].events |= POLLERR; | driver->pfd[i].events |= POLLERR; | ||||
| } | } | ||||
| @@ -1316,12 +1329,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||||
| *status = -2; | *status = -2; | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| jack_error ("ALSA: poll call failed (%s)", | jack_error ("ALSA: poll call failed (%s)", | ||||
| strerror (errno)); | strerror (errno)); | ||||
| *status = -3; | *status = -3; | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| poll_ret = jack_get_microseconds (); | 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 (extra_fd < 0) { | ||||
| if (driver->poll_next && poll_ret > driver->poll_next) { | if (driver->poll_next && poll_ret > driver->poll_next) { | ||||
| *delayed_usecs = poll_ret - driver->poll_next; | *delayed_usecs = poll_ret - driver->poll_next; | ||||
| } | |||||
| } | |||||
| driver->poll_last = poll_ret; | driver->poll_last = poll_ret; | ||||
| driver->poll_next = poll_ret + driver->period_usecs; | driver->poll_next = poll_ret + driver->period_usecs; | ||||
| // steph | // steph | ||||
| /* | /* | ||||
| driver->engine->transport_cycle_start (driver->engine, | |||||
| driver->engine->transport_cycle_start (driver->engine, | |||||
| poll_ret); | poll_ret); | ||||
| */ | */ | ||||
| } | } | ||||
| @@ -1358,7 +1371,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||||
| *status = -4; | *status = -4; | ||||
| return -1; | return -1; | ||||
| } | |||||
| } | |||||
| /* if POLLIN was the only bit set, we're OK */ | /* 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 | #endif | ||||
| } | } | ||||
| } | } | ||||
| if (poll_result == 0) { | if (poll_result == 0) { | ||||
| jack_error ("ALSA: poll time out, polled for %" PRIu64 | jack_error ("ALSA: poll time out, polled for %" PRIu64 | ||||
| " usecs", | " usecs", | ||||
| poll_ret - poll_enter); | poll_ret - poll_enter); | ||||
| *status = -5; | *status = -5; | ||||
| return 0; | return 0; | ||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1437,7 +1450,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||||
| } | } | ||||
| } else { | } else { | ||||
| /* odd, but see min() computation below */ | /* odd, but see min() computation below */ | ||||
| capture_avail = INT_MAX; | |||||
| capture_avail = INT_MAX; | |||||
| } | } | ||||
| if (driver->playback_handle) { | if (driver->playback_handle) { | ||||
| @@ -1452,7 +1465,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||||
| } | } | ||||
| } else { | } else { | ||||
| /* odd, but see min() computation below */ | /* odd, but see min() computation below */ | ||||
| playback_avail = INT_MAX; | |||||
| playback_avail = INT_MAX; | |||||
| } | } | ||||
| if (xrun_detected) { | if (xrun_detected) { | ||||
| @@ -1531,7 +1544,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||||
| if (!driver->capture_handle) { | if (!driver->capture_handle) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| nread = 0; | nread = 0; | ||||
| contiguous = 0; | contiguous = 0; | ||||
| orig_nframes = nframes; | orig_nframes = nframes; | ||||
| @@ -1559,11 +1572,11 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||||
| /* // steph | /* // steph | ||||
| for (chn = 0, node = driver->capture_ports; node; | for (chn = 0, node = driver->capture_ports; node; | ||||
| node = jack_slist_next (node), chn++) { | node = jack_slist_next (node), chn++) { | ||||
| port = (jack_port_t *) node->data; | port = (jack_port_t *) node->data; | ||||
| if (!jack_port_connected (port)) { | if (!jack_port_connected (port)) { | ||||
| // no-copy optimization | |||||
| // no-copy optimization | |||||
| continue; | continue; | ||||
| } | } | ||||
| buf = jack_port_get_buffer (port, orig_nframes); | 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, | if ((err = snd_pcm_mmap_commit (driver->capture_handle, | ||||
| offset, contiguous)) < 0) { | offset, contiguous)) < 0) { | ||||
| jack_error ("ALSA: could not complete read of %" | jack_error ("ALSA: could not complete read of %" | ||||
| PRIu32 " frames: error = %d\n", contiguous, err); | PRIu32 " frames: error = %d\n", contiguous, err); | ||||
| return -1; | 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); | monbuf = jack_port_get_buffer (port, orig_nframes); | ||||
| memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); | 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) { | offset, contiguous)) < 0) { | ||||
| jack_error ("ALSA: could not complete playback of %" | jack_error ("ALSA: could not complete playback of %" | ||||
| PRIu32 " frames: error = %d", contiguous, err); | PRIu32 " frames: error = %d", contiguous, err); | ||||
| if (err != EPIPE && err != ESTRPIPE) | |||||
| if (err != -EPIPE && err != -ESTRPIPE) | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -1739,11 +1752,11 @@ JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver) | |||||
| free (node->data); | free (node->data); | ||||
| } | } | ||||
| jack_slist_free (driver->clock_sync_listeners); | jack_slist_free (driver->clock_sync_listeners); | ||||
| if (driver->ctl_handle) { | if (driver->ctl_handle) { | ||||
| snd_ctl_close (driver->ctl_handle); | snd_ctl_close (driver->ctl_handle); | ||||
| driver->ctl_handle = 0; | driver->ctl_handle = 0; | ||||
| } | |||||
| } | |||||
| if (driver->capture_handle) { | if (driver->capture_handle) { | ||||
| snd_pcm_close (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 | jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 | ||||
| "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", | "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", | ||||
| playing ? playback_alsa_device : "-", | playing ? playback_alsa_device : "-", | ||||
| capturing ? capture_alsa_device : "-", | |||||
| capturing ? capture_alsa_device : "-", | |||||
| frames_per_cycle, user_nperiods, rate, | frames_per_cycle, user_nperiods, rate, | ||||
| user_capture_nchnls,user_playback_nchnls, | user_capture_nchnls,user_playback_nchnls, | ||||
| hw_monitoring ? "hwmon": "nomon", | hw_monitoring ? "hwmon": "nomon", | ||||
| hw_metering ? "hwmeter":"swmeter", | hw_metering ? "hwmeter":"swmeter", | ||||
| soft_mode ? "soft-mode":"-", | soft_mode ? "soft-mode":"-", | ||||
| shorts_first ? "16bit":"32bit"); | shorts_first ? "16bit":"32bit"); | ||||
| driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); | driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); | ||||
| jack_driver_nt_init ((jack_driver_nt_t *) driver); | 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->playback_addr = 0; | ||||
| driver->capture_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->silent = 0; | ||||
| driver->all_monitor_in = FALSE; | driver->all_monitor_in = FALSE; | ||||
| @@ -2071,6 +2084,7 @@ int JackAlsaDriver::Attach() | |||||
| unsigned long port_flags; | unsigned long port_flags; | ||||
| char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | ||||
| char alias[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(fCaptureChannels < DRIVER_PORT_NUM); | ||||
| assert(fPlaybackChannels < DRIVER_PORT_NUM); | assert(fPlaybackChannels < DRIVER_PORT_NUM); | ||||
| @@ -2097,7 +2111,8 @@ int JackAlsaDriver::Attach() | |||||
| } | } | ||||
| port = fGraphManager->GetPort(port_index); | port = fGraphManager->GetPort(port_index); | ||||
| port->SetAlias(alias); | 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; | fCapturePortList[i] = port_index; | ||||
| jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index); | jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index); | ||||
| } | } | ||||
| @@ -2114,8 +2129,10 @@ int JackAlsaDriver::Attach() | |||||
| port = fGraphManager->GetPort(port_index); | port = fGraphManager->GetPort(port_index); | ||||
| port->SetAlias(alias); | port->SetAlias(alias); | ||||
| // Add one buffer more latency if "async" mode is used... | // 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; | fPlaybackPortList[i] = port_index; | ||||
| jack_log("JackAudioDriver::Attach fPlaybackPortList[i] %ld ", 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); | jack_error ("ALSA: cannot register monitor port for %s", name); | ||||
| } else { | } else { | ||||
| port = fGraphManager->GetPort(port_index); | 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; | fMonitorPortList[i] = port_index; | ||||
| } | } | ||||
| } | } | ||||
| @@ -2151,7 +2169,7 @@ int JackAlsaDriver::Detach() | |||||
| return JackAudioDriver::Detach(); | return JackAudioDriver::Detach(); | ||||
| } | } | ||||
| static int card_to_num(const char* device) | |||||
| static int card_to_num(const char* device) | |||||
| { | { | ||||
| int err; | int err; | ||||
| char* ctl_name; | char* ctl_name; | ||||
| @@ -2316,13 +2334,13 @@ int JackAlsaDriver::Read() | |||||
| retry: | retry: | ||||
| nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | ||||
| if (wait_status < 0) | if (wait_status < 0) | ||||
| return -1; /* driver failed */ | return -1; /* driver failed */ | ||||
| if (nframes == 0) { | if (nframes == 0) { | ||||
| /* we detected an xrun and restarted: notify | /* we detected an xrun and restarted: notify | ||||
| * clients about the delay. | |||||
| * clients about the delay. | |||||
| */ | */ | ||||
| jack_log("ALSA XRun wait_status = %d", wait_status); | jack_log("ALSA XRun wait_status = %d", wait_status); | ||||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | NotifyXRun(fBeginDateUst, fDelayedUsecs); | ||||
| @@ -2331,7 +2349,7 @@ retry: | |||||
| if (nframes != fEngineControl->fBufferSize) | if (nframes != fEngineControl->fBufferSize) | ||||
| jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes); | jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes); | ||||
| // Has to be done before read | // Has to be done before read | ||||
| JackDriver::CycleIncTime(); | JackDriver::CycleIncTime(); | ||||
| @@ -2619,7 +2637,7 @@ get_dither_constraint() | |||||
| } | } | ||||
| static int | static int | ||||
| dither_opt (char c, DitherAlgorithm* dither) | |||||
| dither_opt (char c, DitherAlgorithm* dither) | |||||
| { | { | ||||
| switch (c) { | switch (c) { | ||||
| case '-': | case '-': | ||||
| @@ -2646,17 +2664,17 @@ dither_opt (char c, DitherAlgorithm* dither) | |||||
| return 0; | 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_desc_t * desc; | ||||
| jack_driver_param_desc_t * params; | jack_driver_param_desc_t * params; | ||||
| unsigned int i; | unsigned int i; | ||||
| desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); | 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->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 | strcpy(desc->desc, "Linux ALSA API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | ||||
| desc->nparams = 18; | desc->nparams = 18; | ||||
| params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | 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; | 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 srate = 48000; | ||||
| jack_nframes_t frames_per_interrupt = 1024; | jack_nframes_t frames_per_interrupt = 1024; | ||||
| @@ -104,7 +104,7 @@ typedef struct input_port_t { | |||||
| // jack | // jack | ||||
| midi_unpack_t unpack; | midi_unpack_t unpack; | ||||
| // midi | // midi | ||||
| int overruns; | int overruns; | ||||
| } input_port_t; | } input_port_t; | ||||
| @@ -114,7 +114,7 @@ typedef struct output_port_t { | |||||
| // jack | // jack | ||||
| midi_pack_t packer; | midi_pack_t packer; | ||||
| // midi | // midi | ||||
| event_head_t next_event; | event_head_t next_event; | ||||
| int todo; | 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) | inline int midi_port_open_jack(alsa_rawmidi_t *midi, midi_port_t *port, int type, const char *alias) | ||||
| { | { | ||||
| char name[128]; | char name[128]; | ||||
| if (type & JackPortIsOutput) | if (type & JackPortIsOutput) | ||||
| snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++midi->midi_in_cnt); | 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); | 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, | 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); | jack_port_set_alias(port->jack, alias); | ||||
| return port->jack == NULL; | return port->jack == NULL; | ||||
| } | } | ||||
| @@ -455,7 +455,7 @@ int midi_port_open(alsa_rawmidi_t *midi, midi_port_t *port) | |||||
| out = &port->rawmidi; | out = &port->rawmidi; | ||||
| type = JackPortIsInput; | type = JackPortIsInput; | ||||
| } | } | ||||
| if ((err = snd_rawmidi_open(in, out, port->dev, SND_RAWMIDI_NONBLOCK))<0) | if ((err = snd_rawmidi_open(in, out, port->dev, SND_RAWMIDI_NONBLOCK))<0) | ||||
| return err; | return err; | ||||
| @@ -749,7 +749,7 @@ void* scan_thread(void *arg) | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* | |||||
| /* | |||||
| * ------------------------------- Input/Output ------------------------------ | * ------------------------------- Input/Output ------------------------------ | ||||
| */ | */ | ||||
| @@ -836,7 +836,7 @@ void *midi_thread(void *arg) | |||||
| npfds = 1; | npfds = 1; | ||||
| if (jack_is_realtime(midi->client)) | if (jack_is_realtime(midi->client)) | ||||
| set_threaded_log_function(); | |||||
| set_threaded_log_function(); | |||||
| //debug_log("midi_thread(%s): enter", str->name); | //debug_log("midi_thread(%s): enter", str->name); | ||||
| @@ -978,7 +978,7 @@ int midi_update_pfds(process_midi_t *proc) | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| /* | |||||
| /* | |||||
| * ------------------------------------ Input ------------------------------ | * ------------------------------------ Input ------------------------------ | ||||
| */ | */ | ||||
| @@ -1083,7 +1083,7 @@ int do_midi_input(process_midi_t *proc) | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| /* | |||||
| /* | |||||
| * ------------------------------------ Output ------------------------------ | * ------------------------------------ Output ------------------------------ | ||||
| */ | */ | ||||
| @@ -1149,7 +1149,7 @@ int do_midi_output(process_midi_t *proc) | |||||
| } else | } 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); | 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) | if (port->todo) | ||||
| debug_log("midi_out: todo = %d at %ld", (int)port->todo, (long)proc->cur_time); | 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->client_id = snd_seq_client_id(self->seq); | ||||
| self->queue = snd_seq_alloc_queue(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_INPUT); | ||||
| stream_attach(self, PORT_OUTPUT); | 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 */ | /* 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)) { | 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) | if (jack_caps & JackPortIsOutput) | ||||
| snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt); | 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); | snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt); | ||||
| port->jack_port = jack_port_register(self->jack, | port->jack_port = jack_port_register(self->jack, | ||||
| name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0); | name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0); | ||||
| if (!port->jack_port) | if (!port->jack_port) | ||||
| @@ -588,7 +588,7 @@ void update_ports(alsa_seqmidi_t *self) | |||||
| snd_seq_port_info_alloca(&info); | snd_seq_port_info_alloca(&info); | ||||
| while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) { | while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) { | ||||
| int err; | int err; | ||||
| assert (size == sizeof(addr)); | 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; | info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec; | ||||
| if (info->period_start + info->nframes < info->cur_frames) { | 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; | info->period_start += periods_lost * info->nframes; | ||||
| debug_log("xrun detected: %d periods lost\n", periods_lost); | 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; | ev.size = size; | ||||
| jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); | jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); | ||||
| jack_ringbuffer_write(port->early_events, (char*)data, size); | 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; | return; | ||||
| } | } | ||||
| @@ -829,7 +829,7 @@ void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes) | |||||
| return; | return; | ||||
| set_process_info(&info, self, PORT_INPUT, nframes); | 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) { | while ((res = snd_seq_event_input(self->seq, &event))>0) { | ||||
| if (event->source.client == SND_SEQ_CLIENT_SYSTEM) | 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 | Copyright (C) 2005 Karsten Wiese, Rui Nuno Capela | ||||
| This program is free software; you can redistribute it and/or modify | This program is free software; you can redistribute it and/or modify | ||||
| @@ -33,14 +33,14 @@ | |||||
| int dbg_offset; | int dbg_offset; | ||||
| char dbg_buffer[8096]; | char dbg_buffer[8096]; | ||||
| #endif | #endif | ||||
| static | |||||
| static | |||||
| int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | ||||
| { | { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| static | 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; | return -1; | ||||
| } | } | ||||
| @@ -52,7 +52,7 @@ usx2y_release (jack_hardware_t *hw) | |||||
| if (h == 0) | if (h == 0) | ||||
| return; | return; | ||||
| if (h->hwdep_handle) | if (h->hwdep_handle) | ||||
| snd_hwdep_close(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) { | offset, nframes_)) < 0) { | ||||
| jack_error ("ALSA/USX2Y: could not complete playback of %" | jack_error ("ALSA/USX2Y: could not complete playback of %" | ||||
| PRIu32 " frames: error = %d", nframes_, err); | PRIu32 " frames: error = %d", nframes_, err); | ||||
| if (err != EPIPE && err != ESTRPIPE) | |||||
| if (err != -EPIPE && err != -ESTRPIPE) | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -37,8 +37,6 @@ | |||||
| * regardless of how fast the machine is. | * regardless of how fast the machine is. | ||||
| */ | */ | ||||
| #ifdef __linux__ | |||||
| #ifdef __x86_64__ | #ifdef __x86_64__ | ||||
| typedef unsigned long cycles_t; | 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 /* 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__ */ | #endif /* __jack_cycles_h__ */ | ||||
| @@ -272,7 +272,7 @@ JackFFADODriver::SetBufferSize (jack_nframes_t nframes) | |||||
| printError("Buffer size change requested but not supported!!!"); | printError("Buffer size change requested but not supported!!!"); | ||||
| /* | /* | ||||
| driver->period_size = nframes; | |||||
| driver->period_size = nframes; | |||||
| driver->period_usecs = | driver->period_usecs = | ||||
| (jack_time_t) floor ((((float) nframes) / driver->sample_rate) | (jack_time_t) floor ((((float) nframes) / driver->sample_rate) | ||||
| * 1000000.0f); | * 1000000.0f); | ||||
| @@ -362,6 +362,7 @@ int JackFFADODriver::Attach() | |||||
| int port_index; | int port_index; | ||||
| char buf[JACK_PORT_NAME_SIZE]; | char buf[JACK_PORT_NAME_SIZE]; | ||||
| char portname[JACK_PORT_NAME_SIZE]; | char portname[JACK_PORT_NAME_SIZE]; | ||||
| jack_latency_range_t range; | |||||
| ffado_driver_t* driver = (ffado_driver_t*)fDriver; | ffado_driver_t* driver = (ffado_driver_t*)fDriver; | ||||
| @@ -447,7 +448,8 @@ int JackFFADODriver::Attach() | |||||
| ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); | ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); | ||||
| port = fGraphManager->GetPort(port_index); | 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) | // capture port aliases (jackd1 style port names) | ||||
| snprintf(buf, sizeof(buf) - 1, "%s:capture_%i", fClientControl.fName, (int) chn + 1); | snprintf(buf, sizeof(buf) - 1, "%s:capture_%i", fClientControl.fName, (int) chn + 1); | ||||
| port->SetAlias(buf); | 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)); | driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); | ||||
| port = fGraphManager->GetPort(port_index); | 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; | fCapturePortList[chn] = port_index; | ||||
| jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); | jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); | ||||
| fCaptureChannels++; | fCaptureChannels++; | ||||
| @@ -523,7 +526,8 @@ int JackFFADODriver::Attach() | |||||
| port = fGraphManager->GetPort(port_index); | port = fGraphManager->GetPort(port_index); | ||||
| // Add one buffer more latency if "async" mode is used... | // 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) | // playback port aliases (jackd1 style port names) | ||||
| snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1); | snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1); | ||||
| port->SetAlias(buf); | port->SetAlias(buf); | ||||
| @@ -549,7 +553,7 @@ int JackFFADODriver::Attach() | |||||
| printError(" cannot enable port %s", buf); | printError(" cannot enable port %s", buf); | ||||
| } | } | ||||
| // setup the midi buffer | // setup the midi buffer | ||||
| // This constructor optionally accepts arguments for the | // This constructor optionally accepts arguments for the | ||||
| // non-realtime buffer size and the realtime buffer size. Ideally, | // non-realtime buffer size and the realtime buffer size. Ideally, | ||||
| // these would become command-line options for the FFADO driver. | // 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)); | driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); | ||||
| port = fGraphManager->GetPort(port_index); | 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; | fPlaybackPortList[chn] = port_index; | ||||
| jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); | jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); | ||||
| fPlaybackChannels++; | fPlaybackChannels++; | ||||
| @@ -676,7 +681,7 @@ retry: | |||||
| if (nframes == 0) { | if (nframes == 0) { | ||||
| /* we detected an xrun and restarted: notify | /* we detected an xrun and restarted: notify | ||||
| * clients about the delay. | |||||
| * clients about the delay. | |||||
| */ | */ | ||||
| jack_log("FFADO XRun"); | jack_log("FFADO XRun"); | ||||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | NotifyXRun(fBeginDateUst, fDelayedUsecs); | ||||
| @@ -685,7 +690,7 @@ retry: | |||||
| if (nframes != fEngineControl->fBufferSize) | if (nframes != fEngineControl->fBufferSize) | ||||
| jack_log("JackFFADODriver::Read warning nframes = %ld", nframes); | jack_log("JackFFADODriver::Read warning nframes = %ld", nframes); | ||||
| // Has to be done before read | // Has to be done before read | ||||
| JackDriver::CycleIncTime(); | JackDriver::CycleIncTime(); | ||||
| @@ -755,7 +760,7 @@ extern "C" | |||||
| strcpy (desc->name, "firewire"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | 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 | strcpy(desc->desc, "Linux FFADO API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | ||||
| desc->nparams = 13; | desc->nparams = 13; | ||||
| params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | 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!!!"); | printError("Buffer size change requested but not supported!!!"); | ||||
| /* | /* | ||||
| driver->period_size = nframes; | |||||
| driver->period_size = nframes; | |||||
| driver->period_usecs = | driver->period_usecs = | ||||
| (jack_time_t) floor ((((float) nframes) / driver->sample_rate) | (jack_time_t) floor ((((float) nframes) / driver->sample_rate) | ||||
| * 1000000.0f); | * 1000000.0f); | ||||
| @@ -667,9 +667,10 @@ int JackFreebobDriver::Attach() | |||||
| { | { | ||||
| JackPort* port; | JackPort* port; | ||||
| int port_index; | int port_index; | ||||
| char buf[JACK_PORT_NAME_SIZE]; | char buf[JACK_PORT_NAME_SIZE]; | ||||
| char portname[JACK_PORT_NAME_SIZE]; | char portname[JACK_PORT_NAME_SIZE]; | ||||
| jack_latency_range_t range; | |||||
| freebob_driver_t* driver = (freebob_driver_t*)fDriver; | freebob_driver_t* driver = (freebob_driver_t*)fDriver; | ||||
| @@ -737,7 +738,8 @@ int JackFreebobDriver::Attach() | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| port = fGraphManager->GetPort(port_index); | 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; | fCapturePortList[i] = port_index; | ||||
| jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index); | jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index); | ||||
| driver->capture_nchannels_audio++; | driver->capture_nchannels_audio++; | ||||
| @@ -766,7 +768,8 @@ int JackFreebobDriver::Attach() | |||||
| } | } | ||||
| port = fGraphManager->GetPort(port_index); | port = fGraphManager->GetPort(port_index); | ||||
| // Add one buffer more latency if "async" mode is used... | // 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; | fPlaybackPortList[i] = port_index; | ||||
| jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index); | jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index); | ||||
| driver->playback_nchannels_audio++; | driver->playback_nchannels_audio++; | ||||
| @@ -866,7 +869,7 @@ retry: | |||||
| if (nframes == 0) { | if (nframes == 0) { | ||||
| /* we detected an xrun and restarted: notify | /* we detected an xrun and restarted: notify | ||||
| * clients about the delay. | |||||
| * clients about the delay. | |||||
| */ | */ | ||||
| jack_log("FreeBoB XRun"); | jack_log("FreeBoB XRun"); | ||||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | NotifyXRun(fBeginDateUst, fDelayedUsecs); | ||||
| @@ -878,7 +881,7 @@ retry: | |||||
| // Has to be done before read | // Has to be done before read | ||||
| JackDriver::CycleIncTime(); | JackDriver::CycleIncTime(); | ||||
| printExit(); | printExit(); | ||||
| return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize); | 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->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 | strcpy(desc->desc, "Linux FreeBob API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | ||||
| desc->nparams = 11; | desc->nparams = 11; | ||||
| params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | ||||
| @@ -7,7 +7,7 @@ | |||||
| <key>CFBundleExecutable</key> | <key>CFBundleExecutable</key> | ||||
| <string>Jackservermp</string> | <string>Jackservermp</string> | ||||
| <key>CFBundleGetInfoString</key> | <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> | <key>CFBundleIdentifier</key> | ||||
| <string>com.grame.Jackmp</string> | <string>com.grame.Jackmp</string> | ||||
| <key>CFBundleInfoDictionaryVersion</key> | <key>CFBundleInfoDictionaryVersion</key> | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 | 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) { | if (inPriority == 96) { | ||||
| // REAL-TIME / TIME-CONSTRAINT THREAD | // 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 | // 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); | return GetThreadPriority(thread, THREAD_SET_PRIORITY); | ||||
| } | } | ||||
| // returns the thread's priority as it was last scheduled by the Kernel | // 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); | 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; | thread_basic_info_data_t threadInfo; | ||||
| policy_info_data_t thePolicyInfo; | policy_info_data_t thePolicyInfo; | ||||
| @@ -127,7 +127,7 @@ UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority) | |||||
| return 0; | 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; | thread_time_constraint_policy_data_t theTCPolicy; | ||||
| mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT; | 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) | // pthread_cancel still not yet implemented in Darwin (TO CHECK ON TIGER) | ||||
| jack_log("JackMachThread::Kill"); | 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); | mach_port_t machThread = pthread_mach_thread_np(fThread); | ||||
| int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1; | int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1; | ||||
| fThread = (pthread_t)NULL; | |||||
| fThread = (jack_native_thread_t)NULL; | |||||
| return res; | return res; | ||||
| } else { | } else { | ||||
| return -1; | return -1; | ||||
| @@ -175,7 +175,7 @@ int JackMachThread::AcquireRealTime() | |||||
| { | { | ||||
| jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld", | jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld", | ||||
| long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000)); | 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() | int JackMachThread::AcquireSelfRealTime() | ||||
| @@ -197,7 +197,7 @@ int JackMachThread::AcquireSelfRealTime(int priority) | |||||
| return AcquireSelfRealTime(); | 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); | SetThreadToPriority(thread, 96, true, period, computation, constraint); | ||||
| return 0; | return 0; | ||||
| @@ -205,7 +205,7 @@ int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 c | |||||
| int JackMachThread::DropRealTime() | int JackMachThread::DropRealTime() | ||||
| { | { | ||||
| return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||||
| return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||||
| } | } | ||||
| int JackMachThread::DropSelfRealTime() | int JackMachThread::DropSelfRealTime() | ||||
| @@ -213,7 +213,7 @@ int JackMachThread::DropSelfRealTime() | |||||
| return DropRealTimeImp(pthread_self()); | 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); | SetThreadToPriority(thread, 63, false, 0, 0, 0); | ||||
| return 0; | return 0; | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 fComputation; | ||||
| UInt64 fConstraint; | 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: | public: | ||||
| @@ -116,23 +116,23 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread | |||||
| int AcquireRealTime(); // Used when called from another thread | int AcquireRealTime(); // Used when called from another thread | ||||
| int AcquireSelfRealTime(); // Used when called from thread itself | int AcquireSelfRealTime(); // Used when called from thread itself | ||||
| int AcquireRealTime(int priority); // Used when called from another thread | int AcquireRealTime(int priority); // Used when called from another thread | ||||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | int AcquireSelfRealTime(int priority); // Used when called from thread itself | ||||
| int DropRealTime(); // Used when called from another thread | int DropRealTime(); // Used when called from another thread | ||||
| int DropSelfRealTime(); // Used when called from thread itself | int DropSelfRealTime(); // Used when called from thread itself | ||||
| void SetParams(UInt64 period, UInt64 computation, UInt64 constraint); | 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 | } // end of namespace | ||||
| @@ -184,9 +184,9 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice | |||||
| AudioDevicePropertyID inPropertyID, | AudioDevicePropertyID inPropertyID, | ||||
| void* inClientData) | void* inClientData) | ||||
| { | { | ||||
| switch (inPropertyID) { | switch (inPropertyID) { | ||||
| case kAudioDeviceProcessorOverload: { | case kAudioDeviceProcessorOverload: { | ||||
| jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload"); | jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload"); | ||||
| break; | break; | ||||
| @@ -196,12 +196,12 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice | |||||
| jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration"); | jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration"); | ||||
| return kAudioHardwareUnsupportedOperationError; | return kAudioHardwareUnsupportedOperationError; | ||||
| } | } | ||||
| case kAudioDevicePropertyNominalSampleRate: { | case kAudioDevicePropertyNominalSampleRate: { | ||||
| jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate"); | jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate"); | ||||
| return kAudioHardwareUnsupportedOperationError; | return kAudioHardwareUnsupportedOperationError; | ||||
| } | } | ||||
| } | } | ||||
| return noErr; | return noErr; | ||||
| } | } | ||||
| @@ -217,7 +217,7 @@ int JackCoreAudioAdapter::AddListeners() | |||||
| printError(err); | printError(err); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); | err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); | ||||
| if (err != noErr) { | if (err != noErr) { | ||||
| jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); | jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); | ||||
| @@ -275,17 +275,17 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon, | |||||
| { | { | ||||
| JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon); | JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon); | ||||
| AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); | AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); | ||||
| float* inputBuffer[adapter->fCaptureChannels]; | float* inputBuffer[adapter->fCaptureChannels]; | ||||
| float* outputBuffer[adapter->fPlaybackChannels]; | float* outputBuffer[adapter->fPlaybackChannels]; | ||||
| for (int i = 0; i < adapter->fCaptureChannels; i++) { | for (int i = 0; i < adapter->fCaptureChannels; i++) { | ||||
| inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData; | inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData; | ||||
| } | } | ||||
| for (int i = 0; i < adapter->fPlaybackChannels; i++) { | for (int i = 0; i < adapter->fPlaybackChannels; i++) { | ||||
| outputBuffer[i] = (float*)ioData->mBuffers[i].mData; | outputBuffer[i] = (float*)ioData->mBuffers[i].mData; | ||||
| } | } | ||||
| adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames); | adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames); | ||||
| return noErr; | return noErr; | ||||
| } | } | ||||
| @@ -302,16 +302,16 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||||
| fCaptureUID[0] = 0; | fCaptureUID[0] = 0; | ||||
| fPlaybackUID[0] = 0; | fPlaybackUID[0] = 0; | ||||
| fClockDriftCompensate = false; | fClockDriftCompensate = false; | ||||
| // Default values | // Default values | ||||
| fCaptureChannels = -1; | fCaptureChannels = -1; | ||||
| fPlaybackChannels = -1; | fPlaybackChannels = -1; | ||||
| SInt32 major; | SInt32 major; | ||||
| SInt32 minor; | SInt32 minor; | ||||
| Gestalt(gestaltSystemVersionMajor, &major); | Gestalt(gestaltSystemVersionMajor, &major); | ||||
| Gestalt(gestaltSystemVersionMinor, &minor); | Gestalt(gestaltSystemVersionMinor, &minor); | ||||
| // Starting with 10.6 systems, the HAL notification thread is created internally | // Starting with 10.6 systems, the HAL notification thread is created internally | ||||
| if (major == 10 && minor >= 6) { | if (major == 10 && minor >= 6) { | ||||
| CFRunLoopRef theRunLoop = NULL; | CFRunLoopRef theRunLoop = NULL; | ||||
| @@ -321,7 +321,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||||
| jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error"); | jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error"); | ||||
| } | } | ||||
| } | } | ||||
| for (node = params; node; node = jack_slist_next(node)) { | for (node = params; node; node = jack_slist_next(node)) { | ||||
| param = (const jack_driver_param_t*) node->data; | param = (const jack_driver_param_t*) node->data; | ||||
| @@ -348,7 +348,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||||
| fPlaying = true; | fPlaying = true; | ||||
| strncpy(fPlaybackUID, param->value.str, 256); | strncpy(fPlaybackUID, param->value.str, 256); | ||||
| break; | break; | ||||
| case 'd': | case 'd': | ||||
| strncpy(fCaptureUID, param->value.str, 256); | strncpy(fCaptureUID, param->value.str, 256); | ||||
| strncpy(fPlaybackUID, 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': | case 'p': | ||||
| SetAdaptedBufferSize(param->value.ui); | SetAdaptedBufferSize(param->value.ui); | ||||
| break; | break; | ||||
| case 'l': | case 'l': | ||||
| DisplayDeviceNames(); | DisplayDeviceNames(); | ||||
| break; | break; | ||||
| case 'q': | case 'q': | ||||
| fQuality = param->value.ui; | fQuality = param->value.ui; | ||||
| break; | break; | ||||
| case 'g': | case 'g': | ||||
| fRingbufferCurSize = param->value.ui; | fRingbufferCurSize = param->value.ui; | ||||
| fAdaptative = false; | fAdaptative = false; | ||||
| break; | break; | ||||
| case 's': | case 's': | ||||
| fClockDriftCompensate = true; | fClockDriftCompensate = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* duplex is the default */ | /* duplex is the default */ | ||||
| if (!fCapturing && !fPlaying) { | if (!fCapturing && !fPlaying) { | ||||
| fCapturing = true; | fCapturing = true; | ||||
| fPlaying = true; | fPlaying = true; | ||||
| } | } | ||||
| if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) | if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) | ||||
| throw -1; | throw -1; | ||||
| if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) | if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) | ||||
| throw -1; | throw -1; | ||||
| if (SetupBufferSize(fAdaptedBufferSize) < 0) | if (SetupBufferSize(fAdaptedBufferSize) < 0) | ||||
| throw -1; | throw -1; | ||||
| if (SetupSampleRate(fAdaptedSampleRate) < 0) | if (SetupSampleRate(fAdaptedSampleRate) < 0) | ||||
| throw -1; | 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; | throw -1; | ||||
| if (fCapturing && fCaptureChannels > 0) | if (fCapturing && fCaptureChannels > 0) | ||||
| if (SetupBuffers(fCaptureChannels) < 0) | if (SetupBuffers(fCaptureChannels) < 0) | ||||
| throw -1; | throw -1; | ||||
| if (AddListeners() < 0) | if (AddListeners() < 0) | ||||
| throw -1; | throw -1; | ||||
| } | } | ||||
| @@ -488,6 +488,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID* id) | |||||
| if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) | if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) | ||||
| return res; | 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); | jack_log("GetDefaultInputDevice: input = %ld ", inDefault); | ||||
| *id = inDefault; | *id = inDefault; | ||||
| return noErr; | return noErr; | ||||
| @@ -502,6 +506,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID* id) | |||||
| if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) | if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) | ||||
| return res; | 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); | jack_log("GetDefaultOutputDevice: output = %ld", outDefault); | ||||
| *id = outDefault; | *id = outDefault; | ||||
| return noErr; | return noErr; | ||||
| @@ -525,10 +533,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||||
| // Duplex | // Duplex | ||||
| if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | ||||
| // Same device for capture and playback... | // Same device for capture and playback... | ||||
| if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { | if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { | ||||
| if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | ||||
| jack_log("Will take default in/out"); | jack_log("Will take default in/out"); | ||||
| if (GetDefaultDevice(&fDeviceID) != noErr) { | 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"); | jack_error("Cannot get device name from device ID"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| } else { | } else { | ||||
| // Creates aggregate device | // Creates aggregate device | ||||
| AudioDeviceID captureID, playbackID; | AudioDeviceID captureID, playbackID; | ||||
| if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | ||||
| jack_log("Will take default input"); | jack_log("Will take default input"); | ||||
| if (GetDefaultInputDevice(&captureID) != noErr) { | if (GetDefaultInputDevice(&captureID) != noErr) { | ||||
| @@ -553,7 +561,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | ||||
| jack_log("Will take default output"); | jack_log("Will take default output"); | ||||
| if (GetDefaultOutputDevice(&playbackID) != noErr) { | if (GetDefaultOutputDevice(&playbackID) != noErr) { | ||||
| @@ -561,7 +569,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -599,10 +607,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||||
| jack_log("JackCoreAudioDriver::Open default driver"); | jack_log("JackCoreAudioDriver::Open default driver"); | ||||
| if (GetDefaultDevice(&fDeviceID) != noErr) { | if (GetDefaultDevice(&fDeviceID) != noErr) { | ||||
| jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); | jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); | ||||
| // Creates aggregate device | // Creates aggregate device | ||||
| AudioDeviceID captureID, playbackID; | AudioDeviceID captureID, playbackID; | ||||
| if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | ||||
| jack_log("Will take default input"); | jack_log("Will take default input"); | ||||
| if (GetDefaultInputDevice(&captureID) != noErr) { | if (GetDefaultInputDevice(&captureID) != noErr) { | ||||
| @@ -610,7 +618,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | ||||
| jack_log("Will take default output"); | jack_log("Will take default output"); | ||||
| if (GetDefaultOutputDevice(&playbackID) != noErr) { | if (GetDefaultOutputDevice(&playbackID) != noErr) { | ||||
| @@ -618,7 +626,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -680,7 +688,7 @@ int JackCoreAudioAdapter::SetupChannels(bool capturing, | |||||
| jack_log("Setup max out channels = %ld", out_nChannels); | jack_log("Setup max out channels = %ld", out_nChannels); | ||||
| outchannels = out_nChannels; | outchannels = out_nChannels; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -694,7 +702,7 @@ int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size) | |||||
| printError(err); | printError(err); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -708,7 +716,7 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||||
| OSStatus err = noErr; | OSStatus err = noErr; | ||||
| UInt32 outSize; | UInt32 outSize; | ||||
| Float64 sampleRate; | Float64 sampleRate; | ||||
| // Get sample rate | // Get sample rate | ||||
| outSize = sizeof(Float64); | outSize = sizeof(Float64); | ||||
| err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); | 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"); | jack_error("Cannot get current sample rate"); | ||||
| printError(err); | printError(err); | ||||
| return -1; | return -1; | ||||
| } else { | |||||
| jack_log("Current sample rate = %f", sampleRate); | |||||
| } | } | ||||
| // If needed, set new sample rate | // If needed, set new sample rate | ||||
| if (samplerate != (jack_nframes_t)sampleRate) { | if (samplerate != (jack_nframes_t)sampleRate) { | ||||
| sampleRate = (Float64)samplerate; | sampleRate = (Float64)samplerate; | ||||
| // To get SR change notification | // To get SR change notification | ||||
| err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); | err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); | ||||
| if (err != noErr) { | if (err != noErr) { | ||||
| @@ -735,18 +745,18 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||||
| printError(err); | printError(err); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| // Waiting for SR change notification | // Waiting for SR change notification | ||||
| int count = 0; | int count = 0; | ||||
| while (!fState && count++ < WAIT_COUNTER) { | while (!fState && count++ < WAIT_COUNTER) { | ||||
| usleep(100000); | usleep(100000); | ||||
| jack_log("Wait count = %d", count); | jack_log("Wait count = %d", count); | ||||
| } | } | ||||
| // Remove SR change notification | // Remove SR change notification | ||||
| AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); | AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -796,7 +806,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| jack_error("No input and output channels..."); | jack_error("No input and output channels..."); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| // AUHAL | // AUHAL | ||||
| ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; | ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; | ||||
| Component HALOutput = FindNextComponent(NULL, &cd); | Component HALOutput = FindNextComponent(NULL, &cd); | ||||
| @@ -823,7 +833,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| enableIO = 0; | enableIO = 0; | ||||
| jack_log("Setup AUHAL input off"); | jack_log("Setup AUHAL input off"); | ||||
| } | } | ||||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); | err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); | jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); | ||||
| @@ -838,14 +848,14 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| enableIO = 0; | enableIO = 0; | ||||
| jack_log("Setup AUHAL output off"); | jack_log("Setup AUHAL output off"); | ||||
| } | } | ||||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); | err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); | jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); | ||||
| printError(err1); | printError(err1); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| size = sizeof(AudioDeviceID); | size = sizeof(AudioDeviceID); | ||||
| err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); | err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| @@ -863,7 +873,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| printError(err1); | printError(err1); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| // Set buffer size | // Set buffer size | ||||
| if (capturing && inchannels > 0) { | if (capturing && inchannels > 0) { | ||||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32)); | 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 | // Setup stream converters | ||||
| if (capturing && inchannels > 0) { | if (capturing && inchannels > 0) { | ||||
| size = sizeof(AudioStreamBasicDescription); | size = sizeof(AudioStreamBasicDescription); | ||||
| err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size); | err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| @@ -927,7 +937,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| goto error; | goto error; | ||||
| } | } | ||||
| PrintStreamDesc(&srcFormat); | PrintStreamDesc(&srcFormat); | ||||
| jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); | jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); | ||||
| srcFormat.mSampleRate = samplerate; | srcFormat.mSampleRate = samplerate; | ||||
| srcFormat.mFormatID = kAudioFormatLinearPCM; | srcFormat.mFormatID = kAudioFormatLinearPCM; | ||||
| @@ -938,9 +948,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| srcFormat.mChannelsPerFrame = inchannels; | srcFormat.mChannelsPerFrame = inchannels; | ||||
| srcFormat.mBitsPerChannel = 32; | srcFormat.mBitsPerChannel = 32; | ||||
| PrintStreamDesc(&srcFormat); | PrintStreamDesc(&srcFormat); | ||||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); | err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); | jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); | ||||
| printError(err1); | printError(err1); | ||||
| @@ -949,7 +959,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| } | } | ||||
| if (playing && outchannels > 0) { | if (playing && outchannels > 0) { | ||||
| size = sizeof(AudioStreamBasicDescription); | size = sizeof(AudioStreamBasicDescription); | ||||
| err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size); | err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| @@ -958,7 +968,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| goto error; | goto error; | ||||
| } | } | ||||
| PrintStreamDesc(&dstFormat); | PrintStreamDesc(&dstFormat); | ||||
| jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); | jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); | ||||
| dstFormat.mSampleRate = samplerate; | dstFormat.mSampleRate = samplerate; | ||||
| dstFormat.mFormatID = kAudioFormatLinearPCM; | dstFormat.mFormatID = kAudioFormatLinearPCM; | ||||
| @@ -969,9 +979,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| dstFormat.mChannelsPerFrame = outchannels; | dstFormat.mChannelsPerFrame = outchannels; | ||||
| dstFormat.mBitsPerChannel = 32; | dstFormat.mBitsPerChannel = 32; | ||||
| PrintStreamDesc(&dstFormat); | PrintStreamDesc(&dstFormat); | ||||
| err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); | err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); | ||||
| if (err1 != noErr) { | if (err1 != noErr) { | ||||
| jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); | jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); | ||||
| printError(err1); | printError(err1); | ||||
| @@ -1003,13 +1013,13 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| error: | error: | ||||
| CloseAUHAL(); | CloseAUHAL(); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||||
| OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||||
| { | { | ||||
| OSStatus osErr = noErr; | OSStatus osErr = noErr; | ||||
| AudioObjectPropertyAddress pluginAOPA; | AudioObjectPropertyAddress pluginAOPA; | ||||
| @@ -1017,21 +1027,21 @@ OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||||
| pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | ||||
| pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | ||||
| UInt32 outDataSize; | UInt32 outDataSize; | ||||
| osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); | jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| return osErr; | return osErr; | ||||
| } | } | ||||
| osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); | osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); | jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| return osErr; | return osErr; | ||||
| } | } | ||||
| return noErr; | return noErr; | ||||
| } | } | ||||
| @@ -1043,15 +1053,15 @@ static CFStringRef GetDeviceName(AudioDeviceID id) | |||||
| return (err == noErr) ? UIname : NULL; | 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; | OSStatus err = noErr; | ||||
| AudioObjectID sub_device[32]; | AudioObjectID sub_device[32]; | ||||
| UInt32 outSize = sizeof(sub_device); | UInt32 outSize = sizeof(sub_device); | ||||
| err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | ||||
| vector<AudioDeviceID> captureDeviceIDArray; | vector<AudioDeviceID> captureDeviceIDArray; | ||||
| if (err != noErr) { | if (err != noErr) { | ||||
| jack_log("Input device does not have subdevices"); | jack_log("Input device does not have subdevices"); | ||||
| captureDeviceIDArray.push_back(captureDeviceID); | captureDeviceIDArray.push_back(captureDeviceID); | ||||
| @@ -1062,10 +1072,10 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice | |||||
| captureDeviceIDArray.push_back(sub_device[i]); | 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; | vector<AudioDeviceID> playbackDeviceIDArray; | ||||
| if (err != noErr) { | if (err != noErr) { | ||||
| jack_log("Output device does not have subdevices"); | jack_log("Output device does not have subdevices"); | ||||
| playbackDeviceIDArray.push_back(playbackDeviceID); | playbackDeviceIDArray.push_back(playbackDeviceID); | ||||
| @@ -1076,16 +1086,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice | |||||
| playbackDeviceIDArray.push_back(sub_device[i]); | playbackDeviceIDArray.push_back(sub_device[i]); | ||||
| } | } | ||||
| } | } | ||||
| return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice); | 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; | OSStatus osErr = noErr; | ||||
| UInt32 outSize; | UInt32 outSize; | ||||
| Boolean outWritable; | Boolean outWritable; | ||||
| // Prepare sub-devices for clock drift compensation | // Prepare sub-devices for clock drift compensation | ||||
| // Workaround for bug in the HAL : until 10.6.2 | // Workaround for bug in the HAL : until 10.6.2 | ||||
| AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; | AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; | ||||
| @@ -1094,7 +1104,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| AudioClassID inClass = kAudioSubDeviceClassID; | AudioClassID inClass = kAudioSubDeviceClassID; | ||||
| void* theQualifierData = &inClass; | void* theQualifierData = &inClass; | ||||
| UInt32 subDevicesNum = 0; | UInt32 subDevicesNum = 0; | ||||
| //--------------------------------------------------------------------------- | //--------------------------------------------------------------------------- | ||||
| // Setup SR of both devices otherwise creating AD may fail... | // Setup SR of both devices otherwise creating AD may fail... | ||||
| //--------------------------------------------------------------------------- | //--------------------------------------------------------------------------- | ||||
| @@ -1102,18 +1112,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| UInt32 clockdomain = 0; | UInt32 clockdomain = 0; | ||||
| outSize = sizeof(UInt32); | outSize = sizeof(UInt32); | ||||
| bool need_clock_drift_compensation = false; | bool need_clock_drift_compensation = false; | ||||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | ||||
| if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { | if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); | ||||
| } else { | } else { | ||||
| // Check clock domain | // Check clock domain | ||||
| osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||||
| osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||||
| if (osErr != 0) { | if (osErr != 0) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| } else { | } else { | ||||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); | jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); | ||||
| if (clockdomain != 0 && clockdomain != keptclockdomain) { | if (clockdomain != 0 && clockdomain != keptclockdomain) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); | 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++) { | for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | ||||
| if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { | if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); | ||||
| } else { | } else { | ||||
| // Check clock domain | // Check clock domain | ||||
| osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||||
| osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||||
| if (osErr != 0) { | if (osErr != 0) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| } else { | } else { | ||||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||||
| keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); | jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); | ||||
| if (clockdomain != 0 && clockdomain != keptclockdomain) { | if (clockdomain != 0 && clockdomain != keptclockdomain) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); | 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 no valid clock domain was found, then assume we have to compensate... | ||||
| if (keptclockdomain == 0) { | if (keptclockdomain == 0) { | ||||
| need_clock_drift_compensation = true; | need_clock_drift_compensation = true; | ||||
| } | } | ||||
| //--------------------------------------------------------------------------- | //--------------------------------------------------------------------------- | ||||
| // Start to create a new aggregate by getting the base audio hardware plugin | // Start to create a new aggregate by getting the base audio hardware plugin | ||||
| //--------------------------------------------------------------------------- | //--------------------------------------------------------------------------- | ||||
| char device_name[256]; | char device_name[256]; | ||||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | ||||
| GetDeviceNameFromID(captureDeviceID[i], device_name); | GetDeviceNameFromID(captureDeviceID[i], device_name); | ||||
| jack_info("Separated input = '%s' ", device_name); | jack_info("Separated input = '%s' ", device_name); | ||||
| } | } | ||||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | ||||
| GetDeviceNameFromID(playbackDeviceID[i], device_name); | GetDeviceNameFromID(playbackDeviceID[i], device_name); | ||||
| jack_info("Separated output = '%s' ", device_name); | jack_info("Separated output = '%s' ", device_name); | ||||
| } | } | ||||
| osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); | osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| return osErr; | return osErr; | ||||
| } | } | ||||
| AudioValueTranslation pluginAVT; | AudioValueTranslation pluginAVT; | ||||
| CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); | CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); | ||||
| pluginAVT.mInputData = &inBundleRef; | pluginAVT.mInputData = &inBundleRef; | ||||
| pluginAVT.mInputDataSize = sizeof(inBundleRef); | pluginAVT.mInputDataSize = sizeof(inBundleRef); | ||||
| pluginAVT.mOutputData = &fPluginID; | pluginAVT.mOutputData = &fPluginID; | ||||
| pluginAVT.mOutputDataSize = sizeof(fPluginID); | pluginAVT.mOutputDataSize = sizeof(fPluginID); | ||||
| osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); | osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| return osErr; | return osErr; | ||||
| } | } | ||||
| //------------------------------------------------- | //------------------------------------------------- | ||||
| // Create a CFDictionary for our aggregate device | // Create a CFDictionary for our aggregate device | ||||
| //------------------------------------------------- | //------------------------------------------------- | ||||
| CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | ||||
| CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); | CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); | ||||
| CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); | CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); | ||||
| // add the name of the device to the dictionary | // add the name of the device to the dictionary | ||||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); | CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); | ||||
| // add our choice of UID for the aggregate device to the dictionary | // add our choice of UID for the aggregate device to the dictionary | ||||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); | CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); | ||||
| // add a "private aggregate key" to the dictionary | // add a "private aggregate key" to the dictionary | ||||
| int value = 1; | int value = 1; | ||||
| CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); | CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); | ||||
| SInt32 system; | SInt32 system; | ||||
| Gestalt(gestaltSystemVersion, &system); | Gestalt(gestaltSystemVersion, &system); | ||||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); | jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); | ||||
| // Starting with 10.5.4 systems, the AD can be internal... (better) | // Starting with 10.5.4 systems, the AD can be internal... (better) | ||||
| if (system < 0x00001054) { | if (system < 0x00001054) { | ||||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); | jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); | ||||
| @@ -1217,16 +1227,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); | jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); | ||||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); | CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); | ||||
| } | } | ||||
| // Prepare sub-devices for clock drift compensation | // Prepare sub-devices for clock drift compensation | ||||
| CFMutableArrayRef subDevicesArrayClock = NULL; | CFMutableArrayRef subDevicesArrayClock = NULL; | ||||
| /* | /* | ||||
| if (fClockDriftCompensate) { | if (fClockDriftCompensate) { | ||||
| if (need_clock_drift_compensation) { | if (need_clock_drift_compensation) { | ||||
| jack_info("Clock drift compensation activated..."); | jack_info("Clock drift compensation activated..."); | ||||
| subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | ||||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | ||||
| CFStringRef UID = GetDeviceName(captureDeviceID[i]); | CFStringRef UID = GetDeviceName(captureDeviceID[i]); | ||||
| if (UID) { | if (UID) { | ||||
| @@ -1237,7 +1247,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | ||||
| } | } | ||||
| } | } | ||||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | ||||
| CFStringRef UID = GetDeviceName(playbackDeviceID[i]); | CFStringRef UID = GetDeviceName(playbackDeviceID[i]); | ||||
| if (UID) { | if (UID) { | ||||
| @@ -1248,7 +1258,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | ||||
| } | } | ||||
| } | } | ||||
| // add sub-device clock array for the aggregate device to the dictionary | // add sub-device clock array for the aggregate device to the dictionary | ||||
| CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); | CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); | ||||
| } else { | } else { | ||||
| @@ -1256,14 +1266,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| } | } | ||||
| } | } | ||||
| */ | */ | ||||
| //------------------------------------------------- | //------------------------------------------------- | ||||
| // Create a CFMutableArray for our sub-device list | // Create a CFMutableArray for our sub-device list | ||||
| //------------------------------------------------- | //------------------------------------------------- | ||||
| // we need to append the UID for each device to a CFMutableArray, so create one here | // we need to append the UID for each device to a CFMutableArray, so create one here | ||||
| CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | ||||
| vector<CFStringRef> captureDeviceUID; | vector<CFStringRef> captureDeviceUID; | ||||
| for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | ||||
| CFStringRef ref = GetDeviceName(captureDeviceID[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 | // input sub-devices in this example, so append the sub-device's UID to the CFArray | ||||
| CFArrayAppendValue(subDevicesArray, ref); | CFArrayAppendValue(subDevicesArray, ref); | ||||
| } | } | ||||
| vector<CFStringRef> playbackDeviceUID; | vector<CFStringRef> playbackDeviceUID; | ||||
| for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | ||||
| CFStringRef ref = GetDeviceName(playbackDeviceID[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 | // output sub-devices in this example, so append the sub-device's UID to the CFArray | ||||
| CFArrayAppendValue(subDevicesArray, ref); | CFArrayAppendValue(subDevicesArray, ref); | ||||
| } | } | ||||
| //----------------------------------------------------------------------- | //----------------------------------------------------------------------- | ||||
| // Feed the dictionary to the plugin, to create a blank aggregate device | // Feed the dictionary to the plugin, to create a blank aggregate device | ||||
| //----------------------------------------------------------------------- | //----------------------------------------------------------------------- | ||||
| AudioObjectPropertyAddress pluginAOPA; | AudioObjectPropertyAddress pluginAOPA; | ||||
| pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; | pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; | ||||
| pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | ||||
| pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | ||||
| UInt32 outDataSize; | UInt32 outDataSize; | ||||
| osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); | osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| // pause for a bit to make sure that everything completed correctly | // 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 | // 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); | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | ||||
| //------------------------- | //------------------------- | ||||
| // Set the sub-device list | // Set the sub-device list | ||||
| //------------------------- | //------------------------- | ||||
| pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; | pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; | ||||
| pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | ||||
| pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | ||||
| @@ -1326,14 +1336,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| printError(osErr); | printError(osErr); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| // pause again to give the changes time to take effect | // pause again to give the changes time to take effect | ||||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | ||||
| //----------------------- | //----------------------- | ||||
| // Set the master device | // Set the master device | ||||
| //----------------------- | //----------------------- | ||||
| // set the master device manually (this is the device which will act as the master clock for the aggregate 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 | // pass in the UID of the device you want to use | ||||
| pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; | pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; | ||||
| @@ -1346,36 +1356,36 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| printError(osErr); | printError(osErr); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| // pause again to give the changes time to take effect | // pause again to give the changes time to take effect | ||||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | ||||
| // Prepare sub-devices for clock drift compensation | // Prepare sub-devices for clock drift compensation | ||||
| // Workaround for bug in the HAL : until 10.6.2 | // Workaround for bug in the HAL : until 10.6.2 | ||||
| if (fClockDriftCompensate) { | if (fClockDriftCompensate) { | ||||
| if (need_clock_drift_compensation) { | if (need_clock_drift_compensation) { | ||||
| jack_info("Clock drift compensation activated..."); | jack_info("Clock drift compensation activated..."); | ||||
| // Get the property data size | // Get the property data size | ||||
| osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); | osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| } | } | ||||
| // Calculate the number of object IDs | // Calculate the number of object IDs | ||||
| subDevicesNum = outSize / sizeof(AudioObjectID); | subDevicesNum = outSize / sizeof(AudioObjectID); | ||||
| jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); | jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); | ||||
| AudioObjectID subDevices[subDevicesNum]; | AudioObjectID subDevices[subDevicesNum]; | ||||
| outSize = sizeof(subDevices); | outSize = sizeof(subDevices); | ||||
| osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); | osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); | ||||
| if (osErr != noErr) { | if (osErr != noErr) { | ||||
| jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | ||||
| printError(osErr); | printError(osErr); | ||||
| } | } | ||||
| // Set kAudioSubDevicePropertyDriftCompensation property... | // Set kAudioSubDevicePropertyDriftCompensation property... | ||||
| for (UInt32 index = 0; index < subDevicesNum; ++index) { | for (UInt32 index = 0; index < subDevicesNum; ++index) { | ||||
| UInt32 theDriftCompensationValue = 1; | UInt32 theDriftCompensationValue = 1; | ||||
| @@ -1388,50 +1398,50 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||||
| } else { | } else { | ||||
| jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); | 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 | // pause again to give the changes time to take effect | ||||
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | ||||
| //---------- | //---------- | ||||
| // Clean up | // Clean up | ||||
| //---------- | //---------- | ||||
| // release the private AD key | // release the private AD key | ||||
| CFRelease(AggregateDeviceNumberRef); | CFRelease(AggregateDeviceNumberRef); | ||||
| // release the CF objects we have created - we don't need them any more | // release the CF objects we have created - we don't need them any more | ||||
| CFRelease(aggDeviceDict); | CFRelease(aggDeviceDict); | ||||
| CFRelease(subDevicesArray); | CFRelease(subDevicesArray); | ||||
| if (subDevicesArrayClock) | if (subDevicesArrayClock) | ||||
| CFRelease(subDevicesArrayClock); | CFRelease(subDevicesArrayClock); | ||||
| // release the device UID | // release the device UID | ||||
| for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { | for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { | ||||
| CFRelease(captureDeviceUID[i]); | CFRelease(captureDeviceUID[i]); | ||||
| } | } | ||||
| for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { | for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { | ||||
| CFRelease(playbackDeviceUID[i]); | CFRelease(playbackDeviceUID[i]); | ||||
| } | } | ||||
| jack_log("New aggregate device %ld", *outAggregateDevice); | jack_log("New aggregate device %ld", *outAggregateDevice); | ||||
| return noErr; | return noErr; | ||||
| error: | error: | ||||
| DestroyAggregateDevice(); | DestroyAggregateDevice(); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device) | bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device) | ||||
| { | { | ||||
| OSStatus err = noErr; | OSStatus err = noErr; | ||||
| AudioObjectID sub_device[32]; | AudioObjectID sub_device[32]; | ||||
| UInt32 outSize = sizeof(sub_device); | UInt32 outSize = sizeof(sub_device); | ||||
| err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | ||||
| if (err != noErr) { | if (err != noErr) { | ||||
| jack_log("Device does not have subdevices"); | jack_log("Device does not have subdevices"); | ||||
| return false; | return false; | ||||
| @@ -1494,7 +1504,7 @@ extern "C" | |||||
| strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | 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 | strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | ||||
| desc->nparams = 13; | desc->nparams = 13; | ||||
| desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); | 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; | desc->params[i].value.i = TRUE; | ||||
| strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); | strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); | ||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| i++; | i++; | ||||
| strcpy(desc->params[i].name, "quality"); | strcpy(desc->params[i].name, "quality"); | ||||
| desc->params[i].character = 'q'; | desc->params[i].character = 'q'; | ||||
| @@ -1582,7 +1592,7 @@ extern "C" | |||||
| desc->params[i].value.ui = 0; | desc->params[i].value.ui = 0; | ||||
| strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); | strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); | ||||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | ||||
| i++; | i++; | ||||
| strcpy(desc->params[i].name, "ring-buffer"); | strcpy(desc->params[i].name, "ring-buffer"); | ||||
| desc->params[i].character = 'g'; | desc->params[i].character = 'g'; | ||||
| @@ -1590,7 +1600,7 @@ extern "C" | |||||
| desc->params[i].value.ui = 32768; | desc->params[i].value.ui = 32768; | ||||
| strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | ||||
| strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); | strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); | ||||
| i++; | i++; | ||||
| strcpy(desc->params[i].name, "clock-drift"); | strcpy(desc->params[i].name, "clock-drift"); | ||||
| desc->params[i].character = 's'; | desc->params[i].character = 's'; | ||||
| @@ -1598,7 +1608,7 @@ extern "C" | |||||
| desc->params[i].value.i = FALSE; | desc->params[i].value.i = FALSE; | ||||
| strcpy(desc->params[i].short_desc, "Clock drift compensation"); | 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"); | strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device"); | ||||
| return desc; | return desc; | ||||
| } | } | ||||
| @@ -6,12 +6,6 @@ def create_jack_driver_obj(bld, target, sources, uselib = None): | |||||
| driver.features.append('cc') | driver.features.append('cc') | ||||
| driver.env['shlib_PATTERN'] = 'jack_%s.so' | driver.env['shlib_PATTERN'] = 'jack_%s.so' | ||||
| driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | 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.includes = ['.', '../macosx', '../posix', '../common', '../common/jack'] | ||||
| driver.target = target | driver.target = target | ||||
| driver.source = sources | 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. | \brief Mutex abstraction. | ||||
| */ | */ | ||||
| class JackBasePosixMutex | class JackBasePosixMutex | ||||
| { | { | ||||
| protected: | protected: | ||||
| pthread_mutex_t fMutex; | pthread_mutex_t fMutex; | ||||
| public: | public: | ||||
| JackBasePosixMutex() | JackBasePosixMutex() | ||||
| { | { | ||||
| pthread_mutex_init(&fMutex, NULL); | |||||
| pthread_mutex_init(&fMutex, NULL); | |||||
| } | } | ||||
| virtual ~JackBasePosixMutex() | virtual ~JackBasePosixMutex() | ||||
| { | { | ||||
| pthread_mutex_destroy(&fMutex); | pthread_mutex_destroy(&fMutex); | ||||
| } | } | ||||
| void Lock() | void Lock() | ||||
| { | { | ||||
| int res = pthread_mutex_lock(&fMutex); | int res = pthread_mutex_lock(&fMutex); | ||||
| if (res != 0) | if (res != 0) | ||||
| jack_error("JackBasePosixMutex::Lock res = %d", res); | |||||
| jack_log("JackBasePosixMutex::Lock res = %d", res); | |||||
| } | } | ||||
| bool Trylock() | bool Trylock() | ||||
| { | { | ||||
| return (pthread_mutex_trylock(&fMutex) == 0); | return (pthread_mutex_trylock(&fMutex) == 0); | ||||
| } | } | ||||
| void Unlock() | void Unlock() | ||||
| { | { | ||||
| int res = pthread_mutex_unlock(&fMutex); | int res = pthread_mutex_unlock(&fMutex); | ||||
| if (res != 0) | if (res != 0) | ||||
| jack_error("JackBasePosixMutex::Unlock res = %d", res); | |||||
| jack_log("JackBasePosixMutex::Unlock res = %d", res); | |||||
| } | } | ||||
| }; | }; | ||||
| class JackPosixMutex | class JackPosixMutex | ||||
| { | { | ||||
| @@ -97,7 +97,7 @@ class JackPosixMutex | |||||
| res = pthread_mutexattr_destroy(&mutex_attr); | res = pthread_mutexattr_destroy(&mutex_attr); | ||||
| assert(res == 0); | assert(res == 0); | ||||
| } | } | ||||
| virtual ~JackPosixMutex() | virtual ~JackPosixMutex() | ||||
| { | { | ||||
| pthread_mutex_destroy(&fMutex); | pthread_mutex_destroy(&fMutex); | ||||
| @@ -107,7 +107,7 @@ class JackPosixMutex | |||||
| { | { | ||||
| int res = pthread_mutex_lock(&fMutex); | int res = pthread_mutex_lock(&fMutex); | ||||
| if (res != 0) | if (res != 0) | ||||
| jack_error("JackPosixMutex::Lock res = %d", res); | |||||
| jack_log("JackPosixMutex::Lock res = %d", res); | |||||
| return (res == 0); | return (res == 0); | ||||
| } | } | ||||
| @@ -120,7 +120,7 @@ class JackPosixMutex | |||||
| { | { | ||||
| int res = pthread_mutex_unlock(&fMutex); | int res = pthread_mutex_unlock(&fMutex); | ||||
| if (res != 0) | if (res != 0) | ||||
| jack_error("JackPosixMutex::Unlock res = %d", res); | |||||
| jack_log("JackPosixMutex::Unlock res = %d", res); | |||||
| return (res == 0); | return (res == 0); | ||||
| } | } | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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) { | if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) { | ||||
| jack_error("pthread_setcanceltype err = %s", strerror(err)); | jack_error("pthread_setcanceltype err = %s", strerror(err)); | ||||
| } | } | ||||
| // Signal creation thread when started with StartSync | // Signal creation thread when started with StartSync | ||||
| jack_log("ThreadHandler: start"); | jack_log("ThreadHandler: start"); | ||||
| obj->fStatus = kIniting; | obj->fStatus = kIniting; | ||||
| // Call Init method | // Call Init method | ||||
| if (!runnable->Init()) { | if (!runnable->Init()) { | ||||
| jack_error("Thread init fails: thread quits"); | jack_error("Thread init fails: thread quits"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| obj->fStatus = kRunning; | obj->fStatus = kRunning; | ||||
| // If Init succeed, start the thread loop | // If Init succeed, start the thread loop | ||||
| bool res = true; | bool res = true; | ||||
| while (obj->fStatus == kRunning && res) { | while (obj->fStatus == kRunning && res) { | ||||
| @@ -76,11 +76,11 @@ int JackPosixThread::Start() | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| int JackPosixThread::StartSync() | int JackPosixThread::StartSync() | ||||
| { | { | ||||
| fStatus = kStarting; | fStatus = kStarting; | ||||
| if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { | if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { | ||||
| fStatus = kIdle; | fStatus = kIdle; | ||||
| return -1; | return -1; | ||||
| @@ -90,10 +90,10 @@ int JackPosixThread::StartSync() | |||||
| JackSleep(1000); | JackSleep(1000); | ||||
| } | } | ||||
| return (count == 1000) ? -1 : 0; | 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; | pthread_attr_t attributes; | ||||
| struct sched_param rt_param; | struct sched_param rt_param; | ||||
| @@ -111,19 +111,19 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi | |||||
| } | } | ||||
| if (realtime) { | if (realtime) { | ||||
| jack_log("Create RT thread"); | jack_log("Create RT thread"); | ||||
| if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) { | if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) { | ||||
| jack_error("Cannot request explicit scheduling for RT thread res = %d", res); | jack_error("Cannot request explicit scheduling for RT thread res = %d", res); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { | if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { | ||||
| jack_error("Cannot set RR scheduling class for RT thread res = %d", res); | jack_error("Cannot set RR scheduling class for RT thread res = %d", res); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| memset(&rt_param, 0, sizeof(rt_param)); | memset(&rt_param, 0, sizeof(rt_param)); | ||||
| rt_param.sched_priority = priority; | rt_param.sched_priority = priority; | ||||
| @@ -152,13 +152,13 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi | |||||
| int JackPosixThread::Kill() | 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"); | jack_log("JackPosixThread::Kill"); | ||||
| void* status; | void* status; | ||||
| pthread_cancel(fThread); | pthread_cancel(fThread); | ||||
| pthread_join(fThread, &status); | pthread_join(fThread, &status); | ||||
| fStatus = kIdle; | fStatus = kIdle; | ||||
| fThread = (pthread_t)NULL; | |||||
| fThread = (jack_native_thread_t)NULL; | |||||
| return 0; | return 0; | ||||
| } else { | } else { | ||||
| return -1; | return -1; | ||||
| @@ -167,21 +167,21 @@ int JackPosixThread::Kill() | |||||
| int JackPosixThread::Stop() | 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"); | jack_log("JackPosixThread::Stop"); | ||||
| void* status; | void* status; | ||||
| fStatus = kIdle; // Request for the thread to stop | fStatus = kIdle; // Request for the thread to stop | ||||
| pthread_join(fThread, &status); | pthread_join(fThread, &status); | ||||
| fThread = (pthread_t)NULL; | |||||
| fThread = (jack_native_thread_t)NULL; | |||||
| return 0; | return 0; | ||||
| } else { | } else { | ||||
| return -1; | 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"); | jack_log("JackPosixThread::Kill"); | ||||
| void* status; | void* status; | ||||
| pthread_cancel(thread); | 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"); | jack_log("JackPosixThread::Stop"); | ||||
| void* status; | void* status; | ||||
| pthread_join(thread, &status); | pthread_join(thread, &status); | ||||
| @@ -206,7 +206,7 @@ int JackPosixThread::StopImp(pthread_t thread) | |||||
| int JackPosixThread::AcquireRealTime() | 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() | int JackPosixThread::AcquireSelfRealTime() | ||||
| @@ -225,7 +225,7 @@ int JackPosixThread::AcquireSelfRealTime(int priority) | |||||
| fPriority = priority; | fPriority = priority; | ||||
| return AcquireSelfRealTime(); | return AcquireSelfRealTime(); | ||||
| } | } | ||||
| int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) | |||||
| int JackPosixThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority) | |||||
| { | { | ||||
| struct sched_param rtparam; | struct sched_param rtparam; | ||||
| int res; | int res; | ||||
| @@ -243,7 +243,7 @@ int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) | |||||
| int JackPosixThread::DropRealTime() | int JackPosixThread::DropRealTime() | ||||
| { | { | ||||
| return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||||
| return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||||
| } | } | ||||
| int JackPosixThread::DropSelfRealTime() | int JackPosixThread::DropSelfRealTime() | ||||
| @@ -251,7 +251,7 @@ int JackPosixThread::DropSelfRealTime() | |||||
| return DropRealTimeImp(pthread_self()); | return DropRealTimeImp(pthread_self()); | ||||
| } | } | ||||
| int JackPosixThread::DropRealTimeImp(pthread_t thread) | |||||
| int JackPosixThread::DropRealTimeImp(jack_native_thread_t thread) | |||||
| { | { | ||||
| struct sched_param rtparam; | struct sched_param rtparam; | ||||
| int res; | int res; | ||||
| @@ -265,7 +265,7 @@ int JackPosixThread::DropRealTimeImp(pthread_t thread) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| pthread_t JackPosixThread::GetThreadID() | |||||
| jack_native_thread_t JackPosixThread::GetThreadID() | |||||
| { | { | ||||
| return fThread; | 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) | bool jack_tls_allocate_key(jack_tls_key *key_ptr) | ||||
| { | { | ||||
| int ret; | int ret; | ||||
| ret = pthread_key_create(key_ptr, NULL); | ret = pthread_key_create(key_ptr, NULL); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| { | { | ||||
| jack_error("pthread_key_create() failed with error %d", ret); | jack_error("pthread_key_create() failed with error %d", ret); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool jack_tls_free_key(jack_tls_key key) | bool jack_tls_free_key(jack_tls_key key) | ||||
| { | { | ||||
| int ret; | int ret; | ||||
| ret = pthread_key_delete(key); | ret = pthread_key_delete(key); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| { | { | ||||
| jack_error("pthread_key_delete() failed with error %d", ret); | jack_error("pthread_key_delete() failed with error %d", ret); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool jack_tls_set(jack_tls_key key, void *data_ptr) | bool jack_tls_set(jack_tls_key key, void *data_ptr) | ||||
| { | { | ||||
| int ret; | int ret; | ||||
| ret = pthread_setspecific(key, (const void *)data_ptr); | ret = pthread_setspecific(key, (const void *)data_ptr); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| { | { | ||||
| jack_error("pthread_setspecific() failed with error %d", ret); | jack_error("pthread_setspecific() failed with error %d", ret); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -40,16 +40,16 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface | |||||
| protected: | protected: | ||||
| pthread_t fThread; | |||||
| jack_native_thread_t fThread; | |||||
| static void* ThreadHandler(void* arg); | static void* ThreadHandler(void* arg); | ||||
| public: | public: | ||||
| JackPosixThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation) | 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) | 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(); | int Start(); | ||||
| @@ -60,23 +60,23 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface | |||||
| int AcquireRealTime(); // Used when called from another thread | int AcquireRealTime(); // Used when called from another thread | ||||
| int AcquireSelfRealTime(); // Used when called from thread itself | int AcquireSelfRealTime(); // Used when called from thread itself | ||||
| int AcquireRealTime(int priority); // Used when called from another thread | int AcquireRealTime(int priority); // Used when called from another thread | ||||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | int AcquireSelfRealTime(int priority); // Used when called from thread itself | ||||
| int DropRealTime(); // Used when called from another thread | int DropRealTime(); // Used when called from another thread | ||||
| int DropSelfRealTime(); // Used when called from thread itself | int DropSelfRealTime(); // Used when called from thread itself | ||||
| pthread_t GetThreadID(); | |||||
| jack_native_thread_t GetThreadID(); | |||||
| bool IsThread(); | 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); } | { 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(); | 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -45,12 +45,12 @@ void JackClientSocket::SetReadTimeOut(long sec) | |||||
| { | { | ||||
| int flags; | int flags; | ||||
| fTimeOut = sec; | fTimeOut = sec; | ||||
| if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | ||||
| jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL"); | jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL"); | ||||
| return; | return; | ||||
| } | } | ||||
| flags |= O_NONBLOCK; | flags |= O_NONBLOCK; | ||||
| if (fcntl(fSocket, F_SETFL, flags) < 0) { | if (fcntl(fSocket, F_SETFL, flags) < 0) { | ||||
| jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL"); | jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL"); | ||||
| @@ -62,12 +62,12 @@ void JackClientSocket::SetWriteTimeOut(long sec) | |||||
| { | { | ||||
| int flags; | int flags; | ||||
| fTimeOut = sec; | fTimeOut = sec; | ||||
| if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | ||||
| jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL"); | jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL"); | ||||
| return; | return; | ||||
| } | } | ||||
| flags |= O_NONBLOCK; | flags |= O_NONBLOCK; | ||||
| if (fcntl(fSocket, F_SETFL, flags) < 0) { | if (fcntl(fSocket, F_SETFL, flags) < 0) { | ||||
| jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL"); | jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL"); | ||||
| @@ -100,7 +100,7 @@ void JackClientSocket::SetWriteTimeOut(long sec) | |||||
| #endif | #endif | ||||
| void JackClientSocket::SetNonBlocking(bool onoff) | void JackClientSocket::SetNonBlocking(bool onoff) | ||||
| { | |||||
| { | |||||
| if (onoff) { | if (onoff) { | ||||
| long flags = 0; | long flags = 0; | ||||
| if (fcntl(fSocket, F_SETFL, flags | O_NONBLOCK) < 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() | int JackClientSocket::Close() | ||||
| { | { | ||||
| jack_log("JackClientSocket::Close"); | |||||
| jack_log("JackClientSocket::Close"); | |||||
| if (fSocket > 0) { | if (fSocket > 0) { | ||||
| shutdown(fSocket, SHUT_RDWR); | shutdown(fSocket, SHUT_RDWR); | ||||
| close(fSocket); | close(fSocket); | ||||
| @@ -161,17 +161,17 @@ int JackClientSocket::Read(void* data, int len) | |||||
| struct timeval tv; | struct timeval tv; | ||||
| fd_set fdset; | fd_set fdset; | ||||
| ssize_t res; | ssize_t res; | ||||
| tv.tv_sec = fTimeOut; | tv.tv_sec = fTimeOut; | ||||
| tv.tv_usec = 0; | tv.tv_usec = 0; | ||||
| FD_ZERO(&fdset); | FD_ZERO(&fdset); | ||||
| FD_SET(fSocket, &fdset); | FD_SET(fSocket, &fdset); | ||||
| do { | do { | ||||
| res = select(fSocket + 1, &fdset, NULL, NULL, &tv); | res = select(fSocket + 1, &fdset, NULL, NULL, &tv); | ||||
| } while (res < 0 && errno == EINTR); | } while (res < 0 && errno == EINTR); | ||||
| if (res < 0) { | if (res < 0) { | ||||
| return res; | return res; | ||||
| } else if (res == 0) { | } else if (res == 0) { | ||||
| @@ -179,9 +179,9 @@ int JackClientSocket::Read(void* data, int len) | |||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| if ((res = read(fSocket, data, len)) != len) { | if ((res = read(fSocket, data, len)) != len) { | ||||
| if (errno == EWOULDBLOCK) { | |||||
| if (errno == EWOULDBLOCK || errno == EAGAIN) { | |||||
| jack_error("JackClientSocket::Read time out"); | jack_error("JackClientSocket::Read time out"); | ||||
| return 0; // For a non blocking socket, a read failure is not considered as an error | return 0; // For a non blocking socket, a read failure is not considered as an error | ||||
| } else if (res != 0) { | } else if (res != 0) { | ||||
| @@ -201,21 +201,21 @@ int JackClientSocket::Write(void* data, int len) | |||||
| #if defined(__sun__) || defined(sun) | #if defined(__sun__) || defined(sun) | ||||
| if (fTimeOut > 0) { | if (fTimeOut > 0) { | ||||
| struct timeval tv; | struct timeval tv; | ||||
| fd_set fdset; | fd_set fdset; | ||||
| ssize_t res; | ssize_t res; | ||||
| tv.tv_sec = fTimeOut; | tv.tv_sec = fTimeOut; | ||||
| tv.tv_usec = 0; | tv.tv_usec = 0; | ||||
| FD_ZERO(&fdset); | FD_ZERO(&fdset); | ||||
| FD_SET(fSocket, &fdset); | FD_SET(fSocket, &fdset); | ||||
| do { | do { | ||||
| res = select(fSocket + 1, NULL, &fdset, NULL, &tv); | res = select(fSocket + 1, NULL, &fdset, NULL, &tv); | ||||
| } while (res < 0 && errno == EINTR); | } while (res < 0 && errno == EINTR); | ||||
| if (res < 0) { | if (res < 0) { | ||||
| return res; | return res; | ||||
| } else if (res == 0) { | } else if (res == 0) { | ||||
| @@ -225,7 +225,7 @@ int JackClientSocket::Write(void* data, int len) | |||||
| #endif | #endif | ||||
| if ((res = write(fSocket, data, len)) != len) { | if ((res = write(fSocket, data, len)) != len) { | ||||
| if (errno == EWOULDBLOCK) { | |||||
| if (errno == EWOULDBLOCK || errno == EAGAIN) { | |||||
| jack_log("JackClientSocket::Write time out"); | jack_log("JackClientSocket::Write time out"); | ||||
| return 0; // For a non blocking socket, a write failure is not considered as an error | return 0; // For a non blocking socket, a write failure is not considered as an error | ||||
| } else if (res != 0) { | } 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; | addr.sun_family = AF_UNIX; | ||||
| BuildName(name, fName, dir, which); | BuildName(name, fName, dir, which); | ||||
| strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1); | strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1); | ||||
| jack_log("Bind: addr.sun_path %s", addr.sun_path); | jack_log("Bind: addr.sun_path %s", addr.sun_path); | ||||
| unlink(fName); // Security... | unlink(fName); // Security... | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -108,7 +108,6 @@ int JackSocketClientChannel::Start() | |||||
| } | } | ||||
| } | } | ||||
| void JackSocketClientChannel::Stop() | void JackSocketClientChannel::Stop() | ||||
| { | { | ||||
| jack_log("JackSocketClientChannel::Stop"); | jack_log("JackSocketClientChannel::Stop"); | ||||
| @@ -246,61 +245,73 @@ void JackSocketClientChannel::SetFreewheel(int onoff, int* result) | |||||
| ServerSyncCall(&req, &res, 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); | JackSessionNotifyRequest req(refnum, path, type, target); | ||||
| JackSessionNotifyResult res; | |||||
| JackSessionNotifyResult res; | |||||
| int intresult; | int intresult; | ||||
| ServerSyncCall(&req, &res, &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++) { | 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].uuid = NULL; | ||||
| session_command[i].client_name = NULL; | session_command[i].client_name = NULL; | ||||
| session_command[i].command = NULL; | session_command[i].command = NULL; | ||||
| session_command[i].flags = (jack_session_flags_t)0; | session_command[i].flags = (jack_session_flags_t)0; | ||||
| *result = session_command; | *result = session_command; | ||||
| } | } | ||||
| void JackSocketClientChannel::SessionReply(int refnum, int* result) | void JackSocketClientChannel::SessionReply(int refnum, int* result) | ||||
| { | { | ||||
| JackSessionReplyRequest req(refnum); | JackSessionReplyRequest req(refnum); | ||||
| JackResult res; | |||||
| JackResult res; | |||||
| ServerSyncCall(&req, &res, result); | 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); | JackGetUUIDRequest req(client_name); | ||||
| JackUUIDResult res; | |||||
| JackUUIDResult res; | |||||
| ServerSyncCall(&req, &res, result); | 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); | 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); | 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); | JackReserveNameRequest req(refnum, client_name, uuid); | ||||
| JackResult res; | |||||
| JackResult res; | |||||
| ServerSyncCall(&req, &res, result); | ServerSyncCall(&req, &res, result); | ||||
| } | } | ||||
| @@ -363,7 +374,7 @@ bool JackSocketClientChannel::Init() | |||||
| jack_error("JackSocketClientChannel: cannot establish notication socket"); | jack_error("JackSocketClientChannel: cannot establish notication socket"); | ||||
| return false; | return false; | ||||
| } else { | } 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | */ | ||||
| @@ -38,11 +38,11 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||||
| private: | 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 | JackThread fThread; // Thread to execute the event loop | ||||
| JackClient* fClient; | |||||
| JackClient* fClient; | |||||
| void ServerSyncCall(JackRequest* req, JackResult* res, int* result); | void ServerSyncCall(JackRequest* req, JackResult* res, int* result); | ||||
| void ServerAsyncCall(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 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 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 PortRename(int refnum, jack_port_id_t port, const char* name, int* result); | ||||
| void SetBufferSize(jack_nframes_t buffer_size, int* result); | void SetBufferSize(jack_nframes_t buffer_size, int* result); | ||||
| void SetFreewheel(int onoff, int* result); | void SetFreewheel(int onoff, int* result); | ||||
| void ComputeTotalLatencies(int* result); | |||||
| void ReleaseTimebase(int refnum, int* result); | void ReleaseTimebase(int refnum, int* result); | ||||
| void SetTimebaseCallback(int refnum, int conditional, 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 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); | 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 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 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 | // JackRunnableInterface interface | ||||
| bool Init(); | bool Init(); | ||||
| bool Execute(); | bool Execute(); | ||||
| bool IsChannelThread() { return fThread.IsThread(); } | 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. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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) | int JackSocketServerChannel::Open(const char* server_name, JackServer* server) | ||||
| { | { | ||||
| jack_log("JackSocketServerChannel::Open"); | jack_log("JackSocketServerChannel::Open"); | ||||
| // Prepare request socket | // Prepare request socket | ||||
| if (fRequestListenSocket.Bind(jack_server_dir, server_name, 0) < 0) { | if (fRequestListenSocket.Bind(jack_server_dir, server_name, 0) < 0) { | ||||
| jack_log("JackSocketServerChannel::Open : cannot create result listen socket"); | jack_log("JackSocketServerChannel::Open : cannot create result listen socket"); | ||||
| @@ -79,14 +79,14 @@ void JackSocketServerChannel::Close() | |||||
| delete socket; | delete socket; | ||||
| } | } | ||||
| } | } | ||||
| int JackSocketServerChannel::Start() | int JackSocketServerChannel::Start() | ||||
| { | { | ||||
| if (fThread.Start() != 0) { | if (fThread.Start() != 0) { | ||||
| jack_error("Cannot start Jack server listener"); | jack_error("Cannot start Jack server listener"); | ||||
| return -1; | return -1; | ||||
| } | |||||
| } | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -168,6 +168,12 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||||
| return false; | 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 | // Read data | ||||
| switch (header.fType) { | switch (header.fType) { | ||||
| @@ -292,7 +298,7 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||||
| jack_error("JackRequest::DisconnectPorts write error ref = %d", req.fRefNum); | jack_error("JackRequest::DisconnectPorts write error ref = %d", req.fRefNum); | ||||
| break; | break; | ||||
| } | } | ||||
| case JackRequest::kPortRename: { | case JackRequest::kPortRename: { | ||||
| jack_log("JackRequest::PortRename"); | jack_log("JackRequest::PortRename"); | ||||
| JackPortRenameRequest req; | JackPortRenameRequest req; | ||||
| @@ -326,6 +332,17 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||||
| break; | 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: { | case JackRequest::kReleaseTimebase: { | ||||
| jack_log("JackRequest::ReleaseTimebase"); | jack_log("JackRequest::ReleaseTimebase"); | ||||
| JackReleaseTimebaseRequest req; | JackReleaseTimebaseRequest req; | ||||
| @@ -430,27 +447,26 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||||
| } | } | ||||
| case JackRequest::kGetClientByUUID: { | case JackRequest::kGetClientByUUID: { | ||||
| jack_log("JackRequest::GetClientNameForUUID"); | |||||
| jack_log("JackRequest::GetClientByUUID"); | |||||
| JackGetClientNameRequest req; | JackGetClientNameRequest req; | ||||
| JackClientNameResult res; | JackClientNameResult res; | ||||
| if (req.Read(socket) == 0) { | if (req.Read(socket) == 0) { | ||||
| fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult); | fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult); | ||||
| } | } | ||||
| if (res.Write(socket) < 0) | if (res.Write(socket) < 0) | ||||
| jack_error("JackRequest::GetClientNameForUUID write error"); | |||||
| jack_error("JackRequest::GetClientByUUID write error"); | |||||
| break; | break; | ||||
| } | } | ||||
| case JackRequest::kGetUUIDByClient: { | case JackRequest::kGetUUIDByClient: { | ||||
| jack_log("JackRequest::GetUUIDForClientName"); | |||||
| jack_log("JackRequest::GetUUIDByClient"); | |||||
| JackGetUUIDRequest req; | JackGetUUIDRequest req; | ||||
| JackUUIDResult res; | JackUUIDResult res; | ||||
| if (req.Read(socket) == 0) { | if (req.Read(socket) == 0) { | ||||
| fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult); | fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult); | ||||
| res.fResult = 0; | |||||
| } | } | ||||
| if (res.Write(socket) < 0) | if (res.Write(socket) < 0) | ||||
| jack_error("JackRequest::GetUUIDForClientName write error"); | |||||
| jack_error("JackRequest::GetUUIDByClient write error"); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -466,11 +482,23 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||||
| break; | 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: | default: | ||||
| jack_error("Unknown request %ld", header.fType); | jack_error("Unknown request %ld", header.fType); | ||||
| break; | break; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -511,7 +539,7 @@ bool JackSocketServerChannel::Init() | |||||
| bool JackSocketServerChannel::Execute() | bool JackSocketServerChannel::Execute() | ||||
| { | { | ||||
| try { | try { | ||||
| // Global poll | // Global poll | ||||
| if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) { | if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) { | ||||
| jack_error("Engine poll failed err = %s request thread quits...", strerror(errno)); | 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)); | jack_log("Poll client error err = %s", strerror(errno)); | ||||
| ClientKill(fd); | ClientKill(fd); | ||||
| } else if (fPollTable[i].revents & POLLIN) { | } else if (fPollTable[i].revents & POLLIN) { | ||||
| if (!HandleRequest(fd)) | |||||
| if (!HandleRequest(fd)) | |||||
| jack_log("Could not handle external client request"); | jack_log("Could not handle external client request"); | ||||
| } | } | ||||
| } | } | ||||
| // Check the server request socket */ | // 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)); | jack_error("Error on server request socket err = %s", strerror(errno)); | ||||
| if (fPollTable[0].revents & POLLIN) | |||||
| if (fPollTable[0].revents & POLLIN) | |||||
| ClientCreate(); | ClientCreate(); | ||||
| } | } | ||||
| BuildPoolTable(); | BuildPoolTable(); | ||||
| return true; | return true; | ||||
| } catch (JackQuitException& e) { | } catch (JackQuitException& e) { | ||||
| jack_log("JackMachServerChannel::Execute JackQuitException"); | jack_log("JackMachServerChannel::Execute JackQuitException"); | ||||
| return false; | return false; | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 | JackServerSocket fRequestListenSocket; // Socket to create request socket for the client | ||||
| JackThread fThread; // Thread to execute the event loop | JackThread fThread; // Thread to execute the event loop | ||||
| JackServer* fServer; | |||||
| JackServer* fServer; | |||||
| pollfd* fPollTable; | pollfd* fPollTable; | ||||
| bool fRebuild; | bool fRebuild; | ||||
| std::map<int, std::pair<int, JackClientSocket*> > fSocketTable; | 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 | int Open(const char* server_name, JackServer* server); // Open the Server/Client connection | ||||
| void Close(); // Close the Server/Client connection | void Close(); // Close the Server/Client connection | ||||
| int Start(); | int Start(); | ||||
| // JackRunnableInterface interface | // JackRunnableInterface interface | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 "JackRequest.h" | ||||
| #include "JackConstants.h" | #include "JackConstants.h" | ||||
| #include "JackNotification.h" | #include "JackNotification.h" | ||||
| #include "JackServerGlobals.h" | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| @@ -33,6 +34,7 @@ int JackSocketServerNotifyChannel::Open(const char* server_name) | |||||
| return -1; | return -1; | ||||
| } else { | } else { | ||||
| fRequestSocket.SetNonBlocking(true); | fRequestSocket.SetNonBlocking(true); | ||||
| JackServerGlobals::fRTNotificationSocket = fRequestSocket.GetFd(); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| @@ -63,7 +65,7 @@ void JackSocketServerNotifyChannel::NotifyQuit() | |||||
| jack_error("Could not write request ref = %d notify = %d", -1, kQUIT); | jack_error("Could not write request ref = %d notify = %d", -1, kQUIT); | ||||
| } | } | ||||
| } | } | ||||
| } // end of namespace | } // end of namespace | ||||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU Lesser General Public License for more details. | GNU Lesser General Public License for more details. | ||||
| You should have received a copy of the GNU Lesser General Public License | 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. | 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 <signal.h> | ||||
| #include <dlfcn.h> | #include <dlfcn.h> | ||||
| #define UINT32_MAX 4294967295U | |||||
| #define DRIVER_HANDLE void* | #define DRIVER_HANDLE void* | ||||
| #define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) | #define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) | ||||
| #define UnloadDriverModule(handle) dlclose((handle)) | #define UnloadDriverModule(handle) dlclose((handle)) | ||||
| @@ -26,6 +26,8 @@ | |||||
| typedef unsigned long long UInt64; | typedef unsigned long long UInt64; | ||||
| typedef pthread_key_t jack_tls_key; | 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); | typedef int (*jack_thread_creator_t)(pthread_t*, const pthread_attr_t*, void* (*function)(void*), void* arg); | ||||
| #endif | #endif | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net> | Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net> | ||||
| This program is free software; you can redistribute it and/or modify | 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 | it under the terms of the GNU General Public License as published by | ||||
| the Free Software Foundation; either version 2 of the License, or | 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++; | vip = *ip++; | ||||
| for (i = 0, F = _freq; i < 5; i++, F++) | 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; | F->p += F->f; | ||||
| c = cosf (a); | |||||
| s = -sinf (a); | |||||
| c = cosf (a); | |||||
| s = -sinf (a); | |||||
| vop += F->a * s; | vop += F->a * s; | ||||
| F->xa += s * vip; | F->xa += s * vip; | ||||
| F->ya += c * vip; | F->ya += c * vip; | ||||
| } | |||||
| } | |||||
| *op++ = vop; | *op++ = vop; | ||||
| if (++_cnt == 16) | if (++_cnt == 16) | ||||
| { | { | ||||
| @@ -142,10 +142,10 @@ int MTDM::resolve (void) | |||||
| k = (int)(floor (p + 0.5)); | k = (int)(floor (p + 0.5)); | ||||
| e = fabs (p - k); | e = fabs (p - k); | ||||
| if (e > _err) _err = e; | if (e > _err) _err = e; | ||||
| if (e > 0.4) return 1; | |||||
| if (e > 0.4) return 1; | |||||
| d += m * (k & 7); | d += m * (k & 7); | ||||
| m *= 8; | m *= 8; | ||||
| } | |||||
| } | |||||
| _del = 16 * d; | _del = 16 * d; | ||||
| return 0; | return 0; | ||||
| @@ -158,6 +158,34 @@ static jack_client_t *jack_handle; | |||||
| static jack_port_t *jack_capt; | static jack_port_t *jack_capt; | ||||
| static jack_port_t *jack_play; | 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) | int jack_callback (jack_nframes_t nframes, void *arg) | ||||
| { | { | ||||
| float *ip, *op; | float *ip, *op; | ||||
| @@ -182,14 +210,12 @@ int main (int ac, char *av []) | |||||
| jack_set_process_callback (jack_handle, jack_callback, 0); | 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_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); | 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); | t = 1000.0f / jack_get_sample_rate (jack_handle); | ||||
| if (jack_activate (jack_handle)) | if (jack_activate (jack_handle)) | ||||
| @@ -200,16 +226,16 @@ int main (int ac, char *av []) | |||||
| while (1) | 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"); | if (mtdm.resolve () < 0) printf ("Signal below threshold...\n"); | ||||
| else | |||||
| else | |||||
| { | { | ||||
| if (mtdm.err () > 0.3) | |||||
| if (mtdm.err () > 0.3) | |||||
| { | { | ||||
| mtdm.invert (); | mtdm.invert (); | ||||
| mtdm.resolve (); | mtdm.resolve (); | ||||
| @@ -9,7 +9,7 @@ test_programs = { | |||||
| #'testSem': ['testSem.cpp'], | #'testSem': ['testSem.cpp'], | ||||
| 'jack_test': ['test.cpp'], | 'jack_test': ['test.cpp'], | ||||
| 'jack_cpu': ['cpu.c'], | 'jack_cpu': ['cpu.c'], | ||||
| 'jack_delay': ['jdelay.cpp'], | |||||
| 'jack_iodelay': ['iodelay.cpp'], | |||||
| 'jack_multiple_metro' : ['external_metro.cpp'], | 'jack_multiple_metro' : ['external_metro.cpp'], | ||||
| } | } | ||||
| @@ -43,7 +43,7 @@ RSC=rc.exe | |||||
| # PROP Ignore_Export_Lib 0 | # PROP Ignore_Export_Lib 0 | ||||
| # PROP Target_Dir "" | # PROP Target_Dir "" | ||||
| # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | # 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 BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||||
| # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | ||||
| # ADD BASE RSC /l 0x409 /d "NDEBUG" | # ADD BASE RSC /l 0x409 /d "NDEBUG" | ||||