git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@4181 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
@@ -27,16 +27,75 @@ Mario Lang | |||
Arnold Krille | |||
Jan Engelhardt | |||
Adrian Knoth | |||
David Garcia Garzon | |||
David Garcia Garzon | |||
Valerio Pilo | |||
--------------------------- | |||
Jackdmp changes log | |||
--------------------------- | |||
2011-03-11 Stephane Letz <letz@grame.fr> | |||
* Correct JackNetMaster::SetBufferSize. | |||
2011-03-10 Stephane Letz <letz@grame.fr> | |||
* Latency callback must always be activated. | |||
* Correct TopologicalSort. | |||
* Add jack_midi_dump client. | |||
* Synchronize netjack1 with JACK1 version. | |||
* Synchronize jack_connect/jack_disconnect with JACK1 version. | |||
2011-03-09 Stephane Letz <letz@grame.fr> | |||
* jack_client_has_session_callback implementation. | |||
* Fix jdelay for new latency API. | |||
* Check requested buffer size and limit to 1..8192 - avoids wierd behaviour caused by jack_bufsize foobar. | |||
* jack_port_type_get_buffer_size implementation. | |||
* Stop using alloca and allocate buffer on the heap for alsa_io. | |||
* Rename jdelay to jack_iodelay as per Fons' request. | |||
* Call buffer size callback in activate (actually this is done on client side in the RT thread Init method). | |||
* JackEngine::ComputeTotalLatencies in progress. | |||
2011-03-08 Stephane Letz <letz@grame.fr> | |||
* Use of latency range in all backends. | |||
* ComputeTotalLatencies now a client/server call. | |||
* Add latent test client for latency API. | |||
* Also print playback and capture latency in jack_lsp. | |||
2011-03-04 Stephane Letz <letz@grame.fr> | |||
* Revert r4119 (RT notification in the server). JackAudioDriver::ProcessSync now skip backend write in case of graph process failure. | |||
* Fix incorrect error codes in alsa/usx2y.c and alsa/JackAlsaDriver.cpp. | |||
* Synchronize public headers with JACK1. Update OSX project. | |||
* New latency API implementation (in progress). | |||
2011-02-09 Stephane Letz <letz@grame.fr> | |||
* Remove JackPortIsActive flag. | |||
2011-02-07 Stephane Letz <letz@grame.fr> | |||
* Valerio Pilo second CAS for ARMv7 patch. | |||
2011-02-03 Stephane Letz <letz@grame.fr> | |||
* Valerio Pilo CAS for ARMv7 patch. | |||
2011-01-11 Stephane Letz <letz@grame.fr> | |||
* Adrian Knoth jack_lsp patch. | |||
2010-11-17 Stephane Letz <letz@grame.fr> | |||
* ALSA backend : suspend/resume handling (jack1 r4075). | |||
* Correct dummy driver. | |||
2010-11-05 Stephane Letz <letz@grame.fr> | |||
* In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. | |||
* Correct symbols export in backends. | |||
* Correct symbols export in backends on OSX. | |||
2010-11-03 Stephane Letz <letz@grame.fr> | |||
@@ -41,7 +41,7 @@ extern "C" | |||
{ | |||
#endif | |||
typedef void (*print_function)(const char *); | |||
typedef void (*print_function)(const char*); | |||
typedef void *(*thread_routine)(void*); | |||
EXPORT | |||
@@ -53,198 +53,219 @@ extern "C" | |||
int *proto_ptr); | |||
EXPORT | |||
const char * | |||
const char* | |||
jack_get_version_string(); | |||
jack_client_t * jack_client_new_aux (const char *client_name, | |||
jack_client_t * jack_client_new_aux(const char* client_name, | |||
jack_options_t options, | |||
jack_status_t *status); | |||
EXPORT jack_client_t * jack_client_open (const char *client_name, | |||
EXPORT jack_client_t * jack_client_open(const char* client_name, | |||
jack_options_t options, | |||
jack_status_t *status, ...); | |||
EXPORT jack_client_t * jack_client_new (const char *client_name); | |||
EXPORT int jack_client_name_size (void); | |||
EXPORT char* jack_get_client_name (jack_client_t *client); | |||
EXPORT int jack_internal_client_new (const char *client_name, | |||
const char *load_name, | |||
const char *load_init); | |||
EXPORT void jack_internal_client_close (const char *client_name); | |||
EXPORT int jack_is_realtime (jack_client_t *client); | |||
EXPORT void jack_on_shutdown (jack_client_t *client, | |||
EXPORT jack_client_t * jack_client_new(const char* client_name); | |||
EXPORT int jack_client_name_size(void); | |||
EXPORT char* jack_get_client_name(jack_client_t *client); | |||
EXPORT int jack_internal_client_new(const char* client_name, | |||
const char* load_name, | |||
const char* load_init); | |||
EXPORT void jack_internal_client_close(const char* client_name); | |||
EXPORT int jack_is_realtime(jack_client_t *client); | |||
EXPORT void jack_on_shutdown(jack_client_t *client, | |||
JackShutdownCallback shutdown_callback, void *arg); | |||
EXPORT void jack_on_info_shutdown (jack_client_t *client, | |||
EXPORT void jack_on_info_shutdown(jack_client_t *client, | |||
JackInfoShutdownCallback shutdown_callback, void *arg); | |||
EXPORT int jack_set_process_callback (jack_client_t *client, | |||
EXPORT int jack_set_process_callback(jack_client_t *client, | |||
JackProcessCallback process_callback, | |||
void *arg); | |||
EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status); | |||
// new | |||
EXPORT jack_nframes_t jack_cycle_wait (jack_client_t*); | |||
EXPORT void jack_cycle_signal (jack_client_t*, int status); | |||
EXPORT jack_nframes_t jack_cycle_wait(jack_client_t*); | |||
EXPORT void jack_cycle_signal(jack_client_t*, int status); | |||
EXPORT int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg); | |||
EXPORT int jack_set_thread_init_callback (jack_client_t *client, | |||
EXPORT int jack_set_thread_init_callback(jack_client_t *client, | |||
JackThreadInitCallback thread_init_callback, | |||
void *arg); | |||
EXPORT int jack_set_freewheel_callback (jack_client_t *client, | |||
EXPORT int jack_set_freewheel_callback(jack_client_t *client, | |||
JackFreewheelCallback freewheel_callback, | |||
void *arg); | |||
EXPORT int jack_set_freewheel(jack_client_t* client, int onoff); | |||
EXPORT int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes); | |||
EXPORT int jack_set_buffer_size_callback (jack_client_t *client, | |||
EXPORT int jack_set_buffer_size(jack_client_t *client, jack_nframes_t nframes); | |||
EXPORT int jack_set_buffer_size_callback(jack_client_t *client, | |||
JackBufferSizeCallback bufsize_callback, | |||
void *arg); | |||
EXPORT int jack_set_sample_rate_callback (jack_client_t *client, | |||
EXPORT int jack_set_sample_rate_callback(jack_client_t *client, | |||
JackSampleRateCallback srate_callback, | |||
void *arg); | |||
EXPORT int jack_set_client_registration_callback (jack_client_t *, | |||
EXPORT int jack_set_client_registration_callback(jack_client_t *, | |||
JackClientRegistrationCallback | |||
registration_callback, void *arg); | |||
EXPORT int jack_set_port_registration_callback (jack_client_t *, | |||
EXPORT int jack_set_port_registration_callback(jack_client_t *, | |||
JackPortRegistrationCallback | |||
registration_callback, void *arg); | |||
EXPORT int jack_set_port_connect_callback (jack_client_t *, | |||
EXPORT int jack_set_port_connect_callback(jack_client_t *, | |||
JackPortConnectCallback | |||
connect_callback, void *arg); | |||
EXPORT int jack_set_port_rename_callback (jack_client_t *, | |||
EXPORT int jack_set_port_rename_callback(jack_client_t *, | |||
JackPortRenameCallback | |||
rename_callback, void *arg); | |||
EXPORT int jack_set_graph_order_callback (jack_client_t *, | |||
EXPORT int jack_set_graph_order_callback(jack_client_t *, | |||
JackGraphOrderCallback graph_callback, | |||
void *); | |||
EXPORT int jack_set_xrun_callback (jack_client_t *, | |||
EXPORT int jack_set_xrun_callback(jack_client_t *, | |||
JackXRunCallback xrun_callback, void *arg); | |||
EXPORT int jack_activate (jack_client_t *client); | |||
EXPORT int jack_deactivate (jack_client_t *client); | |||
EXPORT jack_port_t * jack_port_register (jack_client_t *client, | |||
const char *port_name, | |||
const char *port_type, | |||
EXPORT int jack_set_latency_callback(jack_client_t *client, | |||
JackLatencyCallback callback, void *arg); | |||
EXPORT int jack_activate(jack_client_t *client); | |||
EXPORT int jack_deactivate(jack_client_t *client); | |||
EXPORT jack_port_t * jack_port_register(jack_client_t *client, | |||
const char* port_name, | |||
const char* port_type, | |||
unsigned long flags, | |||
unsigned long buffer_size); | |||
EXPORT int jack_port_unregister (jack_client_t *, jack_port_t *); | |||
EXPORT void * jack_port_get_buffer (jack_port_t *, jack_nframes_t); | |||
EXPORT const char * jack_port_name (const jack_port_t *port); | |||
EXPORT const char * jack_port_short_name (const jack_port_t *port); | |||
EXPORT int jack_port_flags (const jack_port_t *port); | |||
EXPORT const char * jack_port_type (const jack_port_t *port); | |||
EXPORT jack_port_type_id_t jack_port_type_id (const jack_port_t *port); | |||
EXPORT int jack_port_is_mine (const jack_client_t *, const jack_port_t *port); | |||
EXPORT int jack_port_connected (const jack_port_t *port); | |||
EXPORT int jack_port_connected_to (const jack_port_t *port, | |||
const char *port_name); | |||
EXPORT const char ** jack_port_get_connections (const jack_port_t *port); | |||
EXPORT const char ** jack_port_get_all_connections (const jack_client_t *client, | |||
EXPORT int jack_port_unregister(jack_client_t *, jack_port_t *); | |||
EXPORT void * jack_port_get_buffer(jack_port_t *, jack_nframes_t); | |||
EXPORT const char* jack_port_name(const jack_port_t *port); | |||
EXPORT const char* jack_port_short_name(const jack_port_t *port); | |||
EXPORT int jack_port_flags(const jack_port_t *port); | |||
EXPORT const char* jack_port_type(const jack_port_t *port); | |||
EXPORT jack_port_type_id_t jack_port_type_id(const jack_port_t *port); | |||
EXPORT int jack_port_is_mine(const jack_client_t *, const jack_port_t *port); | |||
EXPORT int jack_port_connected(const jack_port_t *port); | |||
EXPORT int jack_port_connected_to(const jack_port_t *port, | |||
const char* port_name); | |||
EXPORT const char* * jack_port_get_connections(const jack_port_t *port); | |||
EXPORT const char* * jack_port_get_all_connections(const jack_client_t *client, | |||
const jack_port_t *port); | |||
EXPORT int jack_port_tie (jack_port_t *src, jack_port_t *dst); | |||
EXPORT int jack_port_untie (jack_port_t *port); | |||
EXPORT jack_nframes_t jack_port_get_latency (jack_port_t *port); | |||
EXPORT jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
EXPORT int jack_port_tie(jack_port_t *src, jack_port_t *dst); | |||
EXPORT int jack_port_untie(jack_port_t *port); | |||
// Old latency API | |||
EXPORT jack_nframes_t jack_port_get_latency(jack_port_t *port); | |||
EXPORT jack_nframes_t jack_port_get_total_latency(jack_client_t *, | |||
jack_port_t *port); | |||
EXPORT void jack_port_set_latency (jack_port_t *, jack_nframes_t); | |||
EXPORT int jack_recompute_total_latency (jack_client_t*, jack_port_t* port); | |||
EXPORT int jack_recompute_total_latencies (jack_client_t*); | |||
EXPORT int jack_port_set_name (jack_port_t *port, const char *port_name); | |||
EXPORT int jack_port_set_alias (jack_port_t *port, const char *alias); | |||
EXPORT int jack_port_unset_alias (jack_port_t *port, const char *alias); | |||
EXPORT int jack_port_get_aliases (const jack_port_t *port, char* const aliases[2]); | |||
EXPORT int jack_port_request_monitor (jack_port_t *port, int onoff); | |||
EXPORT int jack_port_request_monitor_by_name (jack_client_t *client, | |||
const char *port_name, int onoff); | |||
EXPORT int jack_port_ensure_monitor (jack_port_t *port, int onoff); | |||
EXPORT int jack_port_monitoring_input (jack_port_t *port); | |||
EXPORT int jack_connect (jack_client_t *, | |||
const char *source_port, | |||
const char *destination_port); | |||
EXPORT int jack_disconnect (jack_client_t *, | |||
const char *source_port, | |||
const char *destination_port); | |||
EXPORT int jack_port_disconnect (jack_client_t *, jack_port_t *); | |||
EXPORT void jack_port_set_latency(jack_port_t *, jack_nframes_t); | |||
EXPORT int jack_recompute_total_latency(jack_client_t*, jack_port_t* port); | |||
// New latency API | |||
EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range); | |||
EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range); | |||
EXPORT int jack_recompute_total_latencies(jack_client_t*); | |||
EXPORT int jack_port_set_name(jack_port_t *port, const char* port_name); | |||
EXPORT int jack_port_set_alias(jack_port_t *port, const char* alias); | |||
EXPORT int jack_port_unset_alias(jack_port_t *port, const char* alias); | |||
EXPORT int jack_port_get_aliases(const jack_port_t *port, char* const aliases[2]); | |||
EXPORT int jack_port_request_monitor(jack_port_t *port, int onoff); | |||
EXPORT int jack_port_request_monitor_by_name(jack_client_t *client, | |||
const char* port_name, int onoff); | |||
EXPORT int jack_port_ensure_monitor(jack_port_t *port, int onoff); | |||
EXPORT int jack_port_monitoring_input(jack_port_t *port); | |||
EXPORT int jack_connect(jack_client_t *, | |||
const char* source_port, | |||
const char* destination_port); | |||
EXPORT int jack_disconnect(jack_client_t *, | |||
const char* source_port, | |||
const char* destination_port); | |||
EXPORT int jack_port_disconnect(jack_client_t *, jack_port_t *); | |||
EXPORT int jack_port_name_size(void); | |||
EXPORT int jack_port_type_size(void); | |||
EXPORT jack_nframes_t jack_get_sample_rate (jack_client_t *); | |||
EXPORT jack_nframes_t jack_get_buffer_size (jack_client_t *); | |||
EXPORT const char ** jack_get_ports (jack_client_t *, | |||
const char *port_name_pattern, | |||
const char *type_name_pattern, | |||
EXPORT size_t jack_port_type_get_buffer_size(jack_client_t *client, const char* port_type); | |||
EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *); | |||
EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *); | |||
EXPORT const char* * jack_get_ports(jack_client_t *, | |||
const char* port_name_pattern, | |||
const char* type_name_pattern, | |||
unsigned long flags); | |||
EXPORT jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name); | |||
EXPORT jack_port_t * jack_port_by_id (jack_client_t *client, | |||
EXPORT jack_port_t * jack_port_by_name(jack_client_t *, const char* port_name); | |||
EXPORT jack_port_t * jack_port_by_id(jack_client_t *client, | |||
jack_port_id_t port_id); | |||
EXPORT int jack_engine_takeover_timebase (jack_client_t *); | |||
EXPORT jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | |||
EXPORT int jack_engine_takeover_timebase(jack_client_t *); | |||
EXPORT jack_nframes_t jack_frames_since_cycle_start(const jack_client_t *); | |||
EXPORT jack_time_t jack_get_time(); | |||
EXPORT jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t time); | |||
EXPORT jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t frames); | |||
EXPORT jack_nframes_t jack_frame_time (const jack_client_t *); | |||
EXPORT jack_nframes_t jack_last_frame_time (const jack_client_t *client); | |||
EXPORT float jack_cpu_load (jack_client_t *client); | |||
EXPORT pthread_t jack_client_thread_id (jack_client_t *); | |||
EXPORT void jack_set_error_function (print_function); | |||
EXPORT void jack_set_info_function (print_function); | |||
EXPORT float jack_get_max_delayed_usecs (jack_client_t *client); | |||
EXPORT float jack_get_xrun_delayed_usecs (jack_client_t *client); | |||
EXPORT void jack_reset_max_delayed_usecs (jack_client_t *client); | |||
EXPORT int jack_release_timebase (jack_client_t *client); | |||
EXPORT int jack_set_sync_callback (jack_client_t *client, | |||
EXPORT jack_nframes_t jack_frame_time(const jack_client_t *); | |||
EXPORT jack_nframes_t jack_last_frame_time(const jack_client_t *client); | |||
EXPORT float jack_cpu_load(jack_client_t *client); | |||
EXPORT jack_native_thread_t jack_client_thread_id(jack_client_t *); | |||
EXPORT void jack_set_error_function(print_function); | |||
EXPORT void jack_set_info_function(print_function); | |||
EXPORT float jack_get_max_delayed_usecs(jack_client_t *client); | |||
EXPORT float jack_get_xrun_delayed_usecs(jack_client_t *client); | |||
EXPORT void jack_reset_max_delayed_usecs(jack_client_t *client); | |||
EXPORT int jack_release_timebase(jack_client_t *client); | |||
EXPORT int jack_set_sync_callback(jack_client_t *client, | |||
JackSyncCallback sync_callback, | |||
void *arg); | |||
EXPORT int jack_set_sync_timeout (jack_client_t *client, | |||
EXPORT int jack_set_sync_timeout(jack_client_t *client, | |||
jack_time_t timeout); | |||
EXPORT int jack_set_timebase_callback (jack_client_t *client, | |||
EXPORT int jack_set_timebase_callback(jack_client_t *client, | |||
int conditional, | |||
JackTimebaseCallback timebase_callback, | |||
void *arg); | |||
EXPORT int jack_transport_locate (jack_client_t *client, | |||
EXPORT int jack_transport_locate(jack_client_t *client, | |||
jack_nframes_t frame); | |||
EXPORT jack_transport_state_t jack_transport_query (const jack_client_t *client, | |||
EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client, | |||
jack_position_t *pos); | |||
EXPORT jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client); | |||
EXPORT int jack_transport_reposition (jack_client_t *client, | |||
EXPORT jack_nframes_t jack_get_current_transport_frame(const jack_client_t *client); | |||
EXPORT int jack_transport_reposition(jack_client_t *client, | |||
jack_position_t *pos); | |||
EXPORT void jack_transport_start (jack_client_t *client); | |||
EXPORT void jack_transport_stop (jack_client_t *client); | |||
EXPORT void jack_get_transport_info (jack_client_t *client, | |||
EXPORT void jack_transport_start(jack_client_t *client); | |||
EXPORT void jack_transport_stop(jack_client_t *client); | |||
EXPORT void jack_get_transport_info(jack_client_t *client, | |||
jack_transport_info_t *tinfo); | |||
EXPORT void jack_set_transport_info (jack_client_t *client, | |||
EXPORT void jack_set_transport_info(jack_client_t *client, | |||
jack_transport_info_t *tinfo); | |||
EXPORT int jack_client_real_time_priority (jack_client_t*); | |||
EXPORT int jack_client_max_real_time_priority (jack_client_t*); | |||
EXPORT int jack_acquire_real_time_scheduling (pthread_t thread, int priority); | |||
EXPORT int jack_client_create_thread (jack_client_t* client, | |||
pthread_t *thread, | |||
EXPORT int jack_client_real_time_priority(jack_client_t*); | |||
EXPORT int jack_client_max_real_time_priority(jack_client_t*); | |||
EXPORT int jack_acquire_real_time_scheduling(jack_native_thread_t thread, int priority); | |||
EXPORT int jack_client_create_thread(jack_client_t* client, | |||
jack_native_thread_t *thread, | |||
int priority, | |||
int realtime, // boolean | |||
thread_routine routine, | |||
void *arg); | |||
EXPORT int jack_drop_real_time_scheduling (pthread_t thread); | |||
EXPORT int jack_drop_real_time_scheduling(jack_native_thread_t thread); | |||
EXPORT int jack_client_stop_thread (jack_client_t* client, pthread_t thread); | |||
EXPORT int jack_client_kill_thread (jack_client_t* client, pthread_t thread); | |||
EXPORT int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread); | |||
EXPORT int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread); | |||
#ifndef WIN32 | |||
EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc); | |||
EXPORT void jack_set_thread_creator(jack_thread_creator_t jtc); | |||
#endif | |||
EXPORT char * jack_get_internal_client_name (jack_client_t *client, | |||
EXPORT char * jack_get_internal_client_name(jack_client_t *client, | |||
jack_intclient_t intclient); | |||
EXPORT jack_intclient_t jack_internal_client_handle (jack_client_t *client, | |||
const char *client_name, | |||
EXPORT jack_intclient_t jack_internal_client_handle(jack_client_t *client, | |||
const char* client_name, | |||
jack_status_t *status); | |||
EXPORT jack_intclient_t jack_internal_client_load (jack_client_t *client, | |||
const char *client_name, | |||
EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, | |||
const char* client_name, | |||
jack_options_t options, | |||
jack_status_t *status, ...); | |||
EXPORT jack_intclient_t jack_internal_client_load_aux (jack_client_t *client, | |||
const char *client_name, | |||
EXPORT jack_intclient_t jack_internal_client_load_aux(jack_client_t *client, | |||
const char* client_name, | |||
jack_options_t options, | |||
jack_status_t *status, va_list ap); | |||
EXPORT jack_status_t jack_internal_client_unload (jack_client_t *client, | |||
EXPORT jack_status_t jack_internal_client_unload(jack_client_t *client, | |||
jack_intclient_t intclient); | |||
EXPORT void jack_free(void* ptr); | |||
EXPORT int jack_set_session_callback(jack_client_t* ext_client, JackSessionCallback session_callback, void* arg); | |||
EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path); | |||
EXPORT int jack_session_reply(jack_client_t* ext_client, jack_session_event_t *event); | |||
EXPORT void jack_session_event_free(jack_session_event_t* ev); | |||
EXPORT char* jack_get_uuid_for_client_name(jack_client_t* ext_client, const char* client_name); | |||
EXPORT char* jack_get_client_name_by_uuid(jack_client_t* ext_client, const char* client_uuid); | |||
EXPORT int jack_reserve_client_name(jack_client_t* ext_client, const char* name, const char* uuid); | |||
EXPORT void jack_session_commands_free(jack_session_command_t *cmds); | |||
EXPORT int jack_client_has_session_callback(jack_client_t *client, const char* client_name); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
@@ -256,7 +277,7 @@ static inline bool CheckPort(jack_port_id_t port_index) | |||
static inline bool CheckBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
return (buffer_size <= BUFFER_SIZE_MAX); | |||
return (buffer_size >= 1 && buffer_size <= BUFFER_SIZE_MAX); | |||
} | |||
static inline void WaitGraphChange() | |||
@@ -278,12 +299,12 @@ static inline void WaitGraphChange() | |||
} | |||
} | |||
EXPORT void jack_set_error_function (print_function func) | |||
EXPORT void jack_set_error_function(print_function func) | |||
{ | |||
jack_error_callback = (func == NULL) ? &default_jack_error_callback : func; | |||
} | |||
EXPORT void jack_set_info_function (print_function func) | |||
EXPORT void jack_set_info_function(print_function func) | |||
{ | |||
jack_info_callback = (func == NULL) ? &default_jack_info_callback : func; | |||
} | |||
@@ -526,6 +547,40 @@ EXPORT void jack_port_set_latency(jack_port_t* port, jack_nframes_t frames) | |||
} | |||
} | |||
EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_port_get_latency_range"); | |||
#endif | |||
uintptr_t port_aux = (uintptr_t)port; | |||
jack_port_id_t myport = (jack_port_id_t)port_aux; | |||
if (!CheckPort(myport)) { | |||
jack_error("jack_port_get_latency_range called with an incorrect port %ld", myport); | |||
} else { | |||
WaitGraphChange(); | |||
JackGraphManager* manager = GetGraphManager(); | |||
if (manager) | |||
manager->GetPort(myport)->GetLatencyRange(mode, range); | |||
} | |||
} | |||
EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_port_set_latency_range"); | |||
#endif | |||
uintptr_t port_aux = (uintptr_t)port; | |||
jack_port_id_t myport = (jack_port_id_t)port_aux; | |||
if (!CheckPort(myport)) { | |||
jack_error("jack_port_set_latency_range called with an incorrect port %ld", myport); | |||
} else { | |||
WaitGraphChange(); | |||
JackGraphManager* manager = GetGraphManager(); | |||
if (manager) | |||
manager->GetPort(myport)->SetLatencyRange(mode, range); | |||
} | |||
} | |||
EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* port) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
@@ -536,10 +591,10 @@ EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* | |||
uintptr_t port_aux = (uintptr_t)port; | |||
jack_port_id_t myport = (jack_port_id_t)port_aux; | |||
if (client == NULL) { | |||
jack_error("jack_recompute_total_latencies called with a NULL client"); | |||
jack_error("jack_recompute_total_latency called with a NULL client"); | |||
return -1; | |||
} else if (!CheckPort(myport)) { | |||
jack_error("jack_recompute_total_latencies called with a NULL port"); | |||
jack_error("jack_recompute_total_latency called with a NULL port"); | |||
return -1; | |||
} else { | |||
WaitGraphChange(); | |||
@@ -559,9 +614,7 @@ EXPORT int jack_recompute_total_latencies(jack_client_t* ext_client) | |||
jack_error("jack_recompute_total_latencies called with a NULL client"); | |||
return -1; | |||
} else { | |||
WaitGraphChange(); | |||
JackGraphManager* manager = GetGraphManager(); | |||
return (manager ? manager->ComputeTotalLatencies() : -1); | |||
return client->ComputeTotalLatencies(); | |||
} | |||
} | |||
@@ -988,6 +1041,20 @@ EXPORT int jack_set_xrun_callback(jack_client_t* ext_client, JackXRunCallback xr | |||
} | |||
} | |||
EXPORT int jack_set_latency_callback(jack_client_t* ext_client, JackLatencyCallback latency_callback, void *arg) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_set_latency_callback"); | |||
#endif | |||
JackClient* client = (JackClient*)ext_client; | |||
if (client == NULL) { | |||
jack_error("jack_set_latency_callback called with a NULL client"); | |||
return -1; | |||
} else { | |||
return client->SetLatencyCallback(latency_callback, arg); | |||
} | |||
} | |||
EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback init_callback, void *arg) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
@@ -1396,7 +1463,7 @@ EXPORT float jack_cpu_load(jack_client_t* ext_client) | |||
} | |||
} | |||
EXPORT pthread_t jack_client_thread_id(jack_client_t* ext_client) | |||
EXPORT jack_native_thread_t jack_client_thread_id(jack_client_t* ext_client) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_thread_id"); | |||
@@ -1404,7 +1471,7 @@ EXPORT pthread_t jack_client_thread_id(jack_client_t* ext_client) | |||
JackClient* client = (JackClient*)ext_client; | |||
if (client == NULL) { | |||
jack_error("jack_client_thread_id called with a NULL client"); | |||
return (pthread_t)NULL; | |||
return (jack_native_thread_t)NULL; | |||
} else { | |||
return client->GetThreadID(); | |||
} | |||
@@ -1439,6 +1506,26 @@ EXPORT int jack_port_type_size(void) | |||
return JACK_PORT_TYPE_SIZE; | |||
} | |||
EXPORT size_t jack_port_type_get_buffer_size(jack_client_t* ext_client, const char* port_type) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_port_type_get_buffer_size"); | |||
#endif | |||
JackClient* client = (JackClient*)ext_client; | |||
if (client == NULL) { | |||
jack_error("jack_port_type_get_buffer_size called with a NULL client"); | |||
return 0; | |||
} else { | |||
jack_port_type_id_t port_id = GetPortTypeId(port_type); | |||
if (port_id == PORT_TYPES_MAX) { | |||
jack_error("jack_port_type_get_buffer_size called with an unknown port type = %s", port_type); | |||
return 0; | |||
} else { | |||
return GetPortType(port_id)->size(); | |||
} | |||
} | |||
} | |||
// transport.h | |||
EXPORT int jack_release_timebase(jack_client_t* ext_client) | |||
{ | |||
@@ -1595,7 +1682,7 @@ EXPORT void jack_set_transport_info(jack_client_t* ext_client, jack_transport_in | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_set_transport_info"); | |||
#endif | |||
#endif | |||
jack_error("jack_set_transport_info: deprecated"); | |||
if (tinfo) | |||
memset(tinfo, 0, sizeof(jack_transport_info_t)); | |||
@@ -1677,14 +1764,14 @@ EXPORT int jack_client_max_real_time_priority(jack_client_t* ext_client) | |||
} | |||
} | |||
EXPORT int jack_acquire_real_time_scheduling(pthread_t thread, int priority) | |||
EXPORT int jack_acquire_real_time_scheduling(jack_native_thread_t thread, int priority) | |||
{ | |||
JackEngineControl* control = GetEngineControl(); | |||
return (control ? JackThread::AcquireRealTimeImp(thread, priority, GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint) : -1); | |||
} | |||
EXPORT int jack_client_create_thread(jack_client_t* client, | |||
pthread_t *thread, | |||
jack_native_thread_t *thread, | |||
int priority, | |||
int realtime, /* boolean */ | |||
thread_routine routine, | |||
@@ -1692,28 +1779,28 @@ EXPORT int jack_client_create_thread(jack_client_t* client, | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_create_thread"); | |||
#endif | |||
#endif | |||
return JackThread::StartImp(thread, priority, realtime, routine, arg); | |||
} | |||
EXPORT int jack_drop_real_time_scheduling(pthread_t thread) | |||
EXPORT int jack_drop_real_time_scheduling(jack_native_thread_t thread) | |||
{ | |||
return JackThread::DropRealTimeImp(thread); | |||
} | |||
EXPORT int jack_client_stop_thread(jack_client_t* client, pthread_t thread) | |||
EXPORT int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_stop_thread"); | |||
#endif | |||
#endif | |||
return JackThread::StopImp(thread); | |||
} | |||
EXPORT int jack_client_kill_thread(jack_client_t* client, pthread_t thread) | |||
EXPORT int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_kill_thread"); | |||
#endif | |||
#endif | |||
return JackThread::KillImp(thread); | |||
} | |||
@@ -1725,15 +1812,15 @@ EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc) | |||
#endif | |||
// intclient.h | |||
EXPORT int jack_internal_client_new (const char *client_name, | |||
const char *load_name, | |||
const char *load_init) | |||
EXPORT int jack_internal_client_new (const char* client_name, | |||
const char* load_name, | |||
const char* load_init) | |||
{ | |||
jack_error("jack_internal_client_new: deprecated"); | |||
return -1; | |||
} | |||
EXPORT void jack_internal_client_close (const char *client_name) | |||
EXPORT void jack_internal_client_close (const char* client_name) | |||
{ | |||
jack_error("jack_internal_client_close: deprecated"); | |||
} | |||
@@ -1803,7 +1890,7 @@ EXPORT jack_intclient_t jack_internal_client_load_aux(jack_client_t* ext_client, | |||
} | |||
} | |||
EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, const char *client_name, jack_options_t options, jack_status_t *status, ...) | |||
EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, const char* client_name, jack_options_t options, jack_status_t *status, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, status); | |||
@@ -1847,7 +1934,7 @@ jack_get_version( | |||
} | |||
EXPORT | |||
const char * | |||
const char* | |||
jack_get_version_string() | |||
{ | |||
return VERSION; | |||
@@ -1876,7 +1963,7 @@ EXPORT int jack_set_session_callback(jack_client_t* ext_client, JackSessionCallb | |||
} | |||
} | |||
EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char *path) | |||
EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_session_notify"); | |||
@@ -1891,7 +1978,7 @@ EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, co | |||
} | |||
} | |||
EXPORT int jack_session_reply(jack_client_t *ext_client, jack_session_event_t *event) | |||
EXPORT int jack_session_reply(jack_client_t* ext_client, jack_session_event_t *event) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_session_reply"); | |||
@@ -1919,7 +2006,7 @@ EXPORT void jack_session_event_free(jack_session_event_t* ev) | |||
} | |||
} | |||
EXPORT char *jack_get_uuid_for_client_name( jack_client_t *ext_client, const char *client_name ) | |||
EXPORT char *jack_get_uuid_for_client_name(jack_client_t* ext_client, const char* client_name) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_get_uuid_for_client_name"); | |||
@@ -1934,7 +2021,7 @@ EXPORT char *jack_get_uuid_for_client_name( jack_client_t *ext_client, const cha | |||
} | |||
} | |||
EXPORT char *jack_get_client_name_by_uuid( jack_client_t *ext_client, const char *client_uuid ) | |||
EXPORT char *jack_get_client_name_by_uuid(jack_client_t* ext_client, const char* client_uuid) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_get_client_name_by_uuid"); | |||
@@ -1945,11 +2032,11 @@ EXPORT char *jack_get_client_name_by_uuid( jack_client_t *ext_client, const char | |||
jack_error("jack_get_client_name_by_uuid called with a NULL client"); | |||
return NULL; | |||
} else { | |||
return client->GetClientNameForUUID(client_uuid); | |||
return client->GetClientNameByUUID(client_uuid); | |||
} | |||
} | |||
EXPORT int jack_reserve_client_name( jack_client_t *ext_client, const char *name, const char *uuid ) | |||
EXPORT int jack_reserve_client_name(jack_client_t* ext_client, const char* client_name, const char* uuid) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_reserve_client_name"); | |||
@@ -1960,17 +2047,17 @@ EXPORT int jack_reserve_client_name( jack_client_t *ext_client, const char *name | |||
jack_error("jack_reserve_client_name called with a NULL client"); | |||
return -1; | |||
} else { | |||
return client->ReserveClientName(name, uuid); | |||
return client->ReserveClientName(client_name, uuid); | |||
} | |||
} | |||
EXPORT void jack_session_commands_free( jack_session_command_t *cmds ) | |||
EXPORT void jack_session_commands_free(jack_session_command_t *cmds) | |||
{ | |||
if (!cmds) | |||
return; | |||
int i=0; | |||
while(1) { | |||
int i = 0; | |||
while (1) { | |||
if (cmds[i].client_name) | |||
free ((char *)cmds[i].client_name); | |||
if (cmds[i].command) | |||
@@ -1985,3 +2072,18 @@ EXPORT void jack_session_commands_free( jack_session_command_t *cmds ) | |||
free(cmds); | |||
} | |||
EXPORT int jack_client_has_session_callback(jack_client_t* ext_client, const char* client_name) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_has_session_callback"); | |||
#endif | |||
JackClient* client = (JackClient*)ext_client; | |||
jack_log("jack_client_has_session_callback ext_client %x client %x ", ext_client, client); | |||
if (client == NULL) { | |||
jack_error("jack_client_has_session_callback called with a NULL client"); | |||
return -1; | |||
} else { | |||
return client->ClientHasSessionCallback(client_name); | |||
} | |||
} |
@@ -101,6 +101,7 @@ int JackAudioDriver::Attach() | |||
jack_port_id_t port_index; | |||
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
jack_latency_range_t range; | |||
int i; | |||
jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); | |||
@@ -114,7 +115,8 @@ int JackAudioDriver::Attach() | |||
} | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetAlias(alias); | |||
port->SetLatency(fEngineControl->fBufferSize + fCaptureLatency); | |||
range.min = range.max = fEngineControl->fBufferSize + fCaptureLatency; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fCapturePortList[i] = port_index; | |||
jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", port_index); | |||
} | |||
@@ -129,7 +131,8 @@ int JackAudioDriver::Attach() | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetAlias(alias); | |||
// Add more latency if "async" mode is used... | |||
port->SetLatency(fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency); | |||
range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency; | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
fPlaybackPortList[i] = port_index; | |||
jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); | |||
@@ -143,7 +146,8 @@ int JackAudioDriver::Attach() | |||
} else { | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetAlias(alias); | |||
port->SetLatency(fEngineControl->fBufferSize); | |||
range.min = range.max = fEngineControl->fBufferSize; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fMonitorPortList[i] = port_index; | |||
} | |||
} | |||
@@ -188,13 +192,13 @@ int JackAudioDriver::ProcessNull() | |||
{ | |||
// Keep begin cycle time | |||
JackDriver::CycleTakeBeginTime(); | |||
if (fEngineControl->fSyncMode) { | |||
ProcessGraphSync(); | |||
} else { | |||
ProcessGraphAsync(); | |||
} | |||
// Keep end cycle time | |||
JackDriver::CycleTakeEndTime(); | |||
WaitUntilNextCycle(); | |||
@@ -214,23 +218,24 @@ synchronize to the end of client graph execution. | |||
int JackAudioDriver::ProcessAsync() | |||
{ | |||
// Read input buffers for the current cycle | |||
if (Read() < 0) { | |||
if (Read() < 0) { | |||
jack_error("JackAudioDriver::ProcessAsync: read error, stopping..."); | |||
return -1; | |||
return -1; | |||
} | |||
// Write output buffers from the previous cycle | |||
if (Write() < 0) { | |||
jack_error("JackAudioDriver::ProcessAsync: write error, stopping..."); | |||
return -1; | |||
return -1; | |||
} | |||
// Process graph | |||
if (fIsMaster) { | |||
ProcessGraphAsync(); | |||
} else { | |||
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
} | |||
// Keep end cycle time | |||
JackDriver::CycleTakeEndTime(); | |||
return 0; | |||
@@ -238,29 +243,38 @@ int JackAudioDriver::ProcessAsync() | |||
/* | |||
The driver SYNC mode: the server does synchronize to the end of client graph execution, | |||
output buffers computed at the *current cycle* are used. | |||
if graph process succeed, output buffers computed at the *current cycle* are used. | |||
*/ | |||
int JackAudioDriver::ProcessSync() | |||
{ | |||
// Read input buffers for the current cycle | |||
if (Read() < 0) { | |||
if (Read() < 0) { | |||
jack_error("JackAudioDriver::ProcessSync: read error, stopping..."); | |||
return -1; | |||
return -1; | |||
} | |||
// Process graph | |||
if (fIsMaster) { | |||
ProcessGraphSync(); | |||
if (ProcessGraphSync() < 0) { | |||
jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); | |||
goto end; | |||
} | |||
} else { | |||
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { | |||
jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); | |||
goto end; | |||
} | |||
} | |||
// Write output buffers from the current cycle | |||
if (Write() < 0) { | |||
jack_error("JackAudioDriver::ProcessSync: write error, stopping..."); | |||
return -1; | |||
return -1; | |||
} | |||
end: | |||
// Keep end cycle time | |||
JackDriver::CycleTakeEndTime(); | |||
return 0; | |||
@@ -269,25 +283,34 @@ int JackAudioDriver::ProcessSync() | |||
void JackAudioDriver::ProcessGraphAsync() | |||
{ | |||
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
if (!fEngine->Process(fBeginDateUst, fEndDateUst)) | |||
if (!fEngine->Process(fBeginDateUst, fEndDateUst)) | |||
jack_error("JackAudioDriver::ProcessGraphAsync: Process error"); | |||
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
if (ProcessSlaves() < 0) | |||
jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error"); | |||
} | |||
void JackAudioDriver::ProcessGraphSync() | |||
int JackAudioDriver::ProcessGraphSync() | |||
{ | |||
int res = 0; | |||
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
if (fEngine->Process(fBeginDateUst, fEndDateUst)) { | |||
if (fEngine->Process(fBeginDateUst, fEndDateUst)) { | |||
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); | |||
if (ProcessSlaves() < 0) | |||
if (ProcessSlaves() < 0) { | |||
jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!"); | |||
if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) | |||
res = -1; | |||
} | |||
if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { | |||
jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!"); | |||
res = -1; | |||
} | |||
} else { // Graph not finished: do not activate it | |||
jack_error("JackAudioDriver::ProcessGraphSync: Process error"); | |||
res = -1; | |||
} | |||
return res; | |||
} | |||
void JackAudioDriver::WaitUntilNextCycle() | |||
@@ -316,4 +339,37 @@ jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index) | |||
return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize); | |||
} | |||
int JackAudioDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) | |||
{ | |||
switch (notify) { | |||
case kLatencyCallback: | |||
HandleLatencyCallback(value1); | |||
break; | |||
default: | |||
JackDriver::ClientNotify(refnum, name, notify, sync, message, value1, value2); | |||
break; | |||
} | |||
return 0; | |||
} | |||
void JackAudioDriver::HandleLatencyCallback(int status) | |||
{ | |||
jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency; | |||
for (int i = 0; i < fCaptureChannels; i++) { | |||
if (mode == JackPlaybackLatency) { | |||
fGraphManager->RecalculateLatency(fCapturePortList[i], mode); | |||
} | |||
} | |||
for (int i = 0; i < fPlaybackChannels; i++) { | |||
if (mode == JackCaptureLatency) { | |||
fGraphManager->RecalculateLatency(fPlaybackPortList[i], mode); | |||
} | |||
} | |||
} | |||
} // end of namespace |
@@ -36,12 +36,12 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
protected: | |||
void ProcessGraphAsync(); | |||
void ProcessGraphSync(); | |||
int ProcessGraphSync(); | |||
void WaitUntilNextCycle(); | |||
virtual int ProcessAsync(); | |||
virtual int ProcessSync(); | |||
int fCaptureChannels; | |||
int fPlaybackChannels; | |||
@@ -57,6 +57,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
jack_default_audio_sample_t* GetOutputBuffer(int port_index); | |||
jack_default_audio_sample_t* GetMonitorBuffer(int port_index); | |||
void HandleLatencyCallback(int status); | |||
public: | |||
JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | |||
@@ -73,7 +75,7 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
const char* playback_driver_name, | |||
jack_nframes_t capture_latency, | |||
jack_nframes_t playback_latency); | |||
virtual int Open(bool capturing, | |||
bool playing, | |||
int inchannels, | |||
@@ -83,18 +85,20 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||
const char* playback_driver_name, | |||
jack_nframes_t capture_latency, | |||
jack_nframes_t playback_latency); | |||
virtual int Process(); | |||
virtual int ProcessNull(); | |||
virtual int Attach(); | |||
virtual int Detach(); | |||
virtual int Write(); | |||
virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | |||
}; | |||
} // end of namespace | |||
@@ -18,7 +18,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#include "JackGlobals.h" | |||
#include "JackEngineControl.h" | |||
#include "JackPortType.h" | |||
#include <string.h> | |||
#if defined (__APPLE__) | |||
@@ -46,7 +49,7 @@ static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_ | |||
frames = frames % 4; | |||
while (frames_group > 0) { | |||
#if defined (__SSE__) && !defined (__sun__) | |||
#if defined (__SSE__) && !defined (__sun__) | |||
__m128 vec = _mm_add_ps(_mm_load_ps(mixbuffer), _mm_load_ps(buffer)); | |||
_mm_store_ps(mixbuffer, vec); | |||
@@ -97,7 +100,7 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun | |||
void* buffer; | |||
// Copy first buffer | |||
#if defined (__SSE__) && !defined (__sun__) | |||
#if defined (__SSE__) && !defined (__sun__) | |||
jack_nframes_t frames_group = nframes / 4; | |||
jack_nframes_t remaining_frames = nframes % 4; | |||
@@ -127,12 +130,18 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun | |||
} | |||
} | |||
static size_t AudioBufferSize() | |||
{ | |||
return GetEngineControl()->fBufferSize * sizeof(float); | |||
} | |||
const JackPortType gAudioPortType = | |||
{ | |||
JACK_DEFAULT_AUDIO_TYPE, | |||
AudioBufferInit, | |||
AudioBufferMixdown | |||
}; | |||
{ | |||
JACK_DEFAULT_AUDIO_TYPE, | |||
AudioBufferSize, | |||
AudioBufferInit, | |||
AudioBufferMixdown | |||
}; | |||
} // namespace Jack | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#ifndef __JackChannel__ | |||
#define __JackChannel__ | |||
#include "types.h" | |||
#include "session.h" | |||
namespace Jack | |||
@@ -108,43 +107,39 @@ class JackClientChannelInterface | |||
{} | |||
virtual void SetFreewheel(int onoff, int* result) | |||
{} | |||
virtual void ComputeTotalLatencies(int* result) | |||
{} | |||
virtual void ReleaseTimebase(int refnum, int* result) | |||
{} | |||
virtual void SetTimebaseCallback(int refnum, int conditional, int* result) | |||
{} | |||
virtual void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | |||
{} | |||
virtual void InternalClientHandle(int refnum, const char* client_name, int* status, int* int_ref, int* result) | |||
{} | |||
virtual void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) | |||
{} | |||
virtual void InternalClientUnload(int refnum, int int_ref, int* status, int* result) | |||
{} | |||
virtual void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, jack_session_command_t **result) | |||
{} | |||
virtual void SessionReply(int refnum, int *result) | |||
virtual void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result) | |||
{} | |||
virtual void GetUUIDForClientName(int refnum, const char *client_name, char *uuid_res, int *result) | |||
virtual void SessionReply(int refnum, int* result) | |||
{} | |||
virtual void GetClientNameForUUID(int refnum, const char *uuid, char *name_res, int *result) | |||
virtual void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result) | |||
{} | |||
virtual void ReserveClientName(int refnum, const char *client_name, const char *uuid, int *result) | |||
virtual void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result) | |||
{} | |||
virtual void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result) | |||
{} | |||
virtual void ClientHasSessionCallback(const char* client_name, int* result) | |||
{} | |||
virtual bool IsChannelThread() | |||
{ | |||
return false; | |||
{ | |||
return false; | |||
} | |||
}; | |||
@@ -13,12 +13,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#include "JackClient.h" | |||
#include "JackSystemDeps.h" | |||
#include "JackGraphManager.h" | |||
#include "JackClientControl.h" | |||
#include "JackEngineControl.h" | |||
@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "driver_interface.h" | |||
#include "JackLibGlobals.h" | |||
#include <math.h> | |||
#include <string> | |||
#include <algorithm> | |||
@@ -60,6 +61,9 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||
fTimebase = NULL; | |||
fSync = NULL; | |||
fThreadFun = NULL; | |||
fSession = NULL; | |||
fLatency = NULL; | |||
fProcessArg = NULL; | |||
fGraphOrderArg = NULL; | |||
fXrunArg = NULL; | |||
@@ -75,6 +79,8 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||
fSyncArg = NULL; | |||
fTimebaseArg = NULL; | |||
fThreadFunArg = NULL; | |||
fSessionArg = NULL; | |||
fLatencyArg = NULL; | |||
} | |||
JackClient::~JackClient() | |||
@@ -84,17 +90,17 @@ int JackClient::Close() | |||
{ | |||
jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); | |||
int result = 0; | |||
Deactivate(); | |||
fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing | |||
// Request close only if server is still running | |||
if (JackGlobals::fServerRunning) { | |||
fChannel->ClientClose(GetClientControl()->fRefNum, &result); | |||
} else { | |||
jack_log("JackClient::Close server is shutdown"); | |||
jack_log("JackClient::Close server is shutdown"); | |||
} | |||
fChannel->Close(); | |||
fSynchroTable[GetClientControl()->fRefNum].Disconnect(); | |||
JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; | |||
@@ -106,7 +112,7 @@ bool JackClient::IsActive() | |||
return (GetClientControl()) ? GetClientControl()->fActive : false; | |||
} | |||
pthread_t JackClient::GetThreadID() | |||
jack_native_thread_t JackClient::GetThreadID() | |||
{ | |||
return fThread.GetThreadID(); | |||
} | |||
@@ -156,7 +162,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
case kActivateClient: | |||
jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); | |||
Init(); | |||
InitAux(); | |||
break; | |||
} | |||
@@ -188,7 +194,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
res = fBufferSize(value1, fBufferSizeArg); | |||
} | |||
break; | |||
case kSampleRateCallback: | |||
jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); | |||
if (fSampleRate) { | |||
@@ -219,7 +225,9 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
fFreewheel(0, fFreewheelArg); | |||
} | |||
if (GetEngineControl()->fRealTime) { | |||
fThread.AcquireRealTime(); | |||
if (fThread.AcquireRealTime() < 0) { | |||
jack_error("JackClient::AcquireRealTime error"); | |||
} | |||
} | |||
break; | |||
@@ -250,7 +258,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
fPortConnect(value1, value2, 0, fPortConnectArg); | |||
} | |||
break; | |||
case kPortRenameCallback: | |||
jack_log("JackClient::kPortRenameCallback port = %ld", value1); | |||
if (fPortRename) { | |||
@@ -264,7 +272,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
res = fXrun(fXrunArg); | |||
} | |||
break; | |||
case kShutDownCallback: | |||
jack_log("JackClient::kShutDownCallback"); | |||
if (fInfoShutdown) { | |||
@@ -289,15 +297,109 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
res = (fImmediateSessionReply) ? 1 : 2; | |||
} | |||
break; | |||
case kLatencyCallback: | |||
res = HandleLatencyCallback(value1); | |||
break; | |||
} | |||
} | |||
return res; | |||
} | |||
int JackClient::HandleLatencyCallback(int status) | |||
{ | |||
jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency; | |||
jack_latency_range_t latency = { UINT32_MAX, 0 }; | |||
/* first setup all latency values of the ports. | |||
* this is based on the connections of the ports. | |||
*/ | |||
list<jack_port_id_t>::iterator it; | |||
for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
JackPort* port = GetGraphManager()->GetPort(*it); | |||
if ((port->GetFlags() & JackPortIsOutput) && (mode == JackPlaybackLatency)) { | |||
GetGraphManager()->RecalculateLatency(*it, mode); | |||
} | |||
if ((port->GetFlags() & JackPortIsInput) && (mode == JackCaptureLatency)) { | |||
GetGraphManager()->RecalculateLatency(*it, mode); | |||
} | |||
} | |||
if (!fLatency) { | |||
/* | |||
* default action is to assume all ports depend on each other. | |||
* then always take the maximum latency. | |||
*/ | |||
if (mode == JackPlaybackLatency) { | |||
/* iterate over all OutputPorts, to find maximum playback latency | |||
*/ | |||
for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
JackPort* port = GetGraphManager()->GetPort(*it); | |||
if (port->GetFlags() & JackPortIsOutput) { | |||
jack_latency_range_t other_latency; | |||
port->GetLatencyRange(mode, &other_latency); | |||
if (other_latency.max > latency.max) | |||
latency.max = other_latency.max; | |||
if (other_latency.min < latency.min) | |||
latency.min = other_latency.min; | |||
} | |||
} | |||
if (latency.min == UINT32_MAX) | |||
latency.min = 0; | |||
/* now set the found latency on all input ports | |||
*/ | |||
for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
JackPort* port = GetGraphManager()->GetPort(*it); | |||
if (port->GetFlags() & JackPortIsInput) { | |||
port->SetLatencyRange(mode, &latency); | |||
} | |||
} | |||
} | |||
if (mode == JackCaptureLatency) { | |||
/* iterate over all InputPorts, to find maximum playback latency | |||
*/ | |||
for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
JackPort* port = GetGraphManager()->GetPort(*it); | |||
if (port->GetFlags() & JackPortIsInput) { | |||
jack_latency_range_t other_latency; | |||
port->GetLatencyRange(mode, &other_latency); | |||
if (other_latency.max > latency.max) | |||
latency.max = other_latency.max; | |||
if (other_latency.min < latency.min) | |||
latency.min = other_latency.min; | |||
} | |||
} | |||
if (latency.min == UINT32_MAX) | |||
latency.min = 0; | |||
/* now set the found latency on all output ports | |||
*/ | |||
for (it = fPortList.begin(); it != fPortList.end(); it++) { | |||
JackPort* port = GetGraphManager()->GetPort(*it); | |||
if (port->GetFlags() & JackPortIsOutput) { | |||
port->SetLatencyRange(mode, &latency); | |||
} | |||
} | |||
} | |||
return 0; | |||
} | |||
/* we have a latency callback setup by the client, | |||
* lets use it... | |||
*/ | |||
fLatency(mode, fLatencyArg); | |||
return 0; | |||
} | |||
/*! | |||
\brief We need to start thread before activating in the server, otherwise the FW driver | |||
connected to the client may not be activated. | |||
connected to the client may not be activated. | |||
*/ | |||
int JackClient::Activate() | |||
{ | |||
@@ -310,13 +412,13 @@ int JackClient::Activate() | |||
if (StartThread() < 0) | |||
return -1; | |||
} | |||
/* | |||
Insertion of client in the graph will cause a kGraphOrderCallback notification | |||
Insertion of client in the graph will cause a kGraphOrderCallback notification | |||
to be delivered by the server, the client wants to receive it. | |||
*/ | |||
GetClientControl()->fActive = true; | |||
// Transport related callback become "active" | |||
GetClientControl()->fTransportSync = true; | |||
GetClientControl()->fTransportTimebase = true; | |||
@@ -337,18 +439,18 @@ int JackClient::Deactivate() | |||
return 0; | |||
GetClientControl()->fActive = false; | |||
// Transport related callback become "unactive" | |||
GetClientControl()->fTransportSync = false; | |||
GetClientControl()->fTransportTimebase = false; | |||
// We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate | |||
int result = -1; | |||
fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | |||
jack_log("JackClient::Deactivate res = %ld", result); | |||
// RT thread is stopped only when needed... | |||
if (IsRealTime()) | |||
if (IsRealTime()) | |||
fThread.Kill(); | |||
return result; | |||
} | |||
@@ -357,15 +459,48 @@ int JackClient::Deactivate() | |||
// RT thread management | |||
//---------------------- | |||
void JackClient::InitAux() | |||
{ | |||
if (fInit) { | |||
jack_log("JackClient::Init calling client thread init callback"); | |||
fInit(fInitArg); | |||
} | |||
} | |||
/*! | |||
\brief Called once when the thread starts. | |||
*/ | |||
bool JackClient::Init() | |||
{ | |||
if (fInit) { | |||
jack_log("JackClient::Init calling client thread init callback"); | |||
fInit(fInitArg); | |||
/* | |||
Execute buffer_size callback. | |||
Since StartThread uses fThread.StartSync, we are sure that buffer_size callback | |||
is executed before StartThread returns (and then IsActive will be true). | |||
So no RT callback can be called at the same time. | |||
*/ | |||
jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize); | |||
if (fBufferSize) { | |||
fBufferSize(GetEngineControl()->fBufferSize, fBufferSizeArg); | |||
} | |||
// Init callback | |||
InitAux(); | |||
// Setup context | |||
if (!jack_tls_set(JackGlobals::fRealTime, this)) | |||
jack_error("failed to set thread realtime key"); | |||
if (GetEngineControl()->fRealTime) | |||
set_threaded_log_function(); | |||
// Setup RT | |||
if (GetEngineControl()->fRealTime) { | |||
if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { | |||
jack_error("JackClient::AcquireRealTime error"); | |||
} | |||
} | |||
return true; | |||
} | |||
@@ -384,12 +519,6 @@ int JackClient::StartThread() | |||
return -1; | |||
} | |||
if (GetEngineControl()->fRealTime) { | |||
if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { | |||
jack_error("AcquireRealTime error"); | |||
} | |||
} | |||
return 0; | |||
} | |||
@@ -399,21 +528,15 @@ int JackClient::StartThread() | |||
bool JackClient::Execute() | |||
{ | |||
if (!jack_tls_set(JackGlobals::fRealTime, this)) | |||
jack_error("failed to set thread realtime key"); | |||
if (GetEngineControl()->fRealTime) | |||
set_threaded_log_function(); | |||
// Execute a dummy cycle to be sure thread has the correct properties | |||
DummyCycle(); | |||
if (fThreadFun) { | |||
fThreadFun(fThreadFunArg); | |||
} else { | |||
ExecuteThread(); | |||
} | |||
return false; | |||
return false; | |||
} | |||
void JackClient::DummyCycle() | |||
@@ -424,15 +547,15 @@ void JackClient::DummyCycle() | |||
inline void JackClient::ExecuteThread() | |||
{ | |||
while (true) { | |||
while (true) { | |||
CycleWaitAux(); | |||
CycleSignalAux(CallProcessCallback()); | |||
} | |||
CycleSignalAux(CallProcessCallback()); | |||
} | |||
} | |||
inline jack_nframes_t JackClient::CycleWaitAux() | |||
{ | |||
if (!WaitSync()) | |||
if (!WaitSync()) | |||
Error(); // Terminates the thread | |||
CallSyncCallbackAux(); | |||
return GetEngineControl()->fBufferSize; | |||
@@ -443,7 +566,7 @@ inline void JackClient::CycleSignalAux(int status) | |||
if (status == 0) | |||
CallTimebaseCallbackAux(); | |||
SignalSync(); | |||
if (status != 0) | |||
if (status != 0) | |||
End(); // Terminates the thread | |||
} | |||
@@ -531,7 +654,7 @@ int JackClient::PortRegister(const char* port_name, const char* port_type, unsig | |||
int result = -1; | |||
jack_port_id_t port_index = NO_PORT; | |||
fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); | |||
if (result == 0) { | |||
jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index); | |||
fPortList.push_back(port_index); | |||
@@ -612,6 +735,13 @@ int JackClient::SetFreeWheel(int onoff) | |||
return result; | |||
} | |||
int JackClient::ComputeTotalLatencies() | |||
{ | |||
int result = -1; | |||
fChannel->ComputeTotalLatencies(&result); | |||
return result; | |||
} | |||
/* | |||
ShutDown is called: | |||
- from the RT thread when Execute method fails | |||
@@ -621,9 +751,9 @@ ShutDown is called: | |||
void JackClient::ShutDown() | |||
{ | |||
jack_log("ShutDown"); | |||
jack_log("JackClient::ShutDown"); | |||
JackGlobals::fServerRunning = false; | |||
if (fInfoShutdown) { | |||
fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); | |||
fInfoShutdown = NULL; | |||
@@ -641,18 +771,18 @@ inline int JackClient::ActivateAux() | |||
{ | |||
// If activated without RT thread... | |||
if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { | |||
jack_log("ActivateAux"); | |||
jack_log("JackClient::ActivateAux"); | |||
// RT thread is started | |||
if (StartThread() < 0) | |||
return -1; | |||
int result = -1; | |||
GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); | |||
fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); | |||
return result; | |||
} else { | |||
return 0; | |||
} | |||
@@ -683,7 +813,7 @@ int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timeba | |||
{ | |||
int result = -1; | |||
fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | |||
if (result == 0) { | |||
GetClientControl()->fTransportTimebase = true; | |||
fTimebase = timebase_callback; | |||
@@ -709,14 +839,14 @@ void JackClient::TransportLocate(jack_nframes_t frame) | |||
jack_position_t pos; | |||
pos.frame = frame; | |||
pos.valid = (jack_position_bits_t)0; | |||
jack_log("TransportLocate pos = %ld", pos.frame); | |||
jack_log("JackClient::TransportLocate pos = %ld", pos.frame); | |||
GetEngineControl()->fTransport.RequestNewPos(&pos); | |||
} | |||
int JackClient::TransportReposition(jack_position_t* pos) | |||
{ | |||
jack_position_t tmp = *pos; | |||
jack_log("TransportReposition pos = %ld", pos->frame); | |||
jack_log("JackClient::TransportReposition pos = %ld", pos->frame); | |||
if (tmp.valid & ~JACK_POSITION_MASK) { | |||
return EINVAL; | |||
} else { | |||
@@ -758,11 +888,11 @@ void JackClient::CallSyncCallback() | |||
inline void JackClient::CallSyncCallbackAux() | |||
{ | |||
if (GetClientControl()->fTransportSync) { | |||
JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
jack_position_t* cur_pos = transport.ReadCurrentState(); | |||
jack_transport_state_t transport_state = transport.GetState(); | |||
if (fSync != NULL) { | |||
if (fSync(transport_state, cur_pos, fSyncArg)) { | |||
GetClientControl()->fTransportState = JackTransportRolling; | |||
@@ -785,21 +915,21 @@ inline void JackClient::CallTimebaseCallbackAux() | |||
JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
int master; | |||
bool unused; | |||
transport.GetTimebaseMaster(master, unused); | |||
if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... | |||
jack_transport_state_t transport_state = transport.GetState(); | |||
jack_position_t* cur_pos = transport.WriteNextStateStart(1); | |||
if (GetClientControl()->fTransportTimebase) { | |||
fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); | |||
GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true | |||
fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); | |||
GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true | |||
} else if (transport_state == JackTransportRolling) { | |||
fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); | |||
} | |||
} | |||
transport.WriteNextStateStop(1); | |||
} | |||
} | |||
@@ -817,7 +947,7 @@ void JackClient::OnShutdown(JackShutdownCallback callback, void *arg) | |||
fShutdown = callback; | |||
} | |||
} | |||
void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) | |||
{ | |||
if (IsActive()) { | |||
@@ -873,8 +1003,6 @@ int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||
int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) | |||
{ | |||
jack_log("SetGraphOrderCallback "); | |||
if (IsActive()) { | |||
jack_error("You cannot set callbacks on an active client"); | |||
return -1; | |||
@@ -908,8 +1036,8 @@ int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg | |||
GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); | |||
fSampleRateArg = arg; | |||
fSampleRate = callback; | |||
// Now invoke it | |||
if (callback) | |||
// Now invoke it | |||
if (callback) | |||
callback(GetEngineControl()->fSampleRate, arg); | |||
return 0; | |||
} | |||
@@ -1011,6 +1139,19 @@ int JackClient::SetSessionCallback(JackSessionCallback callback, void *arg) | |||
} | |||
} | |||
int JackClient::SetLatencyCallback(JackLatencyCallback callback, void *arg) | |||
{ | |||
if (IsActive()) { | |||
jack_error("You cannot set callbacks on an active client"); | |||
return -1; | |||
} else { | |||
// fCallback[kLatencyCallback] must always be 'true' | |||
fLatencyArg = arg; | |||
fLatency = callback; | |||
return 0; | |||
} | |||
} | |||
//------------------ | |||
// Internal clients | |||
//------------------ | |||
@@ -1072,65 +1213,64 @@ void JackClient::InternalClientUnload(int ref, jack_status_t* status) | |||
// Session API | |||
//------------------ | |||
jack_session_command_t *JackClient::SessionNotify( const char* target, jack_session_event_type_t type, const char* path ) | |||
jack_session_command_t* JackClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path) | |||
{ | |||
jack_session_command_t *res; | |||
fChannel->SessionNotify( GetClientControl()->fRefNum, target, type, path, &res ); | |||
jack_session_command_t* res; | |||
fChannel->SessionNotify(GetClientControl()->fRefNum, target, type, path, &res); | |||
return res; | |||
} | |||
int JackClient::SessionReply( jack_session_event_t *ev ) | |||
int JackClient::SessionReply(jack_session_event_t* ev) | |||
{ | |||
if (ev->command_line) { | |||
strncpy( GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand) ); | |||
strncpy(GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand)); | |||
} else { | |||
GetClientControl()->fSessionCommand[0] = '\0'; | |||
} | |||
GetClientControl()->fSessionFlags = ev->flags; | |||
jack_log( "JackClient::SessionReply... we are here" ); | |||
jack_log("JackClient::SessionReply... we are here"); | |||
if (fChannel->IsChannelThread()) { | |||
jack_log( "JackClient::SessionReply... in callback reply" ); | |||
jack_log( "JackClient::SessionReply... in callback reply"); | |||
fImmediateSessionReply = true; | |||
return 0; | |||
} | |||
jack_log( "JackClient::SessionReply... out of cb" ); | |||
jack_log("JackClient::SessionReply... out of cb"); | |||
int res; | |||
fChannel->SessionReply( GetClientControl()->fRefNum, &res); | |||
return res; | |||
int result = -1; | |||
fChannel->SessionReply(GetClientControl()->fRefNum, &result); | |||
return result; | |||
} | |||
char* JackClient::GetUUIDForClientName(const char* client_name) | |||
{ | |||
char uuid_res[JACK_UUID_SIZE]; | |||
int result = -1; | |||
fChannel->GetUUIDForClientName( GetClientControl()->fRefNum, client_name, uuid_res, &result); | |||
if (result) | |||
return NULL; | |||
return strdup(uuid_res); | |||
fChannel->GetUUIDForClientName(GetClientControl()->fRefNum, client_name, uuid_res, &result); | |||
return (result) ? NULL : strdup(uuid_res); | |||
} | |||
char* JackClient::GetClientNameForUUID(const char* uuid) | |||
char* JackClient::GetClientNameByUUID(const char* uuid) | |||
{ | |||
char name_res[JACK_CLIENT_NAME_SIZE + 1]; | |||
int result = -1; | |||
fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result); | |||
return (result) ? NULL : strdup(name_res); | |||
} | |||
if (result) | |||
return NULL; | |||
return strdup(name_res); | |||
int JackClient::ReserveClientName(const char* client_name, const char* uuid) | |||
{ | |||
int result = -1; | |||
fChannel->ReserveClientName( GetClientControl()->fRefNum, client_name, uuid, &result); | |||
return result; | |||
} | |||
int JackClient::ReserveClientName(const char *name, const char* uuid) | |||
int JackClient::ClientHasSessionCallback(const char* client_name) | |||
{ | |||
int result = -1; | |||
fChannel->ReserveClientName( GetClientControl()->fRefNum, name, uuid, &result); | |||
fChannel->ClientHasSessionCallback(client_name, &result); | |||
return result; | |||
} | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackSynchro.h" | |||
#include "JackPlatformPlug.h" | |||
#include "JackChannel.h" | |||
#include "types.h" | |||
#include "session.h" | |||
#include "varargs.h" | |||
#include <list> | |||
@@ -68,6 +67,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
JackSyncCallback fSync; | |||
JackThreadCallback fThreadFun; | |||
JackSessionCallback fSession; | |||
JackLatencyCallback fLatency; | |||
void* fProcessArg; | |||
void* fGraphOrderArg; | |||
@@ -86,6 +86,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
void* fSyncArg; | |||
void* fThreadFunArg; | |||
void* fSessionArg; | |||
void* fLatencyArg; | |||
char fServerName[64]; | |||
JackThread fThread; /*! Thread to execute the Process function */ | |||
@@ -94,14 +95,14 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
std::list<jack_port_id_t> fPortList; | |||
bool fImmediateSessionReply; | |||
int StartThread(); | |||
void SetupDriverSync(bool freewheel); | |||
bool IsActive(); | |||
void CallSyncCallback(); | |||
void CallTimebaseCallback(); | |||
virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value); | |||
inline void DummyCycle(); | |||
@@ -116,7 +117,10 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
inline void CallSyncCallbackAux(); | |||
inline void CallTimebaseCallbackAux(); | |||
inline int ActivateAux(); | |||
inline void InitAux(); | |||
int HandleLatencyCallback(int status); | |||
public: | |||
JackClient(); | |||
@@ -138,8 +142,9 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
// Context | |||
virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
virtual int SetFreeWheel(int onoff); | |||
virtual int ComputeTotalLatencies(); | |||
virtual void ShutDown(); | |||
virtual pthread_t GetThreadID(); | |||
virtual jack_native_thread_t GetThreadID(); | |||
// Port management | |||
virtual int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); | |||
@@ -179,6 +184,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
virtual int SetPortConnectCallback(JackPortConnectCallback callback, void *arg); | |||
virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg); | |||
virtual int SetSessionCallback(JackSessionCallback callback, void *arg); | |||
virtual int SetLatencyCallback(JackLatencyCallback callback, void *arg); | |||
// Internal clients | |||
virtual char* GetInternalClientName(int ref); | |||
@@ -186,16 +192,18 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
virtual int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va); | |||
virtual void InternalClientUnload(int ref, jack_status_t* status); | |||
// RT Thread | |||
jack_nframes_t CycleWait(); | |||
void CycleSignal(int status); | |||
int SetProcessThread(JackThreadCallback fun, void *arg); | |||
// Session api | |||
virtual jack_session_command_t *SessionNotify(const char *target, jack_session_event_type_t type, const char *path); | |||
virtual int SessionReply(jack_session_event_t *ev); | |||
char* GetUUIDForClientName(const char* client_name); | |||
char* GetClientNameForUUID(const char* uuid); | |||
int ReserveClientName(const char *name, const char* uuid); | |||
// Session API | |||
virtual jack_session_command_t* SessionNotify(const char* target, jack_session_event_type_t type, const char* path); | |||
virtual int SessionReply(jack_session_event_t* ev); | |||
char* GetUUIDForClientName(const char* client_name); | |||
char* GetClientNameByUUID(const char* uuid); | |||
int ReserveClientName(const char* client_name, const char* uuid); | |||
int ClientHasSessionCallback(const char* client_name); | |||
// JackRunnableInterface interface | |||
bool Init(); | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -25,8 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackPort.h" | |||
#include "JackSynchro.h" | |||
#include "JackNotification.h" | |||
#include "jack/session.h" | |||
#include "session.h" | |||
namespace Jack | |||
{ | |||
@@ -74,6 +73,7 @@ struct JackClientControl : public JackShmMemAble | |||
fCallback[kAddClient] = true; | |||
fCallback[kRemoveClient] = true; | |||
fCallback[kActivateClient] = true; | |||
fCallback[kLatencyCallback] = true; | |||
// So that driver synchro are correctly setup in "flush" or "normal" mode | |||
fCallback[kStartFreewheelCallback] = true; | |||
fCallback[kStopFreewheelCallback] = true; | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackEngineControl.h" | |||
#include "JackGlobals.h" | |||
#include "JackError.h" | |||
#include <set> | |||
#include <iostream> | |||
#include <assert.h> | |||
@@ -246,7 +247,7 @@ int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro | |||
int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) | |||
{ | |||
jack_time_t current_date = GetMicroSeconds(); | |||
const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum); | |||
const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum); | |||
int res = 0; | |||
// Update state and timestamp of current client | |||
@@ -256,7 +257,7 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
// Signal connected clients or drivers | |||
if (outputRef[i] > 0) { | |||
if (output_ref[i] > 0) { | |||
// Update state and timestamp of destination clients | |||
timing[i].fStatus = Triggered; | |||
@@ -272,6 +273,44 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* | |||
return res; | |||
} | |||
static bool HasNoConnection(jack_int_t* table) | |||
{ | |||
for (int ref = 0; ref < CLIENT_NUM; ref++) { | |||
if (table[ref] > 0) return false; | |||
} | |||
return true; | |||
} | |||
// Using http://en.wikipedia.org/wiki/Topological_sorting | |||
void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted) | |||
{ | |||
JackFixedMatrix<CLIENT_NUM> tmp; | |||
std::set<jack_int_t> level; | |||
fConnectionRef.Copy(tmp); | |||
// Inputs of the graph | |||
level.insert(AUDIO_DRIVER_REFNUM); | |||
level.insert(FREEWHEEL_DRIVER_REFNUM); | |||
while (level.size() > 0) { | |||
jack_int_t refnum = *level.begin(); | |||
sorted.push_back(refnum); | |||
level.erase(level.begin()); | |||
const jack_int_t* output_ref1 = tmp.GetItems(refnum); | |||
for (int dst = 0; dst < CLIENT_NUM; dst++) { | |||
if (output_ref1[dst] > 0) { | |||
tmp.ClearItem(refnum, dst); | |||
jack_int_t output_ref2[CLIENT_NUM]; | |||
tmp.GetOutputTable1(dst, output_ref2); | |||
if (HasNoConnection(output_ref2)) | |||
level.insert(dst); | |||
} | |||
} | |||
} | |||
} | |||
/*! | |||
\brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated. | |||
*/ | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackActivationCount.h" | |||
#include "JackError.h" | |||
#include "JackCompilerDeps.h" | |||
#include <vector> | |||
#include <assert.h> | |||
namespace Jack | |||
@@ -151,7 +151,7 @@ class JackFixedArray1 : public JackFixedArray<SIZE> | |||
return true; | |||
} | |||
} | |||
} POST_PACKED_STRUCTURE; | |||
/*! | |||
@@ -200,6 +200,11 @@ class JackFixedMatrix | |||
return fTable[index1][index2]; | |||
} | |||
void ClearItem(jack_int_t index1, jack_int_t index2) | |||
{ | |||
fTable[index1][index2] = 0; | |||
} | |||
/*! | |||
\brief Get the output indexes of a given index. | |||
*/ | |||
@@ -218,6 +223,13 @@ class JackFixedMatrix | |||
} | |||
} | |||
void GetOutputTable1(jack_int_t index, jack_int_t* output) const | |||
{ | |||
for (int i = 0; i < SIZE; i++) { | |||
output[i] = fTable[i][index]; | |||
} | |||
} | |||
bool IsInsideTable(jack_int_t index, jack_int_t* output) const | |||
{ | |||
for (int i = 0; i < SIZE && output[i] != EMPTY; i++) { | |||
@@ -227,6 +239,14 @@ class JackFixedMatrix | |||
return false; | |||
} | |||
void Copy(JackFixedMatrix& copy) | |||
{ | |||
for (int i = 0; i < SIZE; i++) { | |||
memcpy(copy.fTable[i], fTable[i], sizeof(jack_int_t) * SIZE); | |||
} | |||
} | |||
} POST_PACKED_STRUCTURE; | |||
/*! | |||
@@ -359,7 +379,7 @@ struct JackClientTiming | |||
} | |||
~JackClientTiming() | |||
{} | |||
void Init() | |||
{ | |||
fSignaledAt = 0; | |||
@@ -367,7 +387,7 @@ struct JackClientTiming | |||
fFinishedAt = 0; | |||
fStatus = NotTriggered; | |||
} | |||
} POST_PACKED_STRUCTURE; | |||
/*! | |||
@@ -375,11 +395,9 @@ struct JackClientTiming | |||
<UL> | |||
<LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port. | |||
<LI>The <B>fConnectionCount</B> array contains the number of connected ports to a given port. | |||
<LI>The <B>fInputPort</B> array contains the list (array line) of input connected ports for a given client. | |||
<LI>The <B>fOutputPort</B> array contains the list (array line) of ouput connected ports for a given client. | |||
<LI>The <B>fConnectionRef</B> array contains the number of ports connected between two clients. | |||
<LI>The <B>fInputRef</B> array contains the number of input clients connected to a given client. | |||
<LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose. | |||
</UL> | |||
*/ | |||
@@ -461,7 +479,8 @@ class SERVER_EXPORT JackConnectionManager | |||
void ResetGraph(JackClientTiming* timing); | |||
int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing); | |||
int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec); | |||
void TopologicalSort(std::vector<jack_int_t>& sorted); | |||
} POST_PACKED_STRUCTURE; | |||
} // end of namespace | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -116,17 +116,17 @@ int JackDebugClient::Close() | |||
void JackDebugClient::CheckClient(const char* function_name) const | |||
{ | |||
*fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl; | |||
if (fIsClosed > 0) { | |||
*fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl; | |||
*fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl; | |||
*fStream << "This is likely to cause crash !'" << endl; | |||
#ifdef __APPLE__ | |||
// Debugger(); | |||
#endif | |||
#endif | |||
} | |||
} | |||
pthread_t JackDebugClient::GetThreadID() | |||
jack_native_thread_t JackDebugClient::GetThreadID() | |||
{ | |||
CheckClient("GetThreadID"); | |||
return fClient->GetThreadID(); | |||
@@ -428,7 +428,7 @@ void JackDebugClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *ar | |||
CheckClient("OnInfoShutdown"); | |||
fClient->OnInfoShutdown(callback, arg); | |||
} | |||
int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) | |||
{ | |||
JackDebugClient* client = (JackDebugClient*)arg; | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -84,7 +84,7 @@ class JackDebugClient : public JackClient | |||
int SetBufferSize(jack_nframes_t buffer_size); | |||
int SetFreeWheel(int onoff); | |||
void ShutDown(); | |||
pthread_t GetThreadID(); | |||
jack_native_thread_t GetThreadID(); | |||
// Port management | |||
int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); | |||
@@ -167,7 +167,7 @@ int JackDriver::Open(jack_nframes_t buffer_size, | |||
int JackDriver::Close() | |||
{ | |||
if (fClientControl.fRefNum >= 0) { | |||
if (fClientControl.fRefNum >= 0) { | |||
jack_log("JackDriver::Close"); | |||
fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync | |||
fClientControl.fActive = false; | |||
@@ -207,7 +207,7 @@ int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync, | |||
jack_log("JackDriver::kStopFreewheel"); | |||
SetupDriverSync(fClientControl.fRefNum, false); | |||
break; | |||
} | |||
} | |||
return 0; | |||
} | |||
@@ -223,13 +223,13 @@ void JackDriver::CycleIncTime() | |||
} | |||
void JackDriver::CycleTakeBeginTime() | |||
{ | |||
{ | |||
fBeginDateUst = GetMicroSeconds(); // Take callback date here | |||
fEngineControl->CycleIncTime(fBeginDateUst); | |||
} | |||
void JackDriver::CycleTakeEndTime() | |||
{ | |||
{ | |||
fEndDateUst = GetMicroSeconds(); // Take end date here | |||
} | |||
@@ -254,7 +254,7 @@ void JackDriver::NotifySampleRate(jack_nframes_t sample_rate) | |||
fEngine->NotifySampleRate(sample_rate); | |||
fEngineControl->InitFrameTime(); | |||
} | |||
void JackDriver::NotifyFailure(int code, const char* reason) | |||
{ | |||
fEngine->NotifyFailure(code, reason); | |||
@@ -1,21 +1,21 @@ | |||
/* | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2004-2008 Grame | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#ifndef __JackDriver__ | |||
@@ -30,27 +30,27 @@ | |||
namespace Jack | |||
{ | |||
class JackLockedEngine; | |||
class JackGraphManager; | |||
struct JackEngineControl; | |||
/*! | |||
\brief The base interface for drivers. | |||
*/ | |||
class SERVER_EXPORT JackDriverInterface | |||
{ | |||
public: | |||
JackDriverInterface() | |||
{} | |||
virtual ~JackDriverInterface() | |||
{} | |||
virtual int Open() = 0; | |||
virtual int Open (bool capturing, | |||
bool playing, | |||
int inchannels, | |||
@@ -60,7 +60,7 @@ class SERVER_EXPORT JackDriverInterface | |||
const char* playback_driver_name, | |||
jack_nframes_t capture_latency, | |||
jack_nframes_t playback_latency) = 0; | |||
virtual int Open(jack_nframes_t buffer_size, | |||
jack_nframes_t samplerate, | |||
bool capturing, | |||
@@ -72,30 +72,30 @@ class SERVER_EXPORT JackDriverInterface | |||
const char* playback_driver_name, | |||
jack_nframes_t capture_latency, | |||
jack_nframes_t playback_latency) = 0; | |||
virtual int Attach() = 0; | |||
virtual int Detach() = 0; | |||
virtual int Read() = 0; | |||
virtual int Write() = 0; | |||
virtual int Start() = 0; | |||
virtual int Stop() = 0; | |||
virtual bool IsFixedBufferSize() = 0; | |||
virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; | |||
virtual int SetSampleRate(jack_nframes_t sample_rate) = 0; | |||
virtual int Process() = 0; | |||
virtual int ProcessNull() = 0; | |||
virtual void SetMaster(bool onoff) = 0; | |||
virtual bool GetMaster() = 0; | |||
virtual void AddSlave(JackDriverInterface* slave) = 0; | |||
virtual void RemoveSlave(JackDriverInterface* slave) = 0; | |||
virtual std::list<JackDriverInterface*> GetSlaves() = 0; | |||
virtual int ProcessSlaves() = 0; | |||
virtual bool IsRealTime() const = 0; | |||
}; | |||
@@ -109,16 +109,16 @@ class SERVER_EXPORT JackDriverClientInterface : public JackDriverInterface, publ | |||
/*! | |||
\brief The base class for drivers. | |||
*/ | |||
#define CaptureDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive) | |||
#define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive) | |||
#define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsActive) | |||
#define CaptureDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal) | |||
#define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal) | |||
#define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput) | |||
class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
{ | |||
protected: | |||
char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1]; | |||
char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1]; | |||
char fAliasName[JACK_CLIENT_NAME_SIZE + 1]; | |||
@@ -134,27 +134,27 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
JackClientControl fClientControl; | |||
std::list<JackDriverInterface*> fSlaveList; | |||
bool fIsMaster; | |||
void CycleIncTime(); | |||
void CycleTakeBeginTime(); | |||
void CycleTakeEndTime(); | |||
void SetupDriverSync(int ref, bool freewheel); | |||
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver | |||
void NotifyBufferSize(jack_nframes_t buffer_size); // BufferSize notification sent by the driver | |||
void NotifySampleRate(jack_nframes_t sample_rate); // SampleRate notification sent by the driver | |||
void NotifyFailure(int code, const char* reason); // Failure notification sent by the driver | |||
public: | |||
JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | |||
JackDriver(); | |||
virtual ~JackDriver(); | |||
void SetMaster(bool onoff); | |||
bool GetMaster(); | |||
void AddSlave(JackDriverInterface* slave); | |||
void RemoveSlave(JackDriverInterface* slave); | |||
std::list<JackDriverInterface*> GetSlaves() | |||
@@ -162,9 +162,9 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
return fSlaveList; | |||
} | |||
int ProcessSlaves(); | |||
virtual int Open(); | |||
virtual int Open (bool capturing, | |||
bool playing, | |||
int inchannels, | |||
@@ -174,7 +174,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
const char* playback_driver_name, | |||
jack_nframes_t capture_latency, | |||
jack_nframes_t playback_latency); | |||
virtual int Open(jack_nframes_t buffer_size, | |||
jack_nframes_t samplerate, | |||
bool capturing, | |||
@@ -187,31 +187,31 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
jack_nframes_t capture_latency, | |||
jack_nframes_t playback_latency); | |||
virtual int Close(); | |||
virtual int Process(); | |||
virtual int ProcessNull(); | |||
virtual int Attach(); | |||
virtual int Detach(); | |||
virtual int Read(); | |||
virtual int Write(); | |||
virtual int Start(); | |||
virtual int Stop(); | |||
virtual bool IsFixedBufferSize(); | |||
virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | |||
virtual JackClientControl* GetClientControl() const; | |||
virtual bool IsRealTime() const; | |||
virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one | |||
virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one | |||
}; | |||
} // end of namespace | |||
#endif |
@@ -56,6 +56,12 @@ int JackDummyDriver::Open(jack_nframes_t buffer_size, | |||
fEngineControl->fPeriod = 0; | |||
fEngineControl->fComputation = 500 * 1000; | |||
fEngineControl->fConstraint = 500 * 1000; | |||
int buffer_size = int((fWaitTime * fEngineControl->fSampleRate) / 1000000.0f); | |||
if (buffer_size > BUFFER_SIZE_MAX) { | |||
buffer_size = BUFFER_SIZE_MAX; | |||
jack_error("Buffer size set to %d ", BUFFER_SIZE_MAX); | |||
} | |||
SetBufferSize(buffer_size); | |||
return 0; | |||
} else { | |||
return -1; | |||
@@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include <iostream> | |||
#include <fstream> | |||
#include <set> | |||
#include <assert.h> | |||
#include "JackSystemDeps.h" | |||
@@ -90,7 +91,7 @@ int JackEngine::Close() | |||
return 0; | |||
} | |||
void JackEngine::NotifyQuit() | |||
{ | |||
fChannel.NotifyQuit(); | |||
@@ -137,8 +138,10 @@ void JackEngine::ReleaseRefnum(int ref) | |||
void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) | |||
{ | |||
fLastSwitchUsecs = cur_cycle_begin; | |||
if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state | |||
if (fGraphManager->RunNextGraph()) { // True if the graph actually switched to a new state | |||
fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0); | |||
//NotifyGraphReorder(); | |||
} | |||
fSignal.Signal(); // Signal for threads waiting for next cycle | |||
} | |||
@@ -195,16 +198,44 @@ void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions | |||
if (status != NotTriggered && status != Finished) { | |||
jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status); | |||
fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | |||
//NotifyXRun(ALL_CLIENTS); | |||
} | |||
if (status == Finished && (long)(finished_date - callback_usecs) > 0) { | |||
jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName); | |||
fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients | |||
//NotifyXRun(ALL_CLIENTS); | |||
} | |||
} | |||
} | |||
} | |||
int JackEngine::ComputeTotalLatencies() | |||
{ | |||
std::vector<jack_int_t> sorted; | |||
std::vector<jack_int_t>::iterator it; | |||
std::vector<jack_int_t>::reverse_iterator rit; | |||
fGraphManager->TopologicalSort(sorted); | |||
/* iterate over all clients in graph order, and emit | |||
* capture latency callback. | |||
*/ | |||
for (it = sorted.begin(); it != sorted.end(); it++) { | |||
jack_log("Sorted %d", *it); | |||
NotifyClient(*it, kLatencyCallback, true, "", 0, 0); | |||
} | |||
/* now issue playback latency callbacks in reverse graph order. | |||
*/ | |||
for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) { | |||
NotifyClient(*rit, kLatencyCallback, true, "", 1, 0); | |||
} | |||
return 0; | |||
} | |||
//--------------- | |||
// Notifications | |||
//--------------- | |||
@@ -215,8 +246,8 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, const char* messa | |||
// The client may be notified by the RT thread while closing | |||
if (client) { | |||
if (client && client->GetClientControl()->fCallback[event]) { | |||
if (client->GetClientControl()->fCallback[event]) { | |||
/* | |||
Important for internal clients : unlock before calling the notification callbacks. | |||
*/ | |||
@@ -225,7 +256,7 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, const char* messa | |||
jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2); | |||
if (res) | |||
fMutex.Lock(); | |||
} else { | |||
jack_log("JackEngine::NotifyClient: no callback for event = %ld", event); | |||
} | |||
@@ -277,6 +308,7 @@ void JackEngine::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
// Use the audio thread => request thread communication channel | |||
fEngineControl->NotifyXRun(callback_usecs, delayed_usecs); | |||
fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); | |||
//NotifyXRun(ALL_CLIENTS); | |||
} | |||
void JackEngine::NotifyXRun(int refnum) | |||
@@ -290,6 +322,7 @@ void JackEngine::NotifyXRun(int refnum) | |||
void JackEngine::NotifyGraphReorder() | |||
{ | |||
ComputeTotalLatencies(); | |||
NotifyClients(kGraphOrderCallback, false, "", 0, 0); | |||
} | |||
@@ -307,7 +340,7 @@ void JackEngine::NotifyFailure(int code, const char* reason) | |||
{ | |||
NotifyClients(kShutDownCallback, false, reason, code, 0); | |||
} | |||
void JackEngine::NotifyFreewheel(bool onoff) | |||
{ | |||
if (onoff) { | |||
@@ -406,7 +439,7 @@ int JackEngine::ClientCheck(const char* name, int uuid, char* name_res, int prot | |||
std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | |||
if (res != fReservationMap.end()) { | |||
strncpy( name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE ); | |||
strncpy(name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE); | |||
} else if (ClientCheckName(name)) { | |||
*status |= JackNameNotUnique; | |||
@@ -467,7 +500,7 @@ bool JackEngine::ClientCheckName(const char* name) | |||
return true; | |||
} | |||
for (std::map<int,std::string>::iterator i=fReservationMap.begin(); i!=fReservationMap.end(); i++) { | |||
for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) { | |||
if (i->second == name) | |||
return true; | |||
} | |||
@@ -522,14 +555,14 @@ int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref | |||
if (uuid < 0) { | |||
uuid = GetNewUUID(); | |||
strncpy( real_name, name, JACK_CLIENT_NAME_SIZE ); | |||
strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); | |||
} else { | |||
std::map<int,std::string>::iterator res = fReservationMap.find(uuid); | |||
if (res != fReservationMap.end()) { | |||
strncpy( real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE ); | |||
strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE); | |||
fReservationMap.erase(uuid); | |||
} else { | |||
strncpy( real_name, name, JACK_CLIENT_NAME_SIZE ); | |||
strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); | |||
} | |||
EnsureUUID(uuid); | |||
@@ -689,7 +722,7 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time) | |||
{ | |||
JackClientInterface* client = fClientTable[refnum]; | |||
jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); | |||
if (is_real_time) | |||
fGraphManager->Activate(refnum); | |||
@@ -702,18 +735,10 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time) | |||
jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; | |||
fGraphManager->GetInputPorts(refnum, input_ports); | |||
fGraphManager->GetOutputPorts(refnum, output_ports); | |||
// First add port state to JackPortIsActive | |||
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
fGraphManager->ActivatePort(input_ports[i]); | |||
} | |||
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { | |||
fGraphManager->ActivatePort(output_ports[i]); | |||
} | |||
// Notify client | |||
NotifyActivate(refnum); | |||
// Then issue port registration notification | |||
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
NotifyPortRegistation(input_ports[i], true); | |||
@@ -740,13 +765,11 @@ int JackEngine::ClientDeactivate(int refnum) | |||
// First disconnect all ports and remove their JackPortIsActive state | |||
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
PortDisconnect(refnum, input_ports[i], ALL_PORTS); | |||
fGraphManager->DeactivatePort(input_ports[i]); | |||
} | |||
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { | |||
PortDisconnect(refnum, output_ports[i], ALL_PORTS); | |||
fGraphManager->DeactivatePort(output_ports[i]); | |||
} | |||
// Then issue port registration notification | |||
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { | |||
NotifyPortRegistation(input_ports[i], false); | |||
@@ -867,7 +890,7 @@ int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst) | |||
int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst) | |||
{ | |||
jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst); | |||
if (dst == ALL_PORTS) { | |||
jack_int_t connections[CONNECTION_NUM_FOR_PORT]; | |||
@@ -910,6 +933,10 @@ int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name) | |||
return 0; | |||
} | |||
//-------------------- | |||
// Session management | |||
//-------------------- | |||
void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket) | |||
{ | |||
if (fSessionPendingReplies != 0) { | |||
@@ -940,11 +967,11 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||
char path_buf[JACK_PORT_NAME_SIZE]; | |||
snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR ); | |||
int res = JackTools::MkDir(path_buf); | |||
if (res) | |||
if (res) | |||
jack_error( "JackEngine::SessionNotify: can not create session directory '%s'", path_buf ); | |||
int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int) type, 0); | |||
if (result == 2) { | |||
@@ -952,9 +979,9 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||
} else if (result == 1) { | |||
char uuid_buf[JACK_UUID_SIZE]; | |||
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID ); | |||
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf, | |||
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf, | |||
client->GetClientControl()->fName, | |||
client->GetClientControl()->fSessionCommand, | |||
client->GetClientControl()->fSessionCommand, | |||
client->GetClientControl()->fSessionFlags )); | |||
} | |||
} | |||
@@ -973,11 +1000,11 @@ void JackEngine::SessionReply(int refnum) | |||
{ | |||
JackClientInterface* client = fClientTable[refnum]; | |||
char uuid_buf[JACK_UUID_SIZE]; | |||
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID ); | |||
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf, | |||
client->GetClientControl()->fName, | |||
client->GetClientControl()->fSessionCommand, | |||
client->GetClientControl()->fSessionFlags )); | |||
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID); | |||
fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf, | |||
client->GetClientControl()->fName, | |||
client->GetClientControl()->fSessionCommand, | |||
client->GetClientControl()->fSessionFlags)); | |||
fSessionPendingReplies -= 1; | |||
if (fSessionPendingReplies == 0) { | |||
@@ -998,9 +1025,8 @@ void JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res, i | |||
return; | |||
} | |||
} | |||
// did not find name. | |||
// Did not find name. | |||
*result = -1; | |||
return; | |||
} | |||
void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *result) | |||
@@ -1020,18 +1046,17 @@ void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *res | |||
return; | |||
} | |||
} | |||
// did not find uuid. | |||
// Did not find uuid. | |||
*result = -1; | |||
return; | |||
} | |||
void JackEngine::ReserveClientName(const char *name, const char *uuid, int *result) | |||
{ | |||
jack_log( "JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid ); | |||
jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid); | |||
if (ClientCheckName(name)) { | |||
*result = -1; | |||
jack_log( "name already taken" ); | |||
jack_log("name already taken"); | |||
return; | |||
} | |||
@@ -1040,5 +1065,21 @@ void JackEngine::ReserveClientName(const char *name, const char *uuid, int *resu | |||
*result = 0; | |||
} | |||
void JackEngine::ClientHasSessionCallbackRequest(const char *name, int *result) | |||
{ | |||
JackClientInterface* client = NULL; | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) | |||
break; | |||
} | |||
if (client) { | |||
*result = client->GetClientControl()->fCallback[kSessionCallback]; | |||
} else { | |||
*result = -1; | |||
} | |||
} | |||
} // end of namespace | |||
@@ -129,6 +129,8 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
int PortRename(int refnum, jack_port_id_t port, const char* name); | |||
int ComputeTotalLatencies(); | |||
// Graph | |||
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | |||
@@ -142,12 +144,14 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
void NotifyFreewheel(bool onoff); | |||
void NotifyQuit(); | |||
void SessionNotify( int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket ); | |||
void SessionReply( int refnum ); | |||
// Session management | |||
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket); | |||
void SessionReply(int refnum); | |||
void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result); | |||
void GetClientNameForUUID(const char *uuid, char *name_res, int *result); | |||
void ReserveClientName(const char *name, const char *uuid, int *result); | |||
void ClientHasSessionCallbackRequest(const char *name, int *result); | |||
}; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -33,39 +33,39 @@ static inline jack_time_t JACK_MAX(jack_time_t a, jack_time_t b) | |||
return (a < b) ? b : a; | |||
} | |||
void JackEngineControl::CalcCPULoad(JackClientInterface** table, | |||
JackGraphManager* manager, | |||
jack_time_t cur_cycle_begin, | |||
void JackEngineControl::CalcCPULoad(JackClientInterface** table, | |||
JackGraphManager* manager, | |||
jack_time_t cur_cycle_begin, | |||
jack_time_t prev_cycle_end) | |||
{ | |||
fPrevCycleTime = fCurCycleTime; | |||
fCurCycleTime = cur_cycle_begin; | |||
jack_time_t last_cycle_end = prev_cycle_end; | |||
// In Asynchronous mode, last cycle end is the max of client end dates | |||
if (!fSyncMode) { | |||
for (int i = fDriverNum; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = table[i]; | |||
JackClientTiming* timing = manager->GetClientTiming(i); | |||
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | |||
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | |||
last_cycle_end = JACK_MAX(last_cycle_end, timing->fFinishedAt); | |||
} | |||
} | |||
// Store the execution time for later averaging | |||
// Store the execution time for later averaging | |||
fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime; | |||
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||
fRollingClientUsecsIndex = 0; | |||
// Every so often, recompute the current maximum use over the | |||
// last JACK_ENGINE_ROLLING_COUNT client iterations. | |||
if (++fRollingClientUsecsCnt % fRollingInterval == 0) { | |||
jack_time_t max_usecs = 0; | |||
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) | |||
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) | |||
max_usecs = JACK_MAX(fRollingClientUsecs[i], max_usecs); | |||
fMaxUsecs = JACK_MAX(fMaxUsecs, max_usecs); | |||
fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0); | |||
fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f)); | |||
@@ -80,7 +80,7 @@ void JackEngineControl::ResetRollingUsecs() | |||
fSpareUsecs = 0; | |||
fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs)); | |||
} | |||
void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
{ | |||
ResetFrameTime(callback_usecs); | |||
@@ -88,5 +88,5 @@ void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_use | |||
if (delayed_usecs > fMaxDelayedUsecs) | |||
fMaxDelayedUsecs = delayed_usecs; | |||
} | |||
} // end of namespace |
@@ -7,12 +7,12 @@ | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
@@ -25,7 +25,6 @@ | |||
#include <string.h> | |||
#include <errno.h> | |||
#include "JackCompilerDeps.h" | |||
#include "types.h" | |||
#ifdef __cplusplus | |||
extern "C" | |||
@@ -44,17 +43,17 @@ extern "C" | |||
EXPORT extern void (*jack_error_callback)(const char *desc); | |||
EXPORT extern void (*jack_info_callback)(const char *desc); | |||
EXPORT extern void default_jack_error_callback(const char *desc); | |||
EXPORT extern void default_jack_info_callback(const char *desc); | |||
EXPORT extern void silent_jack_error_callback(const char *desc); | |||
EXPORT extern void silent_jack_info_callback(const char *desc); | |||
typedef void (* jack_log_function_t)(int level, const char *message); | |||
void jack_log_function(int level, const char *message); | |||
EXPORT int set_threaded_log_function(); | |||
#ifdef __cplusplus | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -36,9 +36,9 @@ class SERVER_EXPORT JackTimer | |||
{ | |||
friend class JackFrameTimer; | |||
private: | |||
private: | |||
jack_nframes_t fFrames; | |||
jack_time_t fCurrentWakeup; | |||
jack_time_t fCurrentCallback; | |||
@@ -47,21 +47,21 @@ class SERVER_EXPORT JackTimer | |||
float fFilterCoefficient; /* set once, never altered */ | |||
bool fInitialized; | |||
public: | |||
public: | |||
JackTimer(); | |||
~JackTimer() | |||
{} | |||
jack_nframes_t Time2Frames(jack_time_t time, jack_nframes_t buffer_size); | |||
jack_time_t Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size); | |||
jack_nframes_t FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate); | |||
jack_nframes_t CurFrame() | |||
{ | |||
return fFrames; | |||
} | |||
jack_time_t CurTime() | |||
{ | |||
return fCurrentWakeup; | |||
@@ -75,7 +75,7 @@ class SERVER_EXPORT JackTimer | |||
class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | |||
{ | |||
private: | |||
bool fFirstWakeUp; | |||
@@ -93,7 +93,7 @@ class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | |||
void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs); | |||
void IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs); | |||
void ReadFrameTime(JackTimer* timer); | |||
} POST_PACKED_STRUCTURE; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -37,7 +37,7 @@ static void AssertBufferSize(jack_nframes_t buffer_size) | |||
assert(buffer_size <= BUFFER_SIZE_MAX); | |||
} | |||
} | |||
void JackGraphManager::AssertPort(jack_port_id_t port_index) | |||
{ | |||
if (port_index >= fPortMax) { | |||
@@ -45,7 +45,7 @@ void JackGraphManager::AssertPort(jack_port_id_t port_index) | |||
assert(port_index < fPortMax); | |||
} | |||
} | |||
JackGraphManager* JackGraphManager::Allocate(int port_max) | |||
{ | |||
// Using "Placement" new | |||
@@ -59,18 +59,18 @@ void JackGraphManager::Destroy(JackGraphManager* manager) | |||
manager->~JackGraphManager(); | |||
JackShmMem::operator delete(manager); | |||
} | |||
JackGraphManager::JackGraphManager(int port_max) | |||
JackGraphManager::JackGraphManager(int port_max) | |||
{ | |||
assert(port_max <= PORT_NUM_MAX); | |||
for (int i = 0; i < port_max; i++) { | |||
fPortArray[i].Release(); | |||
} | |||
fPortMax = port_max; | |||
} | |||
JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) | |||
{ | |||
AssertPort(port_index); | |||
@@ -127,6 +127,19 @@ int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* tab | |||
return manager->SuspendRefNum(control, table, fClientTiming, usec); | |||
} | |||
void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& sorted) | |||
{ | |||
UInt16 cur_index; | |||
UInt16 next_index; | |||
do { | |||
cur_index = GetCurrentIndex(); | |||
sorted.clear(); | |||
ReadCurrentState()->TopologicalSort(sorted); | |||
next_index = GetCurrentIndex(); | |||
} while (cur_index != next_index); // Until a coherent state has been read | |||
} | |||
// Server | |||
void JackGraphManager::DirectConnect(int ref1, int ref2) | |||
{ | |||
@@ -176,14 +189,14 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff | |||
jack_int_t len = manager->Connections(port_index); | |||
// No connections : return a zero-filled buffer | |||
if (len == 0) { | |||
if (len == 0) { | |||
port->ClearBuffer(buffer_size); | |||
return port->GetBuffer(); | |||
// One connection | |||
} else if (len == 1) { | |||
} else if (len == 1) { | |||
jack_port_id_t src_index = manager->GetPort(port_index, 0); | |||
// Ports in same client : copy the buffer | |||
if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) { | |||
void* buffers[1]; | |||
@@ -194,10 +207,10 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff | |||
} else { | |||
return GetBuffer(src_index, buffer_size); | |||
} | |||
// Multiple connections : mix all buffers | |||
} else { | |||
} else { | |||
const jack_int_t* connections = manager->GetConnections(port_index); | |||
void* buffers[CONNECTION_NUM_FOR_PORT]; | |||
jack_port_id_t src_index; | |||
@@ -220,10 +233,10 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C | |||
JackPort* port = GetPort(port_index); | |||
/** | |||
jackd.h | |||
jackd.h | |||
* If @ref JackPortCanMonitor is set for this @a port, turn input | |||
* monitoring on or off. Otherwise, do nothing. | |||
if (!(fFlags & JackPortCanMonitor)) | |||
return -1; | |||
*/ | |||
@@ -245,7 +258,7 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C | |||
// Client | |||
jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count) | |||
{ | |||
const jack_int_t* connections = manager->GetConnections(port_index); | |||
const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); | |||
jack_nframes_t max_latency = 0; | |||
jack_port_id_t dst_index; | |||
@@ -296,6 +309,46 @@ int JackGraphManager::ComputeTotalLatencies() | |||
return 0; | |||
} | |||
void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode) | |||
{ | |||
const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); | |||
JackPort* port = GetPort(port_index); | |||
jack_latency_range_t latency = { UINT32_MAX, 0 }; | |||
jack_port_id_t dst_index; | |||
for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) { | |||
AssertPort(dst_index); | |||
JackPort* dst_port = GetPort(dst_index); | |||
jack_latency_range_t other_latency; | |||
dst_port->GetLatencyRange(mode, &other_latency); | |||
if (other_latency.max > latency.max) | |||
latency.max = other_latency.max; | |||
if (other_latency.min < latency.min) | |||
latency.min = other_latency.min; | |||
} | |||
if (latency.min == UINT32_MAX) | |||
latency.min = 0; | |||
port->SetLatencyRange(mode, &latency); | |||
} | |||
void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode) | |||
{ | |||
UInt16 cur_index; | |||
UInt16 next_index; | |||
do { | |||
cur_index = GetCurrentIndex(); | |||
RecalculateLatencyAux(port_index, mode); | |||
next_index = GetCurrentIndex(); | |||
} while (cur_index != next_index); // Until a coherent state has been read | |||
jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index); | |||
} | |||
// Server | |||
void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
@@ -376,18 +429,6 @@ int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index) | |||
return res; | |||
} | |||
void JackGraphManager::ActivatePort(jack_port_id_t port_index) | |||
{ | |||
JackPort* port = GetPort(port_index); | |||
port->fFlags = (JackPortFlags)(port->fFlags | JackPortIsActive); | |||
} | |||
void JackGraphManager::DeactivatePort(jack_port_id_t port_index) | |||
{ | |||
JackPort* port = GetPort(port_index); | |||
port->fFlags = (JackPortFlags)(port->fFlags & ~JackPortIsActive); | |||
} | |||
void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res) | |||
{ | |||
JackConnectionManager* manager = WriteNextStateStart(); | |||
@@ -430,7 +471,7 @@ void JackGraphManager::RemoveAllPorts(int refnum) | |||
jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index); | |||
assert(true); | |||
break; | |||
} | |||
} | |||
} | |||
WriteNextStateStop(); | |||
@@ -717,7 +758,7 @@ void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const c | |||
const jack_int_t* connections = manager->GetConnections(port_index); | |||
jack_int_t index; | |||
int i; | |||
// Cleanup connection array | |||
memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT); | |||
@@ -740,7 +781,7 @@ const char** JackGraphManager::GetConnections(jack_port_id_t port_index) | |||
{ | |||
const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT); | |||
UInt16 cur_index, next_index; | |||
if (!res) | |||
return NULL; | |||
@@ -763,7 +804,7 @@ void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port | |||
{ | |||
int match_cnt = 0; | |||
regex_t port_regex, type_regex; | |||
if (port_name_pattern && port_name_pattern[0]) { | |||
regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB); | |||
} | |||
@@ -823,15 +864,15 @@ const char** JackGraphManager::GetPorts(const char* port_name_pattern, const cha | |||
{ | |||
const char** res = (const char**)malloc(sizeof(char*) * fPortMax); | |||
UInt16 cur_index, next_index; | |||
if (!res) | |||
return NULL; | |||
do { | |||
cur_index = GetCurrentIndex(); | |||
GetPortsAux(res, port_name_pattern, type_name_pattern, flags); | |||
next_index = GetCurrentIndex(); | |||
} while (cur_index != next_index); // Until a coherent state has been read | |||
} while (cur_index != next_index); // Until a coherent state has been read | |||
if (res[0]) { // at least one port | |||
return res; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -29,14 +29,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackPlatformPlug.h" | |||
#include "JackSystemDeps.h" | |||
namespace Jack | |||
{ | |||
/*! | |||
\brief Graph manager: contains the connection manager and the port array. | |||
*/ | |||
class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState<JackConnectionManager> | |||
{ | |||
@@ -53,6 +52,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
float* GetBuffer(jack_port_id_t port_index); | |||
void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames); | |||
jack_nframes_t ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count); | |||
void RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode); | |||
public: | |||
@@ -65,8 +65,6 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
// Ports management | |||
jack_port_id_t AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size); | |||
int ReleasePort(int refnum, jack_port_id_t port_index); | |||
void ActivatePort(jack_port_id_t port_index); | |||
void DeactivatePort(jack_port_id_t port_index); | |||
void GetInputPorts(int refnum, jack_int_t* res); | |||
void GetOutputPorts(int refnum, jack_int_t* res); | |||
void RemoveAllPorts(int refnum); | |||
@@ -74,10 +72,13 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
JackPort* GetPort(jack_port_id_t index); | |||
jack_port_id_t GetPort(const char* name); | |||
int ComputeTotalLatency(jack_port_id_t port_index); | |||
int ComputeTotalLatencies(); | |||
void RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode); | |||
int RequestMonitor(jack_port_id_t port_index, bool onoff); | |||
// Connections management | |||
int Connect(jack_port_id_t src_index, jack_port_id_t dst_index); | |||
int Disconnect(jack_port_id_t src_index, jack_port_id_t dst_index); | |||
@@ -122,6 +123,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
void InitRefNum(int refnum); | |||
int ResumeRefNum(JackClientControl* control, JackSynchro* table); | |||
int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs); | |||
void TopologicalSort(std::vector<jack_int_t>& sorted); | |||
JackClientTiming* GetClientTiming(int refnum) | |||
{ | |||
@@ -130,7 +132,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState | |||
void Save(JackConnectionManager* dst); | |||
void Restore(JackConnectionManager* src); | |||
static JackGraphManager* Allocate(int port_max); | |||
static void Destroy(JackGraphManager* manager); | |||
@@ -80,7 +80,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
{ | |||
*result = fEngine->PortUnRegister(refnum, port_index); | |||
} | |||
void PortConnect(int refnum, const char* src, const char* dst, int* result) | |||
{ | |||
*result = fEngine->PortConnect(refnum, src, dst); | |||
@@ -89,7 +88,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
{ | |||
*result = fEngine->PortDisconnect(refnum, src, dst); | |||
} | |||
void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) | |||
{ | |||
*result = fEngine->PortConnect(refnum, src, dst); | |||
@@ -111,10 +109,9 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
{ | |||
*result = fServer->SetFreewheel(onoff); | |||
} | |||
void SessionNotify( int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t **result ) | |||
void ComputeTotalLatencies(int* result) | |||
{ | |||
*result = NULL; | |||
*result = fEngine->ComputeTotalLatencies(); | |||
} | |||
void ReleaseTimebase(int refnum, int* result) | |||
@@ -126,7 +123,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
{ | |||
*result = fServer->SetTimebaseCallback(refnum, conditional); | |||
} | |||
void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | |||
{ | |||
*result = fEngine->GetInternalClientName(int_ref, name_res); | |||
@@ -139,7 +136,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) | |||
{ | |||
*result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status); | |||
*result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status); | |||
} | |||
void InternalClientUnload(int refnum, int int_ref, int* status, int* result) | |||
@@ -147,6 +144,12 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
*result = fEngine->InternalClientUnload(int_ref, status); | |||
} | |||
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t** result) | |||
{ | |||
*result = NULL; | |||
} | |||
}; | |||
} // end of namespace | |||
@@ -66,7 +66,7 @@ catch (...) { | |||
\brief Locked Engine, access to methods is serialized using a mutex. | |||
*/ | |||
class SERVER_EXPORT JackLockedEngine | |||
class SERVER_EXPORT JackLockedEngine | |||
{ | |||
private: | |||
@@ -94,7 +94,7 @@ class SERVER_EXPORT JackLockedEngine | |||
return fEngine.Close(); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
// Client management | |||
int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status) | |||
{ | |||
@@ -226,6 +226,14 @@ class SERVER_EXPORT JackLockedEngine | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
int ComputeTotalLatencies() | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
return fEngine.ComputeTotalLatencies(); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
// Graph | |||
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) | |||
{ | |||
@@ -245,7 +253,7 @@ class SERVER_EXPORT JackLockedEngine | |||
// RT : no lock | |||
fEngine.NotifyXRun(refnum); | |||
} | |||
void NotifyGraphReorder() | |||
{ | |||
TRY_CALL | |||
@@ -298,7 +306,7 @@ class SERVER_EXPORT JackLockedEngine | |||
return fEngine.GetClientRefNum(name); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
void NotifyQuit() | |||
{ | |||
TRY_CALL | |||
@@ -314,7 +322,7 @@ class SERVER_EXPORT JackLockedEngine | |||
fEngine.SessionNotify(refnum, target, type, path, socket); | |||
CATCH_EXCEPTION | |||
} | |||
void SessionReply(int refnum) | |||
{ | |||
TRY_CALL | |||
@@ -322,7 +330,7 @@ class SERVER_EXPORT JackLockedEngine | |||
fEngine.SessionReply(refnum); | |||
CATCH_EXCEPTION | |||
} | |||
void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) | |||
{ | |||
TRY_CALL | |||
@@ -344,6 +352,14 @@ class SERVER_EXPORT JackLockedEngine | |||
fEngine.ReserveClientName(name, uuid, result); | |||
CATCH_EXCEPTION | |||
} | |||
void ClientHasSessionCallbackRequest(const char *name, int *result) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
fEngine.ClientHasSessionCallbackRequest(name, result); | |||
CATCH_EXCEPTION | |||
} | |||
}; | |||
} // end of namespace | |||
@@ -2,19 +2,19 @@ | |||
* Copyright (C) 2004 Rui Nuno Capela, Steve Harris | |||
* Copyright (C) 2008 Nedko Arnaudov | |||
* Copyright (C) 2008 Grame | |||
* | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation; either version 2.1 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
* | |||
*/ | |||
@@ -34,7 +34,7 @@ JackMessageBuffer::JackMessageBuffer() | |||
JackMessageBuffer::~JackMessageBuffer() | |||
{} | |||
void JackMessageBuffer::Start() | |||
{ | |||
fRunning = true; | |||
@@ -44,9 +44,9 @@ void JackMessageBuffer::Start() | |||
void JackMessageBuffer::Stop() | |||
{ | |||
if (fOverruns > 0) { | |||
jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||
jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||
} else { | |||
jack_log("no message buffer overruns"); | |||
jack_log("no message buffer overruns"); | |||
} | |||
fGuard.Lock(); | |||
fRunning = false; | |||
@@ -55,7 +55,7 @@ void JackMessageBuffer::Stop() | |||
fThread.Stop(); | |||
Flush(); | |||
} | |||
void JackMessageBuffer::Flush() | |||
{ | |||
while (fOutBuffer != fInBuffer) { | |||
@@ -76,7 +76,7 @@ void JackMessageBuffer::AddMessage(int level, const char *message) | |||
INC_ATOMIC(&fOverruns); | |||
} | |||
} | |||
bool JackMessageBuffer::Execute() | |||
{ | |||
while (fRunning) { | |||
@@ -94,10 +94,10 @@ bool JackMessageBuffer::Execute() | |||
Flush(); | |||
fGuard.Unlock(); | |||
} | |||
return false; | |||
return false; | |||
} | |||
void JackMessageBuffer::Create() | |||
void JackMessageBuffer::Create() | |||
{ | |||
if (fInstance == NULL) { | |||
fInstance = new JackMessageBuffer(); | |||
@@ -105,7 +105,7 @@ void JackMessageBuffer::Create() | |||
} | |||
} | |||
void JackMessageBuffer::Destroy() | |||
void JackMessageBuffer::Destroy() | |||
{ | |||
if (fInstance != NULL) { | |||
fInstance->Stop(); | |||
@@ -114,7 +114,7 @@ void JackMessageBuffer::Destroy() | |||
} | |||
} | |||
void JackMessageBufferAdd(int level, const char *message) | |||
void JackMessageBufferAdd(int level, const char *message) | |||
{ | |||
if (Jack::JackMessageBuffer::fInstance == NULL) { | |||
/* Unable to print message with realtime safety. Complain and print it anyway. */ | |||
@@ -137,7 +137,6 @@ void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *a | |||
/* and we're done */ | |||
fGuard.Unlock(); | |||
} | |||
}; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -133,11 +133,17 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count | |||
mix->lost_events += event_count - events_done; | |||
} | |||
static size_t MidiBufferSize() | |||
{ | |||
return BUFFER_SIZE_MAX * sizeof(float); | |||
} | |||
const JackPortType gMidiPortType = | |||
{ | |||
JACK_DEFAULT_MIDI_TYPE, | |||
MidiBufferInit, | |||
MidiBufferMixdown | |||
}; | |||
{ | |||
JACK_DEFAULT_MIDI_TYPE, | |||
MidiBufferSize, | |||
MidiBufferInit, | |||
MidiBufferMixdown | |||
}; | |||
} // namespace Jack |
@@ -118,10 +118,10 @@ namespace Jack | |||
//init and restart-------------------------------------------------------------------- | |||
/* | |||
JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves | |||
JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves | |||
as a "dummy driver, until Init method returns. | |||
*/ | |||
bool JackNetDriver::Initialize() | |||
{ | |||
jack_log("JackNetDriver::Initialize()"); | |||
@@ -221,7 +221,7 @@ namespace Jack | |||
void JackNetDriver::FreeAll() | |||
{ | |||
FreePorts(); | |||
delete[] fTxBuffer; | |||
delete[] fRxBuffer; | |||
delete fNetAudioCaptureBuffer; | |||
@@ -230,7 +230,7 @@ namespace Jack | |||
delete fNetMidiPlaybackBuffer; | |||
delete[] fMidiCapturePortList; | |||
delete[] fMidiPlaybackPortList; | |||
fTxBuffer = NULL; | |||
fRxBuffer = NULL; | |||
fNetAudioCaptureBuffer = NULL; | |||
@@ -239,7 +239,7 @@ namespace Jack | |||
fNetMidiPlaybackBuffer = NULL; | |||
fMidiCapturePortList = NULL; | |||
fMidiPlaybackPortList = NULL; | |||
#ifdef JACK_MONITOR | |||
delete fNetTimeMon; | |||
fNetTimeMon = NULL; | |||
@@ -258,6 +258,7 @@ namespace Jack | |||
unsigned long port_flags; | |||
int audio_port_index; | |||
uint midi_port_index; | |||
jack_latency_range_t range; | |||
//audio | |||
port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; | |||
@@ -274,7 +275,8 @@ namespace Jack | |||
port = fGraphManager->GetPort ( port_id ); | |||
port->SetAlias ( alias ); | |||
//port latency | |||
port->SetLatency ( fEngineControl->fBufferSize ); | |||
range.min = range.max = fEngineControl->fBufferSize; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fCapturePortList[audio_port_index] = port_id; | |||
jack_log ( "JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); | |||
} | |||
@@ -295,15 +297,16 @@ namespace Jack | |||
switch ( fParams.fNetworkMode ) | |||
{ | |||
case 'f' : | |||
port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize; | |||
break; | |||
case 'n' : | |||
port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
break; | |||
case 's' : | |||
port->SetLatency ( 2 * fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
break; | |||
} | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
fPlaybackPortList[audio_port_index] = port_id; | |||
jack_log ( "JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); | |||
} | |||
@@ -321,7 +324,8 @@ namespace Jack | |||
} | |||
port = fGraphManager->GetPort ( port_id ); | |||
//port latency | |||
port->SetLatency ( fEngineControl->fBufferSize ); | |||
range.min = range.max = fEngineControl->fBufferSize; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fMidiCapturePortList[midi_port_index] = port_id; | |||
jack_log ( "JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); | |||
} | |||
@@ -342,15 +346,16 @@ namespace Jack | |||
switch ( fParams.fNetworkMode ) | |||
{ | |||
case 'f' : | |||
port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize; | |||
break; | |||
case 'n' : | |||
port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ; | |||
range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
break; | |||
case 's' : | |||
port->SetLatency ( 2 * fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ); | |||
range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize); | |||
break; | |||
} | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
fMidiPlaybackPortList[midi_port_index] = port_id; | |||
jack_log ( "JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); | |||
} | |||
@@ -409,7 +414,7 @@ namespace Jack | |||
//is there a transport state change to handle ? | |||
if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) ) | |||
{ | |||
switch ( fSendTransportData.fState ) | |||
{ | |||
case JackTransportStopped : | |||
@@ -458,13 +463,13 @@ namespace Jack | |||
else | |||
fReturnTransportData.fTimebaseMaster = NO_CHANGE; | |||
*/ | |||
//update transport state and position | |||
fReturnTransportData.fState = fEngineControl->fTransport.Query ( &fReturnTransportData.fPosition ); | |||
//is it a new state (that the master need to know...) ? | |||
fReturnTransportData.fNewState = (( fReturnTransportData.fState == JackTransportNetStarting) && | |||
( fReturnTransportData.fState != fLastTransportState ) && | |||
( fReturnTransportData.fState != fLastTransportState ) && | |||
( fReturnTransportData.fState != fSendTransportData.fState ) ); | |||
if ( fReturnTransportData.fNewState ) | |||
jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) ); | |||
@@ -492,14 +497,14 @@ namespace Jack | |||
return 0; | |||
#ifdef JACK_MONITOR | |||
// For timing | |||
// For timing | |||
fRcvSyncUst = GetMicroSeconds(); | |||
#endif | |||
//decode sync | |||
//if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified | |||
DecodeSyncPacket(); | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - fRcvSyncUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f ); | |||
#endif | |||
@@ -534,7 +539,7 @@ namespace Jack | |||
//sync | |||
EncodeSyncPacket(); | |||
//send sync | |||
if ( SyncSend() == SOCKET_ERROR ) | |||
return SOCKET_ERROR; | |||
@@ -134,7 +134,7 @@ namespace Jack | |||
if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0) | |||
goto fail; | |||
if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) | |||
goto fail; | |||
@@ -153,7 +153,7 @@ namespace Jack | |||
jack_error ( "Can't activate jack client." ); | |||
goto fail; | |||
} | |||
if (auto_connect) | |||
ConnectPorts(); | |||
jack_info ( "New NetMaster started." ); | |||
@@ -172,7 +172,8 @@ namespace Jack | |||
uint i; | |||
char name[24]; | |||
jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); | |||
jack_latency_range_t range; | |||
jack_log ( "JackNetMaster::AllocPorts" ); | |||
//audio | |||
@@ -182,9 +183,10 @@ namespace Jack | |||
if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
return -1; | |||
//port latency | |||
jack_port_set_latency ( fAudioCapturePorts[i], 0 ); | |||
range.min = range.max = 0; | |||
jack_port_set_latency_range(fAudioCapturePorts[i], JackCaptureLatency, &range); | |||
} | |||
for ( i = 0; i < fParams.fReturnAudioChannels; i++ ) | |||
{ | |||
sprintf ( name, "from_slave_%d", i+1 ); | |||
@@ -194,17 +196,20 @@ namespace Jack | |||
switch ( fParams.fNetworkMode ) | |||
{ | |||
case 'f' : | |||
jack_port_set_latency ( fAudioPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
range.min = range.max = (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range); | |||
break; | |||
case 'n' : | |||
jack_port_set_latency ( fAudioPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
range.min = range.max = port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range); | |||
break; | |||
case 's' : | |||
jack_port_set_latency ( fAudioPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
range.min = range.max = 2 * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range); | |||
break; | |||
} | |||
} | |||
//midi | |||
for ( i = 0; i < fParams.fSendMidiChannels; i++ ) | |||
{ | |||
@@ -212,7 +217,8 @@ namespace Jack | |||
if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) | |||
return -1; | |||
//port latency | |||
jack_port_set_latency ( fMidiCapturePorts[i], 0 ); | |||
range.min = range.max = 0; | |||
jack_port_set_latency_range(fMidiCapturePorts[i], JackCaptureLatency, &range); | |||
} | |||
for ( i = 0; i < fParams.fReturnMidiChannels; i++ ) | |||
{ | |||
@@ -223,23 +229,26 @@ namespace Jack | |||
switch ( fParams.fNetworkMode ) | |||
{ | |||
case 'f' : | |||
jack_port_set_latency ( fMidiPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
range.min = range.max = (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range); | |||
break; | |||
case 'n' : | |||
jack_port_set_latency ( fMidiPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
range.min = range.max = port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range); | |||
break; | |||
case 's' : | |||
jack_port_set_latency ( fMidiPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency ); | |||
range.min = range.max = 2 * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range); | |||
break; | |||
} | |||
} | |||
return 0; | |||
} | |||
void JackNetMaster::ConnectPorts() | |||
{ | |||
const char **ports; | |||
ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | |||
if (ports != NULL) { | |||
for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { | |||
@@ -247,7 +256,7 @@ namespace Jack | |||
} | |||
free(ports); | |||
} | |||
ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | |||
if (ports != NULL) { | |||
for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { | |||
@@ -309,7 +318,7 @@ namespace Jack | |||
else | |||
jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName ); | |||
break; | |||
case TIMEBASEMASTER : | |||
timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this ); | |||
if ( timebase < 0 ) | |||
@@ -317,7 +326,7 @@ namespace Jack | |||
else | |||
jack_info ( "'%s' is the new timebase master.", fParams.fName ); | |||
break; | |||
case CONDITIONAL_TIMEBASEMASTER : | |||
timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this ); | |||
if ( timebase != EBUSY ) | |||
@@ -340,18 +349,18 @@ namespace Jack | |||
jack_transport_stop ( fJackClient ); | |||
jack_info ( "'%s' stops transport.", fParams.fName ); | |||
break; | |||
case JackTransportStarting : | |||
if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL ) | |||
jack_error ( "Can't set new position." ); | |||
jack_transport_start ( fJackClient ); | |||
jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); | |||
break; | |||
case JackTransportNetStarting : | |||
jack_info ( "'%s' is ready to roll..", fParams.fName ); | |||
break; | |||
case JackTransportRolling : | |||
jack_info ( "'%s' is rolling.", fParams.fName ); | |||
break; | |||
@@ -377,16 +386,19 @@ namespace Jack | |||
} | |||
//sync-------------------------------------------------------------------------------- | |||
bool JackNetMaster::IsSlaveReadyToRoll() | |||
{ | |||
return ( fReturnTransportData.fState == JackTransportNetStarting ); | |||
} | |||
int JackNetMaster::SetBufferSize (jack_nframes_t nframes, void* arg) | |||
int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg) | |||
{ | |||
jack_error("Cannot handle bufer size change, so proxy will be removed..."); | |||
static_cast<JackNetMaster*> ( arg )->Exit(); | |||
JackNetMaster* obj = static_cast<JackNetMaster*>(arg); | |||
if (nframes != obj->fParams.fPeriodSize) { | |||
jack_error("Cannot handle bufer size change, so JackNetMaster proxy will be removed..."); | |||
obj->Exit(); | |||
} | |||
return 0; | |||
} | |||
@@ -424,10 +436,10 @@ namespace Jack | |||
fParams.fPeriodSize ) ) ); | |||
if (IsSynched()) { // only send if connection is "synched" | |||
//encode the first packet | |||
EncodeSyncPacket(); | |||
//send sync | |||
if ( SyncSend() == SOCKET_ERROR ) | |||
return SOCKET_ERROR; | |||
@@ -443,7 +455,7 @@ namespace Jack | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f ); | |||
#endif | |||
} else { | |||
jack_error("Connection is not synched, skip cycle..."); | |||
} | |||
@@ -459,7 +471,7 @@ namespace Jack | |||
//decode sync | |||
DecodeSyncPacket(); | |||
//receive data | |||
res = DataRecv(); | |||
if ( ( res == 0 ) || ( res == SOCKET_ERROR ) ) | |||
@@ -498,11 +510,11 @@ namespace Jack | |||
else | |||
jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP); | |||
break; | |||
case 'p': | |||
fSocket.SetPort ( param->value.ui ); | |||
break; | |||
case 'c': | |||
fAutoConnect = param->value.i; | |||
break; | |||
@@ -646,7 +658,7 @@ namespace Jack | |||
JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params ) | |||
{ | |||
jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName ); | |||
//check MASTER <<==> SLAVE network protocol coherency | |||
if (params.fProtocolVersion != MASTER_PROTOCOL) { | |||
jack_error ( "Error : slave is running with a different protocol %s", params.fName ); | |||
@@ -740,7 +752,7 @@ extern "C" | |||
desc->params[i].value.i = DEFAULT_PORT; | |||
strcpy ( desc->params[i].short_desc, "UDP port" ); | |||
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); | |||
i++; | |||
strcpy ( desc->params[i].name, "auto_connect" ); | |||
desc->params[i].character = 'c'; | |||
@@ -54,7 +54,7 @@ namespace Jack | |||
//sync and transport | |||
int fLastTransportState; | |||
//monitoring | |||
#ifdef JACK_MONITOR | |||
jack_time_t fPeriodUsecs; | |||
@@ -64,7 +64,7 @@ namespace Jack | |||
bool Init(bool auto_connect); | |||
int AllocPorts(); | |||
void FreePorts(); | |||
//transport | |||
void EncodeTransportData(); | |||
void DecodeTransportData(); | |||
@@ -98,7 +98,7 @@ namespace Jack | |||
const char* fManagerName; | |||
char fMulticastIP[32]; | |||
JackNetSocket fSocket; | |||
pthread_t fManagerThread; | |||
jack_native_thread_t fManagerThread; | |||
master_list_t fMasterList; | |||
uint32_t fGlobalID; | |||
bool fRunning; | |||
@@ -34,45 +34,47 @@ namespace Jack | |||
class JackNetOneDriver : public JackAudioDriver | |||
{ | |||
private: | |||
netjack_driver_state_t netj; | |||
void | |||
render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
void | |||
render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); | |||
#ifdef HAVE_CELT | |||
void | |||
render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes); | |||
void | |||
render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up); | |||
#endif | |||
void | |||
render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
void | |||
render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats); | |||
netjack_driver_state_t netj; | |||
void | |||
render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
void | |||
render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); | |||
#ifdef HAVE_CELT | |||
void | |||
render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes); | |||
void | |||
render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up); | |||
#endif | |||
void | |||
render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); | |||
void | |||
render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats); | |||
public: | |||
JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, | |||
int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, | |||
int sample_rate, int period_size, int resample_factor, | |||
const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, | |||
int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ); | |||
~JackNetOneDriver(); | |||
JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, | |||
int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, | |||
int sample_rate, int period_size, int resample_factor, | |||
const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, | |||
int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ); | |||
~JackNetOneDriver(); | |||
int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing, | |||
int inchannels, int outchannels, bool monitor, const char* capture_driver_name, | |||
const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency ); | |||
int Close(); | |||
int Close(); | |||
int Attach(); | |||
int Detach(); | |||
int Read(); | |||
int Write(); | |||
bool Initialize(); | |||
int AllocPorts(); | |||
void FreePorts(); | |||
bool Initialize(); | |||
int AllocPorts(); | |||
void FreePorts(); | |||
// BufferSize can't be changed | |||
bool IsFixedBufferSize() | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -46,6 +46,7 @@ enum NotificationType { | |||
kShutDownCallback = 15, | |||
kQUIT = 16, | |||
kSessionCallback = 17, | |||
kLatencyCallback = 18, | |||
kMaxNotification | |||
}; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -44,6 +44,8 @@ bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type | |||
fInUse = true; | |||
fLatency = 0; | |||
fTotalLatency = 0; | |||
fPlaybackLatency.min = fPlaybackLatency.max = 0; | |||
fCaptureLatency.min = fCaptureLatency.max = 0; | |||
fTied = NO_PORT; | |||
// DB: At this point we do not know current buffer size in frames, | |||
// but every time buffer will be returned to any user, | |||
@@ -86,6 +88,48 @@ jack_nframes_t JackPort::GetTotalLatency() const | |||
void JackPort::SetLatency(jack_nframes_t nframes) | |||
{ | |||
fLatency = nframes; | |||
/* setup the new latency values here, | |||
* so we dont need to change the backend codes. | |||
*/ | |||
if (fFlags & JackPortIsOutput) { | |||
fCaptureLatency.min = nframes; | |||
fCaptureLatency.max = nframes; | |||
} | |||
if (fFlags & JackPortIsInput) { | |||
fPlaybackLatency.min = nframes; | |||
fPlaybackLatency.max = nframes; | |||
} | |||
} | |||
void JackPort::SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) | |||
{ | |||
if (mode == JackCaptureLatency) { | |||
fCaptureLatency = *range; | |||
/* hack to set port->shared->latency up for | |||
* backend ports | |||
*/ | |||
if ((fFlags & JackPortIsOutput) && (fFlags & JackPortIsPhysical)) | |||
fLatency = (range->min + range->max) / 2; | |||
} else { | |||
fPlaybackLatency = *range; | |||
/* hack to set port->shared->latency up for | |||
* backend ports | |||
*/ | |||
if ((fFlags & JackPortIsInput) && (fFlags & JackPortIsPhysical)) | |||
fLatency = (range->min + range->max) / 2; | |||
} | |||
} | |||
void JackPort::GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const | |||
{ | |||
if (mode == JackCaptureLatency) { | |||
*range = fCaptureLatency; | |||
} else { | |||
*range = fPlaybackLatency; | |||
} | |||
} | |||
int JackPort::Tie(jack_port_id_t port_index) | |||
@@ -103,10 +147,10 @@ int JackPort::UnTie() | |||
int JackPort::RequestMonitor(bool onoff) | |||
{ | |||
/** | |||
jackd.h | |||
jackd.h | |||
* If @ref JackPortCanMonitor is set for this @a port, turn input | |||
* monitoring on or off. Otherwise, do nothing. | |||
if (!(fFlags & JackPortCanMonitor)) | |||
return -1; | |||
*/ | |||
@@ -123,10 +167,10 @@ int JackPort::RequestMonitor(bool onoff) | |||
int JackPort::EnsureMonitor(bool onoff) | |||
{ | |||
/** | |||
jackd.h | |||
jackd.h | |||
* If @ref JackPortCanMonitor is set for this @a port, turn input | |||
* monitoring on or off. Otherwise, do nothing. | |||
if (!(fFlags & JackPortCanMonitor)) | |||
return -1; | |||
*/ | |||
@@ -165,7 +209,7 @@ int JackPort::GetFlags() const | |||
const char* JackPort::GetType() const | |||
{ | |||
const JackPortType* type = GetPortType(fTypeId); | |||
return type->name; | |||
return type->fName; | |||
} | |||
void JackPort::SetName(const char* new_name) | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -51,12 +51,14 @@ class SERVER_EXPORT JackPort | |||
jack_nframes_t fLatency; | |||
jack_nframes_t fTotalLatency; | |||
jack_latency_range_t fPlaybackLatency; | |||
jack_latency_range_t fCaptureLatency; | |||
uint8_t fMonitorRequests; | |||
bool fInUse; | |||
jack_port_id_t fTied; // Locally tied source port | |||
float fBuffer[BUFFER_SIZE_MAX + 4]; | |||
bool IsUsed() const | |||
{ | |||
return fInUse; | |||
@@ -88,9 +90,13 @@ class SERVER_EXPORT JackPort | |||
int UnTie(); | |||
jack_nframes_t GetLatency() const; | |||
jack_nframes_t GetTotalLatency() const; | |||
void SetLatency(jack_nframes_t latency); | |||
void SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range); | |||
void GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const; | |||
jack_nframes_t GetTotalLatency() const; | |||
int RequestMonitor(bool onoff); | |||
int EnsureMonitor(bool onoff); | |||
bool MonitoringInput() | |||
@@ -105,7 +111,7 @@ class SERVER_EXPORT JackPort | |||
} | |||
int GetRefNum() const; | |||
} POST_PACKED_STRUCTURE; | |||
} // end of namespace | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -24,20 +24,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
namespace Jack | |||
{ | |||
static const JackPortType* port_types[] = | |||
static const JackPortType* gPortTypes[] = | |||
{ | |||
&gAudioPortType, | |||
&gMidiPortType, | |||
}; | |||
jack_port_type_id_t PORT_TYPES_MAX = sizeof(port_types) / sizeof(port_types[0]); | |||
jack_port_type_id_t PORT_TYPES_MAX = sizeof(gPortTypes) / sizeof(gPortTypes[0]); | |||
jack_port_type_id_t GetPortTypeId(const char* port_type) | |||
{ | |||
for (jack_port_type_id_t i = 0; i < PORT_TYPES_MAX; ++i) { | |||
const JackPortType* type = port_types[i]; | |||
const JackPortType* type = gPortTypes[i]; | |||
assert(type != 0); | |||
if (strcmp(port_type, type->name) == 0) | |||
if (strcmp(port_type, type->fName) == 0) | |||
return i; | |||
} | |||
return PORT_TYPES_MAX; | |||
@@ -46,7 +46,7 @@ jack_port_type_id_t GetPortTypeId(const char* port_type) | |||
const JackPortType* GetPortType(jack_port_type_id_t type_id) | |||
{ | |||
assert(type_id >= 0 && type_id <= PORT_TYPES_MAX); | |||
const JackPortType* type = port_types[type_id]; | |||
const JackPortType* type = gPortTypes[type_id]; | |||
assert(type != 0); | |||
return type; | |||
} | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -31,7 +31,8 @@ extern jack_port_type_id_t PORT_TYPES_MAX; | |||
struct JackPortType | |||
{ | |||
const char* name; | |||
const char* fName; | |||
size_t (*size)(); | |||
void (*init)(void* buffer, size_t buffer_size, jack_nframes_t nframes); | |||
void (*mixdown)(void *mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes); | |||
}; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -71,7 +71,9 @@ struct JackRequest | |||
kSessionReply = 34, | |||
kGetClientByUUID = 35, | |||
kReserveClientName = 36, | |||
kGetUUIDByClient = 37 | |||
kGetUUIDByClient = 37, | |||
kClientHasSessionCallback = 38, | |||
kComputeTotalLatencies = 39 | |||
}; | |||
RequestType fType; | |||
@@ -122,7 +124,7 @@ struct JackResult | |||
{ | |||
return trans->Write(&fResult, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -161,7 +163,7 @@ struct JackClientCheckRequest : public JackRequest | |||
CheckRes(trans->Write(&fOptions, sizeof(int))); | |||
return trans->Write(&fUUID, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -197,7 +199,7 @@ struct JackClientCheckResult : public JackResult | |||
CheckRes(trans->Write(&fStatus, sizeof(int))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -210,7 +212,7 @@ struct JackClientOpenRequest : public JackRequest | |||
int fPID; | |||
int fUUID; | |||
char fName[JACK_CLIENT_NAME_SIZE + 1]; | |||
JackClientOpenRequest() | |||
{} | |||
JackClientOpenRequest(const char* name, int pid, int uuid): JackRequest(JackRequest::kClientOpen) | |||
@@ -234,7 +236,7 @@ struct JackClientOpenRequest : public JackRequest | |||
CheckRes(trans->Write(&fUUID, sizeof(int))); | |||
return trans->Write(&fName, sizeof(fName)); | |||
} | |||
}; | |||
/*! | |||
@@ -247,7 +249,7 @@ struct JackClientOpenResult : public JackResult | |||
int fSharedEngine; | |||
int fSharedClient; | |||
int fSharedGraph; | |||
JackClientOpenResult() | |||
: JackResult(), fSharedEngine(-1), fSharedClient(-1), fSharedGraph(-1) | |||
{} | |||
@@ -272,7 +274,7 @@ struct JackClientOpenResult : public JackResult | |||
CheckRes(trans->Write(&fSharedGraph, sizeof(int))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -299,7 +301,7 @@ struct JackClientCloseRequest : public JackRequest | |||
CheckRes(JackRequest::Write(trans)); | |||
return trans->Write(&fRefNum, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -402,7 +404,7 @@ struct JackPortRegisterRequest : public JackRequest | |||
CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -428,7 +430,7 @@ struct JackPortRegisterResult : public JackResult | |||
CheckRes(JackResult::Write(trans)); | |||
return trans->Write(&fPortIndex, sizeof(jack_port_id_t)); | |||
} | |||
}; | |||
/*! | |||
@@ -461,7 +463,7 @@ struct JackPortUnRegisterRequest : public JackRequest | |||
CheckRes(trans->Write(&fPortIndex, sizeof(jack_port_id_t))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -501,7 +503,7 @@ struct JackPortConnectNameRequest : public JackRequest | |||
CheckRes(trans->Write(&fDst, sizeof(fDst))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -540,7 +542,7 @@ struct JackPortDisconnectNameRequest : public JackRequest | |||
CheckRes(trans->Write(&fDst, sizeof(fDst))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -576,7 +578,7 @@ struct JackPortConnectRequest : public JackRequest | |||
CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -612,7 +614,7 @@ struct JackPortDisconnectRequest : public JackRequest | |||
CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -651,7 +653,7 @@ struct JackPortRenameRequest : public JackRequest | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -679,7 +681,7 @@ struct JackSetBufferSizeRequest : public JackRequest | |||
CheckRes(JackRequest::Write(trans)); | |||
return trans->Write(&fBufferSize, sizeof(jack_nframes_t)); | |||
} | |||
}; | |||
/*! | |||
@@ -707,7 +709,31 @@ struct JackSetFreeWheelRequest : public JackRequest | |||
CheckRes(JackRequest::Write(trans)); | |||
return trans->Write(&fOnOff, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
\brief ComputeTotalLatencies request. | |||
*/ | |||
struct JackComputeTotalLatenciesRequest : public JackRequest | |||
{ | |||
JackComputeTotalLatenciesRequest() | |||
: JackRequest(JackRequest::kComputeTotalLatencies) | |||
{} | |||
int Read(JackChannelTransaction* trans) | |||
{ | |||
return 0; | |||
} | |||
int Write(JackChannelTransaction* trans) | |||
{ | |||
CheckRes(JackRequest::Write(trans)); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -735,7 +761,7 @@ struct JackReleaseTimebaseRequest : public JackRequest | |||
CheckRes(JackRequest::Write(trans)); | |||
return trans->Write(&fRefNum, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -766,7 +792,7 @@ struct JackSetTimebaseCallbackRequest : public JackRequest | |||
CheckRes(trans->Write(&fRefNum, sizeof(int))); | |||
return trans->Write(&fConditionnal, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -797,7 +823,7 @@ struct JackGetInternalClientNameRequest : public JackRequest | |||
CheckRes(trans->Write(&fRefNum, sizeof(int))); | |||
return trans->Write(&fIntRefNum, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -830,7 +856,7 @@ struct JackGetInternalClientNameResult : public JackResult | |||
CheckRes(trans->Write(&fName, sizeof(fName))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -863,7 +889,7 @@ struct JackInternalClientHandleRequest : public JackRequest | |||
CheckRes(trans->Write(&fRefNum, sizeof(int))); | |||
return trans->Write(&fName, sizeof(fName)); | |||
} | |||
}; | |||
/*! | |||
@@ -897,7 +923,7 @@ struct JackInternalClientHandleResult : public JackResult | |||
CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -949,7 +975,7 @@ struct JackInternalClientLoadRequest : public JackRequest | |||
CheckRes(trans->Write(&fUUID, sizeof(int))); | |||
return trans->Write(&fOptions, sizeof(int)); | |||
} | |||
}; | |||
/*! | |||
@@ -983,7 +1009,7 @@ struct JackInternalClientLoadResult : public JackResult | |||
CheckRes(trans->Write(&fIntRefNum, sizeof(int))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -1044,7 +1070,7 @@ struct JackInternalClientUnloadResult : public JackResult | |||
CheckRes(trans->Write(&fStatus, sizeof(int))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -1147,7 +1173,7 @@ struct JackSessionNotifyResult : public JackResult | |||
CheckRes(trans->Write(terminator, sizeof(terminator))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
@@ -1245,7 +1271,7 @@ struct JackClientNameResult : public JackResult | |||
CheckRes(trans->Write(&fName, sizeof(fName))); | |||
return 0; | |||
} | |||
}; | |||
struct JackUUIDResult : public JackResult | |||
@@ -1274,7 +1300,7 @@ struct JackUUIDResult : public JackResult | |||
CheckRes(trans->Write(&fUUID, sizeof(fUUID))); | |||
return 0; | |||
} | |||
}; | |||
struct JackGetUUIDRequest : public JackRequest | |||
@@ -1368,6 +1394,34 @@ struct JackReserveNameRequest : public JackRequest | |||
}; | |||
struct JackClientHasSessionCallbackRequest : public JackRequest | |||
{ | |||
char fName[JACK_CLIENT_NAME_SIZE + 1]; | |||
JackClientHasSessionCallbackRequest() | |||
{} | |||
JackClientHasSessionCallbackRequest(const char *name) | |||
: JackRequest(JackRequest::kClientHasSessionCallback) | |||
{ | |||
strncpy(fName, name, sizeof(fName)); | |||
} | |||
int Read(JackChannelTransaction* trans) | |||
{ | |||
CheckRes(trans->Read(&fName, sizeof(fName))); | |||
return 0; | |||
} | |||
int Write(JackChannelTransaction* trans) | |||
{ | |||
CheckRes(JackRequest::Write(trans)); | |||
CheckRes(trans->Write(&fName, sizeof(fName))); | |||
return 0; | |||
} | |||
}; | |||
/*! | |||
\brief ClientNotification. | |||
*/ | |||
@@ -45,7 +45,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio | |||
} else { | |||
jack_info("JACK server starting in non-realtime mode"); | |||
} | |||
fGraphManager = JackGraphManager::Allocate(port_max); | |||
fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); | |||
fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); | |||
@@ -72,17 +72,17 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||
{ | |||
// TODO: move that in reworked JackServerGlobals::Init() | |||
JackMessageBuffer::Create(); | |||
if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | |||
jack_error("Cannot initialize driver"); | |||
goto fail_close1; | |||
} | |||
if (fChannel.Open(fEngineControl->fServerName, this) < 0) { | |||
jack_error("Server channel open error"); | |||
goto fail_close2; | |||
} | |||
if (fEngine->Open() < 0) { | |||
jack_error("Cannot open engine"); | |||
goto fail_close3; | |||
@@ -92,12 +92,12 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||
jack_error("Cannot open driver"); | |||
goto fail_close4; | |||
} | |||
if (fAudioDriver->Attach() < 0) { | |||
jack_error("Cannot attach audio driver"); | |||
goto fail_close5; | |||
} | |||
fFreewheelDriver->SetMaster(false); | |||
fAudioDriver->SetMaster(true); | |||
fAudioDriver->AddSlave(fFreewheelDriver); // After ??? | |||
@@ -113,11 +113,11 @@ fail_close4: | |||
fail_close3: | |||
fChannel.Close(); | |||
fail_close2: | |||
fail_close2: | |||
fAudioDriver->Close(); | |||
fail_close1: | |||
fail_close1: | |||
JackMessageBuffer::Destroy(); | |||
return -1; | |||
} | |||
@@ -190,7 +190,7 @@ int JackServer::SetBufferSize(jack_nframes_t buffer_size) | |||
jack_log("SetBufferSize: requirement for new buffer size equals current value"); | |||
return 0; | |||
} | |||
if (fAudioDriver->IsFixedBufferSize()) { | |||
jack_log("SetBufferSize: driver only supports a fixed buffer size"); | |||
return -1; | |||
@@ -316,37 +316,37 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par | |||
fAudioDriver->Stop(); | |||
fAudioDriver->Detach(); | |||
fAudioDriver->Close(); | |||
// Open new master | |||
JackDriverInfo* info = new JackDriverInfo(); | |||
JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); | |||
if (master == NULL || info == NULL) { | |||
delete info; | |||
delete master; | |||
return -1; | |||
} else { | |||
// Get slaves list | |||
std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); | |||
std::list<JackDriverInterface*>::const_iterator it; | |||
// Move slaves in new master | |||
for (it = slave_list.begin(); it != slave_list.end(); it++) { | |||
JackDriverInterface* slave = *it; | |||
master->AddSlave(slave); | |||
} | |||
// Delete old master | |||
delete fAudioDriver; | |||
delete fDriverInfo; | |||
// Activate master | |||
fAudioDriver = master; | |||
fDriverInfo = info; | |||
fAudioDriver->Attach(); | |||
fAudioDriver->SetMaster(true); | |||
return fAudioDriver->Start(); | |||
return fAudioDriver->Start(); | |||
} | |||
} | |||
@@ -28,8 +28,10 @@ static char* server_name = NULL; | |||
namespace Jack | |||
{ | |||
JackServer* JackServerGlobals::fInstance; | |||
JackServer* JackServerGlobals::fInstance; | |||
unsigned int JackServerGlobals::fUserCount; | |||
int JackServerGlobals::fRTNotificationSocket; | |||
bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; | |||
void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL; | |||
@@ -95,7 +97,7 @@ bool JackServerGlobals::Init() | |||
int argc = 0; | |||
char* argv[32]; | |||
jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; | |||
// First user starts the server | |||
if (fUserCount++ == 0) { | |||
@@ -158,7 +160,7 @@ bool JackServerGlobals::Init() | |||
(opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { | |||
switch (opt) { | |||
case 'c': | |||
if (tolower (optarg[0]) == 'h') { | |||
clock_source = JACK_TIMER_HPET; | |||
@@ -168,7 +170,7 @@ bool JackServerGlobals::Init() | |||
clock_source = JACK_TIMER_SYSTEM_CLOCK; | |||
} else { | |||
jack_error("unknown option character %c", optopt); | |||
} | |||
} | |||
break; | |||
case 'd': | |||
@@ -38,9 +38,10 @@ struct SERVER_EXPORT JackServerGlobals | |||
{ | |||
static JackServer* fInstance; | |||
static unsigned int fUserCount; | |||
static bool (* on_device_acquire)(const char * device_name); | |||
static void (* on_device_release)(const char * device_name); | |||
static int fRTNotificationSocket; // For debugging purpose | |||
static bool (* on_device_acquire)(const char* device_name); | |||
static void (* on_device_release)(const char* device_name); | |||
JackServerGlobals(); | |||
~JackServerGlobals(); | |||
@@ -1,21 +1,21 @@ | |||
/* | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2004-2008 Grame | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#ifndef __JackThread__ | |||
@@ -26,23 +26,23 @@ | |||
namespace Jack | |||
{ | |||
/*! | |||
\brief The base class for runnable objects, that have an <B> Init </B> and <B> Execute </B> method to be called in a thread. | |||
*/ | |||
class JackRunnableInterface | |||
{ | |||
protected: | |||
JackRunnableInterface() | |||
{} | |||
virtual ~JackRunnableInterface() | |||
{} | |||
public: | |||
virtual bool Init() /*! Called once when the thread is started */ | |||
{ | |||
return true; | |||
@@ -61,23 +61,23 @@ class SERVER_EXPORT JackThreadInterface | |||
{ | |||
public: | |||
enum kThreadState {kIdle, kStarting, kIniting, kRunning}; | |||
protected: | |||
JackRunnableInterface* fRunnable; | |||
int fPriority; | |||
bool fRealTime; | |||
volatile kThreadState fStatus; | |||
int fCancellation; | |||
public: | |||
JackThreadInterface(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation): | |||
fRunnable(runnable), fPriority(priority), fRealTime(real_time), fStatus(kIdle), fCancellation(cancellation) | |||
{} | |||
kThreadState GetStatus() | |||
{ | |||
return fStatus; | |||
@@ -86,10 +86,10 @@ class SERVER_EXPORT JackThreadInterface | |||
{ | |||
fStatus = status; | |||
} | |||
void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX... | |||
{} | |||
int Start(); | |||
int StartSync(); | |||
int Kill(); | |||
@@ -98,24 +98,24 @@ class SERVER_EXPORT JackThreadInterface | |||
int AcquireRealTime(); // Used when called from another thread | |||
int AcquireSelfRealTime(); // Used when called from thread itself | |||
int AcquireRealTime(int priority); // Used when called from another thread | |||
int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
int DropRealTime(); // Used when called from another thread | |||
int DropSelfRealTime(); // Used when called from thread itself | |||
pthread_t GetThreadID(); | |||
jack_native_thread_t GetThreadID(); | |||
bool IsThread(); | |||
static int AcquireRealTimeImp(pthread_t thread, int priority); | |||
static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int DropRealTimeImp(pthread_t thread); | |||
static int StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
static int StopImp(pthread_t thread); | |||
static int KillImp(pthread_t thread); | |||
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority); | |||
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int DropRealTimeImp(jack_native_thread_t thread); | |||
static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
static int StopImp(jack_native_thread_t thread); | |||
static int KillImp(jack_native_thread_t thread); | |||
}; | |||
} | |||
} // end of namespace | |||
@@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#ifndef __JackTime__ | |||
#define __JackTime__ | |||
#include "types.h" | |||
#include "JackCompilerDeps.h" | |||
#include "JackTypes.h" | |||
@@ -34,6 +34,12 @@ typedef signed long SInt32; | |||
#include "JackTypes_os.h" | |||
/** | |||
* Type used to represent the value of free running | |||
* monotonic clock with units of microseconds. | |||
*/ | |||
typedef uint64_t jack_time_t; | |||
typedef uint16_t jack_int_t; // Internal type for ports and refnum | |||
typedef enum { | |||
@@ -33,7 +33,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackDriverLoader.h" | |||
#if defined(JACK_DBUS) && defined(__linux__) | |||
#include <dbus/dbus.h> | |||
#include <dbus/dbus.h> | |||
#include "audio_reserve.h" | |||
#endif | |||
@@ -85,7 +85,7 @@ static void copyright(FILE* file) | |||
{ | |||
fprintf(file, "jackdmp " VERSION "\n" | |||
"Copyright 2001-2005 Paul Davis and others.\n" | |||
"Copyright 2004-2010 Grame.\n" | |||
"Copyright 2004-2011 Grame.\n" | |||
"jackdmp comes with ABSOLUTELY NO WARRANTY\n" | |||
"This is free software, and you are welcome to redistribute it\n" | |||
"under certain conditions; see the file COPYING for details\n"); | |||
@@ -114,10 +114,10 @@ static void usage(FILE* file) | |||
" -d backend [ ... backend args ... ]\n" | |||
#ifdef __APPLE__ | |||
" Available backends may include: coreaudio, dummy or net.\n\n" | |||
#endif | |||
#endif | |||
#ifdef WIN32 | |||
" Available backends may include: portaudio, dummy or net.\n\n" | |||
#endif | |||
#endif | |||
#ifdef __linux__ | |||
" Available backends may include: alsa, dummy, freebob, firewire or net\n\n" | |||
#endif | |||
@@ -178,13 +178,13 @@ int main(int argc, char* argv[]) | |||
jackctl_driver_t * midi_driver_ctl; | |||
jackctl_driver_t * loopback_driver_ctl; | |||
int replace_registry = 0; | |||
const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" | |||
#ifdef __linux__ | |||
"c:" | |||
#endif | |||
; | |||
struct option long_options[] = { | |||
#ifdef __linux__ | |||
{ "clock-source", 1, 0, 'c' }, | |||
@@ -199,7 +199,7 @@ int main(int argc, char* argv[]) | |||
{ "name", 1, 0, 'n' }, | |||
{ "unlock", 0, 0, 'u' }, | |||
{ "realtime", 0, 0, 'R' }, | |||
{ "no-realtime", 0, 0, 'r' }, | |||
{ "no-realtime", 0, 0, 'r' }, | |||
{ "replace-registry", 0, &replace_registry, 0 }, | |||
{ "loopback", 0, 0, 'L' }, | |||
{ "realtime-priority", 1, 0, 'P' }, | |||
@@ -239,23 +239,23 @@ int main(int argc, char* argv[]) | |||
fprintf(stderr, "Failed to create server object\n"); | |||
return -1; | |||
} | |||
server_parameters = jackctl_server_get_parameters(server_ctl); | |||
// Default setting | |||
param = jackctl_get_parameter(server_parameters, "realtime"); | |||
if (param != NULL) { | |||
value.b = true; | |||
jackctl_parameter_set_value(param, &value); | |||
} | |||
opterr = 0; | |||
while (!seen_audio_driver && | |||
(opt = getopt_long(argc, argv, options, | |||
long_options, &option_index)) != EOF) { | |||
switch (opt) { | |||
#ifdef __linux__ | |||
#ifdef __linux__ | |||
case 'c': | |||
param = jackctl_get_parameter(server_parameters, "clock-source"); | |||
if (param != NULL) { | |||
@@ -280,7 +280,7 @@ int main(int argc, char* argv[]) | |||
seen_audio_driver = true; | |||
audio_driver_name = optarg; | |||
break; | |||
case 'L': | |||
loopback = atoi(optarg); | |||
break; | |||
@@ -342,7 +342,7 @@ int main(int argc, char* argv[]) | |||
jackctl_parameter_set_value(param, &value); | |||
} | |||
break; | |||
case 'r': | |||
param = jackctl_get_parameter(server_parameters, "realtime"); | |||
if (param != NULL) { | |||
@@ -388,14 +388,14 @@ int main(int argc, char* argv[]) | |||
goto fail_free1; | |||
} | |||
} | |||
// Long option with no letter so treated separately | |||
param = jackctl_get_parameter(server_parameters, "replace-registry"); | |||
if (param != NULL) { | |||
value.b = replace_registry; | |||
jackctl_parameter_set_value(param, &value); | |||
} | |||
if (show_version) { | |||
printf( "jackdmp version " VERSION | |||
" tmpdir " jack_server_dir | |||
@@ -441,7 +441,7 @@ int main(int argc, char* argv[]) | |||
// Setup signals then start server | |||
signals = jackctl_setup_signals(0); | |||
if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { | |||
fprintf(stderr, "Failed to start server\n"); | |||
goto fail_free1; | |||
@@ -458,7 +458,7 @@ int main(int argc, char* argv[]) | |||
jackctl_server_add_slave(server_ctl, midi_driver_ctl); | |||
} | |||
// Loopback driver | |||
if (loopback > 0) { | |||
loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); | |||
@@ -480,7 +480,7 @@ int main(int argc, char* argv[]) | |||
if (!jackctl_server_stop(server_ctl)) | |||
fprintf(stderr, "Cannot stop server...\n"); | |||
jackctl_server_destroy(server_ctl); | |||
notify_server_stop(server_name); | |||
return 0; | |||
@@ -488,7 +488,7 @@ int main(int argc, char* argv[]) | |||
fail_free1: | |||
jackctl_server_destroy(server_ctl); | |||
return -1; | |||
fail_free2: | |||
jackctl_server_stop(server_ctl); | |||
jackctl_server_destroy(server_ctl); | |||
@@ -1,19 +1,19 @@ | |||
/* | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2004 Jack O'Quin | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -33,21 +33,21 @@ extern "C" | |||
/** | |||
* Note: More documentation can be found in jack/types.h. | |||
*/ | |||
/************************************************************* | |||
* NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | |||
* added to the JACK API after the 0.116.2 release. | |||
* | |||
* Functions that predate this release are marked with | |||
* | |||
* Functions that predate this release are marked with | |||
* JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile | |||
* time in a variety of ways. The default definition is empty, | |||
* so that these symbols get normal linkage. If you wish to | |||
* use all JACK symbols with weak linkage, include | |||
* use all JACK symbols with weak linkage, include | |||
* <jack/weakjack.h> before jack.h. | |||
*************************************************************/ | |||
#include <jack/weakmacros.h> | |||
/** | |||
* Call this function to get version of the JACK, in form of several numbers | |||
* | |||
@@ -200,7 +200,7 @@ int jack_get_client_pid (const char *name) JACK_OPTIONAL_WEAK_EXPORT; | |||
* @return the pthread ID of the thread running the JACK client side | |||
* code. | |||
*/ | |||
pthread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
jack_native_thread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
/*@}*/ | |||
@@ -228,7 +228,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_ | |||
/** | |||
* Wait until this JACK client should process data. | |||
* | |||
* | |||
* @param client - pointer to a JACK client structure | |||
* | |||
* @return the number of frames of data to process | |||
@@ -237,7 +237,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_ | |||
/** | |||
* Signal next clients in the graph. | |||
* | |||
* | |||
* @param client - pointer to a JACK client structure | |||
* @param status - if non-zero, calling thread should exit | |||
*/ | |||
@@ -254,7 +254,7 @@ void jack_cycle_signal (jack_client_t* client, int status) JACK_OPTIONAL_WEAK_EX | |||
* http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 | |||
* for more information. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code. | |||
@@ -270,13 +270,13 @@ int jack_set_process_thread(jack_client_t* client, JackThreadCallback thread_cal | |||
/** | |||
* Tell JACK to call @a thread_init_callback once just after | |||
* the creation of the thread in which all other callbacks | |||
* the creation of the thread in which all other callbacks | |||
* will be handled. | |||
* | |||
* The code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code, causing JACK | |||
@@ -337,7 +337,7 @@ void jack_on_shutdown (jack_client_t *client, | |||
*/ | |||
void jack_on_info_shutdown (jack_client_t *client, | |||
JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Tell the Jack server to call @a process_callback whenever there is | |||
* work be done, passing @a arg as the second argument. | |||
@@ -350,7 +350,7 @@ void jack_on_info_shutdown (jack_client_t *client, | |||
* http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 | |||
* for more information. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code. | |||
@@ -370,7 +370,7 @@ int jack_set_process_callback (jack_client_t *client, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code. | |||
@@ -389,7 +389,7 @@ int jack_set_freewheel_callback (jack_client_t *client, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @param client pointer to JACK client structure. | |||
@@ -410,7 +410,7 @@ int jack_set_buffer_size_callback (jack_client_t *client, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
@@ -427,7 +427,7 @@ int jack_set_sample_rate_callback (jack_client_t *client, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
@@ -444,7 +444,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
@@ -452,7 +452,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
int jack_set_port_registration_callback (jack_client_t *, | |||
JackPortRegistrationCallback | |||
registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Tell the JACK server to call @a connect_callback whenever a | |||
* port is connected or disconnected, passing @a arg as a parameter. | |||
@@ -461,7 +461,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
@@ -478,7 +478,7 @@ int jack_set_port_connect_callback (jack_client_t *, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
@@ -495,7 +495,7 @@ int jack_set_port_rename_callback (jack_client_t *, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
@@ -512,39 +512,97 @@ int jack_set_graph_order_callback (jack_client_t *, | |||
* the code in the supplied function does not need to be | |||
* suitable for real-time execution. | |||
* | |||
* NOTE: this function cannot be called while the client is activated | |||
* NOTE: this function cannot be called while the client is activated | |||
* (after jack_activate has been called.) | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_xrun_callback (jack_client_t *, | |||
JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
/*@}*/ | |||
/** | |||
* Tell the Jack server to call @a latency_callback whenever it | |||
* is necessary to recompute the latencies for some or all | |||
* Jack ports. | |||
* | |||
* @a latency_callback will be called twice each time it is | |||
* needed, once being passed JackCaptureLatency and once | |||
* JackPlaybackLatency. See @ref LatencyFunctions for | |||
* the definition of each type of latency and related functions. | |||
* | |||
* <b>IMPORTANT: Most JACK clients do NOT need to register a latency | |||
* callback.</b> | |||
* | |||
* Clients that meet any of the following conditions do NOT | |||
* need to register a latency callback: | |||
* | |||
* - have only input ports | |||
* - have only output ports | |||
* - their output is totally unrelated to their input | |||
* - their output is not delayed relative to their input | |||
* (i.e. data that arrives in a given process() | |||
* callback is processed and output again in the | |||
* same callback) | |||
* | |||
* Clients NOT registering a latency callback MUST also | |||
* satisfy this condition: | |||
* | |||
* - have no multiple distinct internal signal pathways | |||
* | |||
* This means that if your client has more than 1 input and | |||
* output port, and considers them always "correlated" | |||
* (e.g. as a stereo pair), then there is only 1 (e.g. stereo) | |||
* signal pathway through the client. This would be true, | |||
* for example, of a stereo FX rack client that has a | |||
* left/right input pair and a left/right output pair. | |||
* | |||
* However, this is somewhat a matter of perspective. The | |||
* same FX rack client could be connected so that its | |||
* two input ports were connected to entirely separate | |||
* sources. Under these conditions, the fact that the client | |||
* does not register a latency callback MAY result | |||
* in port latency values being incorrect. | |||
* | |||
* Clients that do not meet any of those conditions SHOULD | |||
* register a latency callback. | |||
* | |||
* See the documentation for @ref jack_port_set_latency_range() | |||
* on how the callback should operate. Remember that the @a mode | |||
* argument given to the latency callback will need to be | |||
* passed into @ref jack_port_set_latency_range() | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_latency_callback (jack_client_t *, | |||
JackLatencyCallback latency_callback, | |||
void *) JACK_WEAK_EXPORT; | |||
/*@}*/ | |||
/** | |||
* @defgroup ServerClientControl Controlling & querying JACK server operation | |||
* @{ | |||
*/ | |||
/** | |||
* Start/Stop JACK's "freewheel" mode. | |||
* | |||
* When in "freewheel" mode, JACK no longer waits for | |||
* any external event to begin the start of the next process | |||
* cycle. | |||
* cycle. | |||
* | |||
* As a result, freewheel mode causes "faster than realtime" | |||
* execution of a JACK graph. If possessed, real-time | |||
* scheduling is dropped when entering freewheel mode, and | |||
* if appropriate it is reacquired when stopping. | |||
* | |||
* | |||
* IMPORTANT: on systems using capabilities to provide real-time | |||
* scheduling (i.e. Linux kernel 2.4), if onoff is zero, this function | |||
* must be called from the thread that originally called jack_activate(). | |||
* This restriction does not apply to other systems (e.g. Linux kernel 2.6 | |||
* must be called from the thread that originally called jack_activate(). | |||
* This restriction does not apply to other systems (e.g. Linux kernel 2.6 | |||
* or OS X). | |||
* | |||
* | |||
* @param client pointer to JACK client structure | |||
* @param onoff if non-zero, freewheel mode starts. Otherwise | |||
* freewheel mode ends. | |||
@@ -569,7 +627,7 @@ int jack_set_freewheel(jack_client_t* client, int onoff) JACK_OPTIONAL_WEAK_EXPO | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the sample rate of the jack system, as set by the user when | |||
* jackd was started. | |||
@@ -613,7 +671,7 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
* @defgroup PortFunctions Creating & manipulating ports | |||
* @{ | |||
*/ | |||
/** | |||
* Create a new port for the client. This is an object used for moving | |||
* data of any type in or out of the client. Ports may be connected | |||
@@ -625,16 +683,16 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
* name. Exceeding that will cause the port registration to fail and | |||
* return NULL. | |||
* | |||
* The @a port_name must be unique among all ports owned by this client. | |||
* If the name is not unique, the registration will fail. | |||
* | |||
* The @a port_name must be unique among all ports owned by this client. | |||
* If the name is not unique, the registration will fail. | |||
* | |||
* All ports have a type, which may be any non-NULL and non-zero | |||
* length string, passed as an argument. Some port types are built | |||
* into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE. | |||
* | |||
* @param client pointer to JACK client structure. | |||
* @param port_name non-empty short name for the new port (not | |||
* including the leading @a "client_name:"). Must be unique. | |||
* including the leading @a "client_name:"). Must be unique. | |||
* @param port_type port type name. If longer than | |||
* jack_port_type_size(), only that many characters are significant. | |||
* @param flags @ref JackPortFlags bit mask. | |||
@@ -663,7 +721,7 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP | |||
* that can be written to; for an input port, it will be an area | |||
* containing the data from the port's connection(s), or | |||
* zero-filled. if there are multiple inbound connections, the data | |||
* will be mixed appropriately. | |||
* will be mixed appropriately. | |||
* | |||
* FOR OUTPUT PORTS ONLY : DEPRECATED in Jack 2.0 !! | |||
* --------------------------------------------------- | |||
@@ -672,9 +730,9 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP | |||
* either never cache the return value or ensure you have | |||
* a "blocksize" callback and be sure to invalidate the cached | |||
* address from there. | |||
* | |||
* | |||
* Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). | |||
* Port buffers have to be retrieved in each callback for proper functionning. | |||
* Port buffers have to be retrieved in each callback for proper functionning. | |||
*/ | |||
void * jack_port_get_buffer (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -759,7 +817,7 @@ const char ** jack_port_get_connections (const jack_port_t *port) JACK_OPTIONAL_ | |||
* you cannot use it in a GraphReordered handler. | |||
* | |||
* 2) You need not be the owner of the port to get information | |||
* about its connections. | |||
* about its connections. | |||
* | |||
* @see jack_port_name_size() | |||
*/ | |||
@@ -768,8 +826,8 @@ const char ** jack_port_get_all_connections (const jack_client_t *client, | |||
/** | |||
* | |||
* @deprecated This function will be removed from a future version | |||
* of JACK. Do not use it. There is no replacement. It has | |||
* @deprecated This function will be removed from a future version | |||
* of JACK. Do not use it. There is no replacement. It has | |||
* turned out to serve essentially no purpose in real-life | |||
* JACK clients. | |||
*/ | |||
@@ -777,73 +835,13 @@ int jack_port_tie (jack_port_t *src, jack_port_t *dst) JACK_OPTIONAL_WEAK_DEPREC | |||
/** | |||
* | |||
* @deprecated This function will be removed from a future version | |||
* of JACK. Do not use it. There is no replacement. It has | |||
* @deprecated This function will be removed from a future version | |||
* of JACK. Do not use it. There is no replacement. It has | |||
* turned out to serve essentially no purpose in real-life | |||
* JACK clients. | |||
*/ | |||
int jack_port_untie (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/** | |||
* @return the time (in frames) between data being available or | |||
* delivered at/to a port, and the time at which it arrived at or is | |||
* delivered to the "other side" of the port. E.g. for a physical | |||
* audio output port, this is the time between writing to the port and | |||
* when the signal will leave the connector. For a physical audio | |||
* input port, this is the time between the sound arriving at the | |||
* connector and the corresponding frames being readable from the | |||
* port. | |||
*/ | |||
jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* The maximum of the sum of the latencies in every | |||
* connection path that can be drawn between the port and other | |||
* ports with the @ref JackPortIsTerminal flag set. | |||
*/ | |||
jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* The port latency is zero by default. Clients that control | |||
* physical hardware with non-zero latency should call this | |||
* to set the latency to its correct value. Note that the value | |||
* should include any systemic latency present "outside" the | |||
* physical hardware controlled by the client. For example, | |||
* for a client controlling a digital audio interface connected | |||
* to an external digital converter, the latency setting should | |||
* include both buffering by the audio interface *and* the converter. | |||
*/ | |||
void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Request a complete recomputation of a port's total latency. This | |||
* can be called by a client that has just changed the internal | |||
* latency of its port using @function jack_port_set_latency | |||
* and wants to ensure that all signal pathways in the graph | |||
* are updated with respect to the values that will be returned | |||
* by @function jack_port_get_total_latency. | |||
* | |||
* @return zero for successful execution of the request. non-zero | |||
* otherwise. | |||
*/ | |||
int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Request a complete recomputation of all port latencies. This | |||
* can be called by a client that has just changed the internal | |||
* latency of its port using @function jack_port_set_latency | |||
* and wants to ensure that all signal pathways in the graph | |||
* are updated with respect to the values that will be returned | |||
* by @function jack_port_get_total_latency. It allows a client | |||
* to change multiple port latencies without triggering a | |||
* recompute for each change. | |||
* | |||
* @return zero for successful execution of the request. non-zero | |||
* otherwise. | |||
*/ | |||
int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Modify a port's short name. May be called at any time. If the | |||
* resulting full name (including the @a "client_name:" prefix) is | |||
@@ -856,12 +854,12 @@ int jack_port_set_name (jack_port_t *port, const char *port_name) JACK_OPTIONAL_ | |||
/** | |||
* Set @a alias as an alias for @a port. May be called at any time. | |||
* If the alias is longer than jack_port_name_size(), it will be truncated. | |||
* | |||
* | |||
* After a successful call, and until JACK exits or | |||
* @function jack_port_unset_alias() is called, @alias may be | |||
* used as a alternate name for the port. | |||
* | |||
* Ports can have up to two aliases - if both are already | |||
* Ports can have up to two aliases - if both are already | |||
* set, this function will return an error. | |||
* | |||
* @return 0 on success, otherwise a non-zero error code. | |||
@@ -870,8 +868,8 @@ int jack_port_set_alias (jack_port_t *port, const char *alias) JACK_OPTIONAL_WEA | |||
/** | |||
* Remove @a alias as an alias for @a port. May be called at any time. | |||
* | |||
* After a successful call, @a alias can no longer be | |||
* | |||
* After a successful call, @a alias can no longer be | |||
* used as a alternate name for the port. | |||
* | |||
* @return 0 on success, otherwise a non-zero error code. | |||
@@ -981,6 +979,224 @@ int jack_port_name_size(void) JACK_OPTIONAL_WEAK_EXPORT; | |||
*/ | |||
int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the buffersize of a port of type @arg port_type. | |||
* | |||
* this function may only be called in a buffer_size callback. | |||
*/ | |||
size_t jack_port_type_get_buffer_size (jack_client_t *client, const char *port_type) JACK_WEAK_EXPORT; | |||
/*@}*/ | |||
/** | |||
* @defgroup LatencyFunctions Managing and determining latency | |||
* | |||
* The purpose of JACK's latency API is to allow clients to | |||
* easily answer two questions: | |||
* | |||
* - How long has it been since the data read from a port arrived | |||
* at the edge of the JACK graph (either via a physical port | |||
* or being synthesized from scratch)? | |||
* | |||
* - How long will it be before the data written to a port arrives | |||
* at the edge of a JACK graph? | |||
* To help answering these two questions, all JACK ports have two | |||
* latency values associated with them, both measured in frames: | |||
* | |||
* <b>capture latency</b>: how long since the data read from | |||
* the buffer of a port arrived at at | |||
* a port marked with JackPortIsTerminal. | |||
* The data will have come from the "outside | |||
* world" if the terminal port is also | |||
* marked with JackPortIsPhysical, or | |||
* will have been synthesized by the client | |||
* that owns the terminal port. | |||
* | |||
* <b>playback latency</b>: how long until the data | |||
* written to the buffer of port will reach a port | |||
* marked with JackPortIsTerminal. | |||
* | |||
* Both latencies might potentially have more than one value | |||
* because there may be multiple pathways to/from a given port | |||
* and a terminal port. Latency is therefore generally | |||
* expressed a min/max pair. | |||
* | |||
* In most common setups, the minimum and maximum latency | |||
* are the same, but this design accomodates more complex | |||
* routing, and allows applications (and thus users) to | |||
* detect cases where routing is creating an anomalous | |||
* situation that may either need fixing or more | |||
* sophisticated handling by clients that care about | |||
* latency. | |||
* | |||
* See also @ref jack_set_latency_callback for details on how | |||
* clients that add latency to the signal path should interact | |||
* with JACK to ensure that the correct latency figures are | |||
* used. | |||
* @{ | |||
*/ | |||
/** | |||
* The port latency is zero by default. Clients that control | |||
* physical hardware with non-zero latency should call this | |||
* to set the latency to its correct value. Note that the value | |||
* should include any systemic latency present "outside" the | |||
* physical hardware controlled by the client. For example, | |||
* for a client controlling a digital audio interface connected | |||
* to an external digital converter, the latency setting should | |||
* include both buffering by the audio interface *and* the converter. | |||
* | |||
* @deprecated This method will be removed in the next major | |||
* release of JACK. It should not be used in new code, and should | |||
* be replaced by a latency callback that calls @ref | |||
* jack_port_set_latency_range(). | |||
*/ | |||
void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/** | |||
* return the latency range defined by @a mode for | |||
* @a port, in frames. | |||
* | |||
* See @ref LatencyFunctions for the definition of each latency value. | |||
* | |||
* This is normally used in the LatencyCallback. | |||
* and therefor safe to execute from callbacks. | |||
*/ | |||
void jack_port_get_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) JACK_WEAK_EXPORT; | |||
/** | |||
* set the minimum and maximum latencies defined by | |||
* @a mode for @a port, in frames. | |||
* | |||
* See @ref LatencyFunctions for the definition of each latency value. | |||
* | |||
* This function should ONLY be used inside a latency | |||
* callback. The client should determine the current | |||
* value of the latency using @ref jack_port_get_latency_range() | |||
* (called using the same mode as @a mode) | |||
* and then add some number of frames to that reflects | |||
* latency added by the client. | |||
* | |||
* How much latency a client adds will vary | |||
* dramatically. For most clients, the answer is zero | |||
* and there is no reason for them to register a latency | |||
* callback and thus they should never call this | |||
* function. | |||
* | |||
* More complex clients that take an input signal, | |||
* transform it in some way and output the result but | |||
* not during the same process() callback will | |||
* generally know a single constant value to add | |||
* to the value returned by @ref jack_port_get_latency_range(). | |||
* | |||
* Such clients would register a latency callback (see | |||
* @ref jack_set_latency_callback) and must know what input | |||
* ports feed which output ports as part of their | |||
* internal state. Their latency callback will update | |||
* the ports' latency values appropriately. | |||
* | |||
* A pseudo-code example will help. The @a mode argument to the latency | |||
* callback will determine whether playback or capture | |||
* latency is being set. The callback will use | |||
* @ref jack_port_set_latency_range() as follows: | |||
* | |||
* \code | |||
* jack_latency_range_t range; | |||
* if (mode == JackPlaybackLatency) { | |||
* foreach input_port in (all self-registered port) { | |||
* jack_port_get_latency_range (port_feeding_input_port, JackPlaybackLatency, &range); | |||
* range.min += min_delay_added_as_signal_flows_from port_feeding to input_port; | |||
* range.max += max_delay_added_as_signal_flows_from port_feeding to input_port; | |||
* jack_port_set_latency_range (input_port, JackPlaybackLatency, &range); | |||
* } | |||
* } else if (mode == JackCaptureLatency) { | |||
* foreach output_port in (all self-registered port) { | |||
* jack_port_get_latency_range (port_fed_by_output_port, JackCaptureLatency, &range); | |||
* range.min += min_delay_added_as_signal_flows_from_output_port_to_fed_by_port; | |||
* range.max += max_delay_added_as_signal_flows_from_output_port_to_fed_by_port; | |||
* jack_port_set_latency_range (output_port, JackCaptureLatency, &range); | |||
* } | |||
* } | |||
* \endcode | |||
* | |||
* In this relatively simple pseudo-code example, it is assumed that | |||
* each input port or output is connected to only 1 output or input | |||
* port respectively. | |||
* | |||
* If a port is connected to more than 1 other port, then the | |||
* range.min and range.max values passed to @ref | |||
* jack_port_set_latency_range() should reflect the minimum and | |||
* maximum values across all connected ports. | |||
* | |||
* See the description of @ref jack_set_latency_callback for more | |||
* information. | |||
*/ | |||
void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) JACK_WEAK_EXPORT; | |||
/** | |||
* Request a complete recomputation of all port latencies. This | |||
* can be called by a client that has just changed the internal | |||
* latency of its port using jack_port_set_latency | |||
* and wants to ensure that all signal pathways in the graph | |||
* are updated with respect to the values that will be returned | |||
* by jack_port_get_total_latency. It allows a client | |||
* to change multiple port latencies without triggering a | |||
* recompute for each change. | |||
* | |||
* @return zero for successful execution of the request. non-zero | |||
* otherwise. | |||
*/ | |||
int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the time (in frames) between data being available or | |||
* delivered at/to a port, and the time at which it arrived at or is | |||
* delivered to the "other side" of the port. E.g. for a physical | |||
* audio output port, this is the time between writing to the port and | |||
* when the signal will leave the connector. For a physical audio | |||
* input port, this is the time between the sound arriving at the | |||
* connector and the corresponding frames being readable from the | |||
* port. | |||
* | |||
* @deprecated This method will be removed in the next major | |||
* release of JACK. It should not be used in new code, and should | |||
* be replaced by jack_port_get_latency_range() in any existing | |||
* use cases. | |||
*/ | |||
jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/** | |||
* The maximum of the sum of the latencies in every | |||
* connection path that can be drawn between the port and other | |||
* ports with the @ref JackPortIsTerminal flag set. | |||
* | |||
* @deprecated This method will be removed in the next major | |||
* release of JACK. It should not be used in new code, and should | |||
* be replaced by jack_port_get_latency_range() in any existing | |||
* use cases. | |||
*/ | |||
jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/** | |||
* Request a complete recomputation of a port's total latency. This | |||
* can be called by a client that has just changed the internal | |||
* latency of its port using jack_port_set_latency | |||
* and wants to ensure that all signal pathways in the graph | |||
* are updated with respect to the values that will be returned | |||
* by jack_port_get_total_latency. | |||
* | |||
* @return zero for successful execution of the request. non-zero | |||
* otherwise. | |||
* | |||
* @deprecated This method will be removed in the next major | |||
* release of JACK. It should not be used in new code, and should | |||
* be replaced by jack_recompute_total_latencies() in any existing | |||
* use cases. | |||
*/ | |||
int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/*@}*/ | |||
/** | |||
@@ -989,13 +1205,13 @@ int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT; | |||
*/ | |||
/** | |||
* @param port_name_pattern A regular expression used to select | |||
* ports by name. If NULL or of zero length, no selection based | |||
* @param port_name_pattern A regular expression used to select | |||
* ports by name. If NULL or of zero length, no selection based | |||
* on name will be carried out. | |||
* @param type_name_pattern A regular expression used to select | |||
* ports by type. If NULL or of zero length, no selection based | |||
* @param type_name_pattern A regular expression used to select | |||
* ports by type. If NULL or of zero length, no selection based | |||
* on type will be carried out. | |||
* @param flags A value used to select ports by their flags. | |||
* @param flags A value used to select ports by their flags. | |||
* If zero, no selection based on flags will be carried out. | |||
* | |||
* @return a NULL-terminated array of ports that match the specified | |||
@@ -1021,8 +1237,8 @@ jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name) JACK_OP | |||
*/ | |||
jack_port_t * jack_port_by_id (jack_client_t *client, | |||
jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT; | |||
/*@}*/ | |||
/*@}*/ | |||
/** | |||
* @defgroup TimeFunctions Handling time | |||
@@ -1052,7 +1268,7 @@ jack_nframes_t jack_frame_time (const jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT | |||
* This function may only be used from the process callback, and can | |||
* be used to interpret timestamps generated by jack_frame_time() in | |||
* other threads with respect to the current process cycle. | |||
* | |||
* | |||
* This is the only jack time function that returns exact time: | |||
* when used during the process callback it always returns the same | |||
* value (until the next process callback, where it will return | |||
@@ -1075,8 +1291,8 @@ jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t) JAC | |||
/** | |||
* @return return JACK's current system time in microseconds, | |||
* using the JACK clock source. | |||
* | |||
* using the JACK clock source. | |||
* | |||
* The value returned is guaranteed to be monotonic, but not linear. | |||
*/ | |||
jack_time_t jack_get_time() JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -1129,7 +1345,7 @@ void jack_set_info_function (void (*func)(const char *)) JACK_OPTIONAL_WEAK_EXPO | |||
/*@}*/ | |||
/** | |||
* The free function to be used on memory returned by jack_port_get_connections, | |||
* The free function to be used on memory returned by jack_port_get_connections, | |||
* jack_port_get_all_connections and jack_get_ports functions. | |||
* This is MANDATORY on Windows when otherwise all nasty runtime version related crashes can occur. | |||
* Developers are strongly encouraged to use this function instead of the standard "free" function in new code. | |||
@@ -1,18 +1,18 @@ | |||
/* | |||
Copyright (C) 2004 Ian Esten | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -24,11 +24,12 @@ | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#include <jack/weakmacros.h> | |||
#include <jack/types.h> | |||
#include <stdlib.h> | |||
#include <jack/weakmacros.h> | |||
/** Type for raw event data contained in @ref jack_midi_event_t. */ | |||
typedef unsigned char jack_midi_data_t; | |||
@@ -43,7 +44,7 @@ typedef struct _jack_midi_event | |||
/** | |||
* @defgroup MIDIAPI Reading and writing MIDI data | |||
* @defgroup MIDIAPI Reading and writing MIDI data | |||
* @{ | |||
*/ | |||
@@ -57,7 +58,7 @@ jack_midi_get_event_count(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** Get a MIDI event from an event port buffer. | |||
* | |||
* | |||
* Jack MIDI is normalised, the MIDI event returned by this function is | |||
* guaranteed to be a complete MIDI event (the status byte will always be | |||
* present, and no realtime events will interspered with the event). | |||
@@ -74,7 +75,7 @@ jack_midi_event_get(jack_midi_event_t *event, | |||
/** Clear an event buffer. | |||
* | |||
* | |||
* This should be called at the beginning of each process cycle before calling | |||
* @ref jack_midi_event_reserve or @ref jack_midi_event_write. This | |||
* function may not be called on an input port's buffer. | |||
@@ -105,10 +106,10 @@ jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; | |||
* messages interspersed with other messages (realtime messages are fine | |||
* when they occur on their own, like other messages). | |||
* | |||
* Events must be written in order, sorted by their sample offsets. | |||
* JACK will not sort the events for you, and will refuse to store | |||
* out-of-order events. | |||
* | |||
* Events must be written in order, sorted by their sample offsets. | |||
* JACK will not sort the events for you, and will refuse to store | |||
* out-of-order events. | |||
* | |||
* @param port_buffer Buffer to write event to. | |||
* @param time Sample offset of event. | |||
* @param data_size Length of event's raw data in bytes. | |||
@@ -117,7 +118,7 @@ jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; | |||
*/ | |||
jack_midi_data_t* | |||
jack_midi_event_reserve(void *port_buffer, | |||
jack_nframes_t time, | |||
jack_nframes_t time, | |||
size_t data_size) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -125,18 +126,17 @@ jack_midi_event_reserve(void *port_buffer, | |||
* | |||
* This function is simply a wrapper for @ref jack_midi_event_reserve | |||
* which writes the event data into the space reserved in the buffer. | |||
* The same restrictions on the MIDI data apply. | |||
* | |||
* Clients must not write more than | |||
* @a data_size bytes into this buffer. Clients must write normalised | |||
* MIDI data to the port - no running status and no (1-byte) realtime | |||
* messages interspersed with other messages (realtime messages are fine | |||
* when they occur on their own, like other messages). | |||
* | |||
* Events must be written in order, sorted by their sample offsets. | |||
* JACK will not sort the events for you, and will refuse to store | |||
* | |||
* Clients must not write more than | |||
* @a data_size bytes into this buffer. Clients must write normalised | |||
* MIDI data to the port - no running status and no (1-byte) realtime | |||
* messages interspersed with other messages (realtime messages are fine | |||
* when they occur on their own, like other messages). | |||
* | |||
* Events must be written in order, sorted by their sample offsets. | |||
* JACK will not sort the events for you, and will refuse to store | |||
* out-of-order events. | |||
* | |||
* | |||
* @param port_buffer Buffer to write event to. | |||
* @param time Sample offset of event. | |||
* @param data Message data to be written. | |||
@@ -2,21 +2,20 @@ | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2004 Jack O'Quin | |||
Copyright (C) 2010 Torben Hohn | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#ifndef __jack_session_h__ | |||
@@ -36,80 +35,114 @@ extern "C" { | |||
/** | |||
* session event types. | |||
* Session event type. | |||
* | |||
* if a client cant save templates, i might just do a normal save. | |||
* | |||
* the rationale, why there is no quit without save, is that a client | |||
* might refuse to quit when it has unsaved data. | |||
* however some other clients might have already quit. | |||
* this results in too much confusion, so we just dont support that. | |||
* the session manager can check, if the saved state is different from a previous | |||
* save, and just remove the saved stuff. | |||
* | |||
* (an inquiry function, whether a quit is ok, followed by a quit event | |||
* would have a race) | |||
* There is no "quit without saving" event because a client might refuse to | |||
* quit when it has unsaved data, but other clients may have already quit. | |||
* This results in too much confusion, so it is unsupported. | |||
*/ | |||
enum JackSessionEventType { | |||
/** | |||
* Save the session completely. | |||
* | |||
* The client may save references to data outside the provided directory, | |||
* but it must do so by creating a link inside the provided directory and | |||
* referring to that in any save files. The client must not refer to data | |||
* files outside the provided directory directly in save files, because | |||
* this makes it impossible for the session manager to create a session | |||
* archive for distribution or archival. | |||
*/ | |||
JackSessionSave = 1, | |||
/** | |||
* Save the session completly, then quit. | |||
* | |||
* The rules for saving are exactly the same as for JackSessionSave. | |||
*/ | |||
JackSessionSaveAndQuit = 2, | |||
/** | |||
* Save a session template. | |||
* | |||
* A session template is a "skeleton" of the session, but without any data. | |||
* Clients must save a session that, when restored, will create the same | |||
* ports as a full save would have. However, the actual data contained in | |||
* the session may not be saved (e.g. a DAW would create the necessary | |||
* tracks, but not save the actual recorded data). | |||
*/ | |||
JackSessionSaveTemplate = 3 | |||
}; | |||
typedef enum JackSessionEventType jack_session_event_type_t; | |||
/** | |||
* @ref jack_session_flags_t bits | |||
*/ | |||
enum JackSessionFlags { | |||
/** | |||
* an error occured while saving. | |||
* An error occured while saving. | |||
*/ | |||
JackSessionSaveError = 0x01, | |||
/** | |||
* this reply indicates that a client is part of a multiclient application. | |||
* the command reply is left empty. but the session manager should still | |||
* consider this client part of a session. it will come up due to invocation of another | |||
* client. | |||
* Client needs to be run in a terminal. | |||
*/ | |||
JackSessionChildClient = 0x02 | |||
JackSessionNeedTerminal = 0x02 | |||
}; | |||
/** | |||
* Session flags. | |||
*/ | |||
typedef enum JackSessionFlags jack_session_flags_t; | |||
struct _jack_session_event { | |||
/** | |||
* the actual type of this session event. | |||
* The type of this session event. | |||
*/ | |||
jack_session_event_type_t type; | |||
/** | |||
* session_directory with trailing separator | |||
* this is per client. so the client can do whatever it likes in here. | |||
* Session directory path, with trailing separator. | |||
* | |||
* This directory is exclusive to the client; when saving the client may | |||
* create any files it likes in this directory. | |||
*/ | |||
const char *session_dir; | |||
/** | |||
* client_uuid which must be specified to jack_client_open on session reload. | |||
* client can specify it in the returned commandline as an option, or just save it | |||
* with the state file. | |||
* Client UUID which must be passed to jack_client_open on session load. | |||
* | |||
* The client can specify this in the returned command line, or save it | |||
* in a state file within the session directory. | |||
*/ | |||
const char *client_uuid; | |||
/** | |||
* the command_line is the reply of the client. | |||
* it specifies in a platform dependent way, how the client must be restarted upon session reload. | |||
* Reply (set by client): the command line needed to restore the client. | |||
* | |||
* probably it should contain ${SESSION_DIR} instead of the actual session dir. | |||
* this would basically make the session dir moveable. | |||
* This is a platform dependent command line. It must contain | |||
* ${SESSION_DIR} instead of the actual session directory path. More | |||
* generally, just as in session files, clients should not include any | |||
* paths outside the session directory here as this makes | |||
* archival/distribution impossible. | |||
* | |||
* ownership of the memory is handed to jack. | |||
* initially set to NULL by jack; | |||
* This field is set to NULL by Jack when the event is delivered to the | |||
* client. The client must set to allocated memory that is safe to | |||
* free(). This memory will be freed by jack_session_event_free. | |||
*/ | |||
char *command_line; | |||
/** | |||
* flags to be set by the client. normally left 0. | |||
* Reply (set by client): Session flags. | |||
*/ | |||
jack_session_flags_t flags; | |||
/** | |||
* Future flags. Set to zero for now. | |||
*/ | |||
uint32_t future; | |||
}; | |||
typedef struct _jack_session_event jack_session_event_t; | |||
@@ -118,35 +151,42 @@ typedef struct _jack_session_event jack_session_event_t; | |||
* Prototype for the client supplied function that is called | |||
* whenever a session notification is sent via jack_session_notify(). | |||
* | |||
* The session_id must be passed to jack_client_open on session reload (this can be | |||
* done by specifying it somehow on the returned command line). | |||
* Ownership of the memory of @a event is passed to the application. | |||
* It must be freed using jack_session_event_free when its not used anymore. | |||
* | |||
* The client must promptly call jack_session_reply for this event. | |||
* | |||
* @param event the event_structure. | |||
* @param arg pointer to a client supplied structure | |||
* @param event The event structure. | |||
* @param arg Pointer to a client supplied structure. | |||
*/ | |||
typedef void (*JackSessionCallback)(jack_session_event_t *event, void *arg); | |||
typedef void (*JackSessionCallback)(jack_session_event_t *event, | |||
void *arg); | |||
/** | |||
* Tell the JACK server to call @a save_callback the session handler wants | |||
* to save. | |||
* Tell the JACK server to call @a session_callback when a session event | |||
* is to be delivered. | |||
* | |||
* setting more than one session_callback per process is probably a design | |||
* error. if you have a multiclient application its more sensible to create | |||
* a jack_client with only a session callback set. | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_session_callback(jack_client_t *client, | |||
JackSessionCallback session_callback, | |||
void *arg) JACK_WEAK_EXPORT; | |||
int jack_set_session_callback (jack_client_t *client, | |||
JackSessionCallback session_callback, | |||
void *arg) JACK_WEAK_EXPORT; | |||
/** | |||
* reply to a session_event | |||
* Reply to a session event. | |||
* | |||
* this can either be called directly from the callback, or later from a different thread. | |||
* so its possible to just stick the event pointer into a pipe and execute the save code | |||
* from the gui thread. | |||
* This can either be called directly from the callback, or later from a | |||
* different thread. For example, it is possible to push the event through a | |||
* queue and execute the save code from the GUI thread. | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_session_reply( jack_client_t *client, jack_session_event_t *event ) JACK_WEAK_EXPORT; | |||
int jack_session_reply (jack_client_t *client, | |||
jack_session_event_t *event) JACK_WEAK_EXPORT; | |||
/** | |||
@@ -154,74 +194,90 @@ int jack_session_reply( jack_client_t *client, jack_session_event_t *event ) JAC | |||
* this also frees the memory used by the command_line pointer. | |||
* if its non NULL. | |||
*/ | |||
void jack_session_event_free (jack_session_event_t *event) JACK_WEAK_EXPORT; | |||
void jack_session_event_free (jack_session_event_t *event); | |||
/*@}*/ | |||
/** | |||
* get the assigned uuid for client. | |||
* safe to call from callback and all other threads. | |||
* memory needs to be freed. | |||
*/ | |||
char *jack_client_get_uuid (jack_client_t *client) JACK_WEAK_EXPORT; | |||
/** | |||
* @defgroup JackSessionManagerAPI this API is intended for a sessionmanager. | |||
* this API could be server specific. if we dont reach consensus here, | |||
* we can just drop it. | |||
* i know its a bit clumsy. | |||
* but this api isnt required to be as stable as the client api. | |||
* @} | |||
*/ | |||
/** | |||
* @defgroup JackSessionManagerAPI API for a session manager. | |||
* | |||
* @{ | |||
*/ | |||
typedef struct { | |||
const char *uuid; | |||
const char *client_name; | |||
const char *command; | |||
jack_session_flags_t flags; | |||
const char *uuid; | |||
const char *client_name; | |||
const char *command; | |||
jack_session_flags_t flags; | |||
} jack_session_command_t; | |||
/** | |||
* send a save or quit event, to all clients listening for session | |||
* callbacks. the returned strings of the clients are accumulated and | |||
* returned as an array of jack_session_command_t. | |||
* its terminated by ret[i].uuid == NULL | |||
* target == NULL means send to all interested clients. otherwise a clientname | |||
* Send an event to all clients listening for session callbacks. | |||
* | |||
* The returned strings of the clients are accumulated and returned as an array | |||
* of jack_session_command_t. its terminated by ret[i].uuid == NULL target == | |||
* NULL means send to all interested clients. otherwise a clientname | |||
*/ | |||
jack_session_command_t *jack_session_notify (jack_client_t* client, | |||
const char *target, | |||
jack_session_event_type_t type, | |||
const char *path ) JACK_WEAK_EXPORT; | |||
jack_session_command_t *jack_session_notify ( | |||
jack_client_t* client, | |||
const char *target, | |||
jack_session_event_type_t type, | |||
const char *path) JACK_WEAK_EXPORT; | |||
/** | |||
* free the memory allocated by a session command. | |||
* Free the memory allocated by a session command. | |||
*/ | |||
void jack_session_commands_free (jack_session_command_t *cmds) JACK_WEAK_EXPORT; | |||
/** | |||
* get the sessionid for a client name. | |||
* the sessionmanager needs this to reassociate a client_name to the session_id. | |||
* Get the session ID for a client name. | |||
* The session manager needs this to reassociate a client name to the session_id. | |||
*/ | |||
char *jack_get_uuid_for_client_name( jack_client_t *client, const char *client_name ) JACK_WEAK_EXPORT; | |||
char *jack_get_uuid_for_client_name (jack_client_t *client, | |||
const char *client_name) JACK_WEAK_EXPORT; | |||
/** | |||
* get the client name for a session_id. | |||
* in order to snapshot the graph connections, the sessionmanager needs to map | |||
* Get the client name for a session_id. | |||
* | |||
* In order to snapshot the graph connections, the session manager needs to map | |||
* session_ids to client names. | |||
*/ | |||
char *jack_get_client_name_by_uuid( jack_client_t *client, const char *client_uuid ) JACK_WEAK_EXPORT; | |||
char *jack_get_client_name_by_uuid (jack_client_t *client, | |||
const char *client_uuid ) JACK_WEAK_EXPORT; | |||
/** | |||
* reserve a client name and associate it to a uuid. | |||
* when a client later call jack_client_open() and specifies the uuid, | |||
* jackd will assign the reserved name. | |||
* this allows a session manager to know in advance under which client name | |||
* its managed clients will appear. | |||
* Reserve a client name and associate it with a UUID. | |||
* | |||
* When a client later calls jack_client_open() and specifies the UUID, jackd | |||
* will assign the reserved name. This allows a session manager to know in | |||
* advance under which client name its managed clients will appear. | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int | |||
jack_reserve_client_name (jack_client_t *client, | |||
const char *name, | |||
const char *uuid) JACK_WEAK_EXPORT; | |||
/** | |||
* Find out whether a client has set up a session callback. | |||
* | |||
* @return 0 when the client has no session callback, 1 when it has one. | |||
* -1 on error. | |||
*/ | |||
int | |||
jack_reserve_client_name( jack_client_t *client, const char *name, const char *uuid ) JACK_WEAK_EXPORT; | |||
jack_client_has_session_callback (jack_client_t *client, const char *client_name) JACK_WEAK_EXPORT; | |||
#ifdef __cplusplus | |||
} | |||
@@ -36,15 +36,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
typedef LONGLONG int64_t; | |||
typedef ULONGLONG uint64_t; | |||
#endif | |||
#ifndef pthread_t | |||
typedef HANDLE pthread_t; | |||
#endif | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to HANDLE here. | |||
*/ | |||
typedef HANDLE jack_native_thread_t; | |||
#elif __MINGW32__ /* MINGW */ | |||
#include <stdint.h> | |||
#include <sys/types.h> | |||
#ifndef pthread_t | |||
typedef HANDLE pthread_t; | |||
#endif | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to HANDLE here. | |||
*/ | |||
typedef HANDLE jack_native_thread_t; | |||
#else /* other compilers ...*/ | |||
#include <inttypes.h> | |||
#include <pthread.h> | |||
@@ -57,6 +61,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include <inttypes.h> | |||
#include <pthread.h> | |||
#include <sys/types.h> | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to pthread_t here. | |||
*/ | |||
typedef pthread_t jack_native_thread_t; | |||
#endif /* __APPLE__ || __linux__ || __sun__ || sun */ | |||
#endif |
@@ -28,6 +28,10 @@ extern "C" | |||
#include <jack/systemdeps.h> | |||
#include <jack/weakmacros.h> | |||
/* use 512KB stack per thread - the default is way too high to be feasible | |||
* with mlockall() on many systems */ | |||
#define THREAD_STACK 524288 | |||
/** @file thread.h | |||
* | |||
* Library functions to standardize thread creation for JACK and its | |||
@@ -66,7 +70,7 @@ int jack_client_max_real_time_priority (jack_client_t*) JACK_OPTIONAL_WEAK_EXPOR | |||
* @returns 0, if successful; EPERM, if the calling process lacks | |||
* required realtime privileges; otherwise some other error number. | |||
*/ | |||
int jack_acquire_real_time_scheduling (pthread_t thread, int priority) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_acquire_real_time_scheduling (jack_native_thread_t thread, int priority) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Create a thread for JACK or one of its clients. The thread is | |||
@@ -85,7 +89,7 @@ int jack_acquire_real_time_scheduling (pthread_t thread, int priority) JACK_OPTI | |||
* @returns 0, if successful; otherwise some error number. | |||
*/ | |||
int jack_client_create_thread (jack_client_t* client, | |||
pthread_t *thread, | |||
jack_native_thread_t *thread, | |||
int priority, | |||
int realtime, /* boolean */ | |||
void *(*start_routine)(void*), | |||
@@ -98,7 +102,7 @@ int jack_client_create_thread (jack_client_t* client, | |||
* | |||
* @returns 0, if successful; otherwise an error number. | |||
*/ | |||
int jack_drop_real_time_scheduling (pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_drop_real_time_scheduling (jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Stop the thread, waiting for the thread handler to terminate. | |||
@@ -107,7 +111,7 @@ int jack_drop_real_time_scheduling (pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
* | |||
* @returns 0, if successful; otherwise an error number. | |||
*/ | |||
int jack_client_stop_thread(jack_client_t* client, pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Cancel the thread then waits for the thread handler to terminate. | |||
@@ -116,7 +120,7 @@ int jack_client_stop_thread(jack_client_t* client, pthread_t thread) JACK_OPTION | |||
* | |||
* @returns 0, if successful; otherwise an error number. | |||
*/ | |||
int jack_client_kill_thread(jack_client_t* client, pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT; | |||
#ifndef WIN32 | |||
@@ -74,6 +74,205 @@ typedef uint32_t jack_port_id_t; | |||
typedef uint32_t jack_port_type_id_t; | |||
/** | |||
* @ref jack_options_t bits | |||
*/ | |||
enum JackOptions { | |||
/** | |||
* Null value to use when no option bits are needed. | |||
*/ | |||
JackNullOption = 0x00, | |||
/** | |||
* Do not automatically start the JACK server when it is not | |||
* already running. This option is always selected if | |||
* \$JACK_NO_START_SERVER is defined in the calling process | |||
* environment. | |||
*/ | |||
JackNoStartServer = 0x01, | |||
/** | |||
* Use the exact client name requested. Otherwise, JACK | |||
* automatically generates a unique one, if needed. | |||
*/ | |||
JackUseExactName = 0x02, | |||
/** | |||
* Open with optional <em>(char *) server_name</em> parameter. | |||
*/ | |||
JackServerName = 0x04, | |||
/** | |||
* Load internal client from optional <em>(char *) | |||
* load_name</em>. Otherwise use the @a client_name. | |||
*/ | |||
JackLoadName = 0x08, | |||
/** | |||
* Pass optional <em>(char *) load_init</em> string to the | |||
* jack_initialize() entry point of an internal client. | |||
*/ | |||
JackLoadInit = 0x10, | |||
/** | |||
* pass a SessionID Token this allows the sessionmanager to identify the client again. | |||
*/ | |||
JackSessionID = 0x20 | |||
}; | |||
/** Valid options for opening an external client. */ | |||
#define JackOpenOptions (JackSessionID|JackServerName|JackNoStartServer|JackUseExactName) | |||
/** Valid options for loading an internal client. */ | |||
#define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName) | |||
/** | |||
* Options for several JACK operations, formed by OR-ing together the | |||
* relevant @ref JackOptions bits. | |||
*/ | |||
typedef enum JackOptions jack_options_t; | |||
/** | |||
* @ref jack_status_t bits | |||
*/ | |||
enum JackStatus { | |||
/** | |||
* Overall operation failed. | |||
*/ | |||
JackFailure = 0x01, | |||
/** | |||
* The operation contained an invalid or unsupported option. | |||
*/ | |||
JackInvalidOption = 0x02, | |||
/** | |||
* The desired client name was not unique. With the @ref | |||
* JackUseExactName option this situation is fatal. Otherwise, | |||
* the name was modified by appending a dash and a two-digit | |||
* number in the range "-01" to "-99". The | |||
* jack_get_client_name() function will return the exact string | |||
* that was used. If the specified @a client_name plus these | |||
* extra characters would be too long, the open fails instead. | |||
*/ | |||
JackNameNotUnique = 0x04, | |||
/** | |||
* The JACK server was started as a result of this operation. | |||
* Otherwise, it was running already. In either case the caller | |||
* is now connected to jackd, so there is no race condition. | |||
* When the server shuts down, the client will find out. | |||
*/ | |||
JackServerStarted = 0x08, | |||
/** | |||
* Unable to connect to the JACK server. | |||
*/ | |||
JackServerFailed = 0x10, | |||
/** | |||
* Communication error with the JACK server. | |||
*/ | |||
JackServerError = 0x20, | |||
/** | |||
* Requested client does not exist. | |||
*/ | |||
JackNoSuchClient = 0x40, | |||
/** | |||
* Unable to load internal client | |||
*/ | |||
JackLoadFailure = 0x80, | |||
/** | |||
* Unable to initialize client | |||
*/ | |||
JackInitFailure = 0x100, | |||
/** | |||
* Unable to access shared memory | |||
*/ | |||
JackShmFailure = 0x200, | |||
/** | |||
* Client's protocol version does not match | |||
*/ | |||
JackVersionError = 0x400, | |||
/** | |||
* Backend error | |||
*/ | |||
JackBackendError = 0x800, | |||
/** | |||
* Client zombified failure | |||
*/ | |||
JackClientZombie = 0x1000 | |||
}; | |||
/** | |||
* Status word returned from several JACK operations, formed by | |||
* OR-ing together the relevant @ref JackStatus bits. | |||
*/ | |||
typedef enum JackStatus jack_status_t; | |||
/** | |||
* @ref jack_latency_callback_mode_t | |||
*/ | |||
enum JackLatencyCallbackMode { | |||
/** | |||
* Latency Callback for Capture Latency. | |||
* Input Ports have their latency value setup. | |||
* In the Callback the client needs to set the latency of the output ports | |||
*/ | |||
JackCaptureLatency, | |||
/** | |||
* Latency Callback for Playback Latency. | |||
* Output Ports have their latency value setup. | |||
* In the Callback the client needs to set the latency of the input ports | |||
*/ | |||
JackPlaybackLatency | |||
}; | |||
/** | |||
* Type of Latency Callback (Capture or Playback) | |||
*/ | |||
typedef enum JackLatencyCallbackMode jack_latency_callback_mode_t; | |||
/** | |||
* Prototype for the client supplied function that is called | |||
* by the engine when port latencies need to be recalculated | |||
* | |||
* @param mode playback or capture latency | |||
* @param arg pointer to a client supplied data | |||
* | |||
* @return zero on success, non-zero on error | |||
*/ | |||
typedef void (*JackLatencyCallback)(jack_latency_callback_mode_t mode, void *arg); | |||
/** | |||
* the new latency API operates on Ranges. | |||
*/ | |||
struct _jack_latency_range | |||
{ | |||
/** | |||
* minimum latency | |||
*/ | |||
jack_nframes_t min; | |||
/** | |||
* maximum latency | |||
*/ | |||
jack_nframes_t max; | |||
}; | |||
typedef struct _jack_latency_range jack_latency_range_t; | |||
/** | |||
* Prototype for the client supplied function that is called | |||
* by the engine anytime there is work to be done. | |||
@@ -164,9 +363,12 @@ typedef int (*JackSampleRateCallback)(jack_nframes_t nframes, void *arg); | |||
* Prototype for the client supplied function that is called | |||
* whenever a port is registered or unregistered. | |||
* | |||
* @param arg pointer to a client supplied structure | |||
* @param port the ID of the port | |||
* @param arg pointer to a client supplied data | |||
* @param register non-zero if the port is being registered, | |||
* zero if the port is being unregistered | |||
*/ | |||
typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg); | |||
typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int register, void *arg); | |||
/** | |||
* Prototype for the client supplied function that is called | |||
@@ -177,7 +379,7 @@ typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg | |||
* zero if the client is being unregistered | |||
* @param arg pointer to a client supplied structure | |||
*/ | |||
typedef void (*JackClientRegistrationCallback)(const char* name, int val, void *arg); | |||
typedef void (*JackClientRegistrationCallback)(const char* name, int register, void *arg); | |||
/** | |||
* Prototype for the client supplied function that is called | |||
@@ -214,7 +416,7 @@ typedef void (*JackFreewheelCallback)(int starting, void *arg); | |||
/** | |||
* Prototype for the client supplied function that is called | |||
* whenever jackd is shutdown. Note that after server shutdown, | |||
* whenever jackd is shutdown. Note that after server shutdown, | |||
* the client pointer is *not* deallocated by libjack, | |||
* the application is responsible to properly use jack_client_close() | |||
* to release client ressources. Warning: jack_client_close() cannot be | |||
@@ -225,6 +427,21 @@ typedef void (*JackFreewheelCallback)(int starting, void *arg); | |||
*/ | |||
typedef void (*JackShutdownCallback)(void *arg); | |||
/** | |||
* Prototype for the client supplied function that is called | |||
* whenever jackd is shutdown. Note that after server shutdown, | |||
* the client pointer is *not* deallocated by libjack, | |||
* the application is responsible to properly use jack_client_close() | |||
* to release client ressources. Warning: jack_client_close() cannot be | |||
* safely used inside the shutdown callback and has to be called outside of | |||
* the callback context. | |||
* @param code a status word, formed by OR-ing together the relevant @ref JackStatus bits. | |||
* @param reason a string describing the shutdown reason (backend failure, server crash... etc...) | |||
* @param arg pointer to a client supplied structure | |||
*/ | |||
typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg); | |||
/** | |||
* Used for the type argument of jack_port_register() for default | |||
* audio ports and midi ports. | |||
@@ -295,161 +512,9 @@ enum JackPortFlags { | |||
* their ports. | |||
*/ | |||
JackPortIsTerminal = 0x10, | |||
/** | |||
* JackPortIsActive means the port has been registered and the | |||
* client is "active", that is jack_activate has been called | |||
* | |||
* JackPortIsActive is on between jack_activate and jack_deactivate. | |||
*/ | |||
JackPortIsActive = 0x20 | |||
}; | |||
/** | |||
* @ref jack_options_t bits | |||
*/ | |||
enum JackOptions { | |||
/** | |||
* Null value to use when no option bits are needed. | |||
*/ | |||
JackNullOption = 0x00, | |||
/** | |||
* Do not automatically start the JACK server when it is not | |||
* already running. This option is always selected if | |||
* \$JACK_NO_START_SERVER is defined in the calling process | |||
* environment. | |||
*/ | |||
JackNoStartServer = 0x01, | |||
/** | |||
* Use the exact client name requested. Otherwise, JACK | |||
* automatically generates a unique one, if needed. | |||
*/ | |||
JackUseExactName = 0x02, | |||
/** | |||
* Open with optional <em>(char *) server_name</em> parameter. | |||
*/ | |||
JackServerName = 0x04, | |||
/** | |||
* Load internal client from optional <em>(char *) | |||
* load_name</em>. Otherwise use the @a client_name. | |||
*/ | |||
JackLoadName = 0x08, | |||
/** | |||
* Pass optional <em>(char *) load_init</em> string to the | |||
* jack_initialize() entry point of an internal client. | |||
*/ | |||
JackLoadInit = 0x10, | |||
/** | |||
* pass a SessionID Token this allows the sessionmanager to identify the client again. | |||
*/ | |||
JackSessionID = 0x20 | |||
}; | |||
/** Valid options for opening an external client. */ | |||
#define JackOpenOptions (JackSessionID|JackServerName|JackNoStartServer|JackUseExactName) | |||
/** Valid options for loading an internal client. */ | |||
#define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName) | |||
/** | |||
* Options for several JACK operations, formed by OR-ing together the | |||
* relevant @ref JackOptions bits. | |||
*/ | |||
typedef enum JackOptions jack_options_t; | |||
/** | |||
* @ref jack_status_t bits | |||
*/ | |||
enum JackStatus { | |||
/** | |||
* Overall operation failed. | |||
*/ | |||
JackFailure = 0x01, | |||
/** | |||
* The operation contained an invalid or unsupported option. | |||
*/ | |||
JackInvalidOption = 0x02, | |||
/** | |||
* The desired client name was not unique. With the @ref | |||
* JackUseExactName option this situation is fatal. Otherwise, | |||
* the name was modified by appending a dash and a two-digit | |||
* number in the range "-01" to "-99". The | |||
* jack_get_client_name() function will return the exact string | |||
* that was used. If the specified @a client_name plus these | |||
* extra characters would be too long, the open fails instead. | |||
*/ | |||
JackNameNotUnique = 0x04, | |||
/** | |||
* The JACK server was started as a result of this operation. | |||
* Otherwise, it was running already. In either case the caller | |||
* is now connected to jackd, so there is no race condition. | |||
* When the server shuts down, the client will find out. | |||
*/ | |||
JackServerStarted = 0x08, | |||
/** | |||
* Unable to connect to the JACK server. | |||
*/ | |||
JackServerFailed = 0x10, | |||
/** | |||
* Communication error with the JACK server. | |||
*/ | |||
JackServerError = 0x20, | |||
/** | |||
* Requested client does not exist. | |||
*/ | |||
JackNoSuchClient = 0x40, | |||
/** | |||
* Unable to load internal client | |||
*/ | |||
JackLoadFailure = 0x80, | |||
/** | |||
* Unable to initialize client | |||
*/ | |||
JackInitFailure = 0x100, | |||
/** | |||
* Unable to access shared memory | |||
*/ | |||
JackShmFailure = 0x200, | |||
/** | |||
* Client's protocol version does not match | |||
*/ | |||
JackVersionError = 0x400, | |||
/** | |||
* Backend error | |||
*/ | |||
JackBackendError = 0x800, | |||
/** | |||
* Client zombified failure | |||
*/ | |||
JackClientZombie = 0x1000 | |||
}; | |||
/** | |||
* Status word returned from several JACK operations, formed by | |||
* OR-ing together the relevant @ref JackStatus bits. | |||
*/ | |||
typedef enum JackStatus jack_status_t; | |||
/** | |||
* Transport states. | |||
*/ | |||
@@ -476,7 +541,7 @@ typedef enum { | |||
JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */ | |||
JackAudioVideoRatio = 0x80, /**< audio frames per video frame */ | |||
JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */ | |||
} jack_position_bits_t; | |||
/** all valid position bits */ | |||
@@ -666,19 +731,5 @@ typedef struct { | |||
} jack_transport_info_t; | |||
/** | |||
* Prototype for the client supplied function that is called | |||
* whenever jackd is shutdown. Note that after server shutdown, | |||
* the client pointer is *not* deallocated by libjack, | |||
* the application is responsible to properly use jack_client_close() | |||
* to release client ressources. Warning: jack_client_close() cannot be | |||
* safely used inside the shutdown callback and has to be called outside of | |||
* the callback context. | |||
* @param code a status word, formed by OR-ing together the relevant @ref JackStatus bits. | |||
* @param reason a string describing the shutdown reason (backend failure, server crash... etc...) | |||
* @param arg pointer to a client supplied structure | |||
*/ | |||
typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg); | |||
#endif /* __jack_types_h__ */ |
@@ -1,18 +1,18 @@ | |||
/* | |||
Copyright (C) 2010 Paul Davis | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -20,10 +20,63 @@ | |||
#ifndef __weakjack_h__ | |||
#define __weakjack_h__ | |||
/** | |||
* @defgroup WeakLinkage managing support for newer/older versions of JACK | |||
* @{ One challenge faced by developers is that of taking advantage of new features introduced in new versions of [ JACK ] while still | |||
* supporting older versions of the system. Normally, if an application uses a new feature in a library/API, it is unable to run on | |||
* earlier versions of the library/API that do not support that feature. Such applications would either fail to launch or crash when | |||
* an attempt to use the feature was made. This problem cane be solved using weakly-linked symbols. | |||
* | |||
* When a symbol in a framework is defined as weakly linked, the symbol does not have to be present at runtime for a process to | |||
* continue running. The static linker identifies a weakly linked symbol as such in any code module that references the symbol. The | |||
* dynamic linker uses this same information at runtime to determine whether a process can continue running. If a weakly linked symbol | |||
* is not present in the framework, the code module can continue to run as long as it does not reference the symbol. However, if the | |||
* symbol is present, the code can use it normally. | |||
* | |||
* (adapted from: http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html) | |||
* | |||
* A concrete example will help. Suppose that someone uses a version | |||
* of a JACK client we'll call "Jill". Jill was linked against a version | |||
* of JACK that contains a newer part of the API (say, jack_set_latency_callback()) | |||
* and would like to use it if it is available. | |||
* | |||
* When Jill is run on a system that has a suitably "new" version of | |||
* JACK, this function will be available entirely normally. But if Jill | |||
* is run on a system with an old version of JACK, the function isn't | |||
* available. | |||
* | |||
* With normal symbol linkage, this would create a startup error whenever | |||
* someone tries to run Jill with the "old" version of JACK. However, functions | |||
* added to JACK after version 0.116.2 are all declared to have "weak" linkage | |||
* which means that their abscence doesn't cause an error during program | |||
* startup. Instead, Jill can test whether or not the symbol jack_set_latency_callback | |||
* is null or not. If its null, it means that the JACK installed on this machine | |||
* is too old to support this function. If its not null, then Jill can use it | |||
* just like any other function in the API. For example: | |||
* | |||
* \code | |||
* if (jack_set_latency_callback) { | |||
* jack_set_latency_callback (jill_client, jill_latency_callback, arg); | |||
* } | |||
* \endcode | |||
* | |||
* However, there are clients that may want to use this approach to parts of the | |||
* the JACK API that predate 0.116.2. For example, they might want to see if even | |||
* really old basic parts of the API like jack_client_open() exist at runtime. | |||
* | |||
* Such clients should include <jack/weakjack.h> before any other JACK header. | |||
* This will make the \b entire JACK API be subject to weak linkage, so that any | |||
* and all functions can be checked for existence at runtime. It is important | |||
* to understand that very few clients need to do this - if you use this | |||
* feature you should have a clear reason to do so. | |||
* | |||
* | |||
*/ | |||
#ifndef JACK_OPTIONAL_WEAK_EXPORT | |||
/* JACK_OPTIONAL_WEAK_EXPORT needs to be a macro which | |||
expands into a compiler directive. If non-null, the directive | |||
must tell the compiler to arrange for weak linkage of | |||
expands into a compiler directive. If non-null, the directive | |||
must tell the compiler to arrange for weak linkage of | |||
the symbol it used with. For this to work fully may | |||
require linker arguments for the client as well. | |||
*/ | |||
@@ -49,4 +102,6 @@ | |||
#endif | |||
#endif | |||
/*@}*/ | |||
#endif /* weakjack */ |
@@ -1,18 +1,18 @@ | |||
/* | |||
Copyright (C) 2010 Paul Davis | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -23,27 +23,31 @@ | |||
/************************************************************* | |||
* NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function | |||
* added to the JACK API after the 0.116.2 release. | |||
* | |||
* Functions that predate this release are marked with | |||
* | |||
* Functions that predate this release are marked with | |||
* JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile | |||
* time in a variety of ways. The default definition is empty, | |||
* so that these symbols get normal linkage. If you wish to | |||
* use all JACK symbols with weak linkage, include | |||
* use all JACK symbols with weak linkage, include | |||
* <jack/weakjack.h> before jack.h. | |||
*************************************************************/ | |||
#ifndef JACK_WEAK_EXPORT | |||
#ifdef __GNUC__ | |||
/* JACK_WEAK_EXPORT needs to be a macro which | |||
expands into a compiler directive. If non-null, the directive | |||
must tell the compiler to arrange for weak linkage of | |||
expands into a compiler directive. If non-null, the directive | |||
must tell the compiler to arrange for weak linkage of | |||
the symbol it used with. For this to work full may | |||
require linker arguments in the client as well. | |||
*/ | |||
#define JACK_WEAK_EXPORT __attribute__((weak)) | |||
#else | |||
/* Add other things here for non-gcc platforms */ | |||
#define JACK_WEAK_EXPORT | |||
#ifdef WIN32 | |||
#define JACK_WEAK_EXPORT | |||
#endif | |||
#endif | |||
#endif | |||
@@ -54,9 +58,13 @@ | |||
#ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
#ifdef __GNUC__ | |||
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__)) | |||
#else | |||
#else | |||
/* Add other things here for non-gcc platforms */ | |||
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
#ifdef WIN32 | |||
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
#endif | |||
#endif /* __GNUC__ */ | |||
#endif | |||
@@ -25,7 +25,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
$Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
*/ | |||
#include <math.h> | |||
#include <stdio.h> | |||
#include <memory.h> | |||
@@ -48,8 +47,6 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
#include <netinet/in.h> | |||
#endif | |||
#include "netjack.h" | |||
#ifdef __linux__ | |||
#include "config.h" | |||
#endif | |||
@@ -58,15 +55,11 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
#include <samplerate.h> | |||
#endif | |||
#if HAVE_CELT | |||
#include <celt/celt.h> | |||
#endif | |||
#include "netjack.h" | |||
#include "netjack_packet.h" | |||
// JACK2 | |||
#include "jack/control.h" | |||
#include "control.h" | |||
#define MIN(x,y) ((x)<(y) ? (x) : (y)) | |||
@@ -105,8 +98,8 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
netj->expected_framecnt += 1; | |||
} else { | |||
// starting up.... lets look into the packetcache, and fetch the highest packet. | |||
packet_cache_drain_socket( global_packcache, netj->sockfd ); | |||
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail ) ) { | |||
packet_cache_drain_socket( netj->packcache, netj->sockfd ); | |||
if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail ) ) { | |||
netj->expected_framecnt = next_frame_avail; | |||
netj->expected_framecnt_valid = 1; | |||
} else { | |||
@@ -122,7 +115,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// then poll (have deadline calculated) | |||
// then drain socket, rinse and repeat. | |||
while(1) { | |||
if( packet_cache_get_next_available_framecnt( global_packcache, netj->expected_framecnt, &next_frame_avail) ) { | |||
if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) { | |||
if( next_frame_avail == netj->expected_framecnt ) { | |||
we_have_the_expected_frame = 1; | |||
if( !netj->always_deadline ) | |||
@@ -133,13 +126,13 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
break; | |||
} | |||
packet_cache_drain_socket( global_packcache, netj->sockfd ); | |||
packet_cache_drain_socket( netj->packcache, netj->sockfd ); | |||
} | |||
// check if we know who to send our packets too. | |||
if (!netj->srcaddress_valid) | |||
if( global_packcache->master_address_valid ) { | |||
memcpy (&(netj->syncsource_address), &(global_packcache->master_address), sizeof( struct sockaddr_in ) ); | |||
if( netj->packcache->master_address_valid ) { | |||
memcpy (&(netj->syncsource_address), &(netj->packcache->master_address), sizeof( struct sockaddr_in ) ); | |||
netj->srcaddress_valid = 1; | |||
} | |||
@@ -161,7 +154,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
else | |||
netj->time_to_deadline = 0; | |||
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp); | |||
packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp); | |||
pkthdr = (jacknet_packet_header *) netj->rx_buf; | |||
packet_header_ntoh(pkthdr); | |||
netj->deadline_goodness = (int)pkthdr->sync_state; | |||
@@ -203,7 +196,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// lets check if we have the next packets, we will just run a cycle without data. | |||
// in that case. | |||
if( packet_cache_get_next_available_framecnt( global_packcache, netj->expected_framecnt, &next_frame_avail) ) | |||
if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) | |||
{ | |||
jack_nframes_t offset = next_frame_avail - netj->expected_framecnt; | |||
@@ -221,7 +214,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// I also found this happening, when the packet queue, is too full. | |||
// but wtf ? use a smaller latency. this link can handle that ;S | |||
if( packet_cache_get_fill( global_packcache, netj->expected_framecnt ) > 80.0 ) | |||
if( packet_cache_get_fill( netj->packcache, netj->expected_framecnt ) > 80.0 ) | |||
netj->next_deadline -= netj->period_usecs/2; | |||
@@ -229,7 +222,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// the diff is too high. but we have a packet in the future. | |||
// lets resync. | |||
netj->expected_framecnt = next_frame_avail; | |||
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
pkthdr = (jacknet_packet_header *) netj->rx_buf; | |||
packet_header_ntoh(pkthdr); | |||
//netj->deadline_goodness = 0; | |||
@@ -257,7 +250,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// i will make the packet cache drop redundant packets, | |||
// that have already been retreived. | |||
// | |||
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) { | |||
if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) { | |||
if( next_frame_avail == (netj->expected_framecnt - 1) ) { | |||
// Ok. the last packet is there now. | |||
// and it had not been retrieved. | |||
@@ -277,9 +270,9 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// But now we can check for any new frame available. | |||
// | |||
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) { | |||
if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) { | |||
netj->expected_framecnt = next_frame_avail; | |||
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL ); | |||
pkthdr = (jacknet_packet_header *) netj->rx_buf; | |||
packet_header_ntoh(pkthdr); | |||
netj->deadline_goodness = pkthdr->sync_state; | |||
@@ -300,7 +293,7 @@ int netjack_wait( netjack_driver_state_t *netj ) | |||
// reply address changes port. | |||
if (netj->num_lost_packets > 200 ) { | |||
netj->srcaddress_valid = 0; | |||
packet_cache_reset_master_address( global_packcache ); | |||
packet_cache_reset_master_address( netj->packcache ); | |||
} | |||
} | |||
} | |||
@@ -369,6 +362,21 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
int port_flags; | |||
if( netj->bitdepth == CELT_MODE ) | |||
{ | |||
#if HAVE_CELT | |||
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
celt_int32 lookahead; | |||
netj->celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); | |||
#else | |||
celt_int32_t lookahead; | |||
netj->celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL ); | |||
#endif | |||
celt_mode_info( netj->celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); | |||
netj->codec_latency = 2*lookahead; | |||
#endif | |||
} | |||
if (netj->handle_transport_sync) | |||
jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL); | |||
@@ -390,17 +398,11 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
if( netj->bitdepth == CELT_MODE ) { | |||
#if HAVE_CELT | |||
#if HAVE_CELT_API_0_7 | |||
celt_int32 lookahead; | |||
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); | |||
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); | |||
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode, 1, NULL ) ); | |||
#else | |||
celt_int32_t lookahead; | |||
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL ); | |||
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode ) ); | |||
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode ) ); | |||
#endif | |||
celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); | |||
netj->codec_latency = 2*lookahead; | |||
#endif | |||
} else { | |||
#if HAVE_SAMPLERATE | |||
@@ -408,6 +410,7 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
#endif | |||
} | |||
} | |||
for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) { | |||
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1); | |||
@@ -441,7 +444,7 @@ void netjack_attach( netjack_driver_state_t *netj ) | |||
jack_slist_append (netj->playback_ports, port); | |||
if( netj->bitdepth == CELT_MODE ) { | |||
#if HAVE_CELT | |||
#if HAVE_CELT_API_0_7 | |||
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); | |||
netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); | |||
#else | |||
@@ -479,7 +482,6 @@ void netjack_detach( netjack_driver_state_t *netj ) | |||
{ | |||
JSList * node; | |||
for (node = netj->capture_ports; node; node = jack_slist_next (node)) | |||
jack_port_unregister (netj->client, | |||
((jack_port_t *) node->data)); | |||
@@ -487,12 +489,57 @@ void netjack_detach( netjack_driver_state_t *netj ) | |||
jack_slist_free (netj->capture_ports); | |||
netj->capture_ports = NULL; | |||
for (node = netj->capture_srcs; node; node = jack_slist_next (node)) | |||
{ | |||
#if HAVE_CELT | |||
if( netj->bitdepth == CELT_MODE ) | |||
{ | |||
CELTDecoder * decoder = node->data; | |||
celt_decoder_destroy(decoder); | |||
} | |||
else | |||
#endif | |||
{ | |||
#if HAVE_SAMPLERATE | |||
SRC_STATE * src = node->data; | |||
src_delete(src); | |||
#endif | |||
} | |||
} | |||
jack_slist_free (netj->capture_srcs); | |||
netj->playback_srcs = NULL; | |||
for (node = netj->playback_ports; node; node = jack_slist_next (node)) | |||
jack_port_unregister (netj->client, | |||
((jack_port_t *) node->data)); | |||
jack_slist_free (netj->playback_ports); | |||
netj->playback_ports = NULL; | |||
for (node = netj->playback_srcs; node; node = jack_slist_next (node)) | |||
{ | |||
#if HAVE_CELT | |||
if( netj->bitdepth == CELT_MODE ) | |||
{ | |||
CELTEncoder * encoder = node->data; | |||
celt_encoder_destroy(encoder); | |||
} | |||
else | |||
#endif | |||
{ | |||
#if HAVE_SAMPLERATE | |||
SRC_STATE * src = node->data; | |||
src_delete(src); | |||
#endif | |||
} | |||
} | |||
jack_slist_free (netj->playback_srcs); | |||
netj->playback_srcs = NULL; | |||
#if HAVE_CELT | |||
if( netj->bitdepth == CELT_MODE ) | |||
celt_mode_destroy(netj->celt_mode); | |||
#endif | |||
} | |||
@@ -574,8 +621,8 @@ void netjack_release( netjack_driver_state_t *netj ) | |||
close( netj->sockfd ); | |||
close( netj->outsockfd ); | |||
packet_cache_free( global_packcache ); | |||
global_packcache = NULL; | |||
packet_cache_free( netj->packcache ); | |||
netj->packcache = NULL; | |||
} | |||
int | |||
@@ -585,13 +632,7 @@ netjack_startup( netjack_driver_state_t *netj ) | |||
struct sockaddr_in address; | |||
// Now open the socket, and wait for the first packet to arrive... | |||
netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); | |||
#ifdef WIN32 | |||
u_long parm = 1; | |||
DWORD bufsize = 262144; | |||
//ioctlsocket( netj->sockfd, FIONBIO, &parm ); | |||
setsockopt( netj->sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize) ); | |||
setsockopt( netj->sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize) ); | |||
if (netj->sockfd == INVALID_SOCKET) | |||
#else | |||
if (netj->sockfd == -1) | |||
@@ -632,6 +673,10 @@ netjack_startup( netjack_driver_state_t *netj ) | |||
//jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); | |||
while(1) { | |||
if( ! netjack_poll( netj->sockfd, 1000 ) ) { | |||
jack_info ("Waiting aborted"); | |||
return -1; | |||
} | |||
first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); | |||
#ifdef WIN32 | |||
if( first_pack_len == -1 ) { | |||
@@ -735,7 +780,7 @@ netjack_startup( netjack_driver_state_t *netj ) | |||
} | |||
netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth); | |||
global_packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu); | |||
netj->packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu); | |||
netj->expected_framecnt_valid = 0; | |||
netj->num_lost_packets = 0; | |||
@@ -30,6 +30,10 @@ | |||
#include "jack/jslist.h" | |||
#if HAVE_CELT | |||
#include <celt/celt.h> | |||
#endif | |||
//#include <netinet/in.h> | |||
#ifdef __cplusplus | |||
@@ -37,6 +41,8 @@ extern "C" | |||
{ | |||
#endif | |||
struct _packet_cache; | |||
typedef struct _netjack_driver_state netjack_driver_state_t; | |||
struct _netjack_driver_state { | |||
@@ -106,6 +112,10 @@ struct _netjack_driver_state { | |||
unsigned int resample_factor; | |||
unsigned int resample_factor_up; | |||
int jitter_val; | |||
struct _packet_cache * packcache; | |||
#if HAVE_CELT | |||
CELTMode *celt_mode; | |||
#endif | |||
}; | |||
int netjack_wait( netjack_driver_state_t *netj ); | |||
@@ -75,7 +75,7 @@ | |||
#include "netjack_packet.h" | |||
// JACK2 specific. | |||
#include "jack/control.h" | |||
#include "control.h" | |||
#ifdef NO_JACK_ERROR | |||
#define jack_error printf | |||
@@ -83,8 +83,6 @@ | |||
int fraggo = 0; | |||
packet_cache *global_packcache = NULL; | |||
void | |||
packet_header_hton (jacknet_packet_header *pkthdr) | |||
{ | |||
@@ -388,7 +386,7 @@ netjack_poll_deadline (int sockfd, jack_time_t deadline) | |||
#if HAVE_PPOLL | |||
timeout_spec.tv_nsec = (deadline - now) * 1000; | |||
#else | |||
timeout = (deadline - now + 500) / 1000; | |||
timeout = lrintf( (float)(deadline - now) / 1000.0 ); | |||
#endif | |||
@@ -565,7 +563,7 @@ packet_cache_drain_socket( packet_cache *pcache, int sockfd ) | |||
if( pcache->last_framecnt_retreived_valid && (framecnt <= pcache->last_framecnt_retreived )) | |||
continue; | |||
cpack = packet_cache_get_packet (global_packcache, framecnt); | |||
cpack = packet_cache_get_packet (pcache, framecnt); | |||
cache_packet_add_fragment (cpack, rx_packet, rcv_len); | |||
cpack->recv_timestamp = jack_get_time(); | |||
} | |||
@@ -774,61 +772,6 @@ packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecn | |||
return retval; | |||
} | |||
// fragmented packet IO | |||
int | |||
netjack_recvfrom (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, size_t *addr_size, int mtu) | |||
{ | |||
int retval; | |||
socklen_t from_len = *addr_size; | |||
if (pkt_size <= mtu) { | |||
retval = recvfrom (sockfd, packet_buf, pkt_size, flags, addr, &from_len); | |||
*addr_size = from_len; | |||
return retval; | |||
} | |||
char *rx_packet = alloca (mtu); | |||
jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet; | |||
int rcv_len; | |||
jack_nframes_t framecnt; | |||
cache_packet *cpack; | |||
do | |||
{ | |||
rcv_len = recvfrom (sockfd, rx_packet, mtu, 0, addr, &from_len); | |||
if (rcv_len < 0) | |||
return rcv_len; | |||
framecnt = ntohl (pkthdr->framecnt); | |||
cpack = packet_cache_get_packet (global_packcache, framecnt); | |||
cache_packet_add_fragment (cpack, rx_packet, rcv_len); | |||
} while (!cache_packet_is_complete (cpack)); | |||
memcpy (packet_buf, cpack->packet_buf, pkt_size); | |||
cache_packet_reset (cpack); | |||
*addr_size = from_len; | |||
return pkt_size; | |||
} | |||
int | |||
netjack_recv (int sockfd, char *packet_buf, int pkt_size, int flags, int mtu) | |||
{ | |||
if (pkt_size <= mtu) | |||
return recv (sockfd, packet_buf, pkt_size, flags); | |||
char *rx_packet = alloca (mtu); | |||
jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet; | |||
int rcv_len; | |||
jack_nframes_t framecnt; | |||
cache_packet *cpack; | |||
do | |||
{ | |||
rcv_len = recv (sockfd, rx_packet, mtu, flags); | |||
if (rcv_len < 0) | |||
return rcv_len; | |||
framecnt = ntohl (pkthdr->framecnt); | |||
cpack = packet_cache_get_packet (global_packcache, framecnt); | |||
cache_packet_add_fragment (cpack, rx_packet, rcv_len); | |||
} while (!cache_packet_is_complete (cpack)); | |||
memcpy (packet_buf, cpack->packet_buf, pkt_size); | |||
cache_packet_reset (cpack); | |||
return pkt_size; | |||
} | |||
void | |||
netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu) | |||
{ | |||
@@ -1427,10 +1370,17 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri | |||
// audio port, decode celt data. | |||
CELTDecoder *decoder = src_node->data; | |||
#if HAVE_CELT_API_0_8 | |||
if( !packet_payload ) | |||
celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); | |||
else | |||
celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); | |||
#else | |||
if( !packet_payload ) | |||
celt_decode_float( decoder, NULL, net_period_down, buf ); | |||
else | |||
celt_decode_float( decoder, packet_bufX, net_period_down, buf ); | |||
#endif | |||
src_node = jack_slist_next (src_node); | |||
} | |||
@@ -1472,7 +1422,11 @@ render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs | |||
float *floatbuf = alloca (sizeof(float) * nframes ); | |||
memcpy( floatbuf, buf, nframes*sizeof(float) ); | |||
CELTEncoder *encoder = src_node->data; | |||
#if HAVE_CELT_API_0_8 | |||
encoded_bytes = celt_encode_float( encoder, floatbuf, nframes, packet_bufX, net_period_up ); | |||
#else | |||
encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); | |||
#endif | |||
if( encoded_bytes != net_period_up ) | |||
printf( "something in celt changed. netjack needs to be changed to handle this.\n" ); | |||
src_node = jack_slist_next( src_node ); | |||
@@ -107,8 +107,6 @@ struct _packet_cache | |||
int last_framecnt_retreived_valid; | |||
}; | |||
extern packet_cache *global_packcache; | |||
// fragment cache function prototypes | |||
// XXX: Some of these are private. | |||
packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu); | |||
@@ -152,10 +150,6 @@ void render_jack_ports_to_payload(int bitdepth, JSList *playback_ports, JSList * | |||
// This one waits forever. an is not using ppoll | |||
int netjack_poll(int sockfd, int timeout); | |||
// TODO: these are deprecated. | |||
//int netjack_recvfrom(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, socklen_t *addr_size, int mtu); | |||
//int netjack_recv(int sockfd, char *packet_buf, int pkt_size, int flags, int mtu); | |||
void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); | |||
void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); | |||
#ifdef __cplusplus | |||
@@ -1,24 +1,25 @@ | |||
/* | |||
Copyright (C) 2002-2003 Paul Davis | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <inttypes.h> | |||
#include "timestamps.h" | |||
#include "JackTime.h" | |||
@@ -60,7 +61,7 @@ jack_dump_timestamps (FILE *out) | |||
unsigned long i; | |||
for (i = 0; i < timestamp_index; ++i) { | |||
fprintf (out, "%-.32s %" PRIu64 " %" PRIu64, | |||
fprintf (out, "%-.32s %" PRIu64 " %" PRIu64, | |||
timestamps[i].what, timestamps[i].when, | |||
timestamps[i].when - timestamps[0].when); | |||
if (i > 0) { | |||
@@ -11,12 +11,11 @@ | |||
#include <string.h> | |||
#include <signal.h> | |||
#include <alloca.h> | |||
#include <math.h> | |||
#include <jack/jack.h> | |||
#include <jack/jslist.h> | |||
#include <memops.h> | |||
#include <jack/memops.h> | |||
#include "alsa/asoundlib.h" | |||
@@ -77,6 +76,12 @@ volatile float output_diff = 0.0; | |||
snd_pcm_uframes_t real_buffer_size; | |||
snd_pcm_uframes_t real_period_size; | |||
// buffers | |||
char *tmpbuf; | |||
char *outbuf; | |||
float *resampbuf; | |||
// format selection, and corresponding functions from memops in a nice set of structs. | |||
typedef struct alsa_format { | |||
@@ -307,8 +312,6 @@ double hann( double x ) | |||
*/ | |||
int process (jack_nframes_t nframes, void *arg) { | |||
char *outbuf; | |||
float *resampbuf; | |||
int rlen; | |||
int err; | |||
snd_pcm_sframes_t delay = target_delay; | |||
@@ -322,10 +325,15 @@ int process (jack_nframes_t nframes, void *arg) { | |||
// this is for compensating xruns etc... | |||
if( delay > (target_delay+max_diff) ) { | |||
char *tmp = alloca( (delay-target_delay) * formats[format].sample_size * num_channels ); | |||
snd_pcm_readi( alsa_handle, tmp, delay-target_delay ); | |||
output_new_delay = (int) delay; | |||
while ((delay-target_delay) > 0) { | |||
snd_pcm_uframes_t to_read = ((delay-target_delay) > 512) ? 512 : (delay-target_delay); | |||
snd_pcm_readi( alsa_handle, tmpbuf, to_read ); | |||
delay -= to_read; | |||
} | |||
delay = target_delay; | |||
// Set the resample_rate... we need to adjust the offset integral, to do this. | |||
@@ -399,13 +407,6 @@ int process (jack_nframes_t nframes, void *arg) { | |||
// Calculate resample_mean so we can init ourselves to saner values. | |||
resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; | |||
/* | |||
* now this should do it... | |||
*/ | |||
outbuf = alloca( rlen * formats[format].sample_size * num_channels ); | |||
resampbuf = alloca( rlen * sizeof( float ) ); | |||
// get the data... | |||
again: | |||
@@ -465,6 +466,32 @@ again: | |||
return 0; | |||
} | |||
/** | |||
* the latency callback. | |||
* sets up the latencies on the ports. | |||
*/ | |||
void | |||
latency_cb (jack_latency_callback_mode_t mode, void *arg) | |||
{ | |||
jack_latency_range_t range; | |||
JSList *node; | |||
range.min = range.max = target_delay; | |||
if (mode == JackCaptureLatency) { | |||
for (node = capture_ports; node; node = jack_slist_next (node)) { | |||
jack_port_t *port = node->data; | |||
jack_port_set_latency_range (port, mode, &range); | |||
} | |||
} else { | |||
for (node = playback_ports; node; node = jack_slist_next (node)) { | |||
jack_port_t *port = node->data; | |||
jack_port_set_latency_range (port, mode, &range); | |||
} | |||
} | |||
} | |||
/** | |||
* Allocate the necessary jack ports... | |||
@@ -661,6 +688,8 @@ int main (int argc, char *argv[]) { | |||
jack_on_shutdown (client, jack_shutdown, 0); | |||
if (jack_set_latency_callback) | |||
jack_set_latency_callback (client, latency_cb, 0); | |||
// get jack sample_rate | |||
@@ -716,6 +745,17 @@ int main (int argc, char *argv[]) { | |||
// alloc input ports, which are blasted out to alsa... | |||
alloc_ports( num_channels, 0 ); | |||
outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels ); | |||
resampbuf = malloc( num_periods * period_size * sizeof( float ) ); | |||
tmpbuf = malloc( 512 * formats[format].sample_size * num_channels ); | |||
if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL)) | |||
{ | |||
fprintf( stderr, "no memory for buffers.\n" ); | |||
exit(20); | |||
} | |||
memset( tmpbuf, 0, 512 * formats[format].sample_size * num_channels); | |||
/* tell the JACK server that we are ready to roll */ | |||
@@ -11,12 +11,11 @@ | |||
#include <string.h> | |||
#include <signal.h> | |||
#include <alloca.h> | |||
#include <math.h> | |||
#include <jack/jack.h> | |||
#include <jack/jslist.h> | |||
#include <memops.h> | |||
#include <jack/memops.h> | |||
#include "alsa/asoundlib.h" | |||
@@ -35,6 +34,7 @@ snd_pcm_t *alsa_handle; | |||
int jack_sample_rate; | |||
int jack_buffer_size; | |||
int quit = 0; | |||
double resample_mean = 1.0; | |||
double static_resample_factor = 1.0; | |||
double resample_lower_limit = 0.25; | |||
@@ -45,7 +45,6 @@ double *window_array; | |||
int offset_differential_index = 0; | |||
double offset_integral = 0; | |||
int quit = 0; | |||
// ------------------------------------------------------ commandline parameters | |||
@@ -77,6 +76,12 @@ volatile float output_diff = 0.0; | |||
snd_pcm_uframes_t real_buffer_size; | |||
snd_pcm_uframes_t real_period_size; | |||
// buffers | |||
char *tmpbuf; | |||
char *outbuf; | |||
float *resampbuf; | |||
// format selection, and corresponding functions from memops in a nice set of structs. | |||
typedef struct alsa_format { | |||
@@ -90,6 +95,7 @@ typedef struct alsa_format { | |||
alsa_format_t formats[] = { | |||
{ SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, | |||
{ SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, | |||
{ SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, | |||
{ SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, | |||
{ SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } | |||
}; | |||
@@ -311,8 +317,6 @@ double hann( double x ) | |||
*/ | |||
int process (jack_nframes_t nframes, void *arg) { | |||
char *outbuf; | |||
float *resampbuf; | |||
int rlen; | |||
int err; | |||
snd_pcm_sframes_t delay = target_delay; | |||
@@ -321,7 +325,6 @@ int process (jack_nframes_t nframes, void *arg) { | |||
delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; | |||
delay -= jack_frames_since_cycle_start( client ); | |||
delay += jack_get_buffer_size( client ) / 2; | |||
// Do it the hard way. | |||
// this is for compensating xruns etc... | |||
@@ -340,12 +343,15 @@ int process (jack_nframes_t nframes, void *arg) { | |||
offset_array[i] = 0.0; | |||
} | |||
if( delay < (target_delay-max_diff) ) { | |||
char *tmp = alloca( (target_delay-delay) * formats[format].sample_size * num_channels ); | |||
memset( tmp, 0, formats[format].sample_size * num_channels * (target_delay-delay) ); | |||
snd_pcm_writei( alsa_handle, tmp, target_delay-delay ); | |||
output_new_delay = (int) delay; | |||
while ((target_delay-delay) > 0) { | |||
snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); | |||
snd_pcm_writei( alsa_handle, tmpbuf, to_write ); | |||
delay += to_write; | |||
} | |||
delay = target_delay; | |||
// Set the resample_rate... we need to adjust the offset integral, to do this. | |||
@@ -463,6 +469,32 @@ again: | |||
return 0; | |||
} | |||
/** | |||
* the latency callback. | |||
* sets up the latencies on the ports. | |||
*/ | |||
void | |||
latency_cb (jack_latency_callback_mode_t mode, void *arg) | |||
{ | |||
jack_latency_range_t range; | |||
JSList *node; | |||
range.min = range.max = target_delay; | |||
if (mode == JackCaptureLatency) { | |||
for (node = capture_ports; node; node = jack_slist_next (node)) { | |||
jack_port_t *port = node->data; | |||
jack_port_set_latency_range (port, mode, &range); | |||
} | |||
} else { | |||
for (node = playback_ports; node; node = jack_slist_next (node)) { | |||
jack_port_t *port = node->data; | |||
jack_port_set_latency_range (port, mode, &range); | |||
} | |||
} | |||
} | |||
/** | |||
* Allocate the necessary jack ports... | |||
@@ -659,6 +691,8 @@ int main (int argc, char *argv[]) { | |||
jack_on_shutdown (client, jack_shutdown, 0); | |||
if (jack_set_latency_callback) | |||
jack_set_latency_callback (client, latency_cb, 0); | |||
// get jack sample_rate | |||
@@ -714,6 +748,16 @@ int main (int argc, char *argv[]) { | |||
// alloc input ports, which are blasted out to alsa... | |||
alloc_ports( 0, num_channels ); | |||
outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels ); | |||
resampbuf = malloc( num_periods * period_size * sizeof( float ) ); | |||
tmpbuf = malloc( 512 * formats[format].sample_size * num_channels ); | |||
if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL)) | |||
{ | |||
fprintf( stderr, "no memory for buffers.\n" ); | |||
exit(20); | |||
} | |||
/* tell the JACK server that we are ready to roll */ | |||
@@ -2,7 +2,7 @@ | |||
* bufsize.c -- change JACK buffer size. | |||
* | |||
* Copyright (C) 2003 Jack O'Quin. | |||
* | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 2 of the License, or | |||
@@ -64,12 +64,23 @@ void parse_arguments(int argc, char *argv[]) | |||
exit(9); | |||
} | |||
if (strspn (argv[1], "0123456789") != strlen (argv[1])) { | |||
fprintf(stderr, "usage: %s <bufsize>\n", package); | |||
exit(8); | |||
} | |||
nframes = strtoul(argv[1], NULL, 0); | |||
if (errno == ERANGE) { | |||
fprintf(stderr, "%s: invalid buffer size: %s\n", | |||
fprintf(stderr, "%s: invalid buffer size: %s (range is 1-8182)\n", | |||
package, argv[1]); | |||
exit(2); | |||
} | |||
if (nframes < 1 || nframes > 8182) { | |||
fprintf(stderr, "%s: invalid buffer size: %s (range is 1-8182)\n", | |||
package, argv[1]); | |||
exit(3); | |||
} | |||
} | |||
int main(int argc, char *argv[]) | |||
@@ -24,7 +24,9 @@ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#include <math.h> | |||
#include <getopt.h> | |||
#include <jack/jack.h> | |||
#include <jack/session.h> | |||
jack_port_t *input_port; | |||
jack_port_t *output_port; | |||
@@ -33,17 +35,84 @@ int done = 0; | |||
#define TRUE 1 | |||
#define FALSE 0 | |||
void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) | |||
{ | |||
done = 1; | |||
} | |||
void | |||
show_version (char *my_name) | |||
{ | |||
//fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name); | |||
} | |||
void | |||
show_usage (char *my_name) | |||
{ | |||
show_version (my_name); | |||
fprintf (stderr, "\nusage: %s [options] port1 port2\n", my_name); | |||
fprintf (stderr, "Connects two JACK ports together.\n\n"); | |||
fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n"); | |||
fprintf (stderr, " -v, --version Output version information and exit\n"); | |||
fprintf (stderr, " -h, --help Display this help message\n\n"); | |||
fprintf (stderr, "For more information see http://jackaudio.org/\n"); | |||
} | |||
int | |||
main (int argc, char *argv[]) | |||
{ | |||
jack_client_t* client = NULL; | |||
jack_client_t *client; | |||
jack_status_t status; | |||
char *server_name = NULL; | |||
int c; | |||
int option_index; | |||
jack_options_t options = JackNoStartServer; | |||
char *my_name = strrchr(argv[0], '/'); | |||
jack_port_t *src_port = 0; | |||
jack_port_t *dst_port = 0; | |||
jack_port_t *port1 = 0; | |||
jack_port_t *port2 = 0; | |||
char portA[300]; | |||
char portB[300]; | |||
int use_uuid=0; | |||
int connecting, disconnecting; | |||
int port1_flags, port2_flags; | |||
int rc = 1; | |||
struct option long_options[] = { | |||
{ "server", 1, 0, 's' }, | |||
{ "help", 0, 0, 'h' }, | |||
{ "version", 0, 0, 'v' }, | |||
{ "uuid", 0, 0, 'u' }, | |||
{ 0, 0, 0, 0 } | |||
}; | |||
while ((c = getopt_long (argc, argv, "s:hvu", long_options, &option_index)) >= 0) { | |||
switch (c) { | |||
case 's': | |||
server_name = (char *) malloc (sizeof (char) * strlen(optarg)); | |||
strcpy (server_name, optarg); | |||
options |= JackServerName; | |||
break; | |||
case 'u': | |||
use_uuid = 1; | |||
break; | |||
case 'h': | |||
show_usage (my_name); | |||
return 1; | |||
break; | |||
case 'v': | |||
show_version (my_name); | |||
return 1; | |||
break; | |||
default: | |||
show_usage (my_name); | |||
return 1; | |||
break; | |||
} | |||
} | |||
connecting = disconnecting = FALSE; | |||
if (my_name == 0) { | |||
my_name = argv[0]; | |||
@@ -51,90 +120,121 @@ main (int argc, char *argv[]) | |||
my_name ++; | |||
} | |||
printf("name %s\n", my_name); | |||
if (strstr(my_name, "jack_disconnect")) { | |||
disconnecting = TRUE; | |||
} else | |||
if (strstr(my_name, "jack_connect")) { | |||
connecting = TRUE; | |||
if (strstr(my_name, "disconnect")) { | |||
disconnecting = 1; | |||
} else if (strstr(my_name, "connect")) { | |||
connecting = 1; | |||
} else { | |||
fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); | |||
return 1; | |||
} | |||
if (argc != 3) { | |||
fprintf (stderr, "usage: %s <src_port> <dst_port>\n", my_name); | |||
fprintf(stderr, "The source port must be an output port of the source client.\n"); | |||
fprintf (stderr, "The destination port must be an input port of the destination client.\n"); | |||
return 1; | |||
} | |||
if (argc < 3) show_usage(my_name); | |||
/* try to become a client of the JACK server */ | |||
if ((client = jack_client_open (my_name, JackNullOption, NULL)) == 0) { | |||
if ((client = jack_client_open (my_name, options, &status, server_name)) == 0) { | |||
fprintf (stderr, "jack server not running?\n"); | |||
return 1; | |||
} | |||
jack_set_port_connect_callback(client, port_connect_callback, NULL); | |||
/* display the current sample rate. once the client is activated | |||
(see below), you should rely on your own sample rate | |||
callback (see above) for this value. | |||
*/ | |||
/* find the two ports */ | |||
if ((input_port = jack_port_by_name(client, argv[1])) == 0) { | |||
fprintf (stderr, "ERROR %s not a valid port\n", argv[1]); | |||
goto error; | |||
if( use_uuid ) { | |||
char *tmpname; | |||
char *clientname; | |||
char *portname; | |||
tmpname = strdup( argv[argc-1] ); | |||
portname = strchr( tmpname, ':' ); | |||
portname[0] = '\0'; | |||
portname+=1; | |||
clientname = jack_get_client_name_by_uuid( client, tmpname ); | |||
if( clientname ) { | |||
snprintf( portA, sizeof(portA), "%s:%s", clientname, portname ); | |||
jack_free( clientname ); | |||
} else { | |||
snprintf( portA, sizeof(portA), "%s", argv[argc-1] ); | |||
} | |||
free( tmpname ); | |||
tmpname = strdup( argv[argc-2] ); | |||
portname = strchr( tmpname, ':' ); | |||
portname[0] = '\0'; | |||
portname+=1; | |||
clientname = jack_get_client_name_by_uuid( client, tmpname ); | |||
if( clientname ) { | |||
snprintf( portB, sizeof(portB), "%s:%s", clientname, portname ); | |||
jack_free( clientname ); | |||
} else { | |||
snprintf( portB, sizeof(portB), "%s", argv[argc-2] ); | |||
} | |||
free( tmpname ); | |||
} else { | |||
snprintf( portA, sizeof(portA), "%s", argv[argc-1] ); | |||
snprintf( portB, sizeof(portB), "%s", argv[argc-2] ); | |||
} | |||
if ((output_port = jack_port_by_name(client, argv[2])) == 0) { | |||
fprintf (stderr, "ERROR %s not a valid port\n", argv[2]); | |||
goto error; | |||
if ((port1 = jack_port_by_name(client, portA)) == 0) { | |||
fprintf (stderr, "ERROR %s not a valid port\n", portA); | |||
goto exit; | |||
} | |||
if ((port2 = jack_port_by_name(client, portB)) == 0) { | |||
fprintf (stderr, "ERROR %s not a valid port\n", portB); | |||
goto exit; | |||
} | |||
port1_flags = jack_port_flags (port1); | |||
port2_flags = jack_port_flags (port2); | |||
if (port1_flags & JackPortIsInput) { | |||
if (port2_flags & JackPortIsOutput) { | |||
src_port = port2; | |||
dst_port = port1; | |||
} | |||
} else { | |||
if (port2_flags & JackPortIsInput) { | |||
src_port = port1; | |||
dst_port = port2; | |||
} | |||
} | |||
/* tell the JACK server that we are ready to roll */ | |||
if (jack_activate (client)) { | |||
fprintf (stderr, "cannot activate client"); | |||
goto error; | |||
if (!src_port || !dst_port) { | |||
fprintf (stderr, "arguments must include 1 input port and 1 output port\n"); | |||
goto exit; | |||
} | |||
/* connect the ports. Note: you can't do this before | |||
the client is activated (this may change in the future). | |||
*/ | |||
if (connecting) { | |||
if (jack_connect(client, jack_port_name(input_port), jack_port_name(output_port))) { | |||
fprintf (stderr, "cannot connect ports\n"); | |||
goto error; | |||
} | |||
if (connecting) { | |||
if (jack_connect(client, jack_port_name(src_port), jack_port_name(dst_port))) { | |||
goto exit; | |||
} | |||
} | |||
if (disconnecting) { | |||
if (jack_disconnect(client, jack_port_name(input_port), jack_port_name(output_port))) { | |||
fprintf (stderr, "cannot disconnect ports\n"); | |||
goto error; | |||
} | |||
if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) { | |||
goto exit; | |||
} | |||
} | |||
// Wait for connection/disconnection to be effective | |||
while(!done) { | |||
#ifdef WIN32 | |||
Sleep(10); | |||
#else | |||
usleep(10000); | |||
#endif | |||
while(!done) { | |||
#ifdef WIN32 | |||
Sleep(10); | |||
#else | |||
usleep(10000); | |||
#endif | |||
} | |||
jack_deactivate (client); | |||
jack_client_close (client); | |||
return 0; | |||
/* everything was ok, so setting exitcode to 0 */ | |||
rc = 0; | |||
error: | |||
if (client) | |||
jack_client_close (client); | |||
return 1; | |||
exit: | |||
jack_client_close (client); | |||
exit (rc); | |||
} | |||
@@ -0,0 +1,215 @@ | |||
/** @file simple_client.c | |||
* | |||
* @brief This simple client demonstrates the most basic features of JACK | |||
* as they would be used by many applications. | |||
*/ | |||
#include <stdio.h> | |||
#include <errno.h> | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <inttypes.h> | |||
#include <jack/jack.h> | |||
jack_port_t *input_port; | |||
jack_port_t *output_port; | |||
jack_client_t *client; | |||
jack_default_audio_sample_t *delay_line; | |||
jack_nframes_t delay_index; | |||
jack_nframes_t latency = 1024; | |||
#ifdef WIN32 | |||
#define jack_sleep(val) Sleep((val)) | |||
#else | |||
#define jack_sleep(val) usleep((val) * 1000) | |||
#endif | |||
/** | |||
* The process callback for this JACK application is called in a | |||
* special realtime thread once for each audio cycle. | |||
* | |||
* This client does nothing more than copy data from its input | |||
* port to its output port. It will exit when stopped by | |||
* the user (e.g. using Ctrl-C on a unix-ish operating system) | |||
*/ | |||
int | |||
process (jack_nframes_t nframes, void *arg) | |||
{ | |||
jack_default_audio_sample_t *in, *out; | |||
int k; | |||
in = jack_port_get_buffer (input_port, nframes); | |||
out = jack_port_get_buffer (output_port, nframes); | |||
for (k=0; k<nframes; k++) { | |||
out[k] = delay_line[delay_index]; | |||
delay_line[delay_index] = in[k]; | |||
delay_index = (delay_index + 1) % latency; | |||
} | |||
return 0; | |||
} | |||
void | |||
latency_cb (jack_latency_callback_mode_t mode, void *arg) | |||
{ | |||
jack_latency_range_t range; | |||
if (mode == JackCaptureLatency) { | |||
jack_port_get_latency_range (input_port, mode, &range); | |||
range.min += latency; | |||
range.max += latency; | |||
jack_port_set_latency_range (output_port, mode, &range); | |||
} else { | |||
jack_port_get_latency_range (output_port, mode, &range); | |||
range.min += latency; | |||
range.max += latency; | |||
jack_port_set_latency_range (input_port, mode, &range); | |||
} | |||
} | |||
/** | |||
* JACK calls this shutdown_callback if the server ever shuts down or | |||
* decides to disconnect the client. | |||
*/ | |||
void | |||
jack_shutdown (void *arg) | |||
{ | |||
exit (1); | |||
} | |||
int | |||
main (int argc, char *argv[]) | |||
{ | |||
const char **ports; | |||
const char *client_name = "latent"; | |||
const char *server_name = NULL; | |||
jack_options_t options = JackNullOption; | |||
jack_status_t status; | |||
if (argc == 2) | |||
latency = atoi(argv[1]); | |||
delay_line = malloc( latency * sizeof(jack_default_audio_sample_t)); | |||
if (delay_line == NULL) { | |||
fprintf (stderr, "no memory"); | |||
exit(1); | |||
} | |||
memset (delay_line, 0, latency * sizeof(jack_default_audio_sample_t)); | |||
/* open a client connection to the JACK server */ | |||
client = jack_client_open (client_name, options, &status, server_name); | |||
if (client == NULL) { | |||
fprintf (stderr, "jack_client_open() failed, " | |||
"status = 0x%2.0x\n", status); | |||
if (status & JackServerFailed) { | |||
fprintf (stderr, "Unable to connect to JACK server\n"); | |||
} | |||
exit (1); | |||
} | |||
if (status & JackServerStarted) { | |||
fprintf (stderr, "JACK server started\n"); | |||
} | |||
if (status & JackNameNotUnique) { | |||
client_name = jack_get_client_name(client); | |||
fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||
} | |||
/* tell the JACK server to call `process()' whenever | |||
there is work to be done. | |||
*/ | |||
jack_set_process_callback (client, process, 0); | |||
/* tell the JACK server to call `latency()' whenever | |||
the latency needs to be recalculated. | |||
*/ | |||
if (jack_set_latency_callback) | |||
jack_set_latency_callback (client, latency_cb, 0); | |||
/* tell the JACK server to call `jack_shutdown()' if | |||
it ever shuts down, either entirely, or if it | |||
just decides to stop calling us. | |||
*/ | |||
jack_on_shutdown (client, jack_shutdown, 0); | |||
/* display the current sample rate. | |||
*/ | |||
printf ("engine sample rate: %" PRIu32 "\n", | |||
jack_get_sample_rate (client)); | |||
/* create two ports */ | |||
input_port = jack_port_register (client, "input", | |||
JACK_DEFAULT_AUDIO_TYPE, | |||
JackPortIsInput, 0); | |||
output_port = jack_port_register (client, "output", | |||
JACK_DEFAULT_AUDIO_TYPE, | |||
JackPortIsOutput, 0); | |||
if ((input_port == NULL) || (output_port == NULL)) { | |||
fprintf(stderr, "no more JACK ports available\n"); | |||
exit (1); | |||
} | |||
/* Tell the JACK server that we are ready to roll. Our | |||
* process() callback will start running now. */ | |||
if (jack_activate (client)) { | |||
fprintf (stderr, "cannot activate client"); | |||
exit (1); | |||
} | |||
/* Connect the ports. You can't do this before the client is | |||
* activated, because we can't make connections to clients | |||
* that aren't running. Note the confusing (but necessary) | |||
* orientation of the driver backend ports: playback ports are | |||
* "input" to the backend, and capture ports are "output" from | |||
* it. | |||
*/ | |||
ports = jack_get_ports (client, NULL, NULL, | |||
JackPortIsPhysical|JackPortIsOutput); | |||
if (ports == NULL) { | |||
fprintf(stderr, "no physical capture ports\n"); | |||
exit (1); | |||
} | |||
if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
fprintf (stderr, "cannot connect input ports\n"); | |||
} | |||
free (ports); | |||
ports = jack_get_ports (client, NULL, NULL, | |||
JackPortIsPhysical|JackPortIsInput); | |||
if (ports == NULL) { | |||
fprintf(stderr, "no physical playback ports\n"); | |||
exit (1); | |||
} | |||
if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
fprintf (stderr, "cannot connect output ports\n"); | |||
} | |||
free (ports); | |||
/* keep running until stopped by the user */ | |||
jack_sleep (-1); | |||
/* this is never reached but if the program | |||
had some other way to exit besides being killed, | |||
they would be important to call. | |||
*/ | |||
jack_client_close (client); | |||
exit (0); | |||
} |
@@ -20,7 +20,8 @@ | |||
#include <unistd.h> | |||
#endif | |||
#include <string.h> | |||
#include <getopt.h> | |||
#include <getopt.h> | |||
#include <inttypes.h> | |||
#include <jack/jack.h> | |||
char * my_name; | |||
@@ -39,6 +40,7 @@ show_usage (void) | |||
fprintf (stderr, "List active Jack ports, and optionally display extra information.\n"); | |||
fprintf (stderr, "Optionally filter ports which match ALL strings provided after any options.\n\n"); | |||
fprintf (stderr, "Display options:\n"); | |||
fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n"); | |||
fprintf (stderr, " -A, --aliases List aliases for each port\n"); | |||
fprintf (stderr, " -c, --connections List connections to/from each port\n"); | |||
fprintf (stderr, " -l, --latency Display per-port latency in frames at each port\n"); | |||
@@ -56,6 +58,7 @@ main (int argc, char *argv[]) | |||
{ | |||
jack_client_t *client; | |||
jack_status_t status; | |||
jack_options_t options = JackNoStartServer; | |||
const char **ports, **connections; | |||
unsigned int i, j, k; | |||
int skip_port; | |||
@@ -68,9 +71,11 @@ main (int argc, char *argv[]) | |||
int c; | |||
int option_index; | |||
char* aliases[2]; | |||
char *server_name = NULL; | |||
jack_port_t *port; | |||
struct option long_options[] = { | |||
{ "server", 1, 0, 's' }, | |||
{ "aliases", 0, 0, 'A' }, | |||
{ "connections", 0, 0, 'c' }, | |||
{ "port-latency", 0, 0, 'l' }, | |||
@@ -89,8 +94,13 @@ main (int argc, char *argv[]) | |||
my_name ++; | |||
} | |||
while ((c = getopt_long (argc, argv, "AclLphvt", long_options, &option_index)) >= 0) { | |||
while ((c = getopt_long (argc, argv, "s:AclLphvt", long_options, &option_index)) >= 0) { | |||
switch (c) { | |||
case 's': | |||
server_name = (char *) malloc (sizeof (char) * strlen(optarg)); | |||
strcpy (server_name, optarg); | |||
options |= JackServerName; | |||
break; | |||
case 'A': | |||
aliases[0] = (char *) malloc (jack_port_name_size()); | |||
aliases[1] = (char *) malloc (jack_port_name_size()); | |||
@@ -131,7 +141,7 @@ main (int argc, char *argv[]) | |||
* specify JackNoStartServer. */ | |||
//JOQ: need a new server name option | |||
client = jack_client_open ("lsp", JackNoStartServer, &status); | |||
client = jack_client_open ("lsp", options, &status, server_name); | |||
if (client == NULL) { | |||
if (status & JackServerFailed) { | |||
fprintf (stderr, "JACK server not running\n"); | |||
@@ -143,7 +153,7 @@ main (int argc, char *argv[]) | |||
} | |||
ports = jack_get_ports (client, NULL, NULL, 0); | |||
if (!ports) | |||
if (!ports) | |||
goto error; | |||
for (i = 0; ports && ports[i]; ++i) { | |||
@@ -168,19 +178,28 @@ main (int argc, char *argv[]) | |||
printf (" %s\n", aliases[i]); | |||
} | |||
} | |||
if (show_con) { | |||
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { | |||
for (j = 0; connections[j]; j++) { | |||
printf (" %s\n", connections[j]); | |||
} | |||
free (connections); | |||
} | |||
} | |||
} | |||
if (show_port_latency) { | |||
if (port) { | |||
printf (" port latency = %d frames\n", | |||
jack_latency_range_t range; | |||
printf (" port latency = %" PRIu32 " frames\n", | |||
jack_port_get_latency (port)); | |||
jack_port_get_latency_range (port, JackPlaybackLatency, &range); | |||
printf (" port playback latency = [ %" PRIu32 " %" PRIu32 " ] frames\n", | |||
range.min, range.max); | |||
jack_port_get_latency_range (port, JackCaptureLatency, &range); | |||
printf (" port capture latency = [ %" PRIu32 " %" PRIu32 " ] frames\n", | |||
range.min, range.max); | |||
} | |||
} | |||
if (show_total_latency) { | |||
@@ -208,12 +227,7 @@ main (int argc, char *argv[]) | |||
if (flags & JackPortIsTerminal) { | |||
fputs ("terminal,", stdout); | |||
} | |||
if (flags & JackPortIsActive) { | |||
fputs ("active,", stdout); | |||
} else { | |||
fputs ("non-active,", stdout); | |||
} | |||
putc ('\n', stdout); | |||
} | |||
} | |||
@@ -225,7 +239,7 @@ main (int argc, char *argv[]) | |||
} | |||
} | |||
} | |||
error: | |||
if (ports) | |||
jack_free (ports); | |||
@@ -0,0 +1,114 @@ | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <assert.h> | |||
#include <jack/jack.h> | |||
#include <jack/midiport.h> | |||
static jack_port_t* port; | |||
static void | |||
describe (jack_midi_event_t* event, char* buffer, size_t buflen) | |||
{ | |||
assert (buflen > 0); | |||
buffer[0] = '\0'; | |||
if (event->size == 0) { | |||
return; | |||
} | |||
int type = event->buffer[0] & 0xf0; | |||
int channel = event->buffer[0] & 0xf; | |||
switch (type) { | |||
case 0x90: | |||
assert (event->size == 3); | |||
snprintf (buffer, buflen, "note on (channel %d): pitch %d, velocity %d", channel, event->buffer[1], event->buffer[2]); | |||
break; | |||
case 0x80: | |||
assert (event->size == 3); | |||
snprintf (buffer, buflen, "note off (channel %d): pitch %d, velocity %d", channel, event->buffer[1], event->buffer[2]); | |||
break; | |||
case 0xb0: | |||
assert (event->size == 3); | |||
snprintf (buffer, buflen, "control change (channel %d): controller %d, value %d", channel, event->buffer[1], event->buffer[2]); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
int | |||
process (jack_nframes_t frames, void* arg) | |||
{ | |||
void* buffer; | |||
jack_nframes_t N; | |||
jack_nframes_t i; | |||
char description[256]; | |||
buffer = jack_port_get_buffer (port, frames); | |||
assert (buffer); | |||
N = jack_midi_get_event_count (buffer); | |||
for (i = 0; i < N; ++i) { | |||
jack_midi_event_t event; | |||
int r; | |||
r = jack_midi_event_get (&event, buffer, i); | |||
if (r == 0) { | |||
size_t j; | |||
printf ("%d:", event.time); | |||
for (j = 0; j < event.size; ++j) { | |||
printf (" %x", event.buffer[j]); | |||
} | |||
describe (&event, description, sizeof (description)); | |||
printf (" %s", description); | |||
printf ("\n"); | |||
} | |||
} | |||
return 0; | |||
} | |||
int | |||
main (int argc, char* argv[]) | |||
{ | |||
jack_client_t* client; | |||
char const default_name[] = "midi-monitor"; | |||
char const * client_name; | |||
int r; | |||
if (argc == 2) { | |||
client_name = argv[1]; | |||
} else { | |||
client_name = default_name; | |||
} | |||
client = jack_client_open (client_name, JackNullOption, NULL); | |||
if (client == NULL) { | |||
fprintf (stderr, "Could not create JACK client.\n"); | |||
exit (EXIT_FAILURE); | |||
} | |||
jack_set_process_callback (client, process, 0); | |||
port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
if (port == NULL) { | |||
fprintf (stderr, "Could not register port.\n"); | |||
exit (EXIT_FAILURE); | |||
} | |||
r = jack_activate (client); | |||
if (r != 0) { | |||
fprintf (stderr, "Could not activate client.\n"); | |||
exit (EXIT_FAILURE); | |||
} | |||
sleep (-1); | |||
return 0; | |||
} |
@@ -86,6 +86,7 @@ int reply_port = 0; | |||
int bind_port = 0; | |||
int redundancy = 1; | |||
jack_client_t *client; | |||
packet_cache * packcache = 0; | |||
int state_connected = 0; | |||
int state_latency = 0; | |||
@@ -140,7 +141,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int | |||
} | |||
if( bitdepth == 1000 ) { | |||
#if HAVE_CELT | |||
#if HAVE_CELT_API_0_7 | |||
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL ); | |||
capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); | |||
#else | |||
@@ -183,7 +184,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int | |||
} | |||
if( bitdepth == 1000 ) { | |||
#if HAVE_CELT | |||
#if HAVE_CELT_API_0_7 | |||
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 | |||
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL ); | |||
playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); | |||
#else | |||
@@ -224,6 +225,9 @@ sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg) | |||
static int latency_count = 0; | |||
int retval = sync_state; | |||
if (! state_connected) { | |||
return 1; | |||
} | |||
if (latency_count) { | |||
latency_count--; | |||
retval = 0; | |||
@@ -329,7 +333,7 @@ process (jack_nframes_t nframes, void *arg) | |||
else if (cont_miss > 50+5*latency) | |||
{ | |||
state_connected = 0; | |||
packet_cache_reset_master_address( global_packcache ); | |||
packet_cache_reset_master_address( packcache ); | |||
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); | |||
cont_miss = 0; | |||
} | |||
@@ -355,19 +359,19 @@ process (jack_nframes_t nframes, void *arg) | |||
if ( ! netjack_poll_deadline( input_fd, deadline ) ) | |||
break; | |||
packet_cache_drain_socket(global_packcache, input_fd); | |||
packet_cache_drain_socket(packcache, input_fd); | |||
if (packet_cache_get_next_available_framecnt( global_packcache, framecnt - latency, &got_frame )) | |||
if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame )) | |||
if( got_frame == (framecnt - latency) ) | |||
break; | |||
} | |||
} else { | |||
// normally: | |||
// only drain socket. | |||
packet_cache_drain_socket(global_packcache, input_fd); | |||
packet_cache_drain_socket(packcache, input_fd); | |||
} | |||
size = packet_cache_retreive_packet_pointer( global_packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); | |||
size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); | |||
/* First alternative : we received what we expected. Render the data | |||
* to the JACK ports so it can be played. */ | |||
if (size == rx_bufsize) | |||
@@ -394,7 +398,7 @@ process (jack_nframes_t nframes, void *arg) | |||
state_recv_packet_queue_time = recv_time_offset; | |||
state_connected = 1; | |||
sync_state = pkthdr_rx->sync_state; | |||
packet_cache_release_packet( global_packcache, framecnt - latency ); | |||
packet_cache_release_packet( packcache, framecnt - latency ); | |||
} | |||
/* Second alternative : we've received something that's not | |||
* as big as expected or we missed a packet. We render silence | |||
@@ -402,7 +406,7 @@ process (jack_nframes_t nframes, void *arg) | |||
else | |||
{ | |||
jack_nframes_t latency_estimate; | |||
if( packet_cache_find_latency( global_packcache, framecnt, &latency_estimate ) ) | |||
if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) | |||
//if( (state_latency == 0) || (latency_estimate < state_latency) ) | |||
state_latency = latency_estimate; | |||
@@ -468,7 +472,7 @@ process (jack_nframes_t nframes, void *arg) | |||
else if (cont_miss > 50+5*latency) | |||
{ | |||
state_connected = 0; | |||
packet_cache_reset_master_address( global_packcache ); | |||
packet_cache_reset_master_address( packcache ); | |||
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); | |||
cont_miss = 0; | |||
} | |||
@@ -501,12 +505,11 @@ init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t por | |||
if (hostinfo == NULL) { | |||
fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); | |||
fflush( stderr ); | |||
return; | |||
} | |||
#ifdef WIN32 | |||
name->sin_addr.s_addr = inet_addr( hostname ); | |||
name->sin_addr.s_addr = inet_addr( hostname ); | |||
#else | |||
name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; | |||
name->sin_addr = *(struct in_addr *) hostinfo->h_addr ; | |||
#endif | |||
} | |||
else | |||
@@ -621,15 +624,15 @@ main (int argc, char *argv[]) | |||
case 'b': | |||
bitdepth = atoi (optarg); | |||
break; | |||
case 'c': | |||
#if HAVE_CELT | |||
bitdepth = 1000; | |||
case 'c': | |||
#if HAVE_CELT | |||
bitdepth = 1000; | |||
factor = atoi (optarg); | |||
#else | |||
#else | |||
printf( "not built with celt supprt\n" ); | |||
exit(10); | |||
#endif | |||
break; | |||
#endif | |||
break; | |||
case 'm': | |||
mtu = atoi (optarg); | |||
break; | |||
@@ -676,17 +679,18 @@ main (int argc, char *argv[]) | |||
} | |||
init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); | |||
if (bind_port) { | |||
if(bind_port) { | |||
init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); | |||
if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { | |||
fprintf (stderr, "bind failure\n" ); | |||
} | |||
fprintf (stderr, "bind failure\n" ); | |||
} | |||
} | |||
if (reply_port) { | |||
if(reply_port) | |||
{ | |||
init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); | |||
if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { | |||
fprintf (stderr, "bind failure\n" ); | |||
} | |||
fprintf (stderr, "bind failure\n" ); | |||
} | |||
} | |||
/* try to become a client of the JACK server */ | |||
@@ -712,7 +716,7 @@ main (int argc, char *argv[]) | |||
net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor); | |||
int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); | |||
global_packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); | |||
packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); | |||
/* tell the JACK server that we are ready to roll */ | |||
if (jack_activate (client)) | |||
@@ -778,6 +782,6 @@ main (int argc, char *argv[]) | |||
} | |||
jack_client_close (client); | |||
packet_cache_free (global_packcache); | |||
packet_cache_free (packcache); | |||
exit (0); | |||
} |
@@ -25,12 +25,11 @@ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <jack/jack.h> | |||
#include <jack/types.h> | |||
#include <jack/jslist.h> | |||
#include <jack/transport.h> | |||
#include <jack/session.h> | |||
char *package; /* program name */ | |||
char *package; /* program name */ | |||
jack_client_t *client; | |||
jack_session_event_type_t notify_type; | |||
@@ -38,147 +37,145 @@ char *save_path = NULL; | |||
void jack_shutdown(void *arg) | |||
{ | |||
fprintf(stderr, "JACK shut down, exiting ...\n"); | |||
exit(1); | |||
fprintf(stderr, "JACK shut down, exiting ...\n"); | |||
exit(1); | |||
} | |||
void signal_handler(int sig) | |||
{ | |||
jack_client_close(client); | |||
fprintf(stderr, "signal received, exiting ...\n"); | |||
exit(0); | |||
jack_client_close(client); | |||
fprintf(stderr, "signal received, exiting ...\n"); | |||
exit(0); | |||
} | |||
void parse_arguments(int argc, char *argv[]) | |||
{ | |||
/* basename $0 */ | |||
package = strrchr(argv[0], '/'); | |||
if (package == 0) | |||
package = argv[0]; | |||
else | |||
package++; | |||
if (argc==2) { | |||
if( !strcmp( argv[1], "quit" ) ) { | |||
notify_type = JackSessionSaveAndQuit; | |||
return; | |||
} | |||
} | |||
if (argc==3) { | |||
if( !strcmp( argv[1], "save" ) ) { | |||
notify_type = JackSessionSave; | |||
save_path = argv[2]; | |||
return; | |||
} | |||
} | |||
fprintf(stderr, "usage: %s quit|save [path]\n", package); | |||
exit(9); | |||
/* basename $0 */ | |||
package = strrchr(argv[0], '/'); | |||
if (package == 0) | |||
package = argv[0]; | |||
else | |||
package++; | |||
if (argc==2) { | |||
if( !strcmp( argv[1], "quit" ) ) { | |||
notify_type = JackSessionSaveAndQuit; | |||
return; | |||
} | |||
} | |||
if (argc==3) { | |||
if( !strcmp( argv[1], "save" ) ) { | |||
notify_type = JackSessionSave; | |||
save_path = argv[2]; | |||
return; | |||
} | |||
} | |||
fprintf(stderr, "usage: %s quit|save [path]\n", package); | |||
exit(9); | |||
} | |||
typedef struct { | |||
char name[32]; | |||
char uuid[16]; | |||
char name[32]; | |||
char uuid[16]; | |||
} uuid_map_t; | |||
JSList *uuid_map = NULL; | |||
void add_uuid_mapping( const char *uuid ) { | |||
char *clientname = jack_get_client_name_by_uuid( client, uuid ); | |||
if( !clientname ) { | |||
printf( "error... cant find client for uuid %s", uuid ); | |||
return; | |||
} | |||
uuid_map_t *mapping = malloc( sizeof(uuid_map_t) ); | |||
snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid ); | |||
snprintf( mapping->name, sizeof(mapping->name), "%s", clientname ); | |||
uuid_map = jack_slist_append( uuid_map, mapping ); | |||
char *clientname = jack_get_client_name_by_uuid( client, uuid ); | |||
if( !clientname ) { | |||
printf( "error... cant find client for uuid" ); | |||
return; | |||
} | |||
uuid_map_t *mapping = malloc( sizeof(uuid_map_t) ); | |||
snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid ); | |||
snprintf( mapping->name, sizeof(mapping->name), "%s", clientname ); | |||
uuid_map = jack_slist_append( uuid_map, mapping ); | |||
} | |||
char *map_port_name_to_uuid_port( const char *port_name ) | |||
{ | |||
JSList *node; | |||
char retval[300]; | |||
char *port_component = strchr( port_name,':' ); | |||
char *client_component = strdup( port_name ); | |||
strchr( client_component, ':' )[0] = '\0'; | |||
sprintf( retval, "%s", port_name ); | |||
for( node=uuid_map; node; node=jack_slist_next(node) ) { | |||
uuid_map_t *mapping = node->data; | |||
if( !strcmp( mapping->name, client_component ) ) { | |||
sprintf( retval, "%s%s", mapping->uuid, port_component ); | |||
break; | |||
} | |||
} | |||
return strdup(retval); | |||
JSList *node; | |||
char retval[300]; | |||
char *port_component = strchr( port_name,':' ); | |||
char *client_component = strdup( port_name ); | |||
strchr( client_component, ':' )[0] = '\0'; | |||
sprintf( retval, "%s", port_name ); | |||
for( node=uuid_map; node; node=jack_slist_next(node) ) { | |||
uuid_map_t *mapping = node->data; | |||
if( !strcmp( mapping->name, client_component ) ) { | |||
sprintf( retval, "%s%s", mapping->uuid, port_component ); | |||
break; | |||
} | |||
} | |||
return strdup(retval); | |||
} | |||
int main(int argc, char *argv[]) | |||
{ | |||
parse_arguments(argc, argv); | |||
jack_session_command_t *retval; | |||
int k,i,j; | |||
/* become a JACK client */ | |||
if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { | |||
fprintf(stderr, "JACK server not running?\n"); | |||
exit(1); | |||
} | |||
signal(SIGQUIT, signal_handler); | |||
signal(SIGTERM, signal_handler); | |||
signal(SIGHUP, signal_handler); | |||
signal(SIGINT, signal_handler); | |||
jack_on_shutdown(client, jack_shutdown, 0); | |||
jack_activate(client); | |||
retval = jack_session_notify( client, NULL, notify_type, save_path ); | |||
printf( "retval = %p\n", retval ); | |||
for(i=0; retval[i].uuid; i++ ) { | |||
printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name ); | |||
printf( "%s &\n", retval[i].command ); | |||
add_uuid_mapping(retval[i].uuid); | |||
} | |||
printf( "sleep 10\n" ); | |||
for(k=0; retval[k].uuid; k++ ) { | |||
char* port_regexp = alloca( jack_client_name_size()+3 ); | |||
char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid ); | |||
snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name ); | |||
jack_free(client_name); | |||
const char **ports = jack_get_ports( client, port_regexp, NULL, 0 ); | |||
if( !ports ) { | |||
continue; | |||
} | |||
for (i = 0; ports[i]; ++i) { | |||
const char **connections; | |||
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { | |||
for (j = 0; connections[j]; j++) { | |||
char *src = map_port_name_to_uuid_port( ports[i] ); | |||
char *dst = map_port_name_to_uuid_port( connections[j] ); | |||
printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst ); | |||
} | |||
jack_free (connections); | |||
} | |||
} | |||
jack_free(ports); | |||
} | |||
jack_session_commands_free(retval); | |||
jack_client_close(client); | |||
return 0; | |||
parse_arguments(argc, argv); | |||
jack_session_command_t *retval; | |||
int k,i,j; | |||
/* become a JACK client */ | |||
if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) { | |||
fprintf(stderr, "JACK server not running?\n"); | |||
exit(1); | |||
} | |||
signal(SIGQUIT, signal_handler); | |||
signal(SIGTERM, signal_handler); | |||
signal(SIGHUP, signal_handler); | |||
signal(SIGINT, signal_handler); | |||
jack_on_shutdown(client, jack_shutdown, 0); | |||
jack_activate(client); | |||
retval = jack_session_notify( client, NULL, notify_type, save_path ); | |||
for(i=0; retval[i].uuid; i++ ) { | |||
printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name ); | |||
printf( "%s &\n", retval[i].command ); | |||
add_uuid_mapping(retval[i].uuid); | |||
} | |||
printf( "sleep 10\n" ); | |||
for(k=0; retval[k].uuid; k++ ) { | |||
char* port_regexp = alloca( jack_client_name_size()+3 ); | |||
char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid ); | |||
snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name ); | |||
jack_free(client_name); | |||
const char **ports = jack_get_ports( client, port_regexp, NULL, 0 ); | |||
if( !ports ) { | |||
continue; | |||
} | |||
for (i = 0; ports[i]; ++i) { | |||
const char **connections; | |||
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { | |||
for (j = 0; connections[j]; j++) { | |||
char *src = map_port_name_to_uuid_port( ports[i] ); | |||
char *dst = map_port_name_to_uuid_port( connections[j] ); | |||
printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst ); | |||
} | |||
jack_free (connections); | |||
} | |||
} | |||
jack_free(ports); | |||
} | |||
jack_session_commands_free(retval); | |||
jack_client_close(client); | |||
return 0; | |||
} |
@@ -27,6 +27,8 @@ example_programs = { | |||
'jack_server_control' : 'server_control.cpp', | |||
'jack_net_slave' : 'netslave.c', | |||
'jack_net_master' : 'netmaster.c', | |||
'jack_latent_client' : 'latent_client.c', | |||
'jack_midi_dump' : 'midi_dump.c', | |||
} | |||
example_libs = { | |||
@@ -130,12 +132,6 @@ def build(bld): | |||
prog.includes = os_incdir + ['../common/jack', '../common'] | |||
prog.source = ['netsource.c', '../common/netjack_packet.c'] | |||
prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") | |||
# Seems uneeded here... | |||
#if bld.env['HAVE_CELT']: | |||
#if bld.env['HAVE_CELT_API_0_5']: | |||
# prog.defines = ['HAVE_CELT', 'HAVE_CELT_API_0_5'] | |||
#elif bld.env['HAVE_CELT_API_0_7']: | |||
# prog.defines = ['HAVE_CELT', 'HAVE_CELT_API_0_7'] | |||
prog.uselib = 'CELT SAMPLERATE' | |||
prog.uselib_local = 'clientlib' | |||
prog.target = 'jack_netsource' | |||
@@ -69,12 +69,15 @@ static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* ad | |||
#endif | |||
#if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__) | |||
#warning using builtin gcc (version > 4.1) atomic | |||
static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) | |||
{ | |||
return __sync_bool_compare_and_swap (&addr, value, newvalue); | |||
return __sync_bool_compare_and_swap ((UInt32*)addr, value, newvalue); | |||
} | |||
#endif | |||
@@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <inttypes.h> | |||
static jack_time_t __jack_cpu_mhz = 0; | |||
jack_time_t (*_jack_get_microseconds)(void) = 0; | |||
@@ -276,7 +276,7 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
} else { | |||
driver->channel_copy = memcpy_fake; | |||
} | |||
switch (driver->dither) { | |||
case Rectangular: | |||
jack_info("Rectangular dithering at 16 bits"); | |||
@@ -284,42 +284,42 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
sample_move_dither_rect_d16_sSs: | |||
sample_move_dither_rect_d16_sS; | |||
break; | |||
case Triangular: | |||
jack_info("Triangular dithering at 16 bits"); | |||
driver->write_via_copy = driver->quirk_bswap? | |||
sample_move_dither_tri_d16_sSs: | |||
sample_move_dither_tri_d16_sS; | |||
break; | |||
case Shaped: | |||
jack_info("Noise-shaped dithering at 16 bits"); | |||
driver->write_via_copy = driver->quirk_bswap? | |||
sample_move_dither_shaped_d16_sSs: | |||
sample_move_dither_shaped_d16_sS; | |||
break; | |||
default: | |||
driver->write_via_copy = driver->quirk_bswap? | |||
sample_move_d16_sSs : | |||
sample_move_d16_sSs : | |||
sample_move_d16_sS; | |||
break; | |||
} | |||
break; | |||
case 3: /* NO DITHER */ | |||
if (driver->playback_interleaved) { | |||
driver->channel_copy = memcpy_interleave_d24_s24; | |||
} else { | |||
driver->channel_copy = memcpy_fake; | |||
} | |||
driver->write_via_copy = driver->quirk_bswap? | |||
sample_move_d24_sSs: | |||
sample_move_d24_sSs: | |||
sample_move_d24_sS; | |||
break; | |||
case 4: /* NO DITHER */ | |||
if (driver->playback_interleaved) { | |||
driver->channel_copy = memcpy_interleave_d32_s32; | |||
@@ -328,7 +328,7 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
} | |||
driver->write_via_copy = driver->quirk_bswap? | |||
sample_move_d32u24_sSs: | |||
sample_move_d32u24_sSs: | |||
sample_move_d32u24_sS; | |||
break; | |||
@@ -339,27 +339,27 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||
} | |||
} | |||
} | |||
if (driver->capture_handle) { | |||
switch (driver->capture_sample_bytes) { | |||
case 2: | |||
driver->read_via_copy = driver->quirk_bswap? | |||
sample_move_dS_s16s: | |||
sample_move_dS_s16s: | |||
sample_move_dS_s16; | |||
break; | |||
case 3: | |||
driver->read_via_copy = driver->quirk_bswap? | |||
sample_move_dS_s24s: | |||
sample_move_dS_s24s: | |||
sample_move_dS_s24; | |||
break; | |||
case 4: | |||
driver->read_via_copy = driver->quirk_bswap? | |||
sample_move_dS_s32u24s: | |||
sample_move_dS_s32u24s: | |||
sample_move_dS_s32u24; | |||
break; | |||
} | |||
} | |||
return 0; | |||
} | |||
@@ -418,7 +418,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
} | |||
} | |||
} | |||
format = (sample_width == 4) ? 0 : NUMFORMATS - 1; | |||
while (1) { | |||
@@ -444,7 +444,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); | |||
break; | |||
} | |||
} | |||
} | |||
frame_rate = driver->frame_rate ; | |||
err = snd_pcm_hw_params_set_rate_near (handle, hw_params, | |||
@@ -464,7 +464,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
&channels_max); | |||
*nchns = channels_max ; | |||
if (*nchns > 1024) { | |||
if (*nchns > 1024) { | |||
/* the hapless user is an unwitting victim of | |||
the "default" ALSA PCM device, which can | |||
@@ -481,9 +481,9 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
"instead rather than using the plug layer. Usually the name of the\n" | |||
"hardware device that corresponds to the first sound card is hw:0\n" | |||
); | |||
*nchns = 2; | |||
*nchns = 2; | |||
} | |||
} | |||
} | |||
if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, | |||
*nchns)) < 0) { | |||
@@ -491,7 +491,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
*nchns, stream_name); | |||
return -1; | |||
} | |||
if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, | |||
driver->frames_per_cycle, | |||
0)) | |||
@@ -520,7 +520,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
return -1; | |||
} | |||
jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); | |||
#if 0 | |||
#if 0 | |||
if (!jack_power_of_two(driver->frames_per_cycle)) { | |||
jack_error("JACK: frames must be a power of two " | |||
"(64, 512, 1024, ...)\n"); | |||
@@ -557,7 +557,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
if (driver->soft_mode) { | |||
stop_th = (snd_pcm_uframes_t)-1; | |||
} | |||
if ((err = snd_pcm_sw_params_set_stop_threshold ( | |||
handle, sw_params, stop_th)) < 0) { | |||
jack_error ("ALSA: cannot set stop mode for %s", | |||
@@ -594,7 +594,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic | |||
else | |||
err = snd_pcm_sw_params_set_avail_min ( | |||
handle, sw_params, driver->frames_per_cycle); | |||
if (err < 0) { | |||
jack_error ("ALSA: cannot set avail min for %s", stream_name); | |||
return -1; | |||
@@ -1158,7 +1158,7 @@ int | |||
JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) | |||
{ | |||
int res; | |||
driver->xrun_recovery = 1; | |||
if ((res = Stop()) == 0) | |||
res = Start(); | |||
@@ -1189,11 +1189,24 @@ JackAlsaDriver::alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed | |||
} | |||
} | |||
if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SUSPENDED) { | |||
jack_error("**** alsa_pcm: pcm in suspended state, resuming it" ); | |||
if (driver->capture_handle) { | |||
if ((res = snd_pcm_prepare(driver->capture_handle)) < 0) { | |||
jack_error("error preparing after suspend: %s", snd_strerror(res)); | |||
} | |||
} else { | |||
if ((res = snd_pcm_prepare(driver->playback_handle)) < 0) { | |||
jack_error("error preparing after suspend: %s", snd_strerror(res)); | |||
} | |||
} | |||
} | |||
if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN | |||
&& driver->process_count > XRUN_REPORT_DELAY) { | |||
struct timeval now, diff, tstamp; | |||
driver->xrun_count++; | |||
snd_pcm_status_get_tstamp(status,&now); | |||
snd_pcm_status_get_tstamp(status,&now); | |||
snd_pcm_status_get_trigger_tstamp(status, &tstamp); | |||
timersub(&now, &tstamp, &diff); | |||
*delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; | |||
@@ -1253,7 +1266,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
} | |||
again: | |||
while (need_playback || need_capture) { | |||
int poll_result; | |||
@@ -1269,7 +1282,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
driver->playback_nfds); | |||
nfds += driver->playback_nfds; | |||
} | |||
if (need_capture) { | |||
snd_pcm_poll_descriptors (driver->capture_handle, | |||
&driver->pfd[nfds], | |||
@@ -1279,7 +1292,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
} | |||
/* ALSA doesn't set POLLERR in some versions of 0.9.X */ | |||
for (i = 0; i < nfds; i++) { | |||
driver->pfd[i].events |= POLLERR; | |||
} | |||
@@ -1316,12 +1329,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
*status = -2; | |||
return 0; | |||
} | |||
jack_error ("ALSA: poll call failed (%s)", | |||
strerror (errno)); | |||
*status = -3; | |||
return 0; | |||
} | |||
poll_ret = jack_get_microseconds (); | |||
@@ -1332,12 +1345,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
if (extra_fd < 0) { | |||
if (driver->poll_next && poll_ret > driver->poll_next) { | |||
*delayed_usecs = poll_ret - driver->poll_next; | |||
} | |||
} | |||
driver->poll_last = poll_ret; | |||
driver->poll_next = poll_ret + driver->period_usecs; | |||
// steph | |||
/* | |||
driver->engine->transport_cycle_start (driver->engine, | |||
driver->engine->transport_cycle_start (driver->engine, | |||
poll_ret); | |||
*/ | |||
} | |||
@@ -1358,7 +1371,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
*status = -4; | |||
return -1; | |||
} | |||
} | |||
/* if POLLIN was the only bit set, we're OK */ | |||
@@ -1414,14 +1427,14 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
#endif | |||
} | |||
} | |||
if (poll_result == 0) { | |||
jack_error ("ALSA: poll time out, polled for %" PRIu64 | |||
" usecs", | |||
poll_ret - poll_enter); | |||
*status = -5; | |||
return 0; | |||
} | |||
} | |||
} | |||
@@ -1437,7 +1450,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
} | |||
} else { | |||
/* odd, but see min() computation below */ | |||
capture_avail = INT_MAX; | |||
capture_avail = INT_MAX; | |||
} | |||
if (driver->playback_handle) { | |||
@@ -1452,7 +1465,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
} | |||
} else { | |||
/* odd, but see min() computation below */ | |||
playback_avail = INT_MAX; | |||
playback_avail = INT_MAX; | |||
} | |||
if (xrun_detected) { | |||
@@ -1531,7 +1544,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||
if (!driver->capture_handle) { | |||
return 0; | |||
} | |||
nread = 0; | |||
contiguous = 0; | |||
orig_nframes = nframes; | |||
@@ -1559,11 +1572,11 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||
/* // steph | |||
for (chn = 0, node = driver->capture_ports; node; | |||
node = jack_slist_next (node), chn++) { | |||
port = (jack_port_t *) node->data; | |||
if (!jack_port_connected (port)) { | |||
// no-copy optimization | |||
// no-copy optimization | |||
continue; | |||
} | |||
buf = jack_port_get_buffer (port, orig_nframes); | |||
@@ -1574,7 +1587,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) | |||
if ((err = snd_pcm_mmap_commit (driver->capture_handle, | |||
offset, contiguous)) < 0) { | |||
jack_error ("ALSA: could not complete read of %" | |||
PRIu32 " frames: error = %d\n", contiguous, err); | |||
return -1; | |||
@@ -1702,7 +1715,7 @@ JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes | |||
} | |||
monbuf = jack_port_get_buffer (port, orig_nframes); | |||
memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); | |||
mon_node = jack_slist_next (mon_node); | |||
mon_node = jack_slist_next (mon_node); | |||
} | |||
} | |||
*/ | |||
@@ -1716,7 +1729,7 @@ JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes | |||
offset, contiguous)) < 0) { | |||
jack_error ("ALSA: could not complete playback of %" | |||
PRIu32 " frames: error = %d", contiguous, err); | |||
if (err != EPIPE && err != ESTRPIPE) | |||
if (err != -EPIPE && err != -ESTRPIPE) | |||
return -1; | |||
} | |||
@@ -1739,11 +1752,11 @@ JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver) | |||
free (node->data); | |||
} | |||
jack_slist_free (driver->clock_sync_listeners); | |||
if (driver->ctl_handle) { | |||
snd_ctl_close (driver->ctl_handle); | |||
driver->ctl_handle = 0; | |||
} | |||
} | |||
if (driver->capture_handle) { | |||
snd_pcm_close (driver->capture_handle); | |||
@@ -1821,14 +1834,14 @@ JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device, | |||
jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 | |||
"|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", | |||
playing ? playback_alsa_device : "-", | |||
capturing ? capture_alsa_device : "-", | |||
capturing ? capture_alsa_device : "-", | |||
frames_per_cycle, user_nperiods, rate, | |||
user_capture_nchnls,user_playback_nchnls, | |||
hw_monitoring ? "hwmon": "nomon", | |||
hw_metering ? "hwmeter":"swmeter", | |||
soft_mode ? "soft-mode":"-", | |||
shorts_first ? "16bit":"32bit"); | |||
driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); | |||
jack_driver_nt_init ((jack_driver_nt_t *) driver); | |||
@@ -1862,8 +1875,8 @@ JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device, | |||
driver->playback_addr = 0; | |||
driver->capture_addr = 0; | |||
driver->playback_interleave_skip = NULL; | |||
driver->capture_interleave_skip = NULL; | |||
driver->playback_interleave_skip = NULL; | |||
driver->capture_interleave_skip = NULL; | |||
driver->silent = 0; | |||
driver->all_monitor_in = FALSE; | |||
@@ -2071,6 +2084,7 @@ int JackAlsaDriver::Attach() | |||
unsigned long port_flags; | |||
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
jack_latency_range_t range; | |||
assert(fCaptureChannels < DRIVER_PORT_NUM); | |||
assert(fPlaybackChannels < DRIVER_PORT_NUM); | |||
@@ -2097,7 +2111,8 @@ int JackAlsaDriver::Attach() | |||
} | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetAlias(alias); | |||
port->SetLatency(alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency); | |||
range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fCapturePortList[i] = port_index; | |||
jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index); | |||
} | |||
@@ -2114,8 +2129,10 @@ int JackAlsaDriver::Attach() | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetAlias(alias); | |||
// Add one buffer more latency if "async" mode is used... | |||
port->SetLatency((alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + | |||
((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency); | |||
range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + | |||
((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency; | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
fPlaybackPortList[i] = port_index; | |||
jack_log("JackAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
@@ -2127,7 +2144,8 @@ int JackAlsaDriver::Attach() | |||
jack_error ("ALSA: cannot register monitor port for %s", name); | |||
} else { | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetLatency(alsa_driver->frames_per_cycle); | |||
range.min = range.max = alsa_driver->frames_per_cycle; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fMonitorPortList[i] = port_index; | |||
} | |||
} | |||
@@ -2151,7 +2169,7 @@ int JackAlsaDriver::Detach() | |||
return JackAudioDriver::Detach(); | |||
} | |||
static int card_to_num(const char* device) | |||
static int card_to_num(const char* device) | |||
{ | |||
int err; | |||
char* ctl_name; | |||
@@ -2316,13 +2334,13 @@ int JackAlsaDriver::Read() | |||
retry: | |||
nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | |||
if (wait_status < 0) | |||
return -1; /* driver failed */ | |||
if (nframes == 0) { | |||
/* we detected an xrun and restarted: notify | |||
* clients about the delay. | |||
* clients about the delay. | |||
*/ | |||
jack_log("ALSA XRun wait_status = %d", wait_status); | |||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
@@ -2331,7 +2349,7 @@ retry: | |||
if (nframes != fEngineControl->fBufferSize) | |||
jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes); | |||
// Has to be done before read | |||
JackDriver::CycleIncTime(); | |||
@@ -2619,7 +2637,7 @@ get_dither_constraint() | |||
} | |||
static int | |||
dither_opt (char c, DitherAlgorithm* dither) | |||
dither_opt (char c, DitherAlgorithm* dither) | |||
{ | |||
switch (c) { | |||
case '-': | |||
@@ -2646,17 +2664,17 @@ dither_opt (char c, DitherAlgorithm* dither) | |||
return 0; | |||
} | |||
SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
{ | |||
jack_driver_desc_t * desc; | |||
jack_driver_param_desc_t * params; | |||
unsigned int i; | |||
desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); | |||
strcpy(desc->name, "alsa"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
strcpy(desc->desc, "Linux ALSA API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
desc->nparams = 18; | |||
params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | |||
@@ -2825,7 +2843,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
return desc; | |||
} | |||
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) | |||
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) | |||
{ | |||
jack_nframes_t srate = 48000; | |||
jack_nframes_t frames_per_interrupt = 1024; | |||
@@ -104,7 +104,7 @@ typedef struct input_port_t { | |||
// jack | |||
midi_unpack_t unpack; | |||
// midi | |||
int overruns; | |||
} input_port_t; | |||
@@ -114,7 +114,7 @@ typedef struct output_port_t { | |||
// jack | |||
midi_pack_t packer; | |||
// midi | |||
event_head_t next_event; | |||
int todo; | |||
@@ -425,16 +425,16 @@ static | |||
inline int midi_port_open_jack(alsa_rawmidi_t *midi, midi_port_t *port, int type, const char *alias) | |||
{ | |||
char name[128]; | |||
if (type & JackPortIsOutput) | |||
snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++midi->midi_in_cnt); | |||
else | |||
else | |||
snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++midi->midi_out_cnt); | |||
port->jack = jack_port_register(midi->client, name, JACK_DEFAULT_MIDI_TYPE, | |||
type | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive, 0); | |||
if (port->jack) | |||
type | JackPortIsPhysical | JackPortIsTerminal, 0); | |||
if (port->jack) | |||
jack_port_set_alias(port->jack, alias); | |||
return port->jack == NULL; | |||
} | |||
@@ -455,7 +455,7 @@ int midi_port_open(alsa_rawmidi_t *midi, midi_port_t *port) | |||
out = &port->rawmidi; | |||
type = JackPortIsInput; | |||
} | |||
if ((err = snd_rawmidi_open(in, out, port->dev, SND_RAWMIDI_NONBLOCK))<0) | |||
return err; | |||
@@ -749,7 +749,7 @@ void* scan_thread(void *arg) | |||
return NULL; | |||
} | |||
/* | |||
/* | |||
* ------------------------------- Input/Output ------------------------------ | |||
*/ | |||
@@ -836,7 +836,7 @@ void *midi_thread(void *arg) | |||
npfds = 1; | |||
if (jack_is_realtime(midi->client)) | |||
set_threaded_log_function(); | |||
set_threaded_log_function(); | |||
//debug_log("midi_thread(%s): enter", str->name); | |||
@@ -978,7 +978,7 @@ int midi_update_pfds(process_midi_t *proc) | |||
return 1; | |||
} | |||
/* | |||
/* | |||
* ------------------------------------ Input ------------------------------ | |||
*/ | |||
@@ -1083,7 +1083,7 @@ int do_midi_input(process_midi_t *proc) | |||
return 1; | |||
} | |||
/* | |||
/* | |||
* ------------------------------------ Output ------------------------------ | |||
*/ | |||
@@ -1149,7 +1149,7 @@ int do_midi_output(process_midi_t *proc) | |||
} else | |||
debug_log("midi_out: at %ld got %d bytes for %ld", (long)proc->cur_time, (int)port->next_event.size, (long)port->next_event.time); | |||
} | |||
if (port->todo) | |||
debug_log("midi_out: todo = %d at %ld", (int)port->todo, (long)proc->cur_time); | |||
@@ -285,7 +285,7 @@ int alsa_seqmidi_attach(alsa_midi_t *m) | |||
self->client_id = snd_seq_client_id(self->seq); | |||
self->queue = snd_seq_alloc_queue(self->seq); | |||
snd_seq_start_queue(self->seq, self->queue, 0); | |||
snd_seq_start_queue(self->seq, self->queue, 0); | |||
stream_attach(self, PORT_INPUT); | |||
stream_attach(self, PORT_OUTPUT); | |||
@@ -488,14 +488,14 @@ port_t* port_create(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, const s | |||
/* mark anything that looks like a hardware port as physical&terminal */ | |||
if (snd_seq_port_info_get_type (info) & (SND_SEQ_PORT_TYPE_HARDWARE|SND_SEQ_PORT_TYPE_PORT|SND_SEQ_PORT_TYPE_SPECIFIC)) { | |||
jack_caps |= (JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive); | |||
jack_caps |= (JackPortIsPhysical | JackPortIsTerminal); | |||
} | |||
if (jack_caps & JackPortIsOutput) | |||
snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt); | |||
else | |||
else | |||
snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt); | |||
port->jack_port = jack_port_register(self->jack, | |||
name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0); | |||
if (!port->jack_port) | |||
@@ -588,7 +588,7 @@ void update_ports(alsa_seqmidi_t *self) | |||
snd_seq_port_info_alloca(&info); | |||
while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) { | |||
int err; | |||
assert (size == sizeof(addr)); | |||
@@ -666,7 +666,7 @@ void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, | |||
info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec; | |||
if (info->period_start + info->nframes < info->cur_frames) { | |||
int periods_lost = (info->cur_frames - info->period_start) / info->nframes; | |||
int periods_lost = (info->cur_frames - info->period_start) / info->nframes; | |||
info->period_start += periods_lost * info->nframes; | |||
debug_log("xrun detected: %d periods lost\n", periods_lost); | |||
} | |||
@@ -805,7 +805,7 @@ void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct proce | |||
ev.size = size; | |||
jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); | |||
jack_ringbuffer_write(port->early_events, (char*)data, size); | |||
debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes)); | |||
debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes)); | |||
return; | |||
} | |||
@@ -829,7 +829,7 @@ void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes) | |||
return; | |||
set_process_info(&info, self, PORT_INPUT, nframes); | |||
jack_process(self, &info); | |||
jack_process(self, &info); | |||
while ((res = snd_seq_event_input(self->seq, &event))>0) { | |||
if (event->source.client == SND_SEQ_CLIENT_SYSTEM) | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2005 Karsten Wiese, Rui Nuno Capela | |||
This program is free software; you can redistribute it and/or modify | |||
@@ -33,14 +33,14 @@ | |||
int dbg_offset; | |||
char dbg_buffer[8096]; | |||
#endif | |||
static | |||
static | |||
int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | |||
{ | |||
return -1; | |||
} | |||
static | |||
int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||
int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||
{ | |||
return -1; | |||
} | |||
@@ -52,7 +52,7 @@ usx2y_release (jack_hardware_t *hw) | |||
if (h == 0) | |||
return; | |||
if (h->hwdep_handle) | |||
snd_hwdep_close(h->hwdep_handle); | |||
@@ -622,7 +622,7 @@ usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) | |||
offset, nframes_)) < 0) { | |||
jack_error ("ALSA/USX2Y: could not complete playback of %" | |||
PRIu32 " frames: error = %d", nframes_, err); | |||
if (err != EPIPE && err != ESTRPIPE) | |||
if (err != -EPIPE && err != -ESTRPIPE) | |||
return -1; | |||
} | |||
@@ -37,8 +37,6 @@ | |||
* regardless of how fast the machine is. | |||
*/ | |||
#ifdef __linux__ | |||
#ifdef __x86_64__ | |||
typedef unsigned long cycles_t; | |||
@@ -127,21 +125,5 @@ static inline cycles_t get_cycles(void) | |||
#endif /* everything else but x86, amd64, sparcv9 or ppc */ | |||
#endif /* __linux__ */ | |||
#if defined(__FreeBSD_kernel__) | |||
#warning No suitable get_cycles() implementation. Returning 0 instead | |||
typedef unsigned long long cycles_t; | |||
static inline cycles_t get_cycles(void) | |||
{ | |||
return 0; | |||
} | |||
#endif /* __FreeBSD_kernel__ */ | |||
#endif /* __jack_cycles_h__ */ |
@@ -272,7 +272,7 @@ JackFFADODriver::SetBufferSize (jack_nframes_t nframes) | |||
printError("Buffer size change requested but not supported!!!"); | |||
/* | |||
driver->period_size = nframes; | |||
driver->period_size = nframes; | |||
driver->period_usecs = | |||
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) | |||
* 1000000.0f); | |||
@@ -362,6 +362,7 @@ int JackFFADODriver::Attach() | |||
int port_index; | |||
char buf[JACK_PORT_NAME_SIZE]; | |||
char portname[JACK_PORT_NAME_SIZE]; | |||
jack_latency_range_t range; | |||
ffado_driver_t* driver = (ffado_driver_t*)fDriver; | |||
@@ -447,7 +448,8 @@ int JackFFADODriver::Attach() | |||
ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetLatency(driver->period_size + driver->capture_frame_latency); | |||
range.min = range.max = driver->period_size + driver->capture_frame_latency; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
// capture port aliases (jackd1 style port names) | |||
snprintf(buf, sizeof(buf) - 1, "%s:capture_%i", fClientControl.fName, (int) chn + 1); | |||
port->SetAlias(buf); | |||
@@ -479,7 +481,8 @@ int JackFFADODriver::Attach() | |||
driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetLatency(driver->period_size + driver->capture_frame_latency); | |||
range.min = range.max = driver->period_size + driver->capture_frame_latency; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fCapturePortList[chn] = port_index; | |||
jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); | |||
fCaptureChannels++; | |||
@@ -523,7 +526,8 @@ int JackFFADODriver::Attach() | |||
port = fGraphManager->GetPort(port_index); | |||
// Add one buffer more latency if "async" mode is used... | |||
port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency); | |||
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
// playback port aliases (jackd1 style port names) | |||
snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1); | |||
port->SetAlias(buf); | |||
@@ -549,7 +553,7 @@ int JackFFADODriver::Attach() | |||
printError(" cannot enable port %s", buf); | |||
} | |||
// setup the midi buffer | |||
// This constructor optionally accepts arguments for the | |||
// non-realtime buffer size and the realtime buffer size. Ideally, | |||
// these would become command-line options for the FFADO driver. | |||
@@ -558,7 +562,8 @@ int JackFFADODriver::Attach() | |||
driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency); | |||
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency; | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
fPlaybackPortList[chn] = port_index; | |||
jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
fPlaybackChannels++; | |||
@@ -676,7 +681,7 @@ retry: | |||
if (nframes == 0) { | |||
/* we detected an xrun and restarted: notify | |||
* clients about the delay. | |||
* clients about the delay. | |||
*/ | |||
jack_log("FFADO XRun"); | |||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
@@ -685,7 +690,7 @@ retry: | |||
if (nframes != fEngineControl->fBufferSize) | |||
jack_log("JackFFADODriver::Read warning nframes = %ld", nframes); | |||
// Has to be done before read | |||
JackDriver::CycleIncTime(); | |||
@@ -755,7 +760,7 @@ extern "C" | |||
strcpy (desc->name, "firewire"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
strcpy(desc->desc, "Linux FFADO API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
desc->nparams = 13; | |||
params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | |||
@@ -260,7 +260,7 @@ JackFreebobDriver::SetBufferSize (jack_nframes_t nframes) | |||
printError("Buffer size change requested but not supported!!!"); | |||
/* | |||
driver->period_size = nframes; | |||
driver->period_size = nframes; | |||
driver->period_usecs = | |||
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) | |||
* 1000000.0f); | |||
@@ -667,9 +667,10 @@ int JackFreebobDriver::Attach() | |||
{ | |||
JackPort* port; | |||
int port_index; | |||
char buf[JACK_PORT_NAME_SIZE]; | |||
char portname[JACK_PORT_NAME_SIZE]; | |||
jack_latency_range_t range; | |||
freebob_driver_t* driver = (freebob_driver_t*)fDriver; | |||
@@ -737,7 +738,8 @@ int JackFreebobDriver::Attach() | |||
return -1; | |||
} | |||
port = fGraphManager->GetPort(port_index); | |||
port->SetLatency(driver->period_size + driver->capture_frame_latency); | |||
range.min = range.max = driver->period_size + driver->capture_frame_latency; | |||
port->SetLatencyRange(JackCaptureLatency, &range); | |||
fCapturePortList[i] = port_index; | |||
jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index); | |||
driver->capture_nchannels_audio++; | |||
@@ -766,7 +768,8 @@ int JackFreebobDriver::Attach() | |||
} | |||
port = fGraphManager->GetPort(port_index); | |||
// Add one buffer more latency if "async" mode is used... | |||
port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency); | |||
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency); | |||
port->SetLatencyRange(JackPlaybackLatency, &range); | |||
fPlaybackPortList[i] = port_index; | |||
jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
driver->playback_nchannels_audio++; | |||
@@ -866,7 +869,7 @@ retry: | |||
if (nframes == 0) { | |||
/* we detected an xrun and restarted: notify | |||
* clients about the delay. | |||
* clients about the delay. | |||
*/ | |||
jack_log("FreeBoB XRun"); | |||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
@@ -878,7 +881,7 @@ retry: | |||
// Has to be done before read | |||
JackDriver::CycleIncTime(); | |||
printExit(); | |||
return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize); | |||
} | |||
@@ -944,7 +947,7 @@ extern "C" | |||
strcpy (desc->name, "freebob"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
strcpy(desc->desc, "Linux FreeBob API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
desc->nparams = 11; | |||
params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); | |||
@@ -7,7 +7,7 @@ | |||
<key>CFBundleExecutable</key> | |||
<string>Jackservermp</string> | |||
<key>CFBundleGetInfoString</key> | |||
<string>Jackdmp 1.9.7, @03-10 Paul Davis, Grame</string> | |||
<string>Jackdmp 1.9.7, @03-11 Paul Davis, Grame</string> | |||
<key>CFBundleIdentifier</key> | |||
<string>com.grame.Jackmp</string> | |||
<key>CFBundleInfoDictionaryVersion</key> | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
namespace Jack | |||
{ | |||
int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint) | |||
int JackMachThread::SetThreadToPriority(jack_native_thread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint) | |||
{ | |||
if (inPriority == 96) { | |||
// REAL-TIME / TIME-CONSTRAINT THREAD | |||
@@ -73,18 +73,18 @@ int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boo | |||
} | |||
// returns the thread's priority as it was last set by the API | |||
UInt32 JackMachThread::GetThreadSetPriority(pthread_t thread) | |||
UInt32 JackMachThread::GetThreadSetPriority(jack_native_thread_t thread) | |||
{ | |||
return GetThreadPriority(thread, THREAD_SET_PRIORITY); | |||
} | |||
// returns the thread's priority as it was last scheduled by the Kernel | |||
UInt32 JackMachThread::GetThreadScheduledPriority(pthread_t thread) | |||
UInt32 JackMachThread::GetThreadScheduledPriority(jack_native_thread_t thread) | |||
{ | |||
return GetThreadPriority(thread, THREAD_SCHEDULED_PRIORITY); | |||
} | |||
UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority) | |||
UInt32 JackMachThread::GetThreadPriority(jack_native_thread_t thread, int inWhichPriority) | |||
{ | |||
thread_basic_info_data_t threadInfo; | |||
policy_info_data_t thePolicyInfo; | |||
@@ -127,7 +127,7 @@ UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority) | |||
return 0; | |||
} | |||
int JackMachThread::GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint) | |||
int JackMachThread::GetParams(jack_native_thread_t thread, UInt64* period, UInt64* computation, UInt64* constraint) | |||
{ | |||
thread_time_constraint_policy_data_t theTCPolicy; | |||
mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT; | |||
@@ -160,11 +160,11 @@ int JackMachThread::Kill() | |||
{ | |||
// pthread_cancel still not yet implemented in Darwin (TO CHECK ON TIGER) | |||
jack_log("JackMachThread::Kill"); | |||
if (fThread != (pthread_t)NULL) { // If thread has been started | |||
if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
mach_port_t machThread = pthread_mach_thread_np(fThread); | |||
int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1; | |||
fThread = (pthread_t)NULL; | |||
fThread = (jack_native_thread_t)NULL; | |||
return res; | |||
} else { | |||
return -1; | |||
@@ -175,7 +175,7 @@ int JackMachThread::AcquireRealTime() | |||
{ | |||
jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld", | |||
long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000)); | |||
return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1; | |||
return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1; | |||
} | |||
int JackMachThread::AcquireSelfRealTime() | |||
@@ -197,7 +197,7 @@ int JackMachThread::AcquireSelfRealTime(int priority) | |||
return AcquireSelfRealTime(); | |||
} | |||
int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint) | |||
int JackMachThread::AcquireRealTimeImp(jack_native_thread_t thread, UInt64 period, UInt64 computation, UInt64 constraint) | |||
{ | |||
SetThreadToPriority(thread, 96, true, period, computation, constraint); | |||
return 0; | |||
@@ -205,7 +205,7 @@ int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 c | |||
int JackMachThread::DropRealTime() | |||
{ | |||
return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
} | |||
int JackMachThread::DropSelfRealTime() | |||
@@ -213,7 +213,7 @@ int JackMachThread::DropSelfRealTime() | |||
return DropRealTimeImp(pthread_self()); | |||
} | |||
int JackMachThread::DropRealTimeImp(pthread_t thread) | |||
int JackMachThread::DropRealTimeImp(jack_native_thread_t thread) | |||
{ | |||
SetThreadToPriority(thread, 63, false, 0, 0, 0); | |||
return 0; | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -98,9 +98,9 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread | |||
UInt64 fComputation; | |||
UInt64 fConstraint; | |||
static UInt32 GetThreadSetPriority(pthread_t thread); | |||
static UInt32 GetThreadScheduledPriority(pthread_t thread); | |||
static UInt32 GetThreadPriority(pthread_t thread, int inWhichPriority); | |||
static UInt32 GetThreadSetPriority(jack_native_thread_t thread); | |||
static UInt32 GetThreadScheduledPriority(jack_native_thread_t thread); | |||
static UInt32 GetThreadPriority(jack_native_thread_t thread, int inWhichPriority); | |||
public: | |||
@@ -116,23 +116,23 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread | |||
int AcquireRealTime(); // Used when called from another thread | |||
int AcquireSelfRealTime(); // Used when called from thread itself | |||
int AcquireRealTime(int priority); // Used when called from another thread | |||
int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
int DropRealTime(); // Used when called from another thread | |||
int DropSelfRealTime(); // Used when called from thread itself | |||
void SetParams(UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint); | |||
static int SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int GetParams(jack_native_thread_t thread, UInt64* period, UInt64* computation, UInt64* constraint); | |||
static int SetThreadToPriority(jack_native_thread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
{ | |||
return JackMachThread::AcquireRealTimeImp(thread, period, computation, constraint); | |||
static int AcquireRealTimeImp(jack_native_thread_t thread, UInt64 period, UInt64 computation, UInt64 constraint); | |||
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
{ | |||
return JackMachThread::AcquireRealTimeImp(thread, period, computation, constraint); | |||
} | |||
static int DropRealTimeImp(pthread_t thread); | |||
static int DropRealTimeImp(jack_native_thread_t thread); | |||
}; | |||
} // end of namespace | |||
@@ -184,9 +184,9 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice | |||
AudioDevicePropertyID inPropertyID, | |||
void* inClientData) | |||
{ | |||
switch (inPropertyID) { | |||
case kAudioDeviceProcessorOverload: { | |||
jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload"); | |||
break; | |||
@@ -196,12 +196,12 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice | |||
jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration"); | |||
return kAudioHardwareUnsupportedOperationError; | |||
} | |||
case kAudioDevicePropertyNominalSampleRate: { | |||
jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate"); | |||
return kAudioHardwareUnsupportedOperationError; | |||
} | |||
} | |||
return noErr; | |||
} | |||
@@ -217,7 +217,7 @@ int JackCoreAudioAdapter::AddListeners() | |||
printError(err); | |||
return -1; | |||
} | |||
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); | |||
if (err != noErr) { | |||
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); | |||
@@ -275,17 +275,17 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon, | |||
{ | |||
JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon); | |||
AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); | |||
float* inputBuffer[adapter->fCaptureChannels]; | |||
float* outputBuffer[adapter->fPlaybackChannels]; | |||
for (int i = 0; i < adapter->fCaptureChannels; i++) { | |||
inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData; | |||
} | |||
for (int i = 0; i < adapter->fPlaybackChannels; i++) { | |||
outputBuffer[i] = (float*)ioData->mBuffers[i].mData; | |||
} | |||
adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames); | |||
return noErr; | |||
} | |||
@@ -302,16 +302,16 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
fCaptureUID[0] = 0; | |||
fPlaybackUID[0] = 0; | |||
fClockDriftCompensate = false; | |||
// Default values | |||
fCaptureChannels = -1; | |||
fPlaybackChannels = -1; | |||
SInt32 major; | |||
SInt32 minor; | |||
Gestalt(gestaltSystemVersionMajor, &major); | |||
Gestalt(gestaltSystemVersionMinor, &minor); | |||
// Starting with 10.6 systems, the HAL notification thread is created internally | |||
if (major == 10 && minor >= 6) { | |||
CFRunLoopRef theRunLoop = NULL; | |||
@@ -321,7 +321,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error"); | |||
} | |||
} | |||
for (node = params; node; node = jack_slist_next(node)) { | |||
param = (const jack_driver_param_t*) node->data; | |||
@@ -348,7 +348,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
fPlaying = true; | |||
strncpy(fPlaybackUID, param->value.str, 256); | |||
break; | |||
case 'd': | |||
strncpy(fCaptureUID, param->value.str, 256); | |||
strncpy(fPlaybackUID, param->value.str, 256); | |||
@@ -365,51 +365,51 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra | |||
case 'p': | |||
SetAdaptedBufferSize(param->value.ui); | |||
break; | |||
case 'l': | |||
DisplayDeviceNames(); | |||
break; | |||
case 'q': | |||
fQuality = param->value.ui; | |||
break; | |||
case 'g': | |||
fRingbufferCurSize = param->value.ui; | |||
fAdaptative = false; | |||
break; | |||
case 's': | |||
fClockDriftCompensate = true; | |||
break; | |||
} | |||
} | |||
/* duplex is the default */ | |||
if (!fCapturing && !fPlaying) { | |||
fCapturing = true; | |||
fPlaying = true; | |||
} | |||
if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) | |||
throw -1; | |||
if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) | |||
throw -1; | |||
if (SetupBufferSize(fAdaptedBufferSize) < 0) | |||
throw -1; | |||
if (SetupSampleRate(fAdaptedSampleRate) < 0) | |||
throw -1; | |||
if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0) | |||
if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0) | |||
throw -1; | |||
if (fCapturing && fCaptureChannels > 0) | |||
if (SetupBuffers(fCaptureChannels) < 0) | |||
throw -1; | |||
if (AddListeners() < 0) | |||
throw -1; | |||
} | |||
@@ -488,6 +488,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID* id) | |||
if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) | |||
return res; | |||
if (inDefault == 0) { | |||
jack_error("Error : input device is 0, please select a correct one !!"); | |||
return -1; | |||
} | |||
jack_log("GetDefaultInputDevice: input = %ld ", inDefault); | |||
*id = inDefault; | |||
return noErr; | |||
@@ -502,6 +506,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID* id) | |||
if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) | |||
return res; | |||
if (outDefault == 0) { | |||
jack_error("Error : output device is 0, please select a correct one !!"); | |||
return -1; | |||
} | |||
jack_log("GetDefaultOutputDevice: output = %ld", outDefault); | |||
*id = outDefault; | |||
return noErr; | |||
@@ -525,10 +533,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
// Duplex | |||
if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { | |||
// Same device for capture and playback... | |||
if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { | |||
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { | |||
jack_log("Will take default in/out"); | |||
if (GetDefaultDevice(&fDeviceID) != noErr) { | |||
@@ -540,12 +548,12 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
jack_error("Cannot get device name from device ID"); | |||
return -1; | |||
} | |||
} else { | |||
// Creates aggregate device | |||
AudioDeviceID captureID, playbackID; | |||
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | |||
jack_log("Will take default input"); | |||
if (GetDefaultInputDevice(&captureID) != noErr) { | |||
@@ -553,7 +561,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
return -1; | |||
} | |||
} | |||
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | |||
jack_log("Will take default output"); | |||
if (GetDefaultOutputDevice(&playbackID) != noErr) { | |||
@@ -561,7 +569,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
return -1; | |||
} | |||
} | |||
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | |||
return -1; | |||
} | |||
@@ -599,10 +607,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
jack_log("JackCoreAudioDriver::Open default driver"); | |||
if (GetDefaultDevice(&fDeviceID) != noErr) { | |||
jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); | |||
// Creates aggregate device | |||
AudioDeviceID captureID, playbackID; | |||
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { | |||
jack_log("Will take default input"); | |||
if (GetDefaultInputDevice(&captureID) != noErr) { | |||
@@ -610,7 +618,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
return -1; | |||
} | |||
} | |||
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { | |||
jack_log("Will take default output"); | |||
if (GetDefaultOutputDevice(&playbackID) != noErr) { | |||
@@ -618,7 +626,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
return -1; | |||
} | |||
} | |||
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) | |||
return -1; | |||
} | |||
@@ -680,7 +688,7 @@ int JackCoreAudioAdapter::SetupChannels(bool capturing, | |||
jack_log("Setup max out channels = %ld", out_nChannels); | |||
outchannels = out_nChannels; | |||
} | |||
return 0; | |||
} | |||
@@ -694,7 +702,7 @@ int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size) | |||
printError(err); | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
@@ -708,7 +716,7 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||
OSStatus err = noErr; | |||
UInt32 outSize; | |||
Float64 sampleRate; | |||
// Get sample rate | |||
outSize = sizeof(Float64); | |||
err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); | |||
@@ -716,12 +724,14 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||
jack_error("Cannot get current sample rate"); | |||
printError(err); | |||
return -1; | |||
} else { | |||
jack_log("Current sample rate = %f", sampleRate); | |||
} | |||
// If needed, set new sample rate | |||
if (samplerate != (jack_nframes_t)sampleRate) { | |||
sampleRate = (Float64)samplerate; | |||
// To get SR change notification | |||
err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); | |||
if (err != noErr) { | |||
@@ -735,18 +745,18 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe | |||
printError(err); | |||
return -1; | |||
} | |||
// Waiting for SR change notification | |||
int count = 0; | |||
while (!fState && count++ < WAIT_COUNTER) { | |||
usleep(100000); | |||
jack_log("Wait count = %d", count); | |||
} | |||
// Remove SR change notification | |||
AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); | |||
} | |||
return 0; | |||
} | |||
@@ -796,7 +806,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
jack_error("No input and output channels..."); | |||
return -1; | |||
} | |||
// AUHAL | |||
ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; | |||
Component HALOutput = FindNextComponent(NULL, &cd); | |||
@@ -823,7 +833,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
enableIO = 0; | |||
jack_log("Setup AUHAL input off"); | |||
} | |||
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); | |||
if (err1 != noErr) { | |||
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); | |||
@@ -838,14 +848,14 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
enableIO = 0; | |||
jack_log("Setup AUHAL output off"); | |||
} | |||
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); | |||
if (err1 != noErr) { | |||
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); | |||
printError(err1); | |||
goto error; | |||
} | |||
size = sizeof(AudioDeviceID); | |||
err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); | |||
if (err1 != noErr) { | |||
@@ -863,7 +873,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
printError(err1); | |||
goto error; | |||
} | |||
// Set buffer size | |||
if (capturing && inchannels > 0) { | |||
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32)); | |||
@@ -918,7 +928,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
// Setup stream converters | |||
if (capturing && inchannels > 0) { | |||
size = sizeof(AudioStreamBasicDescription); | |||
err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size); | |||
if (err1 != noErr) { | |||
@@ -927,7 +937,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
goto error; | |||
} | |||
PrintStreamDesc(&srcFormat); | |||
jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); | |||
srcFormat.mSampleRate = samplerate; | |||
srcFormat.mFormatID = kAudioFormatLinearPCM; | |||
@@ -938,9 +948,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
srcFormat.mChannelsPerFrame = inchannels; | |||
srcFormat.mBitsPerChannel = 32; | |||
PrintStreamDesc(&srcFormat); | |||
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); | |||
if (err1 != noErr) { | |||
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); | |||
printError(err1); | |||
@@ -949,7 +959,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
} | |||
if (playing && outchannels > 0) { | |||
size = sizeof(AudioStreamBasicDescription); | |||
err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size); | |||
if (err1 != noErr) { | |||
@@ -958,7 +968,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
goto error; | |||
} | |||
PrintStreamDesc(&dstFormat); | |||
jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); | |||
dstFormat.mSampleRate = samplerate; | |||
dstFormat.mFormatID = kAudioFormatLinearPCM; | |||
@@ -969,9 +979,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
dstFormat.mChannelsPerFrame = outchannels; | |||
dstFormat.mBitsPerChannel = 32; | |||
PrintStreamDesc(&dstFormat); | |||
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); | |||
if (err1 != noErr) { | |||
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); | |||
printError(err1); | |||
@@ -1003,13 +1013,13 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, | |||
} | |||
return 0; | |||
error: | |||
CloseAUHAL(); | |||
return -1; | |||
} | |||
OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||
OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||
{ | |||
OSStatus osErr = noErr; | |||
AudioObjectPropertyAddress pluginAOPA; | |||
@@ -1017,21 +1027,21 @@ OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() | |||
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||
UInt32 outDataSize; | |||
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); | |||
printError(osErr); | |||
return osErr; | |||
} | |||
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); | |||
printError(osErr); | |||
return osErr; | |||
} | |||
return noErr; | |||
} | |||
@@ -1043,15 +1053,15 @@ static CFStringRef GetDeviceName(AudioDeviceID id) | |||
return (err == noErr) ? UIname : NULL; | |||
} | |||
OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
{ | |||
OSStatus err = noErr; | |||
AudioObjectID sub_device[32]; | |||
UInt32 outSize = sizeof(sub_device); | |||
err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
vector<AudioDeviceID> captureDeviceIDArray; | |||
if (err != noErr) { | |||
jack_log("Input device does not have subdevices"); | |||
captureDeviceIDArray.push_back(captureDeviceID); | |||
@@ -1062,10 +1072,10 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice | |||
captureDeviceIDArray.push_back(sub_device[i]); | |||
} | |||
} | |||
err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
vector<AudioDeviceID> playbackDeviceIDArray; | |||
if (err != noErr) { | |||
jack_log("Output device does not have subdevices"); | |||
playbackDeviceIDArray.push_back(playbackDeviceID); | |||
@@ -1076,16 +1086,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice | |||
playbackDeviceIDArray.push_back(sub_device[i]); | |||
} | |||
} | |||
return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice); | |||
} | |||
OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice) | |||
{ | |||
OSStatus osErr = noErr; | |||
UInt32 outSize; | |||
Boolean outWritable; | |||
// Prepare sub-devices for clock drift compensation | |||
// Workaround for bug in the HAL : until 10.6.2 | |||
AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; | |||
@@ -1094,7 +1104,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
AudioClassID inClass = kAudioSubDeviceClassID; | |||
void* theQualifierData = &inClass; | |||
UInt32 subDevicesNum = 0; | |||
//--------------------------------------------------------------------------- | |||
// Setup SR of both devices otherwise creating AD may fail... | |||
//--------------------------------------------------------------------------- | |||
@@ -1102,18 +1112,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
UInt32 clockdomain = 0; | |||
outSize = sizeof(UInt32); | |||
bool need_clock_drift_compensation = false; | |||
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); | |||
} else { | |||
// Check clock domain | |||
osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
if (osErr != 0) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | |||
printError(osErr); | |||
} else { | |||
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); | |||
if (clockdomain != 0 && clockdomain != keptclockdomain) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); | |||
@@ -1122,18 +1132,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
} | |||
} | |||
} | |||
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); | |||
} else { | |||
// Check clock domain | |||
osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); | |||
if (osErr != 0) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); | |||
printError(osErr); | |||
} else { | |||
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; | |||
jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); | |||
if (clockdomain != 0 && clockdomain != keptclockdomain) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); | |||
@@ -1142,74 +1152,74 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
} | |||
} | |||
} | |||
// If no valid clock domain was found, then assume we have to compensate... | |||
if (keptclockdomain == 0) { | |||
need_clock_drift_compensation = true; | |||
} | |||
//--------------------------------------------------------------------------- | |||
// Start to create a new aggregate by getting the base audio hardware plugin | |||
//--------------------------------------------------------------------------- | |||
char device_name[256]; | |||
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
GetDeviceNameFromID(captureDeviceID[i], device_name); | |||
jack_info("Separated input = '%s' ", device_name); | |||
} | |||
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
GetDeviceNameFromID(playbackDeviceID[i], device_name); | |||
jack_info("Separated output = '%s' ", device_name); | |||
} | |||
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); | |||
printError(osErr); | |||
return osErr; | |||
} | |||
AudioValueTranslation pluginAVT; | |||
CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); | |||
pluginAVT.mInputData = &inBundleRef; | |||
pluginAVT.mInputDataSize = sizeof(inBundleRef); | |||
pluginAVT.mOutputData = &fPluginID; | |||
pluginAVT.mOutputDataSize = sizeof(fPluginID); | |||
osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); | |||
printError(osErr); | |||
return osErr; | |||
} | |||
//------------------------------------------------- | |||
// Create a CFDictionary for our aggregate device | |||
//------------------------------------------------- | |||
CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |||
CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); | |||
CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); | |||
// add the name of the device to the dictionary | |||
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); | |||
// add our choice of UID for the aggregate device to the dictionary | |||
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); | |||
// add a "private aggregate key" to the dictionary | |||
int value = 1; | |||
CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); | |||
SInt32 system; | |||
Gestalt(gestaltSystemVersion, &system); | |||
jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); | |||
// Starting with 10.5.4 systems, the AD can be internal... (better) | |||
if (system < 0x00001054) { | |||
jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); | |||
@@ -1217,16 +1227,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); | |||
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); | |||
} | |||
// Prepare sub-devices for clock drift compensation | |||
CFMutableArrayRef subDevicesArrayClock = NULL; | |||
/* | |||
if (fClockDriftCompensate) { | |||
if (need_clock_drift_compensation) { | |||
jack_info("Clock drift compensation activated..."); | |||
subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |||
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
CFStringRef UID = GetDeviceName(captureDeviceID[i]); | |||
if (UID) { | |||
@@ -1237,7 +1247,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | |||
} | |||
} | |||
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
CFStringRef UID = GetDeviceName(playbackDeviceID[i]); | |||
if (UID) { | |||
@@ -1248,7 +1258,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); | |||
} | |||
} | |||
// add sub-device clock array for the aggregate device to the dictionary | |||
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); | |||
} else { | |||
@@ -1256,14 +1266,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
} | |||
} | |||
*/ | |||
//------------------------------------------------- | |||
// Create a CFMutableArray for our sub-device list | |||
//------------------------------------------------- | |||
// we need to append the UID for each device to a CFMutableArray, so create one here | |||
CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |||
vector<CFStringRef> captureDeviceUID; | |||
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { | |||
CFStringRef ref = GetDeviceName(captureDeviceID[i]); | |||
@@ -1273,7 +1283,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
// input sub-devices in this example, so append the sub-device's UID to the CFArray | |||
CFArrayAppendValue(subDevicesArray, ref); | |||
} | |||
vector<CFStringRef> playbackDeviceUID; | |||
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { | |||
CFStringRef ref = GetDeviceName(playbackDeviceID[i]); | |||
@@ -1283,39 +1293,39 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
// output sub-devices in this example, so append the sub-device's UID to the CFArray | |||
CFArrayAppendValue(subDevicesArray, ref); | |||
} | |||
//----------------------------------------------------------------------- | |||
// Feed the dictionary to the plugin, to create a blank aggregate device | |||
//----------------------------------------------------------------------- | |||
AudioObjectPropertyAddress pluginAOPA; | |||
pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; | |||
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||
UInt32 outDataSize; | |||
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); | |||
printError(osErr); | |||
goto error; | |||
} | |||
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); | |||
printError(osErr); | |||
goto error; | |||
} | |||
// pause for a bit to make sure that everything completed correctly | |||
// this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created | |||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
//------------------------- | |||
// Set the sub-device list | |||
//------------------------- | |||
pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; | |||
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; | |||
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; | |||
@@ -1326,14 +1336,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
printError(osErr); | |||
goto error; | |||
} | |||
// pause again to give the changes time to take effect | |||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
//----------------------- | |||
// Set the master device | |||
//----------------------- | |||
// set the master device manually (this is the device which will act as the master clock for the aggregate device) | |||
// pass in the UID of the device you want to use | |||
pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; | |||
@@ -1346,36 +1356,36 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
printError(osErr); | |||
goto error; | |||
} | |||
// pause again to give the changes time to take effect | |||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
// Prepare sub-devices for clock drift compensation | |||
// Workaround for bug in the HAL : until 10.6.2 | |||
if (fClockDriftCompensate) { | |||
if (need_clock_drift_compensation) { | |||
jack_info("Clock drift compensation activated..."); | |||
// Get the property data size | |||
osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | |||
printError(osErr); | |||
} | |||
// Calculate the number of object IDs | |||
subDevicesNum = outSize / sizeof(AudioObjectID); | |||
jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); | |||
AudioObjectID subDevices[subDevicesNum]; | |||
outSize = sizeof(subDevices); | |||
osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); | |||
if (osErr != noErr) { | |||
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); | |||
printError(osErr); | |||
} | |||
// Set kAudioSubDevicePropertyDriftCompensation property... | |||
for (UInt32 index = 0; index < subDevicesNum; ++index) { | |||
UInt32 theDriftCompensationValue = 1; | |||
@@ -1388,50 +1398,50 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca | |||
} else { | |||
jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); | |||
} | |||
} | |||
} | |||
// pause again to give the changes time to take effect | |||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); | |||
//---------- | |||
// Clean up | |||
//---------- | |||
// release the private AD key | |||
CFRelease(AggregateDeviceNumberRef); | |||
// release the CF objects we have created - we don't need them any more | |||
CFRelease(aggDeviceDict); | |||
CFRelease(subDevicesArray); | |||
if (subDevicesArrayClock) | |||
CFRelease(subDevicesArrayClock); | |||
// release the device UID | |||
for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { | |||
CFRelease(captureDeviceUID[i]); | |||
} | |||
for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { | |||
CFRelease(playbackDeviceUID[i]); | |||
} | |||
jack_log("New aggregate device %ld", *outAggregateDevice); | |||
return noErr; | |||
error: | |||
DestroyAggregateDevice(); | |||
return -1; | |||
} | |||
bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device) | |||
{ | |||
OSStatus err = noErr; | |||
AudioObjectID sub_device[32]; | |||
UInt32 outSize = sizeof(sub_device); | |||
err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); | |||
if (err != noErr) { | |||
jack_log("Device does not have subdevices"); | |||
return false; | |||
@@ -1494,7 +1504,7 @@ extern "C" | |||
strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 | |||
strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 | |||
desc->nparams = 13; | |||
desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); | |||
@@ -1574,7 +1584,7 @@ extern "C" | |||
desc->params[i].value.i = TRUE; | |||
strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); | |||
strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
i++; | |||
strcpy(desc->params[i].name, "quality"); | |||
desc->params[i].character = 'q'; | |||
@@ -1582,7 +1592,7 @@ extern "C" | |||
desc->params[i].value.ui = 0; | |||
strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); | |||
strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
i++; | |||
strcpy(desc->params[i].name, "ring-buffer"); | |||
desc->params[i].character = 'g'; | |||
@@ -1590,7 +1600,7 @@ extern "C" | |||
desc->params[i].value.ui = 32768; | |||
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); | |||
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); | |||
i++; | |||
strcpy(desc->params[i].name, "clock-drift"); | |||
desc->params[i].character = 's'; | |||
@@ -1598,7 +1608,7 @@ extern "C" | |||
desc->params[i].value.i = FALSE; | |||
strcpy(desc->params[i].short_desc, "Clock drift compensation"); | |||
strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device"); | |||
return desc; | |||
} | |||
@@ -6,12 +6,6 @@ def create_jack_driver_obj(bld, target, sources, uselib = None): | |||
driver.features.append('cc') | |||
driver.env['shlib_PATTERN'] = 'jack_%s.so' | |||
driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
# Seems uneeded here... | |||
#if bld.env['HAVE_CELT']: | |||
#if bld.env['HAVE_CELT_API_0_5']: | |||
# driver.defines += ['HAVE_CELT', 'HAVE_CELT_API_0_5'] | |||
#elif bld.env['HAVE_CELT_API_0_7']: | |||
# driver.defines += ['HAVE_CELT', 'HAVE_CELT_API_0_7'] | |||
driver.includes = ['.', '../macosx', '../posix', '../common', '../common/jack'] | |||
driver.target = target | |||
driver.source = sources | |||
@@ -0,0 +1,53 @@ | |||
.TH JACK_IODELAY "1" "!DATE!" "!VERSION!" | |||
.SH NAME | |||
jack_iodelay \- JACK toolkit client to measure roundtrip latency | |||
.SH SYNOPSIS | |||
.B jack_iodelay | |||
.SH DESCRIPTION | |||
.B jack_iodelay | |||
will create one input and one output port, and then | |||
measures the latency (signal delay) between them. For this to work, | |||
the output port must be connected to its input port. The measurement | |||
is accurate to a resolution of greater than 1 sample. | |||
.PP | |||
The expected use is to connect jack_iodelay's output port to a | |||
hardware playback port, then use a physical loopback cable from the | |||
corresponding hardware output connector to an input connector, and to | |||
connect that corresponding hardware capture port to jack_iodelay's | |||
input port. This creates a roundtrip that goes through any | |||
analog-to-digital or digital-converters that are present in the audio | |||
hardware. | |||
.PP | |||
Although the hardware loopback latency is the expected use, it is also | |||
possible to use jack_iodelay to measure the latency along any fully | |||
connected signal path, such as those involving other JACK clients. | |||
.PP | |||
Once jack_iodelay completes its measurement it will print the total | |||
latency it has detected. This will include the JACK period length in | |||
addition to any other latency in the signal path. It will continue to | |||
print the value every 0.5 seconds or so so that if you wish you can | |||
vary aspects of the signal path to see their effect on the measured | |||
latency. | |||
.PP | |||
If no incoming signal is detected from the input port, jack_iodelay | |||
will print | |||
.PP | |||
\fT Signal below threshold... .\fR | |||
.PP | |||
every second until this changes (e.g. until you establish the correct connections). | |||
.PP | |||
To use the value measured by jack_iodelay with the -I and -O arguments | |||
of a JACK backend (also called Input Latency and Output Latency in the | |||
setup dialog of qjackctl), you must subtract the JACK period size from | |||
the result. Then, if you believe that the latency is equally | |||
distributed between the input and output parts of your audio hardware | |||
(extremely likely), divide the result by two and use that for input | |||
and/or output latency value. Doing this measurement will enable JACK | |||
clients that use the JACK latency API to accurately position/delay | |||
audio to keep signals synchronized even when there are inherent delays | |||
in the end-to-end signal pathways. | |||
.SH AUTHOR | |||
Originally written in C++ by Fons Adriensen, ported to C by Torben Hohn. | |||
@@ -33,47 +33,47 @@ namespace Jack | |||
\brief Mutex abstraction. | |||
*/ | |||
class JackBasePosixMutex | |||
{ | |||
protected: | |||
pthread_mutex_t fMutex; | |||
public: | |||
JackBasePosixMutex() | |||
{ | |||
pthread_mutex_init(&fMutex, NULL); | |||
pthread_mutex_init(&fMutex, NULL); | |||
} | |||
virtual ~JackBasePosixMutex() | |||
{ | |||
pthread_mutex_destroy(&fMutex); | |||
} | |||
void Lock() | |||
{ | |||
int res = pthread_mutex_lock(&fMutex); | |||
if (res != 0) | |||
jack_error("JackBasePosixMutex::Lock res = %d", res); | |||
jack_log("JackBasePosixMutex::Lock res = %d", res); | |||
} | |||
bool Trylock() | |||
{ | |||
return (pthread_mutex_trylock(&fMutex) == 0); | |||
} | |||
void Unlock() | |||
{ | |||
int res = pthread_mutex_unlock(&fMutex); | |||
if (res != 0) | |||
jack_error("JackBasePosixMutex::Unlock res = %d", res); | |||
jack_log("JackBasePosixMutex::Unlock res = %d", res); | |||
} | |||
}; | |||
class JackPosixMutex | |||
{ | |||
@@ -97,7 +97,7 @@ class JackPosixMutex | |||
res = pthread_mutexattr_destroy(&mutex_attr); | |||
assert(res == 0); | |||
} | |||
virtual ~JackPosixMutex() | |||
{ | |||
pthread_mutex_destroy(&fMutex); | |||
@@ -107,7 +107,7 @@ class JackPosixMutex | |||
{ | |||
int res = pthread_mutex_lock(&fMutex); | |||
if (res != 0) | |||
jack_error("JackPosixMutex::Lock res = %d", res); | |||
jack_log("JackPosixMutex::Lock res = %d", res); | |||
return (res == 0); | |||
} | |||
@@ -120,7 +120,7 @@ class JackPosixMutex | |||
{ | |||
int res = pthread_mutex_unlock(&fMutex); | |||
if (res != 0) | |||
jack_error("JackPosixMutex::Unlock res = %d", res); | |||
jack_log("JackPosixMutex::Unlock res = %d", res); | |||
return (res == 0); | |||
} | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -40,19 +40,19 @@ void* JackPosixThread::ThreadHandler(void* arg) | |||
if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) { | |||
jack_error("pthread_setcanceltype err = %s", strerror(err)); | |||
} | |||
// Signal creation thread when started with StartSync | |||
jack_log("ThreadHandler: start"); | |||
obj->fStatus = kIniting; | |||
// Call Init method | |||
if (!runnable->Init()) { | |||
jack_error("Thread init fails: thread quits"); | |||
return 0; | |||
} | |||
obj->fStatus = kRunning; | |||
// If Init succeed, start the thread loop | |||
bool res = true; | |||
while (obj->fStatus == kRunning && res) { | |||
@@ -76,11 +76,11 @@ int JackPosixThread::Start() | |||
return 0; | |||
} | |||
} | |||
int JackPosixThread::StartSync() | |||
{ | |||
fStatus = kStarting; | |||
if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { | |||
fStatus = kIdle; | |||
return -1; | |||
@@ -90,10 +90,10 @@ int JackPosixThread::StartSync() | |||
JackSleep(1000); | |||
} | |||
return (count == 1000) ? -1 : 0; | |||
} | |||
} | |||
} | |||
int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg) | |||
int JackPosixThread::StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg) | |||
{ | |||
pthread_attr_t attributes; | |||
struct sched_param rt_param; | |||
@@ -111,19 +111,19 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi | |||
} | |||
if (realtime) { | |||
jack_log("Create RT thread"); | |||
if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) { | |||
jack_error("Cannot request explicit scheduling for RT thread res = %d", res); | |||
return -1; | |||
} | |||
if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { | |||
jack_error("Cannot set RR scheduling class for RT thread res = %d", res); | |||
return -1; | |||
} | |||
memset(&rt_param, 0, sizeof(rt_param)); | |||
rt_param.sched_priority = priority; | |||
@@ -152,13 +152,13 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi | |||
int JackPosixThread::Kill() | |||
{ | |||
if (fThread != (pthread_t)NULL) { // If thread has been started | |||
if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
jack_log("JackPosixThread::Kill"); | |||
void* status; | |||
pthread_cancel(fThread); | |||
pthread_join(fThread, &status); | |||
fStatus = kIdle; | |||
fThread = (pthread_t)NULL; | |||
fThread = (jack_native_thread_t)NULL; | |||
return 0; | |||
} else { | |||
return -1; | |||
@@ -167,21 +167,21 @@ int JackPosixThread::Kill() | |||
int JackPosixThread::Stop() | |||
{ | |||
if (fThread != (pthread_t)NULL) { // If thread has been started | |||
if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
jack_log("JackPosixThread::Stop"); | |||
void* status; | |||
fStatus = kIdle; // Request for the thread to stop | |||
pthread_join(fThread, &status); | |||
fThread = (pthread_t)NULL; | |||
fThread = (jack_native_thread_t)NULL; | |||
return 0; | |||
} else { | |||
return -1; | |||
} | |||
} | |||
int JackPosixThread::KillImp(pthread_t thread) | |||
int JackPosixThread::KillImp(jack_native_thread_t thread) | |||
{ | |||
if (thread != (pthread_t)NULL) { // If thread has been started | |||
if (thread != (jack_native_thread_t)NULL) { // If thread has been started | |||
jack_log("JackPosixThread::Kill"); | |||
void* status; | |||
pthread_cancel(thread); | |||
@@ -192,9 +192,9 @@ int JackPosixThread::KillImp(pthread_t thread) | |||
} | |||
} | |||
int JackPosixThread::StopImp(pthread_t thread) | |||
int JackPosixThread::StopImp(jack_native_thread_t thread) | |||
{ | |||
if (thread != (pthread_t)NULL) { // If thread has been started | |||
if (thread != (jack_native_thread_t)NULL) { // If thread has been started | |||
jack_log("JackPosixThread::Stop"); | |||
void* status; | |||
pthread_join(thread, &status); | |||
@@ -206,7 +206,7 @@ int JackPosixThread::StopImp(pthread_t thread) | |||
int JackPosixThread::AcquireRealTime() | |||
{ | |||
return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1; | |||
return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1; | |||
} | |||
int JackPosixThread::AcquireSelfRealTime() | |||
@@ -225,7 +225,7 @@ int JackPosixThread::AcquireSelfRealTime(int priority) | |||
fPriority = priority; | |||
return AcquireSelfRealTime(); | |||
} | |||
int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) | |||
int JackPosixThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority) | |||
{ | |||
struct sched_param rtparam; | |||
int res; | |||
@@ -243,7 +243,7 @@ int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) | |||
int JackPosixThread::DropRealTime() | |||
{ | |||
return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
} | |||
int JackPosixThread::DropSelfRealTime() | |||
@@ -251,7 +251,7 @@ int JackPosixThread::DropSelfRealTime() | |||
return DropRealTimeImp(pthread_self()); | |||
} | |||
int JackPosixThread::DropRealTimeImp(pthread_t thread) | |||
int JackPosixThread::DropRealTimeImp(jack_native_thread_t thread) | |||
{ | |||
struct sched_param rtparam; | |||
int res; | |||
@@ -265,7 +265,7 @@ int JackPosixThread::DropRealTimeImp(pthread_t thread) | |||
return 0; | |||
} | |||
pthread_t JackPosixThread::GetThreadID() | |||
jack_native_thread_t JackPosixThread::GetThreadID() | |||
{ | |||
return fThread; | |||
} | |||
@@ -320,42 +320,42 @@ bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr) | |||
bool jack_tls_allocate_key(jack_tls_key *key_ptr) | |||
{ | |||
int ret; | |||
ret = pthread_key_create(key_ptr, NULL); | |||
if (ret != 0) | |||
{ | |||
jack_error("pthread_key_create() failed with error %d", ret); | |||
return false; | |||
} | |||
return true; | |||
} | |||
bool jack_tls_free_key(jack_tls_key key) | |||
{ | |||
int ret; | |||
ret = pthread_key_delete(key); | |||
if (ret != 0) | |||
{ | |||
jack_error("pthread_key_delete() failed with error %d", ret); | |||
return false; | |||
} | |||
return true; | |||
} | |||
bool jack_tls_set(jack_tls_key key, void *data_ptr) | |||
{ | |||
int ret; | |||
ret = pthread_setspecific(key, (const void *)data_ptr); | |||
if (ret != 0) | |||
{ | |||
jack_error("pthread_setspecific() failed with error %d", ret); | |||
return false; | |||
} | |||
return true; | |||
} | |||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -40,16 +40,16 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface | |||
protected: | |||
pthread_t fThread; | |||
jack_native_thread_t fThread; | |||
static void* ThreadHandler(void* arg); | |||
public: | |||
JackPosixThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation) | |||
: JackThreadInterface(runnable, priority, real_time, cancellation), fThread((pthread_t)NULL) | |||
: JackThreadInterface(runnable, priority, real_time, cancellation), fThread((jack_native_thread_t)NULL) | |||
{} | |||
JackPosixThread(JackRunnableInterface* runnable, int cancellation = PTHREAD_CANCEL_ASYNCHRONOUS) | |||
: JackThreadInterface(runnable, 0, false, cancellation), fThread((pthread_t)NULL) | |||
: JackThreadInterface(runnable, 0, false, cancellation), fThread((jack_native_thread_t)NULL) | |||
{} | |||
int Start(); | |||
@@ -60,23 +60,23 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface | |||
int AcquireRealTime(); // Used when called from another thread | |||
int AcquireSelfRealTime(); // Used when called from thread itself | |||
int AcquireRealTime(int priority); // Used when called from another thread | |||
int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
int DropRealTime(); // Used when called from another thread | |||
int DropSelfRealTime(); // Used when called from thread itself | |||
pthread_t GetThreadID(); | |||
jack_native_thread_t GetThreadID(); | |||
bool IsThread(); | |||
static int AcquireRealTimeImp(pthread_t thread, int priority); | |||
static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority); | |||
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
{ return JackPosixThread::AcquireRealTimeImp(thread, priority); } | |||
static int DropRealTimeImp(pthread_t thread); | |||
static int StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
static int StopImp(pthread_t thread); | |||
static int KillImp(pthread_t thread); | |||
static int DropRealTimeImp(jack_native_thread_t thread); | |||
static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
static int StopImp(jack_native_thread_t thread); | |||
static int KillImp(jack_native_thread_t thread); | |||
}; | |||
SERVER_EXPORT void ThreadExit(); | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -45,12 +45,12 @@ void JackClientSocket::SetReadTimeOut(long sec) | |||
{ | |||
int flags; | |||
fTimeOut = sec; | |||
if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | |||
jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL"); | |||
return; | |||
} | |||
flags |= O_NONBLOCK; | |||
if (fcntl(fSocket, F_SETFL, flags) < 0) { | |||
jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL"); | |||
@@ -62,12 +62,12 @@ void JackClientSocket::SetWriteTimeOut(long sec) | |||
{ | |||
int flags; | |||
fTimeOut = sec; | |||
if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { | |||
jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL"); | |||
return; | |||
} | |||
flags |= O_NONBLOCK; | |||
if (fcntl(fSocket, F_SETFL, flags) < 0) { | |||
jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL"); | |||
@@ -100,7 +100,7 @@ void JackClientSocket::SetWriteTimeOut(long sec) | |||
#endif | |||
void JackClientSocket::SetNonBlocking(bool onoff) | |||
{ | |||
{ | |||
if (onoff) { | |||
long flags = 0; | |||
if (fcntl(fSocket, F_SETFL, flags | O_NONBLOCK) < 0) { | |||
@@ -140,7 +140,7 @@ int JackClientSocket::Connect(const char* dir, const char* name, int which) // A | |||
int JackClientSocket::Close() | |||
{ | |||
jack_log("JackClientSocket::Close"); | |||
jack_log("JackClientSocket::Close"); | |||
if (fSocket > 0) { | |||
shutdown(fSocket, SHUT_RDWR); | |||
close(fSocket); | |||
@@ -161,17 +161,17 @@ int JackClientSocket::Read(void* data, int len) | |||
struct timeval tv; | |||
fd_set fdset; | |||
ssize_t res; | |||
tv.tv_sec = fTimeOut; | |||
tv.tv_usec = 0; | |||
FD_ZERO(&fdset); | |||
FD_SET(fSocket, &fdset); | |||
do { | |||
res = select(fSocket + 1, &fdset, NULL, NULL, &tv); | |||
} while (res < 0 && errno == EINTR); | |||
if (res < 0) { | |||
return res; | |||
} else if (res == 0) { | |||
@@ -179,9 +179,9 @@ int JackClientSocket::Read(void* data, int len) | |||
} | |||
} | |||
#endif | |||
if ((res = read(fSocket, data, len)) != len) { | |||
if (errno == EWOULDBLOCK) { | |||
if (errno == EWOULDBLOCK || errno == EAGAIN) { | |||
jack_error("JackClientSocket::Read time out"); | |||
return 0; // For a non blocking socket, a read failure is not considered as an error | |||
} else if (res != 0) { | |||
@@ -201,21 +201,21 @@ int JackClientSocket::Write(void* data, int len) | |||
#if defined(__sun__) || defined(sun) | |||
if (fTimeOut > 0) { | |||
struct timeval tv; | |||
fd_set fdset; | |||
ssize_t res; | |||
tv.tv_sec = fTimeOut; | |||
tv.tv_usec = 0; | |||
FD_ZERO(&fdset); | |||
FD_SET(fSocket, &fdset); | |||
do { | |||
res = select(fSocket + 1, NULL, &fdset, NULL, &tv); | |||
} while (res < 0 && errno == EINTR); | |||
if (res < 0) { | |||
return res; | |||
} else if (res == 0) { | |||
@@ -225,7 +225,7 @@ int JackClientSocket::Write(void* data, int len) | |||
#endif | |||
if ((res = write(fSocket, data, len)) != len) { | |||
if (errno == EWOULDBLOCK) { | |||
if (errno == EWOULDBLOCK || errno == EAGAIN) { | |||
jack_log("JackClientSocket::Write time out"); | |||
return 0; // For a non blocking socket, a write failure is not considered as an error | |||
} else if (res != 0) { | |||
@@ -251,7 +251,7 @@ int JackServerSocket::Bind(const char* dir, const char* name, int which) // A re | |||
addr.sun_family = AF_UNIX; | |||
BuildName(name, fName, dir, which); | |||
strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1); | |||
jack_log("Bind: addr.sun_path %s", addr.sun_path); | |||
unlink(fName); // Security... | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -108,7 +108,6 @@ int JackSocketClientChannel::Start() | |||
} | |||
} | |||
void JackSocketClientChannel::Stop() | |||
{ | |||
jack_log("JackSocketClientChannel::Stop"); | |||
@@ -246,61 +245,73 @@ void JackSocketClientChannel::SetFreewheel(int onoff, int* result) | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t ** result) | |||
void JackSocketClientChannel::ComputeTotalLatencies(int* result) | |||
{ | |||
JackComputeTotalLatenciesRequest req; | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result) | |||
{ | |||
JackSessionNotifyRequest req(refnum, path, type, target); | |||
JackSessionNotifyResult res; | |||
JackSessionNotifyResult res; | |||
int intresult; | |||
ServerSyncCall(&req, &res, &intresult); | |||
jack_session_command_t *session_command = (jack_session_command_t *)malloc( sizeof(jack_session_command_t) * (res.fCommandList.size()+1) ); | |||
int i=0; | |||
jack_session_command_t* session_command = (jack_session_command_t *)malloc(sizeof(jack_session_command_t) * (res.fCommandList.size() + 1)); | |||
int i = 0; | |||
for (std::list<JackSessionCommand>::iterator ci=res.fCommandList.begin(); ci!=res.fCommandList.end(); ci++) { | |||
session_command[i].uuid = strdup( ci->fUUID ); | |||
session_command[i].client_name = strdup( ci->fClientName ); | |||
session_command[i].command = strdup( ci->fCommand ); | |||
session_command[i].flags = ci->fFlags; | |||
i+=1; | |||
} | |||
session_command[i].uuid = strdup( ci->fUUID ); | |||
session_command[i].client_name = strdup( ci->fClientName ); | |||
session_command[i].command = strdup( ci->fCommand ); | |||
session_command[i].flags = ci->fFlags; | |||
i += 1; | |||
} | |||
session_command[i].uuid = NULL; | |||
session_command[i].client_name = NULL; | |||
session_command[i].command = NULL; | |||
session_command[i].flags = (jack_session_flags_t)0; | |||
*result = session_command; | |||
} | |||
void JackSocketClientChannel::SessionReply(int refnum, int* result) | |||
{ | |||
JackSessionReplyRequest req(refnum); | |||
JackResult res; | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackSocketClientChannel::GetUUIDForClientName( int refnum, const char *client_name, char *uuid_res, int *result ) | |||
void JackSocketClientChannel::GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result) | |||
{ | |||
JackGetUUIDRequest req(client_name); | |||
JackUUIDResult res; | |||
JackUUIDResult res; | |||
ServerSyncCall(&req, &res, result); | |||
strncpy( uuid_res, res.fUUID, JACK_UUID_SIZE ); | |||
strncpy(uuid_res, res.fUUID, JACK_UUID_SIZE); | |||
} | |||
void JackSocketClientChannel::GetClientNameForUUID( int refnum, const char *uuid, char *name_res, int *result ) | |||
void JackSocketClientChannel::GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result) | |||
{ | |||
JackGetClientNameRequest req(uuid); | |||
JackClientNameResult res; | |||
JackClientNameResult res; | |||
ServerSyncCall(&req, &res, result); | |||
strncpy(name_res, res.fName, JACK_CLIENT_NAME_SIZE); | |||
} | |||
void JackSocketClientChannel::ClientHasSessionCallback(const char* client_name, int* result) | |||
{ | |||
JackClientHasSessionCallbackRequest req(client_name); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
strncpy( name_res, res.fName, JACK_CLIENT_NAME_SIZE ); | |||
} | |||
void JackSocketClientChannel::ReserveClientName( int refnum, const char *client_name, const char *uuid, int *result ) | |||
void JackSocketClientChannel::ReserveClientName(int refnum, const char* client_name, const char* uuid, int* result) | |||
{ | |||
JackReserveNameRequest req(refnum, client_name, uuid); | |||
JackResult res; | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
@@ -363,7 +374,7 @@ bool JackSocketClientChannel::Init() | |||
jack_error("JackSocketClientChannel: cannot establish notication socket"); | |||
return false; | |||
} else { | |||
return fClient->Init(); | |||
return true; | |||
} | |||
} | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -38,11 +38,11 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||
private: | |||
JackClientSocket fRequestSocket; // Socket to communicate with the server | |||
JackServerSocket fNotificationListenSocket; // Socket listener for server notification | |||
JackClientSocket* fNotificationSocket; // Socket for server notification | |||
JackClientSocket fRequestSocket; // Socket to communicate with the server | |||
JackServerSocket fNotificationListenSocket; // Socket listener for server notification | |||
JackClientSocket* fNotificationSocket; // Socket for server notification | |||
JackThread fThread; // Thread to execute the event loop | |||
JackClient* fClient; | |||
JackClient* fClient; | |||
void ServerSyncCall(JackRequest* req, JackResult* res, int* result); | |||
void ServerAsyncCall(JackRequest* req, JackResult* res, int* result); | |||
@@ -77,12 +77,14 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||
void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); | |||
void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); | |||
void PortRename(int refnum, jack_port_id_t port, const char* name, int* result); | |||
void SetBufferSize(jack_nframes_t buffer_size, int* result); | |||
void SetFreewheel(int onoff, int* result); | |||
void ComputeTotalLatencies(int* result); | |||
void ReleaseTimebase(int refnum, int* result); | |||
void SetTimebaseCallback(int refnum, int conditional, int* result); | |||
@@ -91,18 +93,18 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi | |||
void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result); | |||
void InternalClientUnload(int refnum, int int_ref, int* status, int* result); | |||
// Session Stuff | |||
// Session API | |||
void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result); | |||
void SessionReply(int refnum, int* result); | |||
void GetUUIDForClientName( int refnum, const char *client_name, char *uuid_res, int *result ); | |||
void GetClientNameForUUID( int refnum, const char *uuid, char *name_res, int *result ); | |||
void ReserveClientName( int refnum, const char *client_name, const char *uuid, int *result ); | |||
void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result); | |||
void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result); | |||
void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result); | |||
void ClientHasSessionCallback(const char* client_name, int* result); | |||
// JackRunnableInterface interface | |||
bool Init(); | |||
bool Execute(); | |||
bool IsChannelThread() { return fThread.IsThread(); } | |||
}; | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -51,7 +51,7 @@ JackSocketServerChannel::~JackSocketServerChannel() | |||
int JackSocketServerChannel::Open(const char* server_name, JackServer* server) | |||
{ | |||
jack_log("JackSocketServerChannel::Open"); | |||
// Prepare request socket | |||
if (fRequestListenSocket.Bind(jack_server_dir, server_name, 0) < 0) { | |||
jack_log("JackSocketServerChannel::Open : cannot create result listen socket"); | |||
@@ -79,14 +79,14 @@ void JackSocketServerChannel::Close() | |||
delete socket; | |||
} | |||
} | |||
int JackSocketServerChannel::Start() | |||
{ | |||
if (fThread.Start() != 0) { | |||
jack_error("Cannot start Jack server listener"); | |||
return -1; | |||
} | |||
} | |||
return 0; | |||
} | |||
@@ -168,6 +168,12 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
return false; | |||
} | |||
if (fd == JackServerGlobals::fRTNotificationSocket && header.fType != JackRequest::kNotification) { | |||
jack_error("fRTNotificationSocket = %d", JackServerGlobals::fRTNotificationSocket); | |||
jack_error("JackSocketServerChannel::HandleRequest : incorrect notification !!"); | |||
return true; | |||
} | |||
// Read data | |||
switch (header.fType) { | |||
@@ -292,7 +298,7 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
jack_error("JackRequest::DisconnectPorts write error ref = %d", req.fRefNum); | |||
break; | |||
} | |||
case JackRequest::kPortRename: { | |||
jack_log("JackRequest::PortRename"); | |||
JackPortRenameRequest req; | |||
@@ -326,6 +332,17 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
break; | |||
} | |||
case JackRequest::kComputeTotalLatencies: { | |||
jack_log("JackRequest::ComputeTotalLatencies"); | |||
JackComputeTotalLatenciesRequest req; | |||
JackResult res; | |||
if (req.Read(socket) == 0) | |||
res.fResult = fServer->GetEngine()->ComputeTotalLatencies(); | |||
if (res.Write(socket) < 0) | |||
jack_error("JackRequest::ComputeTotalLatencies write error"); | |||
break; | |||
} | |||
case JackRequest::kReleaseTimebase: { | |||
jack_log("JackRequest::ReleaseTimebase"); | |||
JackReleaseTimebaseRequest req; | |||
@@ -430,27 +447,26 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
} | |||
case JackRequest::kGetClientByUUID: { | |||
jack_log("JackRequest::GetClientNameForUUID"); | |||
jack_log("JackRequest::GetClientByUUID"); | |||
JackGetClientNameRequest req; | |||
JackClientNameResult res; | |||
if (req.Read(socket) == 0) { | |||
fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult); | |||
} | |||
if (res.Write(socket) < 0) | |||
jack_error("JackRequest::GetClientNameForUUID write error"); | |||
jack_error("JackRequest::GetClientByUUID write error"); | |||
break; | |||
} | |||
case JackRequest::kGetUUIDByClient: { | |||
jack_log("JackRequest::GetUUIDForClientName"); | |||
jack_log("JackRequest::GetUUIDByClient"); | |||
JackGetUUIDRequest req; | |||
JackUUIDResult res; | |||
if (req.Read(socket) == 0) { | |||
fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult); | |||
res.fResult = 0; | |||
} | |||
if (res.Write(socket) < 0) | |||
jack_error("JackRequest::GetUUIDForClientName write error"); | |||
jack_error("JackRequest::GetUUIDByClient write error"); | |||
break; | |||
} | |||
@@ -466,11 +482,23 @@ bool JackSocketServerChannel::HandleRequest(int fd) | |||
break; | |||
} | |||
case JackRequest::kClientHasSessionCallback: { | |||
jack_log("JackRequest::ClientHasSessionCallback"); | |||
JackClientHasSessionCallbackRequest req; | |||
JackResult res; | |||
if (req.Read(socket) == 0) { | |||
fServer->GetEngine()->ClientHasSessionCallbackRequest(req.fName, &res.fResult); | |||
} | |||
if (res.Write(socket) < 0) | |||
jack_error("JackRequest::ClientHasSessionCallback write error"); | |||
break; | |||
} | |||
default: | |||
jack_error("Unknown request %ld", header.fType); | |||
break; | |||
} | |||
return true; | |||
} | |||
@@ -511,7 +539,7 @@ bool JackSocketServerChannel::Init() | |||
bool JackSocketServerChannel::Execute() | |||
{ | |||
try { | |||
// Global poll | |||
if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) { | |||
jack_error("Engine poll failed err = %s request thread quits...", strerror(errno)); | |||
@@ -526,22 +554,22 @@ bool JackSocketServerChannel::Execute() | |||
jack_log("Poll client error err = %s", strerror(errno)); | |||
ClientKill(fd); | |||
} else if (fPollTable[i].revents & POLLIN) { | |||
if (!HandleRequest(fd)) | |||
if (!HandleRequest(fd)) | |||
jack_log("Could not handle external client request"); | |||
} | |||
} | |||
// Check the server request socket */ | |||
if (fPollTable[0].revents & POLLERR) | |||
if (fPollTable[0].revents & POLLERR) | |||
jack_error("Error on server request socket err = %s", strerror(errno)); | |||
if (fPollTable[0].revents & POLLIN) | |||
if (fPollTable[0].revents & POLLIN) | |||
ClientCreate(); | |||
} | |||
BuildPoolTable(); | |||
return true; | |||
} catch (JackQuitException& e) { | |||
jack_log("JackMachServerChannel::Execute JackQuitException"); | |||
return false; | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -41,7 +41,7 @@ class JackSocketServerChannel : public JackRunnableInterface | |||
JackServerSocket fRequestListenSocket; // Socket to create request socket for the client | |||
JackThread fThread; // Thread to execute the event loop | |||
JackServer* fServer; | |||
JackServer* fServer; | |||
pollfd* fPollTable; | |||
bool fRebuild; | |||
std::map<int, std::pair<int, JackClientSocket*> > fSocketTable; | |||
@@ -61,7 +61,7 @@ class JackSocketServerChannel : public JackRunnableInterface | |||
int Open(const char* server_name, JackServer* server); // Open the Server/Client connection | |||
void Close(); // Close the Server/Client connection | |||
int Start(); | |||
// JackRunnableInterface interface | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackRequest.h" | |||
#include "JackConstants.h" | |||
#include "JackNotification.h" | |||
#include "JackServerGlobals.h" | |||
namespace Jack | |||
{ | |||
@@ -33,6 +34,7 @@ int JackSocketServerNotifyChannel::Open(const char* server_name) | |||
return -1; | |||
} else { | |||
fRequestSocket.SetNonBlocking(true); | |||
JackServerGlobals::fRTNotificationSocket = fRequestSocket.GetFd(); | |||
return 0; | |||
} | |||
} | |||
@@ -63,7 +65,7 @@ void JackSocketServerNotifyChannel::NotifyQuit() | |||
jack_error("Could not write request ref = %d notify = %d", -1, kQUIT); | |||
} | |||
} | |||
} // end of namespace | |||
@@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
@@ -25,6 +25,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include <signal.h> | |||
#include <dlfcn.h> | |||
#define UINT32_MAX 4294967295U | |||
#define DRIVER_HANDLE void* | |||
#define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) | |||
#define UnloadDriverModule(handle) dlclose((handle)) | |||
@@ -26,6 +26,8 @@ | |||
typedef unsigned long long UInt64; | |||
typedef pthread_key_t jack_tls_key; | |||
typedef pthread_t jack_native_thread_t; | |||
typedef int (*jack_thread_creator_t)(pthread_t*, const pthread_attr_t*, void* (*function)(void*), void* arg); | |||
#endif |
@@ -1,6 +1,6 @@ | |||
/* | |||
Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation; either version 2 of the License, or | |||
@@ -95,14 +95,14 @@ int MTDM::process (size_t len, float *ip, float *op) | |||
vip = *ip++; | |||
for (i = 0, F = _freq; i < 5; i++, F++) | |||
{ | |||
a = 2 * (float) M_PI * (F->p & 65535) / 65536.0; | |||
a = 2 * (float) M_PI * (F->p & 65535) / 65536.0; | |||
F->p += F->f; | |||
c = cosf (a); | |||
s = -sinf (a); | |||
c = cosf (a); | |||
s = -sinf (a); | |||
vop += F->a * s; | |||
F->xa += s * vip; | |||
F->ya += c * vip; | |||
} | |||
} | |||
*op++ = vop; | |||
if (++_cnt == 16) | |||
{ | |||
@@ -142,10 +142,10 @@ int MTDM::resolve (void) | |||
k = (int)(floor (p + 0.5)); | |||
e = fabs (p - k); | |||
if (e > _err) _err = e; | |||
if (e > 0.4) return 1; | |||
if (e > 0.4) return 1; | |||
d += m * (k & 7); | |||
m *= 8; | |||
} | |||
} | |||
_del = 16 * d; | |||
return 0; | |||
@@ -158,6 +158,34 @@ static jack_client_t *jack_handle; | |||
static jack_port_t *jack_capt; | |||
static jack_port_t *jack_play; | |||
jack_latency_range_t capture_latency = {-1, -1}; | |||
jack_latency_range_t playback_latency = {-1, -1}; | |||
void | |||
latency_cb (jack_latency_callback_mode_t mode, void *arg) | |||
{ | |||
jack_latency_range_t range; | |||
range.min = range.max = 0; | |||
if (mode == JackCaptureLatency) { | |||
jack_port_set_latency_range (jack_play, mode, &range); | |||
jack_port_get_latency_range (jack_capt, mode, &range); | |||
if ((range.min != capture_latency.min) || (range.max != capture_latency.max)) { | |||
capture_latency = range; | |||
printf ("new capture latency: [%d, %d]\n", range.min, range.max); | |||
} | |||
} else { | |||
jack_port_set_latency_range (jack_capt, mode, &range); | |||
jack_port_get_latency_range (jack_play, mode, &range); | |||
if ((range.min != playback_latency.min) || (range.max != playback_latency.max)) { | |||
playback_latency = range; | |||
printf ("new playback latency: [%d, %d]\n", range.min, range.max); | |||
} | |||
} | |||
} | |||
int jack_callback (jack_nframes_t nframes, void *arg) | |||
{ | |||
float *ip, *op; | |||
@@ -182,14 +210,12 @@ int main (int ac, char *av []) | |||
jack_set_process_callback (jack_handle, jack_callback, 0); | |||
if (jack_set_latency_callback) | |||
jack_set_latency_callback (jack_handle, latency_cb, 0); | |||
jack_capt = jack_port_register (jack_handle, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
jack_play = jack_port_register (jack_handle, "out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
printf ("capture latency = %d\n", | |||
jack_port_get_latency (jack_port_by_name (jack_handle, "system:capture_1"))); | |||
printf ("playback_latency = %d\n", | |||
jack_port_get_latency (jack_port_by_name (jack_handle, "system:playback_1"))); | |||
t = 1000.0f / jack_get_sample_rate (jack_handle); | |||
if (jack_activate (jack_handle)) | |||
@@ -200,16 +226,16 @@ int main (int ac, char *av []) | |||
while (1) | |||
{ | |||
#ifdef WIN32 | |||
Sleep (250); | |||
#else | |||
usleep (250000); | |||
#endif | |||
#ifdef WIN32 | |||
Sleep (250); | |||
#else | |||
usleep (250000); | |||
#endif | |||
if (mtdm.resolve () < 0) printf ("Signal below threshold...\n"); | |||
else | |||
else | |||
{ | |||
if (mtdm.err () > 0.3) | |||
if (mtdm.err () > 0.3) | |||
{ | |||
mtdm.invert (); | |||
mtdm.resolve (); |
@@ -9,7 +9,7 @@ test_programs = { | |||
#'testSem': ['testSem.cpp'], | |||
'jack_test': ['test.cpp'], | |||
'jack_cpu': ['cpu.c'], | |||
'jack_delay': ['jdelay.cpp'], | |||
'jack_iodelay': ['iodelay.cpp'], | |||
'jack_multiple_metro' : ['external_metro.cpp'], | |||
} | |||
@@ -43,7 +43,7 @@ RSC=rc.exe | |||
# PROP Ignore_Export_Lib 0 | |||
# PROP Target_Dir "" | |||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | |||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | |||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c | |||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | |||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | |||
# ADD BASE RSC /l 0x409 /d "NDEBUG" | |||