Browse Source

rebase from trunk 4083:4180

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@4181 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.8
sletz 14 years ago
parent
commit
a7e8377441
100 changed files with 5448 additions and 2949 deletions
  1. +61
    -2
      ChangeLog
  2. +255
    -153
      common/JackAPI.cpp
  3. +78
    -22
      common/JackAudioDriver.cpp
  4. +9
    -5
      common/JackAudioDriver.h
  5. +16
    -7
      common/JackAudioPort.cpp
  6. +13
    -18
      common/JackChannel.h
  7. +232
    -92
      common/JackClient.cpp
  8. +20
    -12
      common/JackClient.h
  9. +3
    -3
      common/JackClientControl.h
  10. +42
    -3
      common/JackConnectionManager.cpp
  11. +27
    -8
      common/JackConnectionManager.h
  12. +6
    -6
      common/JackDebugClient.cpp
  13. +2
    -2
      common/JackDebugClient.h
  14. +5
    -5
      common/JackDriver.cpp
  15. +44
    -44
      common/JackDriver.h
  16. +6
    -0
      common/JackDummyDriver.cpp
  17. +83
    -42
      common/JackEngine.cpp
  18. +6
    -2
      common/JackEngine.h
  19. +14
    -14
      common/JackEngineControl.cpp
  20. +5
    -6
      common/JackError.h
  21. +11
    -11
      common/JackFrameTimer.h
  22. +78
    -37
      common/JackGraphManager.cpp
  23. +9
    -7
      common/JackGraphManager.h
  24. +10
    -7
      common/JackInternalClientChannel.h
  25. +22
    -6
      common/JackLockedEngine.h
  26. +13
    -14
      common/JackMessageBuffer.cpp
  27. +12
    -6
      common/JackMidiPort.cpp
  28. +25
    -20
      common/JackNetDriver.cpp
  29. +46
    -34
      common/JackNetManager.cpp
  30. +3
    -3
      common/JackNetManager.h
  31. +688
    -692
      common/JackNetOneDriver.cpp
  32. +28
    -26
      common/JackNetOneDriver.h
  33. +2
    -1
      common/JackNotification.h
  34. +50
    -6
      common/JackPort.cpp
  35. +10
    -4
      common/JackPort.h
  36. +6
    -6
      common/JackPortType.cpp
  37. +3
    -2
      common/JackPortType.h
  38. +86
    -32
      common/JackRequest.h
  39. +17
    -17
      common/JackServer.cpp
  40. +6
    -4
      common/JackServerGlobals.cpp
  41. +4
    -3
      common/JackServerGlobals.h
  42. +28
    -28
      common/JackThread.h
  43. +0
    -1
      common/JackTime.h
  44. +6
    -0
      common/JackTypes.h
  45. +19
    -19
      common/Jackdmp.cpp
  46. +340
    -124
      common/jack/jack.h
  47. +26
    -26
      common/jack/midiport.h
  48. +143
    -87
      common/jack/session.h
  49. +17
    -6
      common/jack/systemdeps.h
  50. +9
    -5
      common/jack/thread.h
  51. +222
    -171
      common/jack/types.h
  52. +61
    -6
      common/jack/weakjack.h
  53. +20
    -12
      common/jack/weakmacros.h
  54. +87
    -42
      common/netjack.c
  55. +10
    -0
      common/netjack.h
  56. +14
    -60
      common/netjack_packet.c
  57. +0
    -6
      common/netjack_packet.h
  58. +6
    -5
      common/timestamps.c
  59. +53
    -13
      example-clients/alsa_in.c
  60. +53
    -9
      example-clients/alsa_out.c
  61. +13
    -2
      example-clients/bufsize.c
  62. +155
    -55
      example-clients/connect.c
  63. +215
    -0
      example-clients/latent_client.c
  64. +29
    -15
      example-clients/lsp.c
  65. +114
    -0
      example-clients/midi_dump.c
  66. +31
    -27
      example-clients/netsource.c
  67. +117
    -120
      example-clients/session_notify.c
  68. +2
    -6
      example-clients/wscript
  69. +5
    -2
      linux/JackAtomic_os.h
  70. +1
    -0
      linux/JackLinuxTime.c
  71. +82
    -64
      linux/alsa/JackAlsaDriver.cpp
  72. +13
    -13
      linux/alsa/alsa_rawmidi.c
  73. +8
    -8
      linux/alsa/alsa_seqmidi.c
  74. +5
    -5
      linux/alsa/usx2y.c
  75. +0
    -18
      linux/cycles.h
  76. +14
    -9
      linux/firewire/JackFFADODriver.cpp
  77. +10
    -7
      linux/freebob/JackFreebobDriver.cpp
  78. +1
    -1
      macosx/Jack-Info.plist
  79. +13
    -13
      macosx/JackMachThread.cpp
  80. +14
    -14
      macosx/JackMachThread.h
  81. +835
    -107
      macosx/Jackdmp.xcodeproj/project.pbxproj
  82. +152
    -142
      macosx/coreaudio/JackCoreAudioAdapter.cpp
  83. +158
    -146
      macosx/coreaudio/JackCoreAudioDriver.cpp
  84. +0
    -6
      macosx/wscript
  85. +53
    -0
      man/jack_iodelay.0
  86. +17
    -17
      posix/JackPosixMutex.h
  87. +32
    -32
      posix/JackPosixThread.cpp
  88. +13
    -13
      posix/JackPosixThread.h
  89. +20
    -20
      posix/JackSocket.cpp
  90. +37
    -26
      posix/JackSocketClientChannel.cpp
  91. +13
    -11
      posix/JackSocketClientChannel.h
  92. +46
    -18
      posix/JackSocketServerChannel.cpp
  93. +3
    -3
      posix/JackSocketServerChannel.h
  94. +4
    -2
      posix/JackSocketServerNotifyChannel.cpp
  95. +1
    -1
      posix/JackSocketServerNotifyChannel.h
  96. +2
    -0
      posix/JackSystemDeps_os.h
  97. +2
    -0
      posix/JackTypes_os.h
  98. +46
    -20
      tests/iodelay.cpp
  99. +1
    -1
      tests/wscript
  100. +1
    -1
      windows/JackRouter/JackRouter.dsp

+ 61
- 2
ChangeLog View File

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



+ 255
- 153
common/JackAPI.cpp View File

@@ -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);
}
}

+ 78
- 22
common/JackAudioDriver.cpp View File

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

+ 9
- 5
common/JackAudioDriver.h View File

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


+ 16
- 7
common/JackAudioPort.cpp View File

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


+ 13
- 18
common/JackChannel.h View File

@@ -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;
}
};



+ 232
- 92
common/JackClient.cpp View File

@@ -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;
}



+ 20
- 12
common/JackClient.h View File

@@ -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();


+ 3
- 3
common/JackClientControl.h View File

@@ -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;


+ 42
- 3
common/JackConnectionManager.cpp View File

@@ -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.
*/


+ 27
- 8
common/JackConnectionManager.h View File

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


+ 6
- 6
common/JackDebugClient.cpp View File

@@ -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;


+ 2
- 2
common/JackDebugClient.h View File

@@ -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);


+ 5
- 5
common/JackDriver.cpp View File

@@ -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);


+ 44
- 44
common/JackDriver.h View File

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

+ 6
- 0
common/JackDummyDriver.cpp View File

@@ -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;


+ 83
- 42
common/JackEngine.cpp View File

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


+ 6
- 2
common/JackEngine.h View File

@@ -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);
};




+ 14
- 14
common/JackEngineControl.cpp View File

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

+ 5
- 6
common/JackError.h View File

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


+ 11
- 11
common/JackFrameTimer.h View File

@@ -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;




+ 78
- 37
common/JackGraphManager.cpp View File

@@ -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;


+ 9
- 7
common/JackGraphManager.h View File

@@ -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);



+ 10
- 7
common/JackInternalClientChannel.h View File

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


+ 22
- 6
common/JackLockedEngine.h View File

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


+ 13
- 14
common/JackMessageBuffer.cpp View File

@@ -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();
}

};


+ 12
- 6
common/JackMidiPort.cpp View File

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

+ 25
- 20
common/JackNetDriver.cpp View File

@@ -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;


+ 46
- 34
common/JackNetManager.cpp View File

@@ -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';


+ 3
- 3
common/JackNetManager.h View File

@@ -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;


+ 688
- 692
common/JackNetOneDriver.cpp
File diff suppressed because it is too large
View File


+ 28
- 26
common/JackNetOneDriver.h View File

@@ -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()


+ 2
- 1
common/JackNotification.h View File

@@ -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
};



+ 50
- 6
common/JackPort.cpp View File

@@ -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)


+ 10
- 4
common/JackPort.h View File

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


+ 6
- 6
common/JackPortType.cpp View File

@@ -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;
}


+ 3
- 2
common/JackPortType.h View File

@@ -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);
};


+ 86
- 32
common/JackRequest.h View File

@@ -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.
*/


+ 17
- 17
common/JackServer.cpp View File

@@ -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();
}
}



+ 6
- 4
common/JackServerGlobals.cpp View File

@@ -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':


+ 4
- 3
common/JackServerGlobals.h View File

@@ -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();



+ 28
- 28
common/JackThread.h View File

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


+ 0
- 1
common/JackTime.h View File

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



+ 6
- 0
common/JackTypes.h View File

@@ -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 {


+ 19
- 19
common/Jackdmp.cpp View File

@@ -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);


+ 340
- 124
common/jack/jack.h View File

@@ -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.


+ 26
- 26
common/jack/midiport.h View File

@@ -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.


+ 143
- 87
common/jack/session.h View File

@@ -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
}


+ 17
- 6
common/jack/systemdeps.h View File

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

+ 9
- 5
common/jack/thread.h View File

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



+ 222
- 171
common/jack/types.h View File

@@ -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__ */

+ 61
- 6
common/jack/weakjack.h View File

@@ -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 */

+ 20
- 12
common/jack/weakmacros.h View File

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



+ 87
- 42
common/netjack.c View File

@@ -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;


+ 10
- 0
common/netjack.h View File

@@ -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 );


+ 14
- 60
common/netjack_packet.c View File

@@ -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 );


+ 0
- 6
common/netjack_packet.h View File

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


+ 6
- 5
common/timestamps.c View File

@@ -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) {


+ 53
- 13
example-clients/alsa_in.c View File

@@ -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 */



+ 53
- 9
example-clients/alsa_out.c View File

@@ -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 */



+ 13
- 2
example-clients/bufsize.c View File

@@ -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[])


+ 155
- 55
example-clients/connect.c View File

@@ -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);
}


+ 215
- 0
example-clients/latent_client.c View File

@@ -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);
}

+ 29
- 15
example-clients/lsp.c View File

@@ -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);


+ 114
- 0
example-clients/midi_dump.c View File

@@ -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;
}

+ 31
- 27
example-clients/netsource.c View File

@@ -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);
}

+ 117
- 120
example-clients/session_notify.c View File

@@ -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;
}

+ 2
- 6
example-clients/wscript View File

@@ -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'


+ 5
- 2
linux/JackAtomic_os.h View File

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



+ 1
- 0
linux/JackLinuxTime.c View File

@@ -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;


+ 82
- 64
linux/alsa/JackAlsaDriver.cpp View File

@@ -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;


+ 13
- 13
linux/alsa/alsa_rawmidi.c View File

@@ -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);



+ 8
- 8
linux/alsa/alsa_seqmidi.c View File

@@ -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)


+ 5
- 5
linux/alsa/usx2y.c View File

@@ -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;
}



+ 0
- 18
linux/cycles.h View File

@@ -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__ */

+ 14
- 9
linux/firewire/JackFFADODriver.cpp View File

@@ -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));


+ 10
- 7
linux/freebob/JackFreebobDriver.cpp View File

@@ -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));


+ 1
- 1
macosx/Jack-Info.plist View File

@@ -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
- 13
macosx/JackMachThread.cpp View File

@@ -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;


+ 14
- 14
macosx/JackMachThread.h View File

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


+ 835
- 107
macosx/Jackdmp.xcodeproj/project.pbxproj
File diff suppressed because it is too large
View File


+ 152
- 142
macosx/coreaudio/JackCoreAudioAdapter.cpp View File

@@ -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;
}



+ 158
- 146
macosx/coreaudio/JackCoreAudioDriver.cpp
File diff suppressed because it is too large
View File


+ 0
- 6
macosx/wscript View File

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


+ 53
- 0
man/jack_iodelay.0 View File

@@ -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.




+ 17
- 17
posix/JackPosixMutex.h View File

@@ -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);
}



+ 32
- 32
posix/JackPosixThread.cpp View File

@@ -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
- 13
posix/JackPosixThread.h View File

@@ -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();


+ 20
- 20
posix/JackSocket.cpp View File

@@ -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...



+ 37
- 26
posix/JackSocketClientChannel.cpp View File

@@ -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;
}
}



+ 13
- 11
posix/JackSocketClientChannel.h View File

@@ -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(); }
};



+ 46
- 18
posix/JackSocketServerChannel.cpp View File

@@ -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;


+ 3
- 3
posix/JackSocketServerChannel.h View File

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


+ 4
- 2
posix/JackSocketServerNotifyChannel.cpp View File

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



+ 1
- 1
posix/JackSocketServerNotifyChannel.h View File

@@ -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.

*/


+ 2
- 0
posix/JackSystemDeps_os.h View File

@@ -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))


+ 2
- 0
posix/JackTypes_os.h View File

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

tests/jdelay.cpp → tests/iodelay.cpp View File

@@ -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 ();

+ 1
- 1
tests/wscript View File

@@ -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'],
}



+ 1
- 1
windows/JackRouter/JackRouter.dsp View File

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


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save