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" | ||||