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 Arnold Krille
Jan Engelhardt Jan Engelhardt
Adrian Knoth Adrian Knoth
David Garcia Garzon
David Garcia Garzon
Valerio Pilo
--------------------------- ---------------------------
Jackdmp changes log Jackdmp changes log
--------------------------- ---------------------------


2011-03-11 Stephane Letz <letz@grame.fr>

* Correct JackNetMaster::SetBufferSize.

2011-03-10 Stephane Letz <letz@grame.fr>

* Latency callback must always be activated.
* Correct TopologicalSort.
* Add jack_midi_dump client.
* Synchronize netjack1 with JACK1 version.
* Synchronize jack_connect/jack_disconnect with JACK1 version.

2011-03-09 Stephane Letz <letz@grame.fr>

* jack_client_has_session_callback implementation.
* Fix jdelay for new latency API.
* Check requested buffer size and limit to 1..8192 - avoids wierd behaviour caused by jack_bufsize foobar.
* jack_port_type_get_buffer_size implementation.
* Stop using alloca and allocate buffer on the heap for alsa_io.
* Rename jdelay to jack_iodelay as per Fons' request.
* Call buffer size callback in activate (actually this is done on client side in the RT thread Init method).
* JackEngine::ComputeTotalLatencies in progress.

2011-03-08 Stephane Letz <letz@grame.fr>

* Use of latency range in all backends.
* ComputeTotalLatencies now a client/server call.
* Add latent test client for latency API.
* Also print playback and capture latency in jack_lsp.

2011-03-04 Stephane Letz <letz@grame.fr>

* Revert r4119 (RT notification in the server). JackAudioDriver::ProcessSync now skip backend write in case of graph process failure.
* Fix incorrect error codes in alsa/usx2y.c and alsa/JackAlsaDriver.cpp.
* Synchronize public headers with JACK1. Update OSX project.
* New latency API implementation (in progress).

2011-02-09 Stephane Letz <letz@grame.fr>

* Remove JackPortIsActive flag.

2011-02-07 Stephane Letz <letz@grame.fr>

* Valerio Pilo second CAS for ARMv7 patch.

2011-02-03 Stephane Letz <letz@grame.fr>

* Valerio Pilo CAS for ARMv7 patch.

2011-01-11 Stephane Letz <letz@grame.fr>

* Adrian Knoth jack_lsp patch.

2010-11-17 Stephane Letz <letz@grame.fr>

* ALSA backend : suspend/resume handling (jack1 r4075).
* Correct dummy driver.

2010-11-05 Stephane Letz <letz@grame.fr> 2010-11-05 Stephane Letz <letz@grame.fr>


* In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. * In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start.
* Correct symbols export in backends.
* Correct symbols export in backends on OSX.


2010-11-03 Stephane Letz <letz@grame.fr> 2010-11-03 Stephane Letz <letz@grame.fr>




+ 255
- 153
common/JackAPI.cpp View File

@@ -41,7 +41,7 @@ extern "C"
{ {
#endif #endif


typedef void (*print_function)(const char *);
typedef void (*print_function)(const char*);
typedef void *(*thread_routine)(void*); typedef void *(*thread_routine)(void*);


EXPORT EXPORT
@@ -53,198 +53,219 @@ extern "C"
int *proto_ptr); int *proto_ptr);


EXPORT EXPORT
const char *
const char*
jack_get_version_string(); jack_get_version_string();


jack_client_t * jack_client_new_aux (const char *client_name,
jack_client_t * jack_client_new_aux(const char* client_name,
jack_options_t options, jack_options_t options,
jack_status_t *status); jack_status_t *status);
EXPORT jack_client_t * jack_client_open (const char *client_name,
EXPORT jack_client_t * jack_client_open(const char* client_name,
jack_options_t options, jack_options_t options,
jack_status_t *status, ...); jack_status_t *status, ...);
EXPORT jack_client_t * jack_client_new (const char *client_name);
EXPORT int jack_client_name_size (void);
EXPORT char* jack_get_client_name (jack_client_t *client);
EXPORT int jack_internal_client_new (const char *client_name,
const char *load_name,
const char *load_init);
EXPORT void jack_internal_client_close (const char *client_name);
EXPORT int jack_is_realtime (jack_client_t *client);
EXPORT void jack_on_shutdown (jack_client_t *client,
EXPORT jack_client_t * jack_client_new(const char* client_name);
EXPORT int jack_client_name_size(void);
EXPORT char* jack_get_client_name(jack_client_t *client);
EXPORT int jack_internal_client_new(const char* client_name,
const char* load_name,
const char* load_init);
EXPORT void jack_internal_client_close(const char* client_name);
EXPORT int jack_is_realtime(jack_client_t *client);
EXPORT void jack_on_shutdown(jack_client_t *client,
JackShutdownCallback shutdown_callback, void *arg); JackShutdownCallback shutdown_callback, void *arg);
EXPORT void jack_on_info_shutdown (jack_client_t *client,
EXPORT void jack_on_info_shutdown(jack_client_t *client,
JackInfoShutdownCallback shutdown_callback, void *arg); JackInfoShutdownCallback shutdown_callback, void *arg);
EXPORT int jack_set_process_callback (jack_client_t *client,
EXPORT int jack_set_process_callback(jack_client_t *client,
JackProcessCallback process_callback, JackProcessCallback process_callback,
void *arg); void *arg);
EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status); EXPORT jack_nframes_t jack_thread_wait(jack_client_t *client, int status);


// new // new
EXPORT jack_nframes_t jack_cycle_wait (jack_client_t*);
EXPORT void jack_cycle_signal (jack_client_t*, int status);
EXPORT jack_nframes_t jack_cycle_wait(jack_client_t*);
EXPORT void jack_cycle_signal(jack_client_t*, int status);
EXPORT int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg); EXPORT int jack_set_process_thread(jack_client_t* client, JackThreadCallback fun, void *arg);


EXPORT int jack_set_thread_init_callback (jack_client_t *client,
EXPORT int jack_set_thread_init_callback(jack_client_t *client,
JackThreadInitCallback thread_init_callback, JackThreadInitCallback thread_init_callback,
void *arg); void *arg);
EXPORT int jack_set_freewheel_callback (jack_client_t *client,
EXPORT int jack_set_freewheel_callback(jack_client_t *client,
JackFreewheelCallback freewheel_callback, JackFreewheelCallback freewheel_callback,
void *arg); void *arg);
EXPORT int jack_set_freewheel(jack_client_t* client, int onoff); EXPORT int jack_set_freewheel(jack_client_t* client, int onoff);
EXPORT int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes);
EXPORT int jack_set_buffer_size_callback (jack_client_t *client,
EXPORT int jack_set_buffer_size(jack_client_t *client, jack_nframes_t nframes);
EXPORT int jack_set_buffer_size_callback(jack_client_t *client,
JackBufferSizeCallback bufsize_callback, JackBufferSizeCallback bufsize_callback,
void *arg); void *arg);
EXPORT int jack_set_sample_rate_callback (jack_client_t *client,
EXPORT int jack_set_sample_rate_callback(jack_client_t *client,
JackSampleRateCallback srate_callback, JackSampleRateCallback srate_callback,
void *arg); void *arg);
EXPORT int jack_set_client_registration_callback (jack_client_t *,
EXPORT int jack_set_client_registration_callback(jack_client_t *,
JackClientRegistrationCallback JackClientRegistrationCallback
registration_callback, void *arg); registration_callback, void *arg);
EXPORT int jack_set_port_registration_callback (jack_client_t *,
EXPORT int jack_set_port_registration_callback(jack_client_t *,
JackPortRegistrationCallback JackPortRegistrationCallback
registration_callback, void *arg); registration_callback, void *arg);
EXPORT int jack_set_port_connect_callback (jack_client_t *,
EXPORT int jack_set_port_connect_callback(jack_client_t *,
JackPortConnectCallback JackPortConnectCallback
connect_callback, void *arg); connect_callback, void *arg);
EXPORT int jack_set_port_rename_callback (jack_client_t *,
EXPORT int jack_set_port_rename_callback(jack_client_t *,
JackPortRenameCallback JackPortRenameCallback
rename_callback, void *arg); rename_callback, void *arg);
EXPORT int jack_set_graph_order_callback (jack_client_t *,
EXPORT int jack_set_graph_order_callback(jack_client_t *,
JackGraphOrderCallback graph_callback, JackGraphOrderCallback graph_callback,
void *); void *);
EXPORT int jack_set_xrun_callback (jack_client_t *,
EXPORT int jack_set_xrun_callback(jack_client_t *,
JackXRunCallback xrun_callback, void *arg); JackXRunCallback xrun_callback, void *arg);
EXPORT int jack_activate (jack_client_t *client);
EXPORT int jack_deactivate (jack_client_t *client);
EXPORT jack_port_t * jack_port_register (jack_client_t *client,
const char *port_name,
const char *port_type,
EXPORT int jack_set_latency_callback(jack_client_t *client,
JackLatencyCallback callback, void *arg);

EXPORT int jack_activate(jack_client_t *client);
EXPORT int jack_deactivate(jack_client_t *client);
EXPORT jack_port_t * jack_port_register(jack_client_t *client,
const char* port_name,
const char* port_type,
unsigned long flags, unsigned long flags,
unsigned long buffer_size); unsigned long buffer_size);
EXPORT int jack_port_unregister (jack_client_t *, jack_port_t *);
EXPORT void * jack_port_get_buffer (jack_port_t *, jack_nframes_t);
EXPORT const char * jack_port_name (const jack_port_t *port);
EXPORT const char * jack_port_short_name (const jack_port_t *port);
EXPORT int jack_port_flags (const jack_port_t *port);
EXPORT const char * jack_port_type (const jack_port_t *port);
EXPORT jack_port_type_id_t jack_port_type_id (const jack_port_t *port);
EXPORT int jack_port_is_mine (const jack_client_t *, const jack_port_t *port);
EXPORT int jack_port_connected (const jack_port_t *port);
EXPORT int jack_port_connected_to (const jack_port_t *port,
const char *port_name);
EXPORT const char ** jack_port_get_connections (const jack_port_t *port);
EXPORT const char ** jack_port_get_all_connections (const jack_client_t *client,
EXPORT int jack_port_unregister(jack_client_t *, jack_port_t *);
EXPORT void * jack_port_get_buffer(jack_port_t *, jack_nframes_t);
EXPORT const char* jack_port_name(const jack_port_t *port);
EXPORT const char* jack_port_short_name(const jack_port_t *port);
EXPORT int jack_port_flags(const jack_port_t *port);
EXPORT const char* jack_port_type(const jack_port_t *port);
EXPORT jack_port_type_id_t jack_port_type_id(const jack_port_t *port);
EXPORT int jack_port_is_mine(const jack_client_t *, const jack_port_t *port);
EXPORT int jack_port_connected(const jack_port_t *port);
EXPORT int jack_port_connected_to(const jack_port_t *port,
const char* port_name);
EXPORT const char* * jack_port_get_connections(const jack_port_t *port);
EXPORT const char* * jack_port_get_all_connections(const jack_client_t *client,
const jack_port_t *port); const jack_port_t *port);
EXPORT int jack_port_tie (jack_port_t *src, jack_port_t *dst);
EXPORT int jack_port_untie (jack_port_t *port);
EXPORT jack_nframes_t jack_port_get_latency (jack_port_t *port);
EXPORT jack_nframes_t jack_port_get_total_latency (jack_client_t *,
EXPORT int jack_port_tie(jack_port_t *src, jack_port_t *dst);
EXPORT int jack_port_untie(jack_port_t *port);

// Old latency API
EXPORT jack_nframes_t jack_port_get_latency(jack_port_t *port);
EXPORT jack_nframes_t jack_port_get_total_latency(jack_client_t *,
jack_port_t *port); jack_port_t *port);
EXPORT void jack_port_set_latency (jack_port_t *, jack_nframes_t);
EXPORT int jack_recompute_total_latency (jack_client_t*, jack_port_t* port);
EXPORT int jack_recompute_total_latencies (jack_client_t*);
EXPORT int jack_port_set_name (jack_port_t *port, const char *port_name);
EXPORT int jack_port_set_alias (jack_port_t *port, const char *alias);
EXPORT int jack_port_unset_alias (jack_port_t *port, const char *alias);
EXPORT int jack_port_get_aliases (const jack_port_t *port, char* const aliases[2]);
EXPORT int jack_port_request_monitor (jack_port_t *port, int onoff);
EXPORT int jack_port_request_monitor_by_name (jack_client_t *client,
const char *port_name, int onoff);
EXPORT int jack_port_ensure_monitor (jack_port_t *port, int onoff);
EXPORT int jack_port_monitoring_input (jack_port_t *port);
EXPORT int jack_connect (jack_client_t *,
const char *source_port,
const char *destination_port);
EXPORT int jack_disconnect (jack_client_t *,
const char *source_port,
const char *destination_port);
EXPORT int jack_port_disconnect (jack_client_t *, jack_port_t *);
EXPORT void jack_port_set_latency(jack_port_t *, jack_nframes_t);
EXPORT int jack_recompute_total_latency(jack_client_t*, jack_port_t* port);

// New latency API
EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range);
EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range);
EXPORT int jack_recompute_total_latencies(jack_client_t*);

EXPORT int jack_port_set_name(jack_port_t *port, const char* port_name);
EXPORT int jack_port_set_alias(jack_port_t *port, const char* alias);
EXPORT int jack_port_unset_alias(jack_port_t *port, const char* alias);
EXPORT int jack_port_get_aliases(const jack_port_t *port, char* const aliases[2]);
EXPORT int jack_port_request_monitor(jack_port_t *port, int onoff);
EXPORT int jack_port_request_monitor_by_name(jack_client_t *client,
const char* port_name, int onoff);
EXPORT int jack_port_ensure_monitor(jack_port_t *port, int onoff);
EXPORT int jack_port_monitoring_input(jack_port_t *port);
EXPORT int jack_connect(jack_client_t *,
const char* source_port,
const char* destination_port);
EXPORT int jack_disconnect(jack_client_t *,
const char* source_port,
const char* destination_port);
EXPORT int jack_port_disconnect(jack_client_t *, jack_port_t *);
EXPORT int jack_port_name_size(void); EXPORT int jack_port_name_size(void);
EXPORT int jack_port_type_size(void); EXPORT int jack_port_type_size(void);
EXPORT jack_nframes_t jack_get_sample_rate (jack_client_t *);
EXPORT jack_nframes_t jack_get_buffer_size (jack_client_t *);
EXPORT const char ** jack_get_ports (jack_client_t *,
const char *port_name_pattern,
const char *type_name_pattern,
EXPORT size_t jack_port_type_get_buffer_size(jack_client_t *client, const char* port_type);
EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *);
EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *);
EXPORT const char* * jack_get_ports(jack_client_t *,
const char* port_name_pattern,
const char* type_name_pattern,
unsigned long flags); unsigned long flags);
EXPORT jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name);
EXPORT jack_port_t * jack_port_by_id (jack_client_t *client,
EXPORT jack_port_t * jack_port_by_name(jack_client_t *, const char* port_name);
EXPORT jack_port_t * jack_port_by_id(jack_client_t *client,
jack_port_id_t port_id); jack_port_id_t port_id);
EXPORT int jack_engine_takeover_timebase (jack_client_t *);
EXPORT jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *);
EXPORT int jack_engine_takeover_timebase(jack_client_t *);
EXPORT jack_nframes_t jack_frames_since_cycle_start(const jack_client_t *);
EXPORT jack_time_t jack_get_time(); EXPORT jack_time_t jack_get_time();
EXPORT jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t time); EXPORT jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t time);
EXPORT jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t frames); EXPORT jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t frames);
EXPORT jack_nframes_t jack_frame_time (const jack_client_t *);
EXPORT jack_nframes_t jack_last_frame_time (const jack_client_t *client);
EXPORT float jack_cpu_load (jack_client_t *client);
EXPORT pthread_t jack_client_thread_id (jack_client_t *);
EXPORT void jack_set_error_function (print_function);
EXPORT void jack_set_info_function (print_function);
EXPORT float jack_get_max_delayed_usecs (jack_client_t *client);
EXPORT float jack_get_xrun_delayed_usecs (jack_client_t *client);
EXPORT void jack_reset_max_delayed_usecs (jack_client_t *client);
EXPORT int jack_release_timebase (jack_client_t *client);
EXPORT int jack_set_sync_callback (jack_client_t *client,
EXPORT jack_nframes_t jack_frame_time(const jack_client_t *);
EXPORT jack_nframes_t jack_last_frame_time(const jack_client_t *client);
EXPORT float jack_cpu_load(jack_client_t *client);
EXPORT jack_native_thread_t jack_client_thread_id(jack_client_t *);
EXPORT void jack_set_error_function(print_function);
EXPORT void jack_set_info_function(print_function);
EXPORT float jack_get_max_delayed_usecs(jack_client_t *client);
EXPORT float jack_get_xrun_delayed_usecs(jack_client_t *client);
EXPORT void jack_reset_max_delayed_usecs(jack_client_t *client);
EXPORT int jack_release_timebase(jack_client_t *client);
EXPORT int jack_set_sync_callback(jack_client_t *client,
JackSyncCallback sync_callback, JackSyncCallback sync_callback,
void *arg); void *arg);
EXPORT int jack_set_sync_timeout (jack_client_t *client,
EXPORT int jack_set_sync_timeout(jack_client_t *client,
jack_time_t timeout); jack_time_t timeout);
EXPORT int jack_set_timebase_callback (jack_client_t *client,
EXPORT int jack_set_timebase_callback(jack_client_t *client,
int conditional, int conditional,
JackTimebaseCallback timebase_callback, JackTimebaseCallback timebase_callback,
void *arg); void *arg);
EXPORT int jack_transport_locate (jack_client_t *client,
EXPORT int jack_transport_locate(jack_client_t *client,
jack_nframes_t frame); jack_nframes_t frame);
EXPORT jack_transport_state_t jack_transport_query (const jack_client_t *client,
EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client,
jack_position_t *pos); jack_position_t *pos);
EXPORT jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client);
EXPORT int jack_transport_reposition (jack_client_t *client,
EXPORT jack_nframes_t jack_get_current_transport_frame(const jack_client_t *client);
EXPORT int jack_transport_reposition(jack_client_t *client,
jack_position_t *pos); jack_position_t *pos);
EXPORT void jack_transport_start (jack_client_t *client);
EXPORT void jack_transport_stop (jack_client_t *client);
EXPORT void jack_get_transport_info (jack_client_t *client,
EXPORT void jack_transport_start(jack_client_t *client);
EXPORT void jack_transport_stop(jack_client_t *client);
EXPORT void jack_get_transport_info(jack_client_t *client,
jack_transport_info_t *tinfo); jack_transport_info_t *tinfo);
EXPORT void jack_set_transport_info (jack_client_t *client,
EXPORT void jack_set_transport_info(jack_client_t *client,
jack_transport_info_t *tinfo); jack_transport_info_t *tinfo);


EXPORT int jack_client_real_time_priority (jack_client_t*);
EXPORT int jack_client_max_real_time_priority (jack_client_t*);
EXPORT int jack_acquire_real_time_scheduling (pthread_t thread, int priority);
EXPORT int jack_client_create_thread (jack_client_t* client,
pthread_t *thread,
EXPORT int jack_client_real_time_priority(jack_client_t*);
EXPORT int jack_client_max_real_time_priority(jack_client_t*);
EXPORT int jack_acquire_real_time_scheduling(jack_native_thread_t thread, int priority);
EXPORT int jack_client_create_thread(jack_client_t* client,
jack_native_thread_t *thread,
int priority, int priority,
int realtime, // boolean int realtime, // boolean
thread_routine routine, thread_routine routine,
void *arg); void *arg);
EXPORT int jack_drop_real_time_scheduling (pthread_t thread);
EXPORT int jack_drop_real_time_scheduling(jack_native_thread_t thread);


EXPORT int jack_client_stop_thread (jack_client_t* client, pthread_t thread);
EXPORT int jack_client_kill_thread (jack_client_t* client, pthread_t thread);
EXPORT int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread);
EXPORT int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread);
#ifndef WIN32 #ifndef WIN32
EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc);
EXPORT void jack_set_thread_creator(jack_thread_creator_t jtc);
#endif #endif
EXPORT char * jack_get_internal_client_name (jack_client_t *client,
EXPORT char * jack_get_internal_client_name(jack_client_t *client,
jack_intclient_t intclient); jack_intclient_t intclient);
EXPORT jack_intclient_t jack_internal_client_handle (jack_client_t *client,
const char *client_name,
EXPORT jack_intclient_t jack_internal_client_handle(jack_client_t *client,
const char* client_name,
jack_status_t *status); jack_status_t *status);
EXPORT jack_intclient_t jack_internal_client_load (jack_client_t *client,
const char *client_name,
EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client,
const char* client_name,
jack_options_t options, jack_options_t options,
jack_status_t *status, ...); jack_status_t *status, ...);
EXPORT jack_intclient_t jack_internal_client_load_aux (jack_client_t *client,
const char *client_name,
EXPORT jack_intclient_t jack_internal_client_load_aux(jack_client_t *client,
const char* client_name,
jack_options_t options, jack_options_t options,
jack_status_t *status, va_list ap); jack_status_t *status, va_list ap);


EXPORT jack_status_t jack_internal_client_unload (jack_client_t *client,
EXPORT jack_status_t jack_internal_client_unload(jack_client_t *client,
jack_intclient_t intclient); jack_intclient_t intclient);
EXPORT void jack_free(void* ptr); EXPORT void jack_free(void* ptr);


EXPORT int jack_set_session_callback(jack_client_t* ext_client, JackSessionCallback session_callback, void* arg);
EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path);
EXPORT int jack_session_reply(jack_client_t* ext_client, jack_session_event_t *event);
EXPORT void jack_session_event_free(jack_session_event_t* ev);
EXPORT char* jack_get_uuid_for_client_name(jack_client_t* ext_client, const char* client_name);
EXPORT char* jack_get_client_name_by_uuid(jack_client_t* ext_client, const char* client_uuid);
EXPORT int jack_reserve_client_name(jack_client_t* ext_client, const char* name, const char* uuid);
EXPORT void jack_session_commands_free(jack_session_command_t *cmds);
EXPORT int jack_client_has_session_callback(jack_client_t *client, const char* client_name);

#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -256,7 +277,7 @@ static inline bool CheckPort(jack_port_id_t port_index)


static inline bool CheckBufferSize(jack_nframes_t buffer_size) static inline bool CheckBufferSize(jack_nframes_t buffer_size)
{ {
return (buffer_size <= BUFFER_SIZE_MAX);
return (buffer_size >= 1 && buffer_size <= BUFFER_SIZE_MAX);
} }


static inline void WaitGraphChange() static inline void WaitGraphChange()
@@ -278,12 +299,12 @@ static inline void WaitGraphChange()
} }
} }


EXPORT void jack_set_error_function (print_function func)
EXPORT void jack_set_error_function(print_function func)
{ {
jack_error_callback = (func == NULL) ? &default_jack_error_callback : func; jack_error_callback = (func == NULL) ? &default_jack_error_callback : func;
} }


EXPORT void jack_set_info_function (print_function func)
EXPORT void jack_set_info_function(print_function func)
{ {
jack_info_callback = (func == NULL) ? &default_jack_info_callback : func; jack_info_callback = (func == NULL) ? &default_jack_info_callback : func;
} }
@@ -526,6 +547,40 @@ EXPORT void jack_port_set_latency(jack_port_t* port, jack_nframes_t frames)
} }
} }


EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_port_get_latency_range");
#endif
uintptr_t port_aux = (uintptr_t)port;
jack_port_id_t myport = (jack_port_id_t)port_aux;
if (!CheckPort(myport)) {
jack_error("jack_port_get_latency_range called with an incorrect port %ld", myport);
} else {
WaitGraphChange();
JackGraphManager* manager = GetGraphManager();
if (manager)
manager->GetPort(myport)->GetLatencyRange(mode, range);
}
}

EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_port_set_latency_range");
#endif
uintptr_t port_aux = (uintptr_t)port;
jack_port_id_t myport = (jack_port_id_t)port_aux;
if (!CheckPort(myport)) {
jack_error("jack_port_set_latency_range called with an incorrect port %ld", myport);
} else {
WaitGraphChange();
JackGraphManager* manager = GetGraphManager();
if (manager)
manager->GetPort(myport)->SetLatencyRange(mode, range);
}
}

EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* port) EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* port)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
@@ -536,10 +591,10 @@ EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t*
uintptr_t port_aux = (uintptr_t)port; uintptr_t port_aux = (uintptr_t)port;
jack_port_id_t myport = (jack_port_id_t)port_aux; jack_port_id_t myport = (jack_port_id_t)port_aux;
if (client == NULL) { if (client == NULL) {
jack_error("jack_recompute_total_latencies called with a NULL client");
jack_error("jack_recompute_total_latency called with a NULL client");
return -1; return -1;
} else if (!CheckPort(myport)) { } else if (!CheckPort(myport)) {
jack_error("jack_recompute_total_latencies called with a NULL port");
jack_error("jack_recompute_total_latency called with a NULL port");
return -1; return -1;
} else { } else {
WaitGraphChange(); WaitGraphChange();
@@ -559,9 +614,7 @@ EXPORT int jack_recompute_total_latencies(jack_client_t* ext_client)
jack_error("jack_recompute_total_latencies called with a NULL client"); jack_error("jack_recompute_total_latencies called with a NULL client");
return -1; return -1;
} else { } else {
WaitGraphChange();
JackGraphManager* manager = GetGraphManager();
return (manager ? manager->ComputeTotalLatencies() : -1);
return client->ComputeTotalLatencies();
} }
} }


@@ -988,6 +1041,20 @@ EXPORT int jack_set_xrun_callback(jack_client_t* ext_client, JackXRunCallback xr
} }
} }


EXPORT int jack_set_latency_callback(jack_client_t* ext_client, JackLatencyCallback latency_callback, void *arg)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_set_latency_callback");
#endif
JackClient* client = (JackClient*)ext_client;
if (client == NULL) {
jack_error("jack_set_latency_callback called with a NULL client");
return -1;
} else {
return client->SetLatencyCallback(latency_callback, arg);
}
}

EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback init_callback, void *arg) EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback init_callback, void *arg)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
@@ -1396,7 +1463,7 @@ EXPORT float jack_cpu_load(jack_client_t* ext_client)
} }
} }


EXPORT pthread_t jack_client_thread_id(jack_client_t* ext_client)
EXPORT jack_native_thread_t jack_client_thread_id(jack_client_t* ext_client)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_client_thread_id"); JackGlobals::CheckContext("jack_client_thread_id");
@@ -1404,7 +1471,7 @@ EXPORT pthread_t jack_client_thread_id(jack_client_t* ext_client)
JackClient* client = (JackClient*)ext_client; JackClient* client = (JackClient*)ext_client;
if (client == NULL) { if (client == NULL) {
jack_error("jack_client_thread_id called with a NULL client"); jack_error("jack_client_thread_id called with a NULL client");
return (pthread_t)NULL;
return (jack_native_thread_t)NULL;
} else { } else {
return client->GetThreadID(); return client->GetThreadID();
} }
@@ -1439,6 +1506,26 @@ EXPORT int jack_port_type_size(void)
return JACK_PORT_TYPE_SIZE; return JACK_PORT_TYPE_SIZE;
} }


EXPORT size_t jack_port_type_get_buffer_size(jack_client_t* ext_client, const char* port_type)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_port_type_get_buffer_size");
#endif
JackClient* client = (JackClient*)ext_client;
if (client == NULL) {
jack_error("jack_port_type_get_buffer_size called with a NULL client");
return 0;
} else {
jack_port_type_id_t port_id = GetPortTypeId(port_type);
if (port_id == PORT_TYPES_MAX) {
jack_error("jack_port_type_get_buffer_size called with an unknown port type = %s", port_type);
return 0;
} else {
return GetPortType(port_id)->size();
}
}
}

// transport.h // transport.h
EXPORT int jack_release_timebase(jack_client_t* ext_client) EXPORT int jack_release_timebase(jack_client_t* ext_client)
{ {
@@ -1595,7 +1682,7 @@ EXPORT void jack_set_transport_info(jack_client_t* ext_client, jack_transport_in
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_set_transport_info"); JackGlobals::CheckContext("jack_set_transport_info");
#endif
#endif
jack_error("jack_set_transport_info: deprecated"); jack_error("jack_set_transport_info: deprecated");
if (tinfo) if (tinfo)
memset(tinfo, 0, sizeof(jack_transport_info_t)); memset(tinfo, 0, sizeof(jack_transport_info_t));
@@ -1677,14 +1764,14 @@ EXPORT int jack_client_max_real_time_priority(jack_client_t* ext_client)
} }
} }


EXPORT int jack_acquire_real_time_scheduling(pthread_t thread, int priority)
EXPORT int jack_acquire_real_time_scheduling(jack_native_thread_t thread, int priority)
{ {
JackEngineControl* control = GetEngineControl(); JackEngineControl* control = GetEngineControl();
return (control ? JackThread::AcquireRealTimeImp(thread, priority, GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint) : -1); return (control ? JackThread::AcquireRealTimeImp(thread, priority, GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint) : -1);
} }


EXPORT int jack_client_create_thread(jack_client_t* client, EXPORT int jack_client_create_thread(jack_client_t* client,
pthread_t *thread,
jack_native_thread_t *thread,
int priority, int priority,
int realtime, /* boolean */ int realtime, /* boolean */
thread_routine routine, thread_routine routine,
@@ -1692,28 +1779,28 @@ EXPORT int jack_client_create_thread(jack_client_t* client,
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_client_create_thread"); JackGlobals::CheckContext("jack_client_create_thread");
#endif
#endif
return JackThread::StartImp(thread, priority, realtime, routine, arg); return JackThread::StartImp(thread, priority, realtime, routine, arg);
} }


EXPORT int jack_drop_real_time_scheduling(pthread_t thread)
EXPORT int jack_drop_real_time_scheduling(jack_native_thread_t thread)
{ {
return JackThread::DropRealTimeImp(thread); return JackThread::DropRealTimeImp(thread);
} }


EXPORT int jack_client_stop_thread(jack_client_t* client, pthread_t thread)
EXPORT int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_client_stop_thread"); JackGlobals::CheckContext("jack_client_stop_thread");
#endif
#endif
return JackThread::StopImp(thread); return JackThread::StopImp(thread);
} }


EXPORT int jack_client_kill_thread(jack_client_t* client, pthread_t thread)
EXPORT int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_client_kill_thread"); JackGlobals::CheckContext("jack_client_kill_thread");
#endif
#endif
return JackThread::KillImp(thread); return JackThread::KillImp(thread);
} }


@@ -1725,15 +1812,15 @@ EXPORT void jack_set_thread_creator (jack_thread_creator_t jtc)
#endif #endif


// intclient.h // intclient.h
EXPORT int jack_internal_client_new (const char *client_name,
const char *load_name,
const char *load_init)
EXPORT int jack_internal_client_new (const char* client_name,
const char* load_name,
const char* load_init)
{ {
jack_error("jack_internal_client_new: deprecated"); jack_error("jack_internal_client_new: deprecated");
return -1; return -1;
} }


EXPORT void jack_internal_client_close (const char *client_name)
EXPORT void jack_internal_client_close (const char* client_name)
{ {
jack_error("jack_internal_client_close: deprecated"); jack_error("jack_internal_client_close: deprecated");
} }
@@ -1803,7 +1890,7 @@ EXPORT jack_intclient_t jack_internal_client_load_aux(jack_client_t* ext_client,
} }
} }


EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, const char *client_name, jack_options_t options, jack_status_t *status, ...)
EXPORT jack_intclient_t jack_internal_client_load(jack_client_t *client, const char* client_name, jack_options_t options, jack_status_t *status, ...)
{ {
va_list ap; va_list ap;
va_start(ap, status); va_start(ap, status);
@@ -1847,7 +1934,7 @@ jack_get_version(
} }


EXPORT EXPORT
const char *
const char*
jack_get_version_string() jack_get_version_string()
{ {
return VERSION; return VERSION;
@@ -1876,7 +1963,7 @@ EXPORT int jack_set_session_callback(jack_client_t* ext_client, JackSessionCallb
} }
} }


EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char *path)
EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_session_notify"); JackGlobals::CheckContext("jack_session_notify");
@@ -1891,7 +1978,7 @@ EXPORT jack_session_command_t *jack_session_notify(jack_client_t* ext_client, co
} }
} }


EXPORT int jack_session_reply(jack_client_t *ext_client, jack_session_event_t *event)
EXPORT int jack_session_reply(jack_client_t* ext_client, jack_session_event_t *event)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_session_reply"); JackGlobals::CheckContext("jack_session_reply");
@@ -1919,7 +2006,7 @@ EXPORT void jack_session_event_free(jack_session_event_t* ev)
} }
} }


EXPORT char *jack_get_uuid_for_client_name( jack_client_t *ext_client, const char *client_name )
EXPORT char *jack_get_uuid_for_client_name(jack_client_t* ext_client, const char* client_name)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_get_uuid_for_client_name"); JackGlobals::CheckContext("jack_get_uuid_for_client_name");
@@ -1934,7 +2021,7 @@ EXPORT char *jack_get_uuid_for_client_name( jack_client_t *ext_client, const cha
} }
} }


EXPORT char *jack_get_client_name_by_uuid( jack_client_t *ext_client, const char *client_uuid )
EXPORT char *jack_get_client_name_by_uuid(jack_client_t* ext_client, const char* client_uuid)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_get_client_name_by_uuid"); JackGlobals::CheckContext("jack_get_client_name_by_uuid");
@@ -1945,11 +2032,11 @@ EXPORT char *jack_get_client_name_by_uuid( jack_client_t *ext_client, const char
jack_error("jack_get_client_name_by_uuid called with a NULL client"); jack_error("jack_get_client_name_by_uuid called with a NULL client");
return NULL; return NULL;
} else { } else {
return client->GetClientNameForUUID(client_uuid);
return client->GetClientNameByUUID(client_uuid);
} }
} }


EXPORT int jack_reserve_client_name( jack_client_t *ext_client, const char *name, const char *uuid )
EXPORT int jack_reserve_client_name(jack_client_t* ext_client, const char* client_name, const char* uuid)
{ {
#ifdef __CLIENTDEBUG__ #ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_reserve_client_name"); JackGlobals::CheckContext("jack_reserve_client_name");
@@ -1960,17 +2047,17 @@ EXPORT int jack_reserve_client_name( jack_client_t *ext_client, const char *name
jack_error("jack_reserve_client_name called with a NULL client"); jack_error("jack_reserve_client_name called with a NULL client");
return -1; return -1;
} else { } else {
return client->ReserveClientName(name, uuid);
return client->ReserveClientName(client_name, uuid);
} }
} }


EXPORT void jack_session_commands_free( jack_session_command_t *cmds )
EXPORT void jack_session_commands_free(jack_session_command_t *cmds)
{ {
if (!cmds) if (!cmds)
return; return;


int i=0;
while(1) {
int i = 0;
while (1) {
if (cmds[i].client_name) if (cmds[i].client_name)
free ((char *)cmds[i].client_name); free ((char *)cmds[i].client_name);
if (cmds[i].command) if (cmds[i].command)
@@ -1985,3 +2072,18 @@ EXPORT void jack_session_commands_free( jack_session_command_t *cmds )


free(cmds); free(cmds);
} }

EXPORT int jack_client_has_session_callback(jack_client_t* ext_client, const char* client_name)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_client_has_session_callback");
#endif
JackClient* client = (JackClient*)ext_client;
jack_log("jack_client_has_session_callback ext_client %x client %x ", ext_client, client);
if (client == NULL) {
jack_error("jack_client_has_session_callback called with a NULL client");
return -1;
} else {
return client->ClientHasSessionCallback(client_name);
}
}

+ 78
- 22
common/JackAudioDriver.cpp View File

@@ -101,6 +101,7 @@ int JackAudioDriver::Attach()
jack_port_id_t port_index; jack_port_id_t port_index;
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
jack_latency_range_t range;
int i; int i;


jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
@@ -114,7 +115,8 @@ int JackAudioDriver::Attach()
} }
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetAlias(alias); port->SetAlias(alias);
port->SetLatency(fEngineControl->fBufferSize + fCaptureLatency);
range.min = range.max = fEngineControl->fBufferSize + fCaptureLatency;
port->SetLatencyRange(JackCaptureLatency, &range);
fCapturePortList[i] = port_index; fCapturePortList[i] = port_index;
jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", port_index); jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
} }
@@ -129,7 +131,8 @@ int JackAudioDriver::Attach()
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetAlias(alias); port->SetAlias(alias);
// Add more latency if "async" mode is used... // Add more latency if "async" mode is used...
port->SetLatency(fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency);
range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency;
port->SetLatencyRange(JackPlaybackLatency, &range);
fPlaybackPortList[i] = port_index; fPlaybackPortList[i] = port_index;
jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);


@@ -143,7 +146,8 @@ int JackAudioDriver::Attach()
} else { } else {
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetAlias(alias); port->SetAlias(alias);
port->SetLatency(fEngineControl->fBufferSize);
range.min = range.max = fEngineControl->fBufferSize;
port->SetLatencyRange(JackCaptureLatency, &range);
fMonitorPortList[i] = port_index; fMonitorPortList[i] = port_index;
} }
} }
@@ -188,13 +192,13 @@ int JackAudioDriver::ProcessNull()
{ {
// Keep begin cycle time // Keep begin cycle time
JackDriver::CycleTakeBeginTime(); JackDriver::CycleTakeBeginTime();
if (fEngineControl->fSyncMode) { if (fEngineControl->fSyncMode) {
ProcessGraphSync(); ProcessGraphSync();
} else { } else {
ProcessGraphAsync(); ProcessGraphAsync();
} }
// Keep end cycle time // Keep end cycle time
JackDriver::CycleTakeEndTime(); JackDriver::CycleTakeEndTime();
WaitUntilNextCycle(); WaitUntilNextCycle();
@@ -214,23 +218,24 @@ synchronize to the end of client graph execution.
int JackAudioDriver::ProcessAsync() int JackAudioDriver::ProcessAsync()
{ {
// Read input buffers for the current cycle // Read input buffers for the current cycle
if (Read() < 0) {
if (Read() < 0) {
jack_error("JackAudioDriver::ProcessAsync: read error, stopping..."); jack_error("JackAudioDriver::ProcessAsync: read error, stopping...");
return -1;
return -1;
} }


// Write output buffers from the previous cycle // Write output buffers from the previous cycle
if (Write() < 0) { if (Write() < 0) {
jack_error("JackAudioDriver::ProcessAsync: write error, stopping..."); jack_error("JackAudioDriver::ProcessAsync: write error, stopping...");
return -1;
return -1;
} }


// Process graph
if (fIsMaster) { if (fIsMaster) {
ProcessGraphAsync(); ProcessGraphAsync();
} else { } else {
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
} }
// Keep end cycle time // Keep end cycle time
JackDriver::CycleTakeEndTime(); JackDriver::CycleTakeEndTime();
return 0; return 0;
@@ -238,29 +243,38 @@ int JackAudioDriver::ProcessAsync()


/* /*
The driver SYNC mode: the server does synchronize to the end of client graph execution, The driver SYNC mode: the server does synchronize to the end of client graph execution,
output buffers computed at the *current cycle* are used.
if graph process succeed, output buffers computed at the *current cycle* are used.
*/ */


int JackAudioDriver::ProcessSync() int JackAudioDriver::ProcessSync()
{ {
// Read input buffers for the current cycle // Read input buffers for the current cycle
if (Read() < 0) {
if (Read() < 0) {
jack_error("JackAudioDriver::ProcessSync: read error, stopping..."); jack_error("JackAudioDriver::ProcessSync: read error, stopping...");
return -1;
return -1;
} }


// Process graph
if (fIsMaster) { if (fIsMaster) {
ProcessGraphSync();
if (ProcessGraphSync() < 0) {
jack_error("JackAudioDriver::ProcessSync: process error, skip cycle...");
goto end;
}
} else { } else {
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) {
jack_error("JackAudioDriver::ProcessSync: process error, skip cycle...");
goto end;
}
} }
// Write output buffers from the current cycle // Write output buffers from the current cycle
if (Write() < 0) { if (Write() < 0) {
jack_error("JackAudioDriver::ProcessSync: write error, stopping..."); jack_error("JackAudioDriver::ProcessSync: write error, stopping...");
return -1;
return -1;
} }

end:

// Keep end cycle time // Keep end cycle time
JackDriver::CycleTakeEndTime(); JackDriver::CycleTakeEndTime();
return 0; return 0;
@@ -269,25 +283,34 @@ int JackAudioDriver::ProcessSync()
void JackAudioDriver::ProcessGraphAsync() void JackAudioDriver::ProcessGraphAsync()
{ {
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
if (!fEngine->Process(fBeginDateUst, fEndDateUst))
if (!fEngine->Process(fBeginDateUst, fEndDateUst))
jack_error("JackAudioDriver::ProcessGraphAsync: Process error"); jack_error("JackAudioDriver::ProcessGraphAsync: Process error");
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
if (ProcessSlaves() < 0) if (ProcessSlaves() < 0)
jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error"); jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error");
} }


void JackAudioDriver::ProcessGraphSync()
int JackAudioDriver::ProcessGraphSync()
{ {
int res = 0;

// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle
if (fEngine->Process(fBeginDateUst, fEndDateUst)) {
if (fEngine->Process(fBeginDateUst, fEndDateUst)) {
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
if (ProcessSlaves() < 0)
if (ProcessSlaves() < 0) {
jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!"); jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!");
if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0)
res = -1;
}
if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) {
jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!"); jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!");
res = -1;
}
} else { // Graph not finished: do not activate it } else { // Graph not finished: do not activate it
jack_error("JackAudioDriver::ProcessGraphSync: Process error"); jack_error("JackAudioDriver::ProcessGraphSync: Process error");
res = -1;
} }

return res;
} }


void JackAudioDriver::WaitUntilNextCycle() void JackAudioDriver::WaitUntilNextCycle()
@@ -316,4 +339,37 @@ jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index)
return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize); return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize);
} }


int JackAudioDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
{
switch (notify) {

case kLatencyCallback:
HandleLatencyCallback(value1);
break;

default:
JackDriver::ClientNotify(refnum, name, notify, sync, message, value1, value2);
break;
}

return 0;
}

void JackAudioDriver::HandleLatencyCallback(int status)
{
jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency;

for (int i = 0; i < fCaptureChannels; i++) {
if (mode == JackPlaybackLatency) {
fGraphManager->RecalculateLatency(fCapturePortList[i], mode);
}
}

for (int i = 0; i < fPlaybackChannels; i++) {
if (mode == JackCaptureLatency) {
fGraphManager->RecalculateLatency(fPlaybackPortList[i], mode);
}
}
}

} // end of namespace } // end of namespace

+ 9
- 5
common/JackAudioDriver.h View File

@@ -36,12 +36,12 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
protected: protected:


void ProcessGraphAsync(); void ProcessGraphAsync();
void ProcessGraphSync();
int ProcessGraphSync();
void WaitUntilNextCycle(); void WaitUntilNextCycle();


virtual int ProcessAsync(); virtual int ProcessAsync();
virtual int ProcessSync(); virtual int ProcessSync();
int fCaptureChannels; int fCaptureChannels;
int fPlaybackChannels; int fPlaybackChannels;


@@ -57,6 +57,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
jack_default_audio_sample_t* GetOutputBuffer(int port_index); jack_default_audio_sample_t* GetOutputBuffer(int port_index);
jack_default_audio_sample_t* GetMonitorBuffer(int port_index); jack_default_audio_sample_t* GetMonitorBuffer(int port_index);


void HandleLatencyCallback(int status);

public: public:


JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
@@ -73,7 +75,7 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
const char* playback_driver_name, const char* playback_driver_name,
jack_nframes_t capture_latency, jack_nframes_t capture_latency,
jack_nframes_t playback_latency); jack_nframes_t playback_latency);
virtual int Open(bool capturing, virtual int Open(bool capturing,
bool playing, bool playing,
int inchannels, int inchannels,
@@ -83,18 +85,20 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
const char* playback_driver_name, const char* playback_driver_name,
jack_nframes_t capture_latency, jack_nframes_t capture_latency,
jack_nframes_t playback_latency); jack_nframes_t playback_latency);
virtual int Process(); virtual int Process();
virtual int ProcessNull(); virtual int ProcessNull();


virtual int Attach(); virtual int Attach();
virtual int Detach(); virtual int Detach();
virtual int Write(); virtual int Write();


virtual int SetBufferSize(jack_nframes_t buffer_size); virtual int SetBufferSize(jack_nframes_t buffer_size);
virtual int SetSampleRate(jack_nframes_t sample_rate); virtual int SetSampleRate(jack_nframes_t sample_rate);


virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2);

}; };


} // end of namespace } // end of namespace


+ 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 "JackPortType.h"

#include <string.h> #include <string.h>


#if defined (__APPLE__) #if defined (__APPLE__)
@@ -46,7 +49,7 @@ static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_
frames = frames % 4; frames = frames % 4;


while (frames_group > 0) { while (frames_group > 0) {
#if defined (__SSE__) && !defined (__sun__)
#if defined (__SSE__) && !defined (__sun__)
__m128 vec = _mm_add_ps(_mm_load_ps(mixbuffer), _mm_load_ps(buffer)); __m128 vec = _mm_add_ps(_mm_load_ps(mixbuffer), _mm_load_ps(buffer));
_mm_store_ps(mixbuffer, vec); _mm_store_ps(mixbuffer, vec);


@@ -97,7 +100,7 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun
void* buffer; void* buffer;


// Copy first buffer // Copy first buffer
#if defined (__SSE__) && !defined (__sun__)
#if defined (__SSE__) && !defined (__sun__)
jack_nframes_t frames_group = nframes / 4; jack_nframes_t frames_group = nframes / 4;
jack_nframes_t remaining_frames = nframes % 4; jack_nframes_t remaining_frames = nframes % 4;


@@ -127,12 +130,18 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun
} }
} }


static size_t AudioBufferSize()
{
return GetEngineControl()->fBufferSize * sizeof(float);
}

const JackPortType gAudioPortType = const JackPortType gAudioPortType =
{
JACK_DEFAULT_AUDIO_TYPE,
AudioBufferInit,
AudioBufferMixdown
};
{
JACK_DEFAULT_AUDIO_TYPE,
AudioBufferSize,
AudioBufferInit,
AudioBufferMixdown
};


} // namespace Jack } // namespace Jack



+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef __JackChannel__ #ifndef __JackChannel__
#define __JackChannel__ #define __JackChannel__


#include "types.h"
#include "session.h" #include "session.h"


namespace Jack namespace Jack
@@ -108,43 +107,39 @@ class JackClientChannelInterface
{} {}
virtual void SetFreewheel(int onoff, int* result) virtual void SetFreewheel(int onoff, int* result)
{} {}
virtual void ComputeTotalLatencies(int* result)
{}


virtual void ReleaseTimebase(int refnum, int* result) virtual void ReleaseTimebase(int refnum, int* result)
{} {}

virtual void SetTimebaseCallback(int refnum, int conditional, int* result) virtual void SetTimebaseCallback(int refnum, int conditional, int* result)
{} {}


virtual void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) virtual void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result)
{} {}

virtual void InternalClientHandle(int refnum, const char* client_name, int* status, int* int_ref, int* result) virtual void InternalClientHandle(int refnum, const char* client_name, int* status, int* int_ref, int* result)
{} {}

virtual void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) virtual void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result)
{} {}

virtual void InternalClientUnload(int refnum, int int_ref, int* status, int* result) virtual void InternalClientUnload(int refnum, int int_ref, int* status, int* result)
{} {}
virtual void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, jack_session_command_t **result)
{}


virtual void SessionReply(int refnum, int *result)
virtual void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result)
{} {}

virtual void GetUUIDForClientName(int refnum, const char *client_name, char *uuid_res, int *result)
virtual void SessionReply(int refnum, int* result)
{} {}

virtual void GetClientNameForUUID(int refnum, const char *uuid, char *name_res, int *result)
virtual void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result)
{} {}

virtual void ReserveClientName(int refnum, const char *client_name, const char *uuid, int *result)
virtual void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result)
{}
virtual void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result)
{}
virtual void ClientHasSessionCallback(const char* client_name, int* result)
{} {}


virtual bool IsChannelThread() virtual bool IsChannelThread()
{
return false;
{
return false;
} }
}; };




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */


#include "JackClient.h"
#include "JackSystemDeps.h"
#include "JackGraphManager.h" #include "JackGraphManager.h"
#include "JackClientControl.h" #include "JackClientControl.h"
#include "JackEngineControl.h" #include "JackEngineControl.h"
@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "driver_interface.h" #include "driver_interface.h"
#include "JackLibGlobals.h" #include "JackLibGlobals.h"



#include <math.h> #include <math.h>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
@@ -60,6 +61,9 @@ JackClient::JackClient(JackSynchro* table):fThread(this)
fTimebase = NULL; fTimebase = NULL;
fSync = NULL; fSync = NULL;
fThreadFun = NULL; fThreadFun = NULL;
fSession = NULL;
fLatency = NULL;

fProcessArg = NULL; fProcessArg = NULL;
fGraphOrderArg = NULL; fGraphOrderArg = NULL;
fXrunArg = NULL; fXrunArg = NULL;
@@ -75,6 +79,8 @@ JackClient::JackClient(JackSynchro* table):fThread(this)
fSyncArg = NULL; fSyncArg = NULL;
fTimebaseArg = NULL; fTimebaseArg = NULL;
fThreadFunArg = NULL; fThreadFunArg = NULL;
fSessionArg = NULL;
fLatencyArg = NULL;
} }


JackClient::~JackClient() JackClient::~JackClient()
@@ -84,17 +90,17 @@ int JackClient::Close()
{ {
jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum);
int result = 0; int result = 0;
Deactivate(); Deactivate();
fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing
// Request close only if server is still running // Request close only if server is still running
if (JackGlobals::fServerRunning) { if (JackGlobals::fServerRunning) {
fChannel->ClientClose(GetClientControl()->fRefNum, &result); fChannel->ClientClose(GetClientControl()->fRefNum, &result);
} else { } else {
jack_log("JackClient::Close server is shutdown");
jack_log("JackClient::Close server is shutdown");
} }
fChannel->Close(); fChannel->Close();
fSynchroTable[GetClientControl()->fRefNum].Disconnect(); fSynchroTable[GetClientControl()->fRefNum].Disconnect();
JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL;
@@ -106,7 +112,7 @@ bool JackClient::IsActive()
return (GetClientControl()) ? GetClientControl()->fActive : false; return (GetClientControl()) ? GetClientControl()->fActive : false;
} }


pthread_t JackClient::GetThreadID()
jack_native_thread_t JackClient::GetThreadID()
{ {
return fThread.GetThreadID(); return fThread.GetThreadID();
} }
@@ -156,7 +162,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,


case kActivateClient: case kActivateClient:
jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum); jack_log("JackClient::kActivateClient name = %s ref = %ld ", name, refnum);
Init();
InitAux();
break; break;
} }


@@ -188,7 +194,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
res = fBufferSize(value1, fBufferSizeArg); res = fBufferSize(value1, fBufferSizeArg);
} }
break; break;
case kSampleRateCallback: case kSampleRateCallback:
jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1); jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1);
if (fSampleRate) { if (fSampleRate) {
@@ -219,7 +225,9 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
fFreewheel(0, fFreewheelArg); fFreewheel(0, fFreewheelArg);
} }
if (GetEngineControl()->fRealTime) { if (GetEngineControl()->fRealTime) {
fThread.AcquireRealTime();
if (fThread.AcquireRealTime() < 0) {
jack_error("JackClient::AcquireRealTime error");
}
} }
break; break;


@@ -250,7 +258,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
fPortConnect(value1, value2, 0, fPortConnectArg); fPortConnect(value1, value2, 0, fPortConnectArg);
} }
break; break;
case kPortRenameCallback: case kPortRenameCallback:
jack_log("JackClient::kPortRenameCallback port = %ld", value1); jack_log("JackClient::kPortRenameCallback port = %ld", value1);
if (fPortRename) { if (fPortRename) {
@@ -264,7 +272,7 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
res = fXrun(fXrunArg); res = fXrun(fXrunArg);
} }
break; break;
case kShutDownCallback: case kShutDownCallback:
jack_log("JackClient::kShutDownCallback"); jack_log("JackClient::kShutDownCallback");
if (fInfoShutdown) { if (fInfoShutdown) {
@@ -289,15 +297,109 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
res = (fImmediateSessionReply) ? 1 : 2; res = (fImmediateSessionReply) ? 1 : 2;
} }
break; break;

case kLatencyCallback:
res = HandleLatencyCallback(value1);
break;
} }
} }


return res; return res;
} }


int JackClient::HandleLatencyCallback(int status)
{
jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency;
jack_latency_range_t latency = { UINT32_MAX, 0 };

/* first setup all latency values of the ports.
* this is based on the connections of the ports.
*/
list<jack_port_id_t>::iterator it;

for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);
if ((port->GetFlags() & JackPortIsOutput) && (mode == JackPlaybackLatency)) {
GetGraphManager()->RecalculateLatency(*it, mode);
}
if ((port->GetFlags() & JackPortIsInput) && (mode == JackCaptureLatency)) {
GetGraphManager()->RecalculateLatency(*it, mode);
}
}

if (!fLatency) {
/*
* default action is to assume all ports depend on each other.
* then always take the maximum latency.
*/

if (mode == JackPlaybackLatency) {
/* iterate over all OutputPorts, to find maximum playback latency
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);
if (port->GetFlags() & JackPortIsOutput) {
jack_latency_range_t other_latency;
port->GetLatencyRange(mode, &other_latency);
if (other_latency.max > latency.max)
latency.max = other_latency.max;
if (other_latency.min < latency.min)
latency.min = other_latency.min;
}
}

if (latency.min == UINT32_MAX)
latency.min = 0;

/* now set the found latency on all input ports
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);
if (port->GetFlags() & JackPortIsInput) {
port->SetLatencyRange(mode, &latency);
}
}
}
if (mode == JackCaptureLatency) {
/* iterate over all InputPorts, to find maximum playback latency
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);
if (port->GetFlags() & JackPortIsInput) {
jack_latency_range_t other_latency;
port->GetLatencyRange(mode, &other_latency);
if (other_latency.max > latency.max)
latency.max = other_latency.max;
if (other_latency.min < latency.min)
latency.min = other_latency.min;
}
}

if (latency.min == UINT32_MAX)
latency.min = 0;

/* now set the found latency on all output ports
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);
if (port->GetFlags() & JackPortIsOutput) {
port->SetLatencyRange(mode, &latency);
}
}
}
return 0;
}

/* we have a latency callback setup by the client,
* lets use it...
*/
fLatency(mode, fLatencyArg);
return 0;
}

/*! /*!
\brief We need to start thread before activating in the server, otherwise the FW driver \brief We need to start thread before activating in the server, otherwise the FW driver
connected to the client may not be activated.
connected to the client may not be activated.
*/ */
int JackClient::Activate() int JackClient::Activate()
{ {
@@ -310,13 +412,13 @@ int JackClient::Activate()
if (StartThread() < 0) if (StartThread() < 0)
return -1; return -1;
} }
/* /*
Insertion of client in the graph will cause a kGraphOrderCallback notification
Insertion of client in the graph will cause a kGraphOrderCallback notification
to be delivered by the server, the client wants to receive it. to be delivered by the server, the client wants to receive it.
*/ */
GetClientControl()->fActive = true; GetClientControl()->fActive = true;
// Transport related callback become "active" // Transport related callback become "active"
GetClientControl()->fTransportSync = true; GetClientControl()->fTransportSync = true;
GetClientControl()->fTransportTimebase = true; GetClientControl()->fTransportTimebase = true;
@@ -337,18 +439,18 @@ int JackClient::Deactivate()
return 0; return 0;


GetClientControl()->fActive = false; GetClientControl()->fActive = false;
// Transport related callback become "unactive" // Transport related callback become "unactive"
GetClientControl()->fTransportSync = false; GetClientControl()->fTransportSync = false;
GetClientControl()->fTransportTimebase = false; GetClientControl()->fTransportTimebase = false;
// We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate // We need to wait for the new engine cycle before stopping the RT thread, but this is done by ClientDeactivate
int result = -1; int result = -1;
fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
jack_log("JackClient::Deactivate res = %ld", result); jack_log("JackClient::Deactivate res = %ld", result);
// RT thread is stopped only when needed... // RT thread is stopped only when needed...
if (IsRealTime())
if (IsRealTime())
fThread.Kill(); fThread.Kill();
return result; return result;
} }
@@ -357,15 +459,48 @@ int JackClient::Deactivate()
// RT thread management // RT thread management
//---------------------- //----------------------


void JackClient::InitAux()
{
if (fInit) {
jack_log("JackClient::Init calling client thread init callback");
fInit(fInitArg);
}
}

/*! /*!
\brief Called once when the thread starts. \brief Called once when the thread starts.
*/ */
bool JackClient::Init() bool JackClient::Init()
{ {
if (fInit) {
jack_log("JackClient::Init calling client thread init callback");
fInit(fInitArg);
/*
Execute buffer_size callback.

Since StartThread uses fThread.StartSync, we are sure that buffer_size callback
is executed before StartThread returns (and then IsActive will be true).
So no RT callback can be called at the same time.
*/
jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", GetEngineControl()->fBufferSize);
if (fBufferSize) {
fBufferSize(GetEngineControl()->fBufferSize, fBufferSizeArg);
}

// Init callback
InitAux();

// Setup context
if (!jack_tls_set(JackGlobals::fRealTime, this))
jack_error("failed to set thread realtime key");

if (GetEngineControl()->fRealTime)
set_threaded_log_function();

// Setup RT
if (GetEngineControl()->fRealTime) {
if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) {
jack_error("JackClient::AcquireRealTime error");
}
} }

return true; return true;
} }


@@ -384,12 +519,6 @@ int JackClient::StartThread()
return -1; return -1;
} }


if (GetEngineControl()->fRealTime) {
if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) {
jack_error("AcquireRealTime error");
}
}

return 0; return 0;
} }


@@ -399,21 +528,15 @@ int JackClient::StartThread()


bool JackClient::Execute() bool JackClient::Execute()
{ {
if (!jack_tls_set(JackGlobals::fRealTime, this))
jack_error("failed to set thread realtime key");
if (GetEngineControl()->fRealTime)
set_threaded_log_function();
// Execute a dummy cycle to be sure thread has the correct properties // Execute a dummy cycle to be sure thread has the correct properties
DummyCycle(); DummyCycle();

if (fThreadFun) { if (fThreadFun) {
fThreadFun(fThreadFunArg); fThreadFun(fThreadFunArg);
} else { } else {
ExecuteThread(); ExecuteThread();
} }
return false;
return false;
} }


void JackClient::DummyCycle() void JackClient::DummyCycle()
@@ -424,15 +547,15 @@ void JackClient::DummyCycle()


inline void JackClient::ExecuteThread() inline void JackClient::ExecuteThread()
{ {
while (true) {
while (true) {
CycleWaitAux(); CycleWaitAux();
CycleSignalAux(CallProcessCallback());
}
CycleSignalAux(CallProcessCallback());
}
} }


inline jack_nframes_t JackClient::CycleWaitAux() inline jack_nframes_t JackClient::CycleWaitAux()
{ {
if (!WaitSync())
if (!WaitSync())
Error(); // Terminates the thread Error(); // Terminates the thread
CallSyncCallbackAux(); CallSyncCallbackAux();
return GetEngineControl()->fBufferSize; return GetEngineControl()->fBufferSize;
@@ -443,7 +566,7 @@ inline void JackClient::CycleSignalAux(int status)
if (status == 0) if (status == 0)
CallTimebaseCallbackAux(); CallTimebaseCallbackAux();
SignalSync(); SignalSync();
if (status != 0)
if (status != 0)
End(); // Terminates the thread End(); // Terminates the thread
} }


@@ -531,7 +654,7 @@ int JackClient::PortRegister(const char* port_name, const char* port_type, unsig
int result = -1; int result = -1;
jack_port_id_t port_index = NO_PORT; jack_port_id_t port_index = NO_PORT;
fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result); fChannel->PortRegister(GetClientControl()->fRefNum, name.c_str(), port_type, flags, buffer_size, &port_index, &result);
if (result == 0) { if (result == 0) {
jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index); jack_log("JackClient::PortRegister ref = %ld name = %s type = %s port_index = %ld", GetClientControl()->fRefNum, name.c_str(), port_type, port_index);
fPortList.push_back(port_index); fPortList.push_back(port_index);
@@ -612,6 +735,13 @@ int JackClient::SetFreeWheel(int onoff)
return result; return result;
} }


int JackClient::ComputeTotalLatencies()
{
int result = -1;
fChannel->ComputeTotalLatencies(&result);
return result;
}

/* /*
ShutDown is called: ShutDown is called:
- from the RT thread when Execute method fails - from the RT thread when Execute method fails
@@ -621,9 +751,9 @@ ShutDown is called:


void JackClient::ShutDown() void JackClient::ShutDown()
{ {
jack_log("ShutDown");
jack_log("JackClient::ShutDown");
JackGlobals::fServerRunning = false; JackGlobals::fServerRunning = false;
if (fInfoShutdown) { if (fInfoShutdown) {
fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg);
fInfoShutdown = NULL; fInfoShutdown = NULL;
@@ -641,18 +771,18 @@ inline int JackClient::ActivateAux()
{ {
// If activated without RT thread... // If activated without RT thread...
if (IsActive() && fThread.GetStatus() != JackThread::kRunning) { if (IsActive() && fThread.GetStatus() != JackThread::kRunning) {
jack_log("ActivateAux");
jack_log("JackClient::ActivateAux");
// RT thread is started // RT thread is started
if (StartThread() < 0) if (StartThread() < 0)
return -1; return -1;
int result = -1; int result = -1;
GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime();
fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result); fChannel->ClientActivate(GetClientControl()->fRefNum, IsRealTime(), &result);
return result; return result;
} else { } else {
return 0; return 0;
} }
@@ -683,7 +813,7 @@ int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timeba
{ {
int result = -1; int result = -1;
fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result);
if (result == 0) { if (result == 0) {
GetClientControl()->fTransportTimebase = true; GetClientControl()->fTransportTimebase = true;
fTimebase = timebase_callback; fTimebase = timebase_callback;
@@ -709,14 +839,14 @@ void JackClient::TransportLocate(jack_nframes_t frame)
jack_position_t pos; jack_position_t pos;
pos.frame = frame; pos.frame = frame;
pos.valid = (jack_position_bits_t)0; pos.valid = (jack_position_bits_t)0;
jack_log("TransportLocate pos = %ld", pos.frame);
jack_log("JackClient::TransportLocate pos = %ld", pos.frame);
GetEngineControl()->fTransport.RequestNewPos(&pos); GetEngineControl()->fTransport.RequestNewPos(&pos);
} }


int JackClient::TransportReposition(jack_position_t* pos) int JackClient::TransportReposition(jack_position_t* pos)
{ {
jack_position_t tmp = *pos; jack_position_t tmp = *pos;
jack_log("TransportReposition pos = %ld", pos->frame);
jack_log("JackClient::TransportReposition pos = %ld", pos->frame);
if (tmp.valid & ~JACK_POSITION_MASK) { if (tmp.valid & ~JACK_POSITION_MASK) {
return EINVAL; return EINVAL;
} else { } else {
@@ -758,11 +888,11 @@ void JackClient::CallSyncCallback()
inline void JackClient::CallSyncCallbackAux() inline void JackClient::CallSyncCallbackAux()
{ {
if (GetClientControl()->fTransportSync) { if (GetClientControl()->fTransportSync) {
JackTransportEngine& transport = GetEngineControl()->fTransport; JackTransportEngine& transport = GetEngineControl()->fTransport;
jack_position_t* cur_pos = transport.ReadCurrentState(); jack_position_t* cur_pos = transport.ReadCurrentState();
jack_transport_state_t transport_state = transport.GetState(); jack_transport_state_t transport_state = transport.GetState();
if (fSync != NULL) { if (fSync != NULL) {
if (fSync(transport_state, cur_pos, fSyncArg)) { if (fSync(transport_state, cur_pos, fSyncArg)) {
GetClientControl()->fTransportState = JackTransportRolling; GetClientControl()->fTransportState = JackTransportRolling;
@@ -785,21 +915,21 @@ inline void JackClient::CallTimebaseCallbackAux()
JackTransportEngine& transport = GetEngineControl()->fTransport; JackTransportEngine& transport = GetEngineControl()->fTransport;
int master; int master;
bool unused; bool unused;
transport.GetTimebaseMaster(master, unused); transport.GetTimebaseMaster(master, unused);
if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase... if (GetClientControl()->fRefNum == master && fTimebase) { // Client *is* timebase...
jack_transport_state_t transport_state = transport.GetState(); jack_transport_state_t transport_state = transport.GetState();
jack_position_t* cur_pos = transport.WriteNextStateStart(1); jack_position_t* cur_pos = transport.WriteNextStateStart(1);
if (GetClientControl()->fTransportTimebase) { if (GetClientControl()->fTransportTimebase) {
fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg);
GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true
fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg);
GetClientControl()->fTransportTimebase = false; // Callback is called only once with "new_pos" = true
} else if (transport_state == JackTransportRolling) { } else if (transport_state == JackTransportRolling) {
fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg);
}
}
transport.WriteNextStateStop(1); transport.WriteNextStateStop(1);
} }
} }
@@ -817,7 +947,7 @@ void JackClient::OnShutdown(JackShutdownCallback callback, void *arg)
fShutdown = callback; fShutdown = callback;
} }
} }
void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg) void JackClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *arg)
{ {
if (IsActive()) { if (IsActive()) {
@@ -873,8 +1003,6 @@ int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg)


int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg) int JackClient::SetGraphOrderCallback(JackGraphOrderCallback callback, void *arg)
{ {
jack_log("SetGraphOrderCallback ");

if (IsActive()) { if (IsActive()) {
jack_error("You cannot set callbacks on an active client"); jack_error("You cannot set callbacks on an active client");
return -1; return -1;
@@ -908,8 +1036,8 @@ int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg
GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL);
fSampleRateArg = arg; fSampleRateArg = arg;
fSampleRate = callback; fSampleRate = callback;
// Now invoke it
if (callback)
// Now invoke it
if (callback)
callback(GetEngineControl()->fSampleRate, arg); callback(GetEngineControl()->fSampleRate, arg);
return 0; return 0;
} }
@@ -1011,6 +1139,19 @@ int JackClient::SetSessionCallback(JackSessionCallback callback, void *arg)
} }
} }


int JackClient::SetLatencyCallback(JackLatencyCallback callback, void *arg)
{
if (IsActive()) {
jack_error("You cannot set callbacks on an active client");
return -1;
} else {
// fCallback[kLatencyCallback] must always be 'true'
fLatencyArg = arg;
fLatency = callback;
return 0;
}
}

//------------------ //------------------
// Internal clients // Internal clients
//------------------ //------------------
@@ -1072,65 +1213,64 @@ void JackClient::InternalClientUnload(int ref, jack_status_t* status)
// Session API // Session API
//------------------ //------------------


jack_session_command_t *JackClient::SessionNotify( const char* target, jack_session_event_type_t type, const char* path )
jack_session_command_t* JackClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path)
{ {
jack_session_command_t *res;
fChannel->SessionNotify( GetClientControl()->fRefNum, target, type, path, &res );
jack_session_command_t* res;
fChannel->SessionNotify(GetClientControl()->fRefNum, target, type, path, &res);
return res; return res;
} }


int JackClient::SessionReply( jack_session_event_t *ev )
int JackClient::SessionReply(jack_session_event_t* ev)
{ {
if (ev->command_line) { if (ev->command_line) {
strncpy( GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand) );
strncpy(GetClientControl()->fSessionCommand, ev->command_line, sizeof(GetClientControl()->fSessionCommand));
} else { } else {
GetClientControl()->fSessionCommand[0] = '\0'; GetClientControl()->fSessionCommand[0] = '\0';
} }


GetClientControl()->fSessionFlags = ev->flags; GetClientControl()->fSessionFlags = ev->flags;


jack_log( "JackClient::SessionReply... we are here" );
jack_log("JackClient::SessionReply... we are here");
if (fChannel->IsChannelThread()) { if (fChannel->IsChannelThread()) {
jack_log( "JackClient::SessionReply... in callback reply" );
jack_log( "JackClient::SessionReply... in callback reply");
fImmediateSessionReply = true; fImmediateSessionReply = true;
return 0; return 0;
} }


jack_log( "JackClient::SessionReply... out of cb" );
jack_log("JackClient::SessionReply... out of cb");


int res;
fChannel->SessionReply( GetClientControl()->fRefNum, &res);
return res;
int result = -1;
fChannel->SessionReply(GetClientControl()->fRefNum, &result);
return result;
} }


char* JackClient::GetUUIDForClientName(const char* client_name) char* JackClient::GetUUIDForClientName(const char* client_name)
{ {
char uuid_res[JACK_UUID_SIZE]; char uuid_res[JACK_UUID_SIZE];
int result = -1; int result = -1;
fChannel->GetUUIDForClientName( GetClientControl()->fRefNum, client_name, uuid_res, &result);

if (result)
return NULL;

return strdup(uuid_res);
fChannel->GetUUIDForClientName(GetClientControl()->fRefNum, client_name, uuid_res, &result);
return (result) ? NULL : strdup(uuid_res);
} }


char* JackClient::GetClientNameForUUID(const char* uuid)
char* JackClient::GetClientNameByUUID(const char* uuid)
{ {
char name_res[JACK_CLIENT_NAME_SIZE + 1]; char name_res[JACK_CLIENT_NAME_SIZE + 1];
int result = -1; int result = -1;
fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result); fChannel->GetClientNameForUUID(GetClientControl()->fRefNum, uuid, name_res, &result);
return (result) ? NULL : strdup(name_res);
}


if (result)
return NULL;

return strdup(name_res);
int JackClient::ReserveClientName(const char* client_name, const char* uuid)
{
int result = -1;
fChannel->ReserveClientName( GetClientControl()->fRefNum, client_name, uuid, &result);
return result;
} }


int JackClient::ReserveClientName(const char *name, const char* uuid)
int JackClient::ClientHasSessionCallback(const char* client_name)
{ {
int result = -1; int result = -1;
fChannel->ReserveClientName( GetClientControl()->fRefNum, name, uuid, &result);
fChannel->ClientHasSessionCallback(client_name, &result);
return result; return result;
} }




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackSynchro.h" #include "JackSynchro.h"
#include "JackPlatformPlug.h" #include "JackPlatformPlug.h"
#include "JackChannel.h" #include "JackChannel.h"
#include "types.h"
#include "session.h" #include "session.h"
#include "varargs.h" #include "varargs.h"
#include <list> #include <list>
@@ -68,6 +67,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
JackSyncCallback fSync; JackSyncCallback fSync;
JackThreadCallback fThreadFun; JackThreadCallback fThreadFun;
JackSessionCallback fSession; JackSessionCallback fSession;
JackLatencyCallback fLatency;


void* fProcessArg; void* fProcessArg;
void* fGraphOrderArg; void* fGraphOrderArg;
@@ -86,6 +86,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
void* fSyncArg; void* fSyncArg;
void* fThreadFunArg; void* fThreadFunArg;
void* fSessionArg; void* fSessionArg;
void* fLatencyArg;
char fServerName[64]; char fServerName[64];


JackThread fThread; /*! Thread to execute the Process function */ JackThread fThread; /*! Thread to execute the Process function */
@@ -94,14 +95,14 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
std::list<jack_port_id_t> fPortList; std::list<jack_port_id_t> fPortList;


bool fImmediateSessionReply; bool fImmediateSessionReply;
int StartThread(); int StartThread();
void SetupDriverSync(bool freewheel); void SetupDriverSync(bool freewheel);
bool IsActive(); bool IsActive();


void CallSyncCallback(); void CallSyncCallback();
void CallTimebaseCallback(); void CallTimebaseCallback();
virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value); virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value);


inline void DummyCycle(); inline void DummyCycle();
@@ -116,7 +117,10 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
inline void CallSyncCallbackAux(); inline void CallSyncCallbackAux();
inline void CallTimebaseCallbackAux(); inline void CallTimebaseCallbackAux();
inline int ActivateAux(); inline int ActivateAux();
inline void InitAux();

int HandleLatencyCallback(int status);

public: public:


JackClient(); JackClient();
@@ -138,8 +142,9 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
// Context // Context
virtual int SetBufferSize(jack_nframes_t buffer_size); virtual int SetBufferSize(jack_nframes_t buffer_size);
virtual int SetFreeWheel(int onoff); virtual int SetFreeWheel(int onoff);
virtual int ComputeTotalLatencies();
virtual void ShutDown(); virtual void ShutDown();
virtual pthread_t GetThreadID();
virtual jack_native_thread_t GetThreadID();


// Port management // Port management
virtual int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); virtual int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size);
@@ -179,6 +184,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
virtual int SetPortConnectCallback(JackPortConnectCallback callback, void *arg); virtual int SetPortConnectCallback(JackPortConnectCallback callback, void *arg);
virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg); virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg);
virtual int SetSessionCallback(JackSessionCallback callback, void *arg); virtual int SetSessionCallback(JackSessionCallback callback, void *arg);
virtual int SetLatencyCallback(JackLatencyCallback callback, void *arg);


// Internal clients // Internal clients
virtual char* GetInternalClientName(int ref); virtual char* GetInternalClientName(int ref);
@@ -186,16 +192,18 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
virtual int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va); virtual int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va);
virtual void InternalClientUnload(int ref, jack_status_t* status); virtual void InternalClientUnload(int ref, jack_status_t* status);


// RT Thread
jack_nframes_t CycleWait(); jack_nframes_t CycleWait();
void CycleSignal(int status); void CycleSignal(int status);
int SetProcessThread(JackThreadCallback fun, void *arg); int SetProcessThread(JackThreadCallback fun, void *arg);


// Session api
virtual jack_session_command_t *SessionNotify(const char *target, jack_session_event_type_t type, const char *path);
virtual int SessionReply(jack_session_event_t *ev);
char* GetUUIDForClientName(const char* client_name);
char* GetClientNameForUUID(const char* uuid);
int ReserveClientName(const char *name, const char* uuid);
// Session API
virtual jack_session_command_t* SessionNotify(const char* target, jack_session_event_type_t type, const char* path);
virtual int SessionReply(jack_session_event_t* ev);
char* GetUUIDForClientName(const char* client_name);
char* GetClientNameByUUID(const char* uuid);
int ReserveClientName(const char* client_name, const char* uuid);
int ClientHasSessionCallback(const char* client_name);


// JackRunnableInterface interface // JackRunnableInterface interface
bool Init(); bool Init();


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -25,8 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackPort.h" #include "JackPort.h"
#include "JackSynchro.h" #include "JackSynchro.h"
#include "JackNotification.h" #include "JackNotification.h"

#include "jack/session.h"
#include "session.h"


namespace Jack namespace Jack
{ {
@@ -74,6 +73,7 @@ struct JackClientControl : public JackShmMemAble
fCallback[kAddClient] = true; fCallback[kAddClient] = true;
fCallback[kRemoveClient] = true; fCallback[kRemoveClient] = true;
fCallback[kActivateClient] = true; fCallback[kActivateClient] = true;
fCallback[kLatencyCallback] = true;
// So that driver synchro are correctly setup in "flush" or "normal" mode // So that driver synchro are correctly setup in "flush" or "normal" mode
fCallback[kStartFreewheelCallback] = true; fCallback[kStartFreewheelCallback] = true;
fCallback[kStopFreewheelCallback] = true; fCallback[kStopFreewheelCallback] = true;


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackEngineControl.h" #include "JackEngineControl.h"
#include "JackGlobals.h" #include "JackGlobals.h"
#include "JackError.h" #include "JackError.h"
#include <set>
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>


@@ -246,7 +247,7 @@ int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro
int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing)
{ {
jack_time_t current_date = GetMicroSeconds(); jack_time_t current_date = GetMicroSeconds();
const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum);
const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum);
int res = 0; int res = 0;


// Update state and timestamp of current client // Update state and timestamp of current client
@@ -256,7 +257,7 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro*
for (int i = 0; i < CLIENT_NUM; i++) { for (int i = 0; i < CLIENT_NUM; i++) {


// Signal connected clients or drivers // Signal connected clients or drivers
if (outputRef[i] > 0) {
if (output_ref[i] > 0) {


// Update state and timestamp of destination clients // Update state and timestamp of destination clients
timing[i].fStatus = Triggered; timing[i].fStatus = Triggered;
@@ -272,6 +273,44 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro*
return res; return res;
} }


static bool HasNoConnection(jack_int_t* table)
{
for (int ref = 0; ref < CLIENT_NUM; ref++) {
if (table[ref] > 0) return false;
}
return true;
}

// Using http://en.wikipedia.org/wiki/Topological_sorting

void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted)
{
JackFixedMatrix<CLIENT_NUM> tmp;
std::set<jack_int_t> level;

fConnectionRef.Copy(tmp);

// Inputs of the graph
level.insert(AUDIO_DRIVER_REFNUM);
level.insert(FREEWHEEL_DRIVER_REFNUM);

while (level.size() > 0) {
jack_int_t refnum = *level.begin();
sorted.push_back(refnum);
level.erase(level.begin());
const jack_int_t* output_ref1 = tmp.GetItems(refnum);
for (int dst = 0; dst < CLIENT_NUM; dst++) {
if (output_ref1[dst] > 0) {
tmp.ClearItem(refnum, dst);
jack_int_t output_ref2[CLIENT_NUM];
tmp.GetOutputTable1(dst, output_ref2);
if (HasNoConnection(output_ref2))
level.insert(dst);
}
}
}
}

/*! /*!
\brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated. \brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated.
*/ */


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackActivationCount.h" #include "JackActivationCount.h"
#include "JackError.h" #include "JackError.h"
#include "JackCompilerDeps.h" #include "JackCompilerDeps.h"
#include <vector>
#include <assert.h> #include <assert.h>


namespace Jack namespace Jack
@@ -151,7 +151,7 @@ class JackFixedArray1 : public JackFixedArray<SIZE>
return true; return true;
} }
} }
} POST_PACKED_STRUCTURE; } POST_PACKED_STRUCTURE;


/*! /*!
@@ -200,6 +200,11 @@ class JackFixedMatrix
return fTable[index1][index2]; return fTable[index1][index2];
} }


void ClearItem(jack_int_t index1, jack_int_t index2)
{
fTable[index1][index2] = 0;
}

/*! /*!
\brief Get the output indexes of a given index. \brief Get the output indexes of a given index.
*/ */
@@ -218,6 +223,13 @@ class JackFixedMatrix
} }
} }


void GetOutputTable1(jack_int_t index, jack_int_t* output) const
{
for (int i = 0; i < SIZE; i++) {
output[i] = fTable[i][index];
}
}

bool IsInsideTable(jack_int_t index, jack_int_t* output) const bool IsInsideTable(jack_int_t index, jack_int_t* output) const
{ {
for (int i = 0; i < SIZE && output[i] != EMPTY; i++) { for (int i = 0; i < SIZE && output[i] != EMPTY; i++) {
@@ -227,6 +239,14 @@ class JackFixedMatrix
return false; return false;
} }


void Copy(JackFixedMatrix& copy)
{
for (int i = 0; i < SIZE; i++) {
memcpy(copy.fTable[i], fTable[i], sizeof(jack_int_t) * SIZE);
}
}


} POST_PACKED_STRUCTURE; } POST_PACKED_STRUCTURE;


/*! /*!
@@ -359,7 +379,7 @@ struct JackClientTiming
} }
~JackClientTiming() ~JackClientTiming()
{} {}
void Init() void Init()
{ {
fSignaledAt = 0; fSignaledAt = 0;
@@ -367,7 +387,7 @@ struct JackClientTiming
fFinishedAt = 0; fFinishedAt = 0;
fStatus = NotTriggered; fStatus = NotTriggered;
} }
} POST_PACKED_STRUCTURE; } POST_PACKED_STRUCTURE;


/*! /*!
@@ -375,11 +395,9 @@ struct JackClientTiming


<UL> <UL>
<LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port. <LI>The <B>fConnection</B> array contains the list (array line) of connected ports for a given port.
<LI>The <B>fConnectionCount</B> array contains the number of connected ports to a given port.
<LI>The <B>fInputPort</B> array contains the list (array line) of input connected ports for a given client. <LI>The <B>fInputPort</B> array contains the list (array line) of input connected ports for a given client.
<LI>The <B>fOutputPort</B> array contains the list (array line) of ouput connected ports for a given client. <LI>The <B>fOutputPort</B> array contains the list (array line) of ouput connected ports for a given client.
<LI>The <B>fConnectionRef</B> array contains the number of ports connected between two clients. <LI>The <B>fConnectionRef</B> array contains the number of ports connected between two clients.
<LI>The <B>fInputRef</B> array contains the number of input clients connected to a given client.
<LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose. <LI>The <B>fInputCounter</B> array contains the number of input clients connected to a given for activation purpose.
</UL> </UL>
*/ */
@@ -461,7 +479,8 @@ class SERVER_EXPORT JackConnectionManager
void ResetGraph(JackClientTiming* timing); void ResetGraph(JackClientTiming* timing);
int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing); int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing);
int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec); int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec);
void TopologicalSort(std::vector<jack_int_t>& sorted);

} POST_PACKED_STRUCTURE; } POST_PACKED_STRUCTURE;


} // end of namespace } // end of namespace


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -116,17 +116,17 @@ int JackDebugClient::Close()
void JackDebugClient::CheckClient(const char* function_name) const void JackDebugClient::CheckClient(const char* function_name) const
{ {
*fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl; *fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl;
if (fIsClosed > 0) { if (fIsClosed > 0) {
*fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl;
*fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl;
*fStream << "This is likely to cause crash !'" << endl; *fStream << "This is likely to cause crash !'" << endl;
#ifdef __APPLE__ #ifdef __APPLE__
// Debugger(); // Debugger();
#endif
#endif
} }
} }


pthread_t JackDebugClient::GetThreadID()
jack_native_thread_t JackDebugClient::GetThreadID()
{ {
CheckClient("GetThreadID"); CheckClient("GetThreadID");
return fClient->GetThreadID(); return fClient->GetThreadID();
@@ -428,7 +428,7 @@ void JackDebugClient::OnInfoShutdown(JackInfoShutdownCallback callback, void *ar
CheckClient("OnInfoShutdown"); CheckClient("OnInfoShutdown");
fClient->OnInfoShutdown(callback, arg); fClient->OnInfoShutdown(callback, arg);
} }
int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg)
{ {
JackDebugClient* client = (JackDebugClient*)arg; JackDebugClient* client = (JackDebugClient*)arg;


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -84,7 +84,7 @@ class JackDebugClient : public JackClient
int SetBufferSize(jack_nframes_t buffer_size); int SetBufferSize(jack_nframes_t buffer_size);
int SetFreeWheel(int onoff); int SetFreeWheel(int onoff);
void ShutDown(); void ShutDown();
pthread_t GetThreadID();
jack_native_thread_t GetThreadID();


// Port management // Port management
int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); int PortRegister(const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size);


+ 5
- 5
common/JackDriver.cpp View File

@@ -167,7 +167,7 @@ int JackDriver::Open(jack_nframes_t buffer_size,


int JackDriver::Close() int JackDriver::Close()
{ {
if (fClientControl.fRefNum >= 0) {
if (fClientControl.fRefNum >= 0) {
jack_log("JackDriver::Close"); jack_log("JackDriver::Close");
fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync
fClientControl.fActive = false; fClientControl.fActive = false;
@@ -207,7 +207,7 @@ int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync,
jack_log("JackDriver::kStopFreewheel"); jack_log("JackDriver::kStopFreewheel");
SetupDriverSync(fClientControl.fRefNum, false); SetupDriverSync(fClientControl.fRefNum, false);
break; break;
}
}


return 0; return 0;
} }
@@ -223,13 +223,13 @@ void JackDriver::CycleIncTime()
} }


void JackDriver::CycleTakeBeginTime() void JackDriver::CycleTakeBeginTime()
{
{
fBeginDateUst = GetMicroSeconds(); // Take callback date here fBeginDateUst = GetMicroSeconds(); // Take callback date here
fEngineControl->CycleIncTime(fBeginDateUst); fEngineControl->CycleIncTime(fBeginDateUst);
} }


void JackDriver::CycleTakeEndTime() void JackDriver::CycleTakeEndTime()
{
{
fEndDateUst = GetMicroSeconds(); // Take end date here fEndDateUst = GetMicroSeconds(); // Take end date here
} }


@@ -254,7 +254,7 @@ void JackDriver::NotifySampleRate(jack_nframes_t sample_rate)
fEngine->NotifySampleRate(sample_rate); fEngine->NotifySampleRate(sample_rate);
fEngineControl->InitFrameTime(); fEngineControl->InitFrameTime();
} }
void JackDriver::NotifyFailure(int code, const char* reason) void JackDriver::NotifyFailure(int code, const char* reason)
{ {
fEngine->NotifyFailure(code, reason); fEngine->NotifyFailure(code, reason);


+ 44
- 44
common/JackDriver.h View File

@@ -1,21 +1,21 @@
/* /*
Copyright (C) 2001 Paul Davis Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 Grame Copyright (C) 2004-2008 Grame
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */


#ifndef __JackDriver__ #ifndef __JackDriver__
@@ -30,27 +30,27 @@


namespace Jack namespace Jack
{ {
class JackLockedEngine; class JackLockedEngine;
class JackGraphManager; class JackGraphManager;
struct JackEngineControl; struct JackEngineControl;
/*! /*!
\brief The base interface for drivers. \brief The base interface for drivers.
*/ */
class SERVER_EXPORT JackDriverInterface class SERVER_EXPORT JackDriverInterface
{ {


public: public:
JackDriverInterface() JackDriverInterface()
{} {}
virtual ~JackDriverInterface() virtual ~JackDriverInterface()
{} {}
virtual int Open() = 0; virtual int Open() = 0;
virtual int Open (bool capturing, virtual int Open (bool capturing,
bool playing, bool playing,
int inchannels, int inchannels,
@@ -60,7 +60,7 @@ class SERVER_EXPORT JackDriverInterface
const char* playback_driver_name, const char* playback_driver_name,
jack_nframes_t capture_latency, jack_nframes_t capture_latency,
jack_nframes_t playback_latency) = 0; jack_nframes_t playback_latency) = 0;
virtual int Open(jack_nframes_t buffer_size, virtual int Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate, jack_nframes_t samplerate,
bool capturing, bool capturing,
@@ -72,30 +72,30 @@ class SERVER_EXPORT JackDriverInterface
const char* playback_driver_name, const char* playback_driver_name,
jack_nframes_t capture_latency, jack_nframes_t capture_latency,
jack_nframes_t playback_latency) = 0; jack_nframes_t playback_latency) = 0;
virtual int Attach() = 0; virtual int Attach() = 0;
virtual int Detach() = 0; virtual int Detach() = 0;
virtual int Read() = 0; virtual int Read() = 0;
virtual int Write() = 0; virtual int Write() = 0;
virtual int Start() = 0; virtual int Start() = 0;
virtual int Stop() = 0; virtual int Stop() = 0;
virtual bool IsFixedBufferSize() = 0; virtual bool IsFixedBufferSize() = 0;
virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; virtual int SetBufferSize(jack_nframes_t buffer_size) = 0;
virtual int SetSampleRate(jack_nframes_t sample_rate) = 0; virtual int SetSampleRate(jack_nframes_t sample_rate) = 0;
virtual int Process() = 0; virtual int Process() = 0;
virtual int ProcessNull() = 0; virtual int ProcessNull() = 0;
virtual void SetMaster(bool onoff) = 0; virtual void SetMaster(bool onoff) = 0;
virtual bool GetMaster() = 0; virtual bool GetMaster() = 0;
virtual void AddSlave(JackDriverInterface* slave) = 0; virtual void AddSlave(JackDriverInterface* slave) = 0;
virtual void RemoveSlave(JackDriverInterface* slave) = 0; virtual void RemoveSlave(JackDriverInterface* slave) = 0;
virtual std::list<JackDriverInterface*> GetSlaves() = 0; virtual std::list<JackDriverInterface*> GetSlaves() = 0;
virtual int ProcessSlaves() = 0; virtual int ProcessSlaves() = 0;
virtual bool IsRealTime() const = 0; virtual bool IsRealTime() const = 0;
}; };


@@ -109,16 +109,16 @@ class SERVER_EXPORT JackDriverClientInterface : public JackDriverInterface, publ
/*! /*!
\brief The base class for drivers. \brief The base class for drivers.
*/ */
#define CaptureDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive)
#define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive)
#define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsActive)
#define CaptureDriverFlags static_cast<JackPortFlags>(JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal)
#define PlaybackDriverFlags static_cast<JackPortFlags>(JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal)
#define MonitorDriverFlags static_cast<JackPortFlags>(JackPortIsOutput)


class SERVER_EXPORT JackDriver : public JackDriverClientInterface class SERVER_EXPORT JackDriver : public JackDriverClientInterface
{ {
protected: protected:
char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1]; char fCaptureDriverName[JACK_CLIENT_NAME_SIZE + 1];
char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1]; char fPlaybackDriverName[JACK_CLIENT_NAME_SIZE + 1];
char fAliasName[JACK_CLIENT_NAME_SIZE + 1]; char fAliasName[JACK_CLIENT_NAME_SIZE + 1];
@@ -134,27 +134,27 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface
JackClientControl fClientControl; JackClientControl fClientControl;
std::list<JackDriverInterface*> fSlaveList; std::list<JackDriverInterface*> fSlaveList;
bool fIsMaster; bool fIsMaster;
void CycleIncTime(); void CycleIncTime();
void CycleTakeBeginTime(); void CycleTakeBeginTime();
void CycleTakeEndTime(); void CycleTakeEndTime();
void SetupDriverSync(int ref, bool freewheel); void SetupDriverSync(int ref, bool freewheel);
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver
void NotifyBufferSize(jack_nframes_t buffer_size); // BufferSize notification sent by the driver void NotifyBufferSize(jack_nframes_t buffer_size); // BufferSize notification sent by the driver
void NotifySampleRate(jack_nframes_t sample_rate); // SampleRate notification sent by the driver void NotifySampleRate(jack_nframes_t sample_rate); // SampleRate notification sent by the driver
void NotifyFailure(int code, const char* reason); // Failure notification sent by the driver void NotifyFailure(int code, const char* reason); // Failure notification sent by the driver
public: public:
JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); JackDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
JackDriver(); JackDriver();
virtual ~JackDriver(); virtual ~JackDriver();
void SetMaster(bool onoff); void SetMaster(bool onoff);
bool GetMaster(); bool GetMaster();
void AddSlave(JackDriverInterface* slave); void AddSlave(JackDriverInterface* slave);
void RemoveSlave(JackDriverInterface* slave); void RemoveSlave(JackDriverInterface* slave);
std::list<JackDriverInterface*> GetSlaves() std::list<JackDriverInterface*> GetSlaves()
@@ -162,9 +162,9 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface
return fSlaveList; return fSlaveList;
} }
int ProcessSlaves(); int ProcessSlaves();
virtual int Open(); virtual int Open();
virtual int Open (bool capturing, virtual int Open (bool capturing,
bool playing, bool playing,
int inchannels, int inchannels,
@@ -174,7 +174,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface
const char* playback_driver_name, const char* playback_driver_name,
jack_nframes_t capture_latency, jack_nframes_t capture_latency,
jack_nframes_t playback_latency); jack_nframes_t playback_latency);
virtual int Open(jack_nframes_t buffer_size, virtual int Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate, jack_nframes_t samplerate,
bool capturing, bool capturing,
@@ -187,31 +187,31 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface
jack_nframes_t capture_latency, jack_nframes_t capture_latency,
jack_nframes_t playback_latency); jack_nframes_t playback_latency);
virtual int Close(); virtual int Close();
virtual int Process(); virtual int Process();
virtual int ProcessNull(); virtual int ProcessNull();
virtual int Attach(); virtual int Attach();
virtual int Detach(); virtual int Detach();
virtual int Read(); virtual int Read();
virtual int Write(); virtual int Write();
virtual int Start(); virtual int Start();
virtual int Stop(); virtual int Stop();
virtual bool IsFixedBufferSize(); virtual bool IsFixedBufferSize();
virtual int SetBufferSize(jack_nframes_t buffer_size); virtual int SetBufferSize(jack_nframes_t buffer_size);
virtual int SetSampleRate(jack_nframes_t sample_rate); virtual int SetSampleRate(jack_nframes_t sample_rate);
virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2);
virtual JackClientControl* GetClientControl() const; virtual JackClientControl* GetClientControl() const;
virtual bool IsRealTime() const; virtual bool IsRealTime() const;
virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one
virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one
}; };
} // end of namespace } // end of namespace


#endif #endif

+ 6
- 0
common/JackDummyDriver.cpp View File

@@ -56,6 +56,12 @@ int JackDummyDriver::Open(jack_nframes_t buffer_size,
fEngineControl->fPeriod = 0; fEngineControl->fPeriod = 0;
fEngineControl->fComputation = 500 * 1000; fEngineControl->fComputation = 500 * 1000;
fEngineControl->fConstraint = 500 * 1000; fEngineControl->fConstraint = 500 * 1000;
int buffer_size = int((fWaitTime * fEngineControl->fSampleRate) / 1000000.0f);
if (buffer_size > BUFFER_SIZE_MAX) {
buffer_size = BUFFER_SIZE_MAX;
jack_error("Buffer size set to %d ", BUFFER_SIZE_MAX);
}
SetBufferSize(buffer_size);
return 0; return 0;
} else { } else {
return -1; return -1;


+ 83
- 42
common/JackEngine.cpp View File

@@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <set>
#include <assert.h> #include <assert.h>


#include "JackSystemDeps.h" #include "JackSystemDeps.h"
@@ -90,7 +91,7 @@ int JackEngine::Close()


return 0; return 0;
} }
void JackEngine::NotifyQuit() void JackEngine::NotifyQuit()
{ {
fChannel.NotifyQuit(); fChannel.NotifyQuit();
@@ -137,8 +138,10 @@ void JackEngine::ReleaseRefnum(int ref)
void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) void JackEngine::ProcessNext(jack_time_t cur_cycle_begin)
{ {
fLastSwitchUsecs = cur_cycle_begin; fLastSwitchUsecs = cur_cycle_begin;
if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state
if (fGraphManager->RunNextGraph()) { // True if the graph actually switched to a new state
fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0); fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
//NotifyGraphReorder();
}
fSignal.Signal(); // Signal for threads waiting for next cycle fSignal.Signal(); // Signal for threads waiting for next cycle
} }


@@ -195,16 +198,44 @@ void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions
if (status != NotTriggered && status != Finished) { if (status != NotTriggered && status != Finished) {
jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status); jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status);
fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients
//NotifyXRun(ALL_CLIENTS);
} }


if (status == Finished && (long)(finished_date - callback_usecs) > 0) { if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName); jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients
//NotifyXRun(ALL_CLIENTS);
} }
} }
} }
} }


int JackEngine::ComputeTotalLatencies()
{
std::vector<jack_int_t> sorted;
std::vector<jack_int_t>::iterator it;
std::vector<jack_int_t>::reverse_iterator rit;

fGraphManager->TopologicalSort(sorted);

/* iterate over all clients in graph order, and emit
* capture latency callback.
*/

for (it = sorted.begin(); it != sorted.end(); it++) {
jack_log("Sorted %d", *it);
NotifyClient(*it, kLatencyCallback, true, "", 0, 0);
}

/* now issue playback latency callbacks in reverse graph order.
*/
for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) {
NotifyClient(*rit, kLatencyCallback, true, "", 1, 0);
}

return 0;
}

//--------------- //---------------
// Notifications // Notifications
//--------------- //---------------
@@ -215,8 +246,8 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, const char* messa


// The client may be notified by the RT thread while closing // The client may be notified by the RT thread while closing
if (client) { if (client) {
if (client && client->GetClientControl()->fCallback[event]) {
if (client->GetClientControl()->fCallback[event]) {
/* /*
Important for internal clients : unlock before calling the notification callbacks. Important for internal clients : unlock before calling the notification callbacks.
*/ */
@@ -225,7 +256,7 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, const char* messa
jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2); jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
if (res) if (res)
fMutex.Lock(); fMutex.Lock();
} else { } else {
jack_log("JackEngine::NotifyClient: no callback for event = %ld", event); jack_log("JackEngine::NotifyClient: no callback for event = %ld", event);
} }
@@ -277,6 +308,7 @@ void JackEngine::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs)
// Use the audio thread => request thread communication channel // Use the audio thread => request thread communication channel
fEngineControl->NotifyXRun(callback_usecs, delayed_usecs); fEngineControl->NotifyXRun(callback_usecs, delayed_usecs);
fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);
//NotifyXRun(ALL_CLIENTS);
} }


void JackEngine::NotifyXRun(int refnum) void JackEngine::NotifyXRun(int refnum)
@@ -290,6 +322,7 @@ void JackEngine::NotifyXRun(int refnum)


void JackEngine::NotifyGraphReorder() void JackEngine::NotifyGraphReorder()
{ {
ComputeTotalLatencies();
NotifyClients(kGraphOrderCallback, false, "", 0, 0); NotifyClients(kGraphOrderCallback, false, "", 0, 0);
} }


@@ -307,7 +340,7 @@ void JackEngine::NotifyFailure(int code, const char* reason)
{ {
NotifyClients(kShutDownCallback, false, reason, code, 0); NotifyClients(kShutDownCallback, false, reason, code, 0);
} }
void JackEngine::NotifyFreewheel(bool onoff) void JackEngine::NotifyFreewheel(bool onoff)
{ {
if (onoff) { if (onoff) {
@@ -406,7 +439,7 @@ int JackEngine::ClientCheck(const char* name, int uuid, char* name_res, int prot
std::map<int,std::string>::iterator res = fReservationMap.find(uuid); std::map<int,std::string>::iterator res = fReservationMap.find(uuid);


if (res != fReservationMap.end()) { if (res != fReservationMap.end()) {
strncpy( name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE );
strncpy(name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE);
} else if (ClientCheckName(name)) { } else if (ClientCheckName(name)) {


*status |= JackNameNotUnique; *status |= JackNameNotUnique;
@@ -467,7 +500,7 @@ bool JackEngine::ClientCheckName(const char* name)
return true; return true;
} }


for (std::map<int,std::string>::iterator i=fReservationMap.begin(); i!=fReservationMap.end(); i++) {
for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) {
if (i->second == name) if (i->second == name)
return true; return true;
} }
@@ -522,14 +555,14 @@ int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref


if (uuid < 0) { if (uuid < 0) {
uuid = GetNewUUID(); uuid = GetNewUUID();
strncpy( real_name, name, JACK_CLIENT_NAME_SIZE );
strncpy(real_name, name, JACK_CLIENT_NAME_SIZE);
} else { } else {
std::map<int,std::string>::iterator res = fReservationMap.find(uuid); std::map<int,std::string>::iterator res = fReservationMap.find(uuid);
if (res != fReservationMap.end()) { if (res != fReservationMap.end()) {
strncpy( real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE );
strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE);
fReservationMap.erase(uuid); fReservationMap.erase(uuid);
} else { } else {
strncpy( real_name, name, JACK_CLIENT_NAME_SIZE );
strncpy(real_name, name, JACK_CLIENT_NAME_SIZE);
} }


EnsureUUID(uuid); EnsureUUID(uuid);
@@ -689,7 +722,7 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time)
{ {
JackClientInterface* client = fClientTable[refnum]; JackClientInterface* client = fClientTable[refnum];
jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
if (is_real_time) if (is_real_time)
fGraphManager->Activate(refnum); fGraphManager->Activate(refnum);


@@ -702,18 +735,10 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time)
jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
fGraphManager->GetInputPorts(refnum, input_ports); fGraphManager->GetInputPorts(refnum, input_ports);
fGraphManager->GetOutputPorts(refnum, output_ports); fGraphManager->GetOutputPorts(refnum, output_ports);
// First add port state to JackPortIsActive
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
fGraphManager->ActivatePort(input_ports[i]);
}
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
fGraphManager->ActivatePort(output_ports[i]);
}

// Notify client // Notify client
NotifyActivate(refnum); NotifyActivate(refnum);

// Then issue port registration notification // Then issue port registration notification
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
NotifyPortRegistation(input_ports[i], true); NotifyPortRegistation(input_ports[i], true);
@@ -740,13 +765,11 @@ int JackEngine::ClientDeactivate(int refnum)
// First disconnect all ports and remove their JackPortIsActive state // First disconnect all ports and remove their JackPortIsActive state
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
PortDisconnect(refnum, input_ports[i], ALL_PORTS); PortDisconnect(refnum, input_ports[i], ALL_PORTS);
fGraphManager->DeactivatePort(input_ports[i]);
} }
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
PortDisconnect(refnum, output_ports[i], ALL_PORTS); PortDisconnect(refnum, output_ports[i], ALL_PORTS);
fGraphManager->DeactivatePort(output_ports[i]);
} }
// Then issue port registration notification // Then issue port registration notification
for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
NotifyPortRegistation(input_ports[i], false); NotifyPortRegistation(input_ports[i], false);
@@ -867,7 +890,7 @@ int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst) int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
{ {
jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst); jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst);
if (dst == ALL_PORTS) { if (dst == ALL_PORTS) {


jack_int_t connections[CONNECTION_NUM_FOR_PORT]; jack_int_t connections[CONNECTION_NUM_FOR_PORT];
@@ -910,6 +933,10 @@ int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name)
return 0; return 0;
} }


//--------------------
// Session management
//--------------------

void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket) void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket)
{ {
if (fSessionPendingReplies != 0) { if (fSessionPendingReplies != 0) {
@@ -940,11 +967,11 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even


char path_buf[JACK_PORT_NAME_SIZE]; char path_buf[JACK_PORT_NAME_SIZE];
snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR ); snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR );
int res = JackTools::MkDir(path_buf); int res = JackTools::MkDir(path_buf);
if (res)
if (res)
jack_error( "JackEngine::SessionNotify: can not create session directory '%s'", path_buf ); jack_error( "JackEngine::SessionNotify: can not create session directory '%s'", path_buf );
int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int) type, 0); int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int) type, 0);


if (result == 2) { if (result == 2) {
@@ -952,9 +979,9 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even
} else if (result == 1) { } else if (result == 1) {
char uuid_buf[JACK_UUID_SIZE]; char uuid_buf[JACK_UUID_SIZE];
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID ); snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID );
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf,
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf,
client->GetClientControl()->fName, client->GetClientControl()->fName,
client->GetClientControl()->fSessionCommand,
client->GetClientControl()->fSessionCommand,
client->GetClientControl()->fSessionFlags )); client->GetClientControl()->fSessionFlags ));
} }
} }
@@ -973,11 +1000,11 @@ void JackEngine::SessionReply(int refnum)
{ {
JackClientInterface* client = fClientTable[refnum]; JackClientInterface* client = fClientTable[refnum];
char uuid_buf[JACK_UUID_SIZE]; char uuid_buf[JACK_UUID_SIZE];
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID );
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf,
client->GetClientControl()->fName,
client->GetClientControl()->fSessionCommand,
client->GetClientControl()->fSessionFlags ));
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
client->GetClientControl()->fName,
client->GetClientControl()->fSessionCommand,
client->GetClientControl()->fSessionFlags));
fSessionPendingReplies -= 1; fSessionPendingReplies -= 1;


if (fSessionPendingReplies == 0) { if (fSessionPendingReplies == 0) {
@@ -998,9 +1025,8 @@ void JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res, i
return; return;
} }
} }
// did not find name.
// Did not find name.
*result = -1; *result = -1;
return;
} }


void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *result) void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *result)
@@ -1020,18 +1046,17 @@ void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *res
return; return;
} }
} }
// did not find uuid.
// Did not find uuid.
*result = -1; *result = -1;
return;
} }


void JackEngine::ReserveClientName(const char *name, const char *uuid, int *result) void JackEngine::ReserveClientName(const char *name, const char *uuid, int *result)
{ {
jack_log( "JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid );
jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid);


if (ClientCheckName(name)) { if (ClientCheckName(name)) {
*result = -1; *result = -1;
jack_log( "name already taken" );
jack_log("name already taken");
return; return;
} }


@@ -1040,5 +1065,21 @@ void JackEngine::ReserveClientName(const char *name, const char *uuid, int *resu
*result = 0; *result = 0;
} }


void JackEngine::ClientHasSessionCallbackRequest(const char *name, int *result)
{
JackClientInterface* client = NULL;
for (int i = 0; i < CLIENT_NUM; i++) {
JackClientInterface* client = fClientTable[i];
if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
break;
}

if (client) {
*result = client->GetClientControl()->fCallback[kSessionCallback];
} else {
*result = -1;
}
}

} // end of namespace } // end of namespace



+ 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 PortRename(int refnum, jack_port_id_t port, const char* name);


int ComputeTotalLatencies();

// Graph // Graph
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end);


@@ -142,12 +144,14 @@ class SERVER_EXPORT JackEngine : public JackLockAble
void NotifyFreewheel(bool onoff); void NotifyFreewheel(bool onoff);
void NotifyQuit(); void NotifyQuit();


void SessionNotify( int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket );
void SessionReply( int refnum );
// Session management
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket);
void SessionReply(int refnum);


void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result); void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result);
void GetClientNameForUUID(const char *uuid, char *name_res, int *result); void GetClientNameForUUID(const char *uuid, char *name_res, int *result);
void ReserveClientName(const char *name, const char *uuid, int *result); void ReserveClientName(const char *name, const char *uuid, int *result);
void ClientHasSessionCallbackRequest(const char *name, int *result);
}; };






+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -33,39 +33,39 @@ static inline jack_time_t JACK_MAX(jack_time_t a, jack_time_t b)
return (a < b) ? b : a; return (a < b) ? b : a;
} }


void JackEngineControl::CalcCPULoad(JackClientInterface** table,
JackGraphManager* manager,
jack_time_t cur_cycle_begin,
void JackEngineControl::CalcCPULoad(JackClientInterface** table,
JackGraphManager* manager,
jack_time_t cur_cycle_begin,
jack_time_t prev_cycle_end) jack_time_t prev_cycle_end)
{ {
fPrevCycleTime = fCurCycleTime; fPrevCycleTime = fCurCycleTime;
fCurCycleTime = cur_cycle_begin; fCurCycleTime = cur_cycle_begin;
jack_time_t last_cycle_end = prev_cycle_end; jack_time_t last_cycle_end = prev_cycle_end;
// In Asynchronous mode, last cycle end is the max of client end dates // In Asynchronous mode, last cycle end is the max of client end dates
if (!fSyncMode) { if (!fSyncMode) {
for (int i = fDriverNum; i < CLIENT_NUM; i++) { for (int i = fDriverNum; i < CLIENT_NUM; i++) {
JackClientInterface* client = table[i]; JackClientInterface* client = table[i];
JackClientTiming* timing = manager->GetClientTiming(i); JackClientTiming* timing = manager->GetClientTiming(i);
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished)
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished)
last_cycle_end = JACK_MAX(last_cycle_end, timing->fFinishedAt); last_cycle_end = JACK_MAX(last_cycle_end, timing->fFinishedAt);
} }
} }


// Store the execution time for later averaging
// Store the execution time for later averaging
fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime; fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime;
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT)
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT)
fRollingClientUsecsIndex = 0; fRollingClientUsecsIndex = 0;
// Every so often, recompute the current maximum use over the // Every so often, recompute the current maximum use over the
// last JACK_ENGINE_ROLLING_COUNT client iterations. // last JACK_ENGINE_ROLLING_COUNT client iterations.
if (++fRollingClientUsecsCnt % fRollingInterval == 0) { if (++fRollingClientUsecsCnt % fRollingInterval == 0) {


jack_time_t max_usecs = 0; jack_time_t max_usecs = 0;
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++)
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++)
max_usecs = JACK_MAX(fRollingClientUsecs[i], max_usecs); max_usecs = JACK_MAX(fRollingClientUsecs[i], max_usecs);
fMaxUsecs = JACK_MAX(fMaxUsecs, max_usecs); fMaxUsecs = JACK_MAX(fMaxUsecs, max_usecs);
fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0); fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0);
fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f)); fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f));
@@ -80,7 +80,7 @@ void JackEngineControl::ResetRollingUsecs()
fSpareUsecs = 0; fSpareUsecs = 0;
fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs)); fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs));
} }
void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs)
{ {
ResetFrameTime(callback_usecs); ResetFrameTime(callback_usecs);
@@ -88,5 +88,5 @@ void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_use
if (delayed_usecs > fMaxDelayedUsecs) if (delayed_usecs > fMaxDelayedUsecs)
fMaxDelayedUsecs = delayed_usecs; fMaxDelayedUsecs = delayed_usecs;
} }
} // end of namespace } // end of namespace

+ 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 it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -25,7 +25,6 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "JackCompilerDeps.h" #include "JackCompilerDeps.h"
#include "types.h"


#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
@@ -44,17 +43,17 @@ extern "C"


EXPORT extern void (*jack_error_callback)(const char *desc); EXPORT extern void (*jack_error_callback)(const char *desc);
EXPORT extern void (*jack_info_callback)(const char *desc); EXPORT extern void (*jack_info_callback)(const char *desc);
EXPORT extern void default_jack_error_callback(const char *desc); EXPORT extern void default_jack_error_callback(const char *desc);
EXPORT extern void default_jack_info_callback(const char *desc); EXPORT extern void default_jack_info_callback(const char *desc);
EXPORT extern void silent_jack_error_callback(const char *desc); EXPORT extern void silent_jack_error_callback(const char *desc);
EXPORT extern void silent_jack_info_callback(const char *desc); EXPORT extern void silent_jack_info_callback(const char *desc);


typedef void (* jack_log_function_t)(int level, const char *message); typedef void (* jack_log_function_t)(int level, const char *message);


void jack_log_function(int level, const char *message); void jack_log_function(int level, const char *message);
EXPORT int set_threaded_log_function(); EXPORT int set_threaded_log_function();


#ifdef __cplusplus #ifdef __cplusplus


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -36,9 +36,9 @@ class SERVER_EXPORT JackTimer
{ {


friend class JackFrameTimer; friend class JackFrameTimer;
private:
private:
jack_nframes_t fFrames; jack_nframes_t fFrames;
jack_time_t fCurrentWakeup; jack_time_t fCurrentWakeup;
jack_time_t fCurrentCallback; jack_time_t fCurrentCallback;
@@ -47,21 +47,21 @@ class SERVER_EXPORT JackTimer
float fFilterCoefficient; /* set once, never altered */ float fFilterCoefficient; /* set once, never altered */
bool fInitialized; bool fInitialized;


public:
public:
JackTimer(); JackTimer();
~JackTimer() ~JackTimer()
{} {}
jack_nframes_t Time2Frames(jack_time_t time, jack_nframes_t buffer_size); jack_nframes_t Time2Frames(jack_time_t time, jack_nframes_t buffer_size);
jack_time_t Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size); jack_time_t Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size);
jack_nframes_t FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate); jack_nframes_t FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate);
jack_nframes_t CurFrame() jack_nframes_t CurFrame()
{ {
return fFrames; return fFrames;
} }
jack_time_t CurTime() jack_time_t CurTime()
{ {
return fCurrentWakeup; return fCurrentWakeup;
@@ -75,7 +75,7 @@ class SERVER_EXPORT JackTimer


class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer>
{ {
private: private:


bool fFirstWakeUp; bool fFirstWakeUp;
@@ -93,7 +93,7 @@ class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer>
void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs); void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs);
void IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs); void IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs);
void ReadFrameTime(JackTimer* timer); void ReadFrameTime(JackTimer* timer);
} POST_PACKED_STRUCTURE; } POST_PACKED_STRUCTURE;






+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -37,7 +37,7 @@ static void AssertBufferSize(jack_nframes_t buffer_size)
assert(buffer_size <= BUFFER_SIZE_MAX); assert(buffer_size <= BUFFER_SIZE_MAX);
} }
} }
void JackGraphManager::AssertPort(jack_port_id_t port_index) void JackGraphManager::AssertPort(jack_port_id_t port_index)
{ {
if (port_index >= fPortMax) { if (port_index >= fPortMax) {
@@ -45,7 +45,7 @@ void JackGraphManager::AssertPort(jack_port_id_t port_index)
assert(port_index < fPortMax); assert(port_index < fPortMax);
} }
} }
JackGraphManager* JackGraphManager::Allocate(int port_max) JackGraphManager* JackGraphManager::Allocate(int port_max)
{ {
// Using "Placement" new // Using "Placement" new
@@ -59,18 +59,18 @@ void JackGraphManager::Destroy(JackGraphManager* manager)
manager->~JackGraphManager(); manager->~JackGraphManager();
JackShmMem::operator delete(manager); JackShmMem::operator delete(manager);
} }
JackGraphManager::JackGraphManager(int port_max)
JackGraphManager::JackGraphManager(int port_max)
{ {
assert(port_max <= PORT_NUM_MAX); assert(port_max <= PORT_NUM_MAX);
for (int i = 0; i < port_max; i++) { for (int i = 0; i < port_max; i++) {
fPortArray[i].Release(); fPortArray[i].Release();
} }
fPortMax = port_max; fPortMax = port_max;
} }
JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
{ {
AssertPort(port_index); AssertPort(port_index);
@@ -127,6 +127,19 @@ int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* tab
return manager->SuspendRefNum(control, table, fClientTiming, usec); return manager->SuspendRefNum(control, table, fClientTiming, usec);
} }


void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& sorted)
{
UInt16 cur_index;
UInt16 next_index;

do {
cur_index = GetCurrentIndex();
sorted.clear();
ReadCurrentState()->TopologicalSort(sorted);
next_index = GetCurrentIndex();
} while (cur_index != next_index); // Until a coherent state has been read
}

// Server // Server
void JackGraphManager::DirectConnect(int ref1, int ref2) void JackGraphManager::DirectConnect(int ref1, int ref2)
{ {
@@ -176,14 +189,14 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff
jack_int_t len = manager->Connections(port_index); jack_int_t len = manager->Connections(port_index);


// No connections : return a zero-filled buffer // No connections : return a zero-filled buffer
if (len == 0) {
if (len == 0) {
port->ClearBuffer(buffer_size); port->ClearBuffer(buffer_size);
return port->GetBuffer(); return port->GetBuffer();
// One connection // One connection
} else if (len == 1) {
} else if (len == 1) {
jack_port_id_t src_index = manager->GetPort(port_index, 0); jack_port_id_t src_index = manager->GetPort(port_index, 0);
// Ports in same client : copy the buffer // Ports in same client : copy the buffer
if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) { if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) {
void* buffers[1]; void* buffers[1];
@@ -194,10 +207,10 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff
} else { } else {
return GetBuffer(src_index, buffer_size); return GetBuffer(src_index, buffer_size);
} }
// Multiple connections : mix all buffers // Multiple connections : mix all buffers
} else {
} else {
const jack_int_t* connections = manager->GetConnections(port_index); const jack_int_t* connections = manager->GetConnections(port_index);
void* buffers[CONNECTION_NUM_FOR_PORT]; void* buffers[CONNECTION_NUM_FOR_PORT];
jack_port_id_t src_index; jack_port_id_t src_index;
@@ -220,10 +233,10 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C
JackPort* port = GetPort(port_index); JackPort* port = GetPort(port_index);


/** /**
jackd.h
jackd.h
* If @ref JackPortCanMonitor is set for this @a port, turn input * If @ref JackPortCanMonitor is set for this @a port, turn input
* monitoring on or off. Otherwise, do nothing. * monitoring on or off. Otherwise, do nothing.
if (!(fFlags & JackPortCanMonitor)) if (!(fFlags & JackPortCanMonitor))
return -1; return -1;
*/ */
@@ -245,7 +258,7 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C
// Client // Client
jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count) jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
{ {
const jack_int_t* connections = manager->GetConnections(port_index);
const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
jack_nframes_t max_latency = 0; jack_nframes_t max_latency = 0;
jack_port_id_t dst_index; jack_port_id_t dst_index;


@@ -296,6 +309,46 @@ int JackGraphManager::ComputeTotalLatencies()
return 0; return 0;
} }


void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
{
const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
JackPort* port = GetPort(port_index);
jack_latency_range_t latency = { UINT32_MAX, 0 };
jack_port_id_t dst_index;

for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
AssertPort(dst_index);
JackPort* dst_port = GetPort(dst_index);
jack_latency_range_t other_latency;

dst_port->GetLatencyRange(mode, &other_latency);

if (other_latency.max > latency.max)
latency.max = other_latency.max;
if (other_latency.min < latency.min)
latency.min = other_latency.min;
}

if (latency.min == UINT32_MAX)
latency.min = 0;

port->SetLatencyRange(mode, &latency);
}

void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
{
UInt16 cur_index;
UInt16 next_index;

do {
cur_index = GetCurrentIndex();
RecalculateLatencyAux(port_index, mode);
next_index = GetCurrentIndex();
} while (cur_index != next_index); // Until a coherent state has been read

jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index);
}

// Server // Server
void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size) void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
{ {
@@ -376,18 +429,6 @@ int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
return res; return res;
} }


void JackGraphManager::ActivatePort(jack_port_id_t port_index)
{
JackPort* port = GetPort(port_index);
port->fFlags = (JackPortFlags)(port->fFlags | JackPortIsActive);
}

void JackGraphManager::DeactivatePort(jack_port_id_t port_index)
{
JackPort* port = GetPort(port_index);
port->fFlags = (JackPortFlags)(port->fFlags & ~JackPortIsActive);
}

void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res) void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res)
{ {
JackConnectionManager* manager = WriteNextStateStart(); JackConnectionManager* manager = WriteNextStateStart();
@@ -430,7 +471,7 @@ void JackGraphManager::RemoveAllPorts(int refnum)
jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index); jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
assert(true); assert(true);
break; break;
}
}
} }


WriteNextStateStop(); WriteNextStateStop();
@@ -717,7 +758,7 @@ void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const c
const jack_int_t* connections = manager->GetConnections(port_index); const jack_int_t* connections = manager->GetConnections(port_index);
jack_int_t index; jack_int_t index;
int i; int i;
// Cleanup connection array // Cleanup connection array
memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT); memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT);


@@ -740,7 +781,7 @@ const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
{ {
const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT); const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
UInt16 cur_index, next_index; UInt16 cur_index, next_index;
if (!res) if (!res)
return NULL; return NULL;


@@ -763,7 +804,7 @@ void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port
{ {
int match_cnt = 0; int match_cnt = 0;
regex_t port_regex, type_regex; regex_t port_regex, type_regex;
if (port_name_pattern && port_name_pattern[0]) { if (port_name_pattern && port_name_pattern[0]) {
regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB); regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
} }
@@ -823,15 +864,15 @@ const char** JackGraphManager::GetPorts(const char* port_name_pattern, const cha
{ {
const char** res = (const char**)malloc(sizeof(char*) * fPortMax); const char** res = (const char**)malloc(sizeof(char*) * fPortMax);
UInt16 cur_index, next_index; UInt16 cur_index, next_index;
if (!res) if (!res)
return NULL; return NULL;
do { do {
cur_index = GetCurrentIndex(); cur_index = GetCurrentIndex();
GetPortsAux(res, port_name_pattern, type_name_pattern, flags); GetPortsAux(res, port_name_pattern, type_name_pattern, flags);
next_index = GetCurrentIndex(); next_index = GetCurrentIndex();
} while (cur_index != next_index); // Until a coherent state has been read
} while (cur_index != next_index); // Until a coherent state has been read


if (res[0]) { // at least one port if (res[0]) { // at least one port
return res; return res;


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -29,14 +29,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackPlatformPlug.h" #include "JackPlatformPlug.h"
#include "JackSystemDeps.h" #include "JackSystemDeps.h"



namespace Jack namespace Jack
{ {


/*! /*!
\brief Graph manager: contains the connection manager and the port array. \brief Graph manager: contains the connection manager and the port array.
*/ */
class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState<JackConnectionManager> class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState<JackConnectionManager>
{ {


@@ -53,6 +52,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState
float* GetBuffer(jack_port_id_t port_index); float* GetBuffer(jack_port_id_t port_index);
void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames); void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames);
jack_nframes_t ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count); jack_nframes_t ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count);
void RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode);


public: public:


@@ -65,8 +65,6 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState
// Ports management // Ports management
jack_port_id_t AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size); jack_port_id_t AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size);
int ReleasePort(int refnum, jack_port_id_t port_index); int ReleasePort(int refnum, jack_port_id_t port_index);
void ActivatePort(jack_port_id_t port_index);
void DeactivatePort(jack_port_id_t port_index);
void GetInputPorts(int refnum, jack_int_t* res); void GetInputPorts(int refnum, jack_int_t* res);
void GetOutputPorts(int refnum, jack_int_t* res); void GetOutputPorts(int refnum, jack_int_t* res);
void RemoveAllPorts(int refnum); void RemoveAllPorts(int refnum);
@@ -74,10 +72,13 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState


JackPort* GetPort(jack_port_id_t index); JackPort* GetPort(jack_port_id_t index);
jack_port_id_t GetPort(const char* name); jack_port_id_t GetPort(const char* name);

int ComputeTotalLatency(jack_port_id_t port_index); int ComputeTotalLatency(jack_port_id_t port_index);
int ComputeTotalLatencies(); int ComputeTotalLatencies();
void RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode);

int RequestMonitor(jack_port_id_t port_index, bool onoff); int RequestMonitor(jack_port_id_t port_index, bool onoff);
// Connections management // Connections management
int Connect(jack_port_id_t src_index, jack_port_id_t dst_index); int Connect(jack_port_id_t src_index, jack_port_id_t dst_index);
int Disconnect(jack_port_id_t src_index, jack_port_id_t dst_index); int Disconnect(jack_port_id_t src_index, jack_port_id_t dst_index);
@@ -122,6 +123,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState
void InitRefNum(int refnum); void InitRefNum(int refnum);
int ResumeRefNum(JackClientControl* control, JackSynchro* table); int ResumeRefNum(JackClientControl* control, JackSynchro* table);
int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs); int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs);
void TopologicalSort(std::vector<jack_int_t>& sorted);


JackClientTiming* GetClientTiming(int refnum) JackClientTiming* GetClientTiming(int refnum)
{ {
@@ -130,7 +132,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState


void Save(JackConnectionManager* dst); void Save(JackConnectionManager* dst);
void Restore(JackConnectionManager* src); void Restore(JackConnectionManager* src);
static JackGraphManager* Allocate(int port_max); static JackGraphManager* Allocate(int port_max);
static void Destroy(JackGraphManager* manager); static void Destroy(JackGraphManager* manager);




+ 10
- 7
common/JackInternalClientChannel.h View File

@@ -80,7 +80,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface
{ {
*result = fEngine->PortUnRegister(refnum, port_index); *result = fEngine->PortUnRegister(refnum, port_index);
} }

void PortConnect(int refnum, const char* src, const char* dst, int* result) void PortConnect(int refnum, const char* src, const char* dst, int* result)
{ {
*result = fEngine->PortConnect(refnum, src, dst); *result = fEngine->PortConnect(refnum, src, dst);
@@ -89,7 +88,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface
{ {
*result = fEngine->PortDisconnect(refnum, src, dst); *result = fEngine->PortDisconnect(refnum, src, dst);
} }

void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result)
{ {
*result = fEngine->PortConnect(refnum, src, dst); *result = fEngine->PortConnect(refnum, src, dst);
@@ -111,10 +109,9 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface
{ {
*result = fServer->SetFreewheel(onoff); *result = fServer->SetFreewheel(onoff);
} }

void SessionNotify( int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t **result )
void ComputeTotalLatencies(int* result)
{ {
*result = NULL;
*result = fEngine->ComputeTotalLatencies();
} }


void ReleaseTimebase(int refnum, int* result) void ReleaseTimebase(int refnum, int* result)
@@ -126,7 +123,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface
{ {
*result = fServer->SetTimebaseCallback(refnum, conditional); *result = fServer->SetTimebaseCallback(refnum, conditional);
} }
void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result)
{ {
*result = fEngine->GetInternalClientName(int_ref, name_res); *result = fEngine->GetInternalClientName(int_ref, name_res);
@@ -139,7 +136,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface


void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result)
{ {
*result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status);
*result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status);
} }


void InternalClientUnload(int refnum, int int_ref, int* status, int* result) void InternalClientUnload(int refnum, int int_ref, int* status, int* result)
@@ -147,6 +144,12 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface
*result = fEngine->InternalClientUnload(int_ref, status); *result = fEngine->InternalClientUnload(int_ref, status);
} }


void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t** result)
{
*result = NULL;
}


}; };


} // end of namespace } // end of namespace


+ 22
- 6
common/JackLockedEngine.h View File

@@ -66,7 +66,7 @@ catch (...) {
\brief Locked Engine, access to methods is serialized using a mutex. \brief Locked Engine, access to methods is serialized using a mutex.
*/ */


class SERVER_EXPORT JackLockedEngine
class SERVER_EXPORT JackLockedEngine
{ {
private: private:


@@ -94,7 +94,7 @@ class SERVER_EXPORT JackLockedEngine
return fEngine.Close(); return fEngine.Close();
CATCH_EXCEPTION_RETURN CATCH_EXCEPTION_RETURN
} }
// Client management // Client management
int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status) int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status)
{ {
@@ -226,6 +226,14 @@ class SERVER_EXPORT JackLockedEngine
CATCH_EXCEPTION_RETURN CATCH_EXCEPTION_RETURN
} }


int ComputeTotalLatencies()
{
TRY_CALL
JackLock lock(&fEngine);
return fEngine.ComputeTotalLatencies();
CATCH_EXCEPTION_RETURN
}

// Graph // Graph
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
{ {
@@ -245,7 +253,7 @@ class SERVER_EXPORT JackLockedEngine
// RT : no lock // RT : no lock
fEngine.NotifyXRun(refnum); fEngine.NotifyXRun(refnum);
} }
void NotifyGraphReorder() void NotifyGraphReorder()
{ {
TRY_CALL TRY_CALL
@@ -298,7 +306,7 @@ class SERVER_EXPORT JackLockedEngine
return fEngine.GetClientRefNum(name); return fEngine.GetClientRefNum(name);
CATCH_EXCEPTION_RETURN CATCH_EXCEPTION_RETURN
} }
void NotifyQuit() void NotifyQuit()
{ {
TRY_CALL TRY_CALL
@@ -314,7 +322,7 @@ class SERVER_EXPORT JackLockedEngine
fEngine.SessionNotify(refnum, target, type, path, socket); fEngine.SessionNotify(refnum, target, type, path, socket);
CATCH_EXCEPTION CATCH_EXCEPTION
} }
void SessionReply(int refnum) void SessionReply(int refnum)
{ {
TRY_CALL TRY_CALL
@@ -322,7 +330,7 @@ class SERVER_EXPORT JackLockedEngine
fEngine.SessionReply(refnum); fEngine.SessionReply(refnum);
CATCH_EXCEPTION CATCH_EXCEPTION
} }
void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result)
{ {
TRY_CALL TRY_CALL
@@ -344,6 +352,14 @@ class SERVER_EXPORT JackLockedEngine
fEngine.ReserveClientName(name, uuid, result); fEngine.ReserveClientName(name, uuid, result);
CATCH_EXCEPTION CATCH_EXCEPTION
} }

void ClientHasSessionCallbackRequest(const char *name, int *result)
{
TRY_CALL
JackLock lock(&fEngine);
fEngine.ClientHasSessionCallbackRequest(name, result);
CATCH_EXCEPTION
}
}; };


} // end of namespace } // end of namespace


+ 13
- 14
common/JackMessageBuffer.cpp View File

@@ -2,19 +2,19 @@
* Copyright (C) 2004 Rui Nuno Capela, Steve Harris * Copyright (C) 2004 Rui Nuno Capela, Steve Harris
* Copyright (C) 2008 Nedko Arnaudov * Copyright (C) 2008 Nedko Arnaudov
* Copyright (C) 2008 Grame * Copyright (C) 2008 Grame
*
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version. * (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* *
*/ */
@@ -34,7 +34,7 @@ JackMessageBuffer::JackMessageBuffer()


JackMessageBuffer::~JackMessageBuffer() JackMessageBuffer::~JackMessageBuffer()
{} {}
void JackMessageBuffer::Start() void JackMessageBuffer::Start()
{ {
fRunning = true; fRunning = true;
@@ -44,9 +44,9 @@ void JackMessageBuffer::Start()
void JackMessageBuffer::Stop() void JackMessageBuffer::Stop()
{ {
if (fOverruns > 0) { if (fOverruns > 0) {
jack_error("WARNING: %d message buffer overruns!", fOverruns);
jack_error("WARNING: %d message buffer overruns!", fOverruns);
} else { } else {
jack_log("no message buffer overruns");
jack_log("no message buffer overruns");
} }
fGuard.Lock(); fGuard.Lock();
fRunning = false; fRunning = false;
@@ -55,7 +55,7 @@ void JackMessageBuffer::Stop()
fThread.Stop(); fThread.Stop();
Flush(); Flush();
} }
void JackMessageBuffer::Flush() void JackMessageBuffer::Flush()
{ {
while (fOutBuffer != fInBuffer) { while (fOutBuffer != fInBuffer) {
@@ -76,7 +76,7 @@ void JackMessageBuffer::AddMessage(int level, const char *message)
INC_ATOMIC(&fOverruns); INC_ATOMIC(&fOverruns);
} }
} }
bool JackMessageBuffer::Execute() bool JackMessageBuffer::Execute()
{ {
while (fRunning) { while (fRunning) {
@@ -94,10 +94,10 @@ bool JackMessageBuffer::Execute()
Flush(); Flush();
fGuard.Unlock(); fGuard.Unlock();
} }
return false;
return false;
} }


void JackMessageBuffer::Create()
void JackMessageBuffer::Create()
{ {
if (fInstance == NULL) { if (fInstance == NULL) {
fInstance = new JackMessageBuffer(); fInstance = new JackMessageBuffer();
@@ -105,7 +105,7 @@ void JackMessageBuffer::Create()
} }
} }


void JackMessageBuffer::Destroy()
void JackMessageBuffer::Destroy()
{ {
if (fInstance != NULL) { if (fInstance != NULL) {
fInstance->Stop(); fInstance->Stop();
@@ -114,7 +114,7 @@ void JackMessageBuffer::Destroy()
} }
} }


void JackMessageBufferAdd(int level, const char *message)
void JackMessageBufferAdd(int level, const char *message)
{ {
if (Jack::JackMessageBuffer::fInstance == NULL) { if (Jack::JackMessageBuffer::fInstance == NULL) {
/* Unable to print message with realtime safety. Complain and print it anyway. */ /* Unable to print message with realtime safety. Complain and print it anyway. */
@@ -137,7 +137,6 @@ void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *a
/* and we're done */ /* and we're done */
fGuard.Unlock(); fGuard.Unlock();
} }


}; };



+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -133,11 +133,17 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count
mix->lost_events += event_count - events_done; mix->lost_events += event_count - events_done;
} }


static size_t MidiBufferSize()
{
return BUFFER_SIZE_MAX * sizeof(float);
}

const JackPortType gMidiPortType = const JackPortType gMidiPortType =
{
JACK_DEFAULT_MIDI_TYPE,
MidiBufferInit,
MidiBufferMixdown
};
{
JACK_DEFAULT_MIDI_TYPE,
MidiBufferSize,
MidiBufferInit,
MidiBufferMixdown
};


} // namespace Jack } // namespace Jack

+ 25
- 20
common/JackNetDriver.cpp View File

@@ -118,10 +118,10 @@ namespace Jack


//init and restart-------------------------------------------------------------------- //init and restart--------------------------------------------------------------------
/* /*
JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
as a "dummy driver, until Init method returns. as a "dummy driver, until Init method returns.
*/ */
bool JackNetDriver::Initialize() bool JackNetDriver::Initialize()
{ {
jack_log("JackNetDriver::Initialize()"); jack_log("JackNetDriver::Initialize()");
@@ -221,7 +221,7 @@ namespace Jack
void JackNetDriver::FreeAll() void JackNetDriver::FreeAll()
{ {
FreePorts(); FreePorts();
delete[] fTxBuffer; delete[] fTxBuffer;
delete[] fRxBuffer; delete[] fRxBuffer;
delete fNetAudioCaptureBuffer; delete fNetAudioCaptureBuffer;
@@ -230,7 +230,7 @@ namespace Jack
delete fNetMidiPlaybackBuffer; delete fNetMidiPlaybackBuffer;
delete[] fMidiCapturePortList; delete[] fMidiCapturePortList;
delete[] fMidiPlaybackPortList; delete[] fMidiPlaybackPortList;
fTxBuffer = NULL; fTxBuffer = NULL;
fRxBuffer = NULL; fRxBuffer = NULL;
fNetAudioCaptureBuffer = NULL; fNetAudioCaptureBuffer = NULL;
@@ -239,7 +239,7 @@ namespace Jack
fNetMidiPlaybackBuffer = NULL; fNetMidiPlaybackBuffer = NULL;
fMidiCapturePortList = NULL; fMidiCapturePortList = NULL;
fMidiPlaybackPortList = NULL; fMidiPlaybackPortList = NULL;
#ifdef JACK_MONITOR #ifdef JACK_MONITOR
delete fNetTimeMon; delete fNetTimeMon;
fNetTimeMon = NULL; fNetTimeMon = NULL;
@@ -258,6 +258,7 @@ namespace Jack
unsigned long port_flags; unsigned long port_flags;
int audio_port_index; int audio_port_index;
uint midi_port_index; uint midi_port_index;
jack_latency_range_t range;


//audio //audio
port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
@@ -274,7 +275,8 @@ namespace Jack
port = fGraphManager->GetPort ( port_id ); port = fGraphManager->GetPort ( port_id );
port->SetAlias ( alias ); port->SetAlias ( alias );
//port latency //port latency
port->SetLatency ( fEngineControl->fBufferSize );
range.min = range.max = fEngineControl->fBufferSize;
port->SetLatencyRange(JackCaptureLatency, &range);
fCapturePortList[audio_port_index] = port_id; fCapturePortList[audio_port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); jack_log ( "JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() );
} }
@@ -295,15 +297,16 @@ namespace Jack
switch ( fParams.fNetworkMode ) switch ( fParams.fNetworkMode )
{ {
case 'f' : case 'f' :
port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize );
range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize;
break; break;
case 'n' : case 'n' :
port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize );
range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
break; break;
case 's' : case 's' :
port->SetLatency ( 2 * fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize );
range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
break; break;
} }
port->SetLatencyRange(JackPlaybackLatency, &range);
fPlaybackPortList[audio_port_index] = port_id; fPlaybackPortList[audio_port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() ); jack_log ( "JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_id, port->GetLatency() );
} }
@@ -321,7 +324,8 @@ namespace Jack
} }
port = fGraphManager->GetPort ( port_id ); port = fGraphManager->GetPort ( port_id );
//port latency //port latency
port->SetLatency ( fEngineControl->fBufferSize );
range.min = range.max = fEngineControl->fBufferSize;
port->SetLatencyRange(JackCaptureLatency, &range);
fMidiCapturePortList[midi_port_index] = port_id; fMidiCapturePortList[midi_port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); jack_log ( "JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() );
} }
@@ -342,15 +346,16 @@ namespace Jack
switch ( fParams.fNetworkMode ) switch ( fParams.fNetworkMode )
{ {
case 'f' : case 'f' :
port->SetLatency ( ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize );
range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize;
break; break;
case 'n' : case 'n' :
port->SetLatency ( fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize ) ;
range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
break; break;
case 's' : case 's' :
port->SetLatency ( 2 * fEngineControl->fBufferSize + ( fEngineControl->fSyncMode ) ? 0 : fEngineControl->fBufferSize );
range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
break; break;
} }
port->SetLatencyRange(JackPlaybackLatency, &range);
fMidiPlaybackPortList[midi_port_index] = port_id; fMidiPlaybackPortList[midi_port_index] = port_id;
jack_log ( "JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() ); jack_log ( "JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_id, port->GetLatency() );
} }
@@ -409,7 +414,7 @@ namespace Jack
//is there a transport state change to handle ? //is there a transport state change to handle ?
if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) ) if ( fSendTransportData.fNewState && ( fSendTransportData.fState != fEngineControl->fTransport.GetState() ) )
{ {
switch ( fSendTransportData.fState ) switch ( fSendTransportData.fState )
{ {
case JackTransportStopped : case JackTransportStopped :
@@ -458,13 +463,13 @@ namespace Jack
else else
fReturnTransportData.fTimebaseMaster = NO_CHANGE; fReturnTransportData.fTimebaseMaster = NO_CHANGE;
*/ */
//update transport state and position //update transport state and position
fReturnTransportData.fState = fEngineControl->fTransport.Query ( &fReturnTransportData.fPosition ); fReturnTransportData.fState = fEngineControl->fTransport.Query ( &fReturnTransportData.fPosition );
//is it a new state (that the master need to know...) ? //is it a new state (that the master need to know...) ?
fReturnTransportData.fNewState = (( fReturnTransportData.fState == JackTransportNetStarting) && fReturnTransportData.fNewState = (( fReturnTransportData.fState == JackTransportNetStarting) &&
( fReturnTransportData.fState != fLastTransportState ) &&
( fReturnTransportData.fState != fLastTransportState ) &&
( fReturnTransportData.fState != fSendTransportData.fState ) ); ( fReturnTransportData.fState != fSendTransportData.fState ) );
if ( fReturnTransportData.fNewState ) if ( fReturnTransportData.fNewState )
jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) ); jack_info ( "Sending '%s'.", GetTransportState ( fReturnTransportData.fState ) );
@@ -492,14 +497,14 @@ namespace Jack
return 0; return 0;


#ifdef JACK_MONITOR #ifdef JACK_MONITOR
// For timing
// For timing
fRcvSyncUst = GetMicroSeconds(); fRcvSyncUst = GetMicroSeconds();
#endif #endif


//decode sync //decode sync
//if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
DecodeSyncPacket(); DecodeSyncPacket();
#ifdef JACK_MONITOR #ifdef JACK_MONITOR
fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - fRcvSyncUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f ); fNetTimeMon->Add ( ( ( float ) ( GetMicroSeconds() - fRcvSyncUst ) / ( float ) fEngineControl->fPeriodUsecs ) * 100.f );
#endif #endif
@@ -534,7 +539,7 @@ namespace Jack


//sync //sync
EncodeSyncPacket(); EncodeSyncPacket();
//send sync //send sync
if ( SyncSend() == SOCKET_ERROR ) if ( SyncSend() == SOCKET_ERROR )
return SOCKET_ERROR; return SOCKET_ERROR;


+ 46
- 34
common/JackNetManager.cpp View File

@@ -134,7 +134,7 @@ namespace Jack


if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0) if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0)
goto fail; goto fail;
if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0)
goto fail; goto fail;


@@ -153,7 +153,7 @@ namespace Jack
jack_error ( "Can't activate jack client." ); jack_error ( "Can't activate jack client." );
goto fail; goto fail;
} }
if (auto_connect) if (auto_connect)
ConnectPorts(); ConnectPorts();
jack_info ( "New NetMaster started." ); jack_info ( "New NetMaster started." );
@@ -172,7 +172,8 @@ namespace Jack
uint i; uint i;
char name[24]; char name[24];
jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient );
jack_latency_range_t range;

jack_log ( "JackNetMaster::AllocPorts" ); jack_log ( "JackNetMaster::AllocPorts" );


//audio //audio
@@ -182,9 +183,10 @@ namespace Jack
if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL )
return -1; return -1;
//port latency //port latency
jack_port_set_latency ( fAudioCapturePorts[i], 0 );
range.min = range.max = 0;
jack_port_set_latency_range(fAudioCapturePorts[i], JackCaptureLatency, &range);
} }
for ( i = 0; i < fParams.fReturnAudioChannels; i++ ) for ( i = 0; i < fParams.fReturnAudioChannels; i++ )
{ {
sprintf ( name, "from_slave_%d", i+1 ); sprintf ( name, "from_slave_%d", i+1 );
@@ -194,17 +196,20 @@ namespace Jack
switch ( fParams.fNetworkMode ) switch ( fParams.fNetworkMode )
{ {
case 'f' : case 'f' :
jack_port_set_latency ( fAudioPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
range.min = range.max = (fParams.fSlaveSyncMode) ? 0 : port_latency;
jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range);
break; break;
case 'n' : case 'n' :
jack_port_set_latency ( fAudioPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
range.min = range.max = port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range);
break; break;
case 's' : case 's' :
jack_port_set_latency ( fAudioPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
range.min = range.max = 2 * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range);
break; break;
} }
} }
//midi //midi
for ( i = 0; i < fParams.fSendMidiChannels; i++ ) for ( i = 0; i < fParams.fSendMidiChannels; i++ )
{ {
@@ -212,7 +217,8 @@ namespace Jack
if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL ) if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL )
return -1; return -1;
//port latency //port latency
jack_port_set_latency ( fMidiCapturePorts[i], 0 );
range.min = range.max = 0;
jack_port_set_latency_range(fMidiCapturePorts[i], JackCaptureLatency, &range);
} }
for ( i = 0; i < fParams.fReturnMidiChannels; i++ ) for ( i = 0; i < fParams.fReturnMidiChannels; i++ )
{ {
@@ -223,23 +229,26 @@ namespace Jack
switch ( fParams.fNetworkMode ) switch ( fParams.fNetworkMode )
{ {
case 'f' : case 'f' :
jack_port_set_latency ( fMidiPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
range.min = range.max = (fParams.fSlaveSyncMode) ? 0 : port_latency;
jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range);
break; break;
case 'n' : case 'n' :
jack_port_set_latency ( fMidiPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
range.min = range.max = port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range);
break; break;
case 's' : case 's' :
jack_port_set_latency ( fMidiPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
range.min = range.max = 2 * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range);
break; break;
} }
} }
return 0; return 0;
} }
void JackNetMaster::ConnectPorts() void JackNetMaster::ConnectPorts()
{ {
const char **ports; const char **ports;
ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
if (ports != NULL) { if (ports != NULL) {
for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
@@ -247,7 +256,7 @@ namespace Jack
} }
free(ports); free(ports);
} }
ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
if (ports != NULL) { if (ports != NULL) {
for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
@@ -309,7 +318,7 @@ namespace Jack
else else
jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName ); jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName );
break; break;
case TIMEBASEMASTER : case TIMEBASEMASTER :
timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this ); timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this );
if ( timebase < 0 ) if ( timebase < 0 )
@@ -317,7 +326,7 @@ namespace Jack
else else
jack_info ( "'%s' is the new timebase master.", fParams.fName ); jack_info ( "'%s' is the new timebase master.", fParams.fName );
break; break;
case CONDITIONAL_TIMEBASEMASTER : case CONDITIONAL_TIMEBASEMASTER :
timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this ); timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this );
if ( timebase != EBUSY ) if ( timebase != EBUSY )
@@ -340,18 +349,18 @@ namespace Jack
jack_transport_stop ( fJackClient ); jack_transport_stop ( fJackClient );
jack_info ( "'%s' stops transport.", fParams.fName ); jack_info ( "'%s' stops transport.", fParams.fName );
break; break;
case JackTransportStarting : case JackTransportStarting :
if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL ) if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL )
jack_error ( "Can't set new position." ); jack_error ( "Can't set new position." );
jack_transport_start ( fJackClient ); jack_transport_start ( fJackClient );
jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
break; break;
case JackTransportNetStarting : case JackTransportNetStarting :
jack_info ( "'%s' is ready to roll..", fParams.fName ); jack_info ( "'%s' is ready to roll..", fParams.fName );
break; break;
case JackTransportRolling : case JackTransportRolling :
jack_info ( "'%s' is rolling.", fParams.fName ); jack_info ( "'%s' is rolling.", fParams.fName );
break; break;
@@ -377,16 +386,19 @@ namespace Jack
} }


//sync-------------------------------------------------------------------------------- //sync--------------------------------------------------------------------------------
bool JackNetMaster::IsSlaveReadyToRoll() bool JackNetMaster::IsSlaveReadyToRoll()
{ {
return ( fReturnTransportData.fState == JackTransportNetStarting ); return ( fReturnTransportData.fState == JackTransportNetStarting );
} }
int JackNetMaster::SetBufferSize (jack_nframes_t nframes, void* arg)
int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg)
{ {
jack_error("Cannot handle bufer size change, so proxy will be removed...");
static_cast<JackNetMaster*> ( arg )->Exit();
JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
if (nframes != obj->fParams.fPeriodSize) {
jack_error("Cannot handle bufer size change, so JackNetMaster proxy will be removed...");
obj->Exit();
}
return 0; return 0;
} }


@@ -424,10 +436,10 @@ namespace Jack
fParams.fPeriodSize ) ) ); fParams.fPeriodSize ) ) );


if (IsSynched()) { // only send if connection is "synched" if (IsSynched()) { // only send if connection is "synched"
//encode the first packet //encode the first packet
EncodeSyncPacket(); EncodeSyncPacket();
//send sync //send sync
if ( SyncSend() == SOCKET_ERROR ) if ( SyncSend() == SOCKET_ERROR )
return SOCKET_ERROR; return SOCKET_ERROR;
@@ -443,7 +455,7 @@ namespace Jack
#ifdef JACK_MONITOR #ifdef JACK_MONITOR
fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f ); fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f );
#endif #endif
} else { } else {
jack_error("Connection is not synched, skip cycle..."); jack_error("Connection is not synched, skip cycle...");
} }
@@ -459,7 +471,7 @@ namespace Jack


//decode sync //decode sync
DecodeSyncPacket(); DecodeSyncPacket();
//receive data //receive data
res = DataRecv(); res = DataRecv();
if ( ( res == 0 ) || ( res == SOCKET_ERROR ) ) if ( ( res == 0 ) || ( res == SOCKET_ERROR ) )
@@ -498,11 +510,11 @@ namespace Jack
else else
jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP); jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
break; break;
case 'p': case 'p':
fSocket.SetPort ( param->value.ui ); fSocket.SetPort ( param->value.ui );
break; break;
case 'c': case 'c':
fAutoConnect = param->value.i; fAutoConnect = param->value.i;
break; break;
@@ -646,7 +658,7 @@ namespace Jack
JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params ) JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params )
{ {
jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName ); jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName );
//check MASTER <<==> SLAVE network protocol coherency //check MASTER <<==> SLAVE network protocol coherency
if (params.fProtocolVersion != MASTER_PROTOCOL) { if (params.fProtocolVersion != MASTER_PROTOCOL) {
jack_error ( "Error : slave is running with a different protocol %s", params.fName ); jack_error ( "Error : slave is running with a different protocol %s", params.fName );
@@ -740,7 +752,7 @@ extern "C"
desc->params[i].value.i = DEFAULT_PORT; desc->params[i].value.i = DEFAULT_PORT;
strcpy ( desc->params[i].short_desc, "UDP port" ); strcpy ( desc->params[i].short_desc, "UDP port" );
strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
i++; i++;
strcpy ( desc->params[i].name, "auto_connect" ); strcpy ( desc->params[i].name, "auto_connect" );
desc->params[i].character = 'c'; desc->params[i].character = 'c';


+ 3
- 3
common/JackNetManager.h View File

@@ -54,7 +54,7 @@ namespace Jack


//sync and transport //sync and transport
int fLastTransportState; int fLastTransportState;
//monitoring //monitoring
#ifdef JACK_MONITOR #ifdef JACK_MONITOR
jack_time_t fPeriodUsecs; jack_time_t fPeriodUsecs;
@@ -64,7 +64,7 @@ namespace Jack
bool Init(bool auto_connect); bool Init(bool auto_connect);
int AllocPorts(); int AllocPorts();
void FreePorts(); void FreePorts();
//transport //transport
void EncodeTransportData(); void EncodeTransportData();
void DecodeTransportData(); void DecodeTransportData();
@@ -98,7 +98,7 @@ namespace Jack
const char* fManagerName; const char* fManagerName;
char fMulticastIP[32]; char fMulticastIP[32];
JackNetSocket fSocket; JackNetSocket fSocket;
pthread_t fManagerThread;
jack_native_thread_t fManagerThread;
master_list_t fMasterList; master_list_t fMasterList;
uint32_t fGlobalID; uint32_t fGlobalID;
bool fRunning; bool fRunning;


+ 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 class JackNetOneDriver : public JackAudioDriver
{ {
private: private:
netjack_driver_state_t netj;

void
render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats);
void
render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats );
#ifdef HAVE_CELT
void
render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes);
void
render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up);
#endif
void
render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats);
void
render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats);

netjack_driver_state_t netj;

void
render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats);
void
render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats );
#ifdef HAVE_CELT
void
render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes);
void
render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up);
#endif
void
render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats);
void
render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats);


public: public:
JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports,
int sample_rate, int period_size, int resample_factor,
const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig,
int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val );
~JackNetOneDriver();

JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports,
int sample_rate, int period_size, int resample_factor,
const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig,
int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val );
~JackNetOneDriver();


int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing, int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, bool capturing, bool playing,
int inchannels, int outchannels, bool monitor, const char* capture_driver_name, int inchannels, int outchannels, bool monitor, const char* capture_driver_name,
const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency ); const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency );


int Close();
int Close();
int Attach(); int Attach();
int Detach(); int Detach();


int Read(); int Read();
int Write(); int Write();


bool Initialize();
int AllocPorts();
void FreePorts();
bool Initialize();
int AllocPorts();
void FreePorts();


// BufferSize can't be changed // BufferSize can't be changed
bool IsFixedBufferSize() bool IsFixedBufferSize()


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -46,6 +46,7 @@ enum NotificationType {
kShutDownCallback = 15, kShutDownCallback = 15,
kQUIT = 16, kQUIT = 16,
kSessionCallback = 17, kSessionCallback = 17,
kLatencyCallback = 18,
kMaxNotification kMaxNotification
}; };




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -44,6 +44,8 @@ bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type
fInUse = true; fInUse = true;
fLatency = 0; fLatency = 0;
fTotalLatency = 0; fTotalLatency = 0;
fPlaybackLatency.min = fPlaybackLatency.max = 0;
fCaptureLatency.min = fCaptureLatency.max = 0;
fTied = NO_PORT; fTied = NO_PORT;
// DB: At this point we do not know current buffer size in frames, // DB: At this point we do not know current buffer size in frames,
// but every time buffer will be returned to any user, // but every time buffer will be returned to any user,
@@ -86,6 +88,48 @@ jack_nframes_t JackPort::GetTotalLatency() const
void JackPort::SetLatency(jack_nframes_t nframes) void JackPort::SetLatency(jack_nframes_t nframes)
{ {
fLatency = nframes; fLatency = nframes;

/* setup the new latency values here,
* so we dont need to change the backend codes.
*/
if (fFlags & JackPortIsOutput) {
fCaptureLatency.min = nframes;
fCaptureLatency.max = nframes;
}
if (fFlags & JackPortIsInput) {
fPlaybackLatency.min = nframes;
fPlaybackLatency.max = nframes;
}
}

void JackPort::SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range)
{
if (mode == JackCaptureLatency) {
fCaptureLatency = *range;

/* hack to set port->shared->latency up for
* backend ports
*/
if ((fFlags & JackPortIsOutput) && (fFlags & JackPortIsPhysical))
fLatency = (range->min + range->max) / 2;
} else {
fPlaybackLatency = *range;

/* hack to set port->shared->latency up for
* backend ports
*/
if ((fFlags & JackPortIsInput) && (fFlags & JackPortIsPhysical))
fLatency = (range->min + range->max) / 2;
}
}

void JackPort::GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const
{
if (mode == JackCaptureLatency) {
*range = fCaptureLatency;
} else {
*range = fPlaybackLatency;
}
} }


int JackPort::Tie(jack_port_id_t port_index) int JackPort::Tie(jack_port_id_t port_index)
@@ -103,10 +147,10 @@ int JackPort::UnTie()
int JackPort::RequestMonitor(bool onoff) int JackPort::RequestMonitor(bool onoff)
{ {
/** /**
jackd.h
jackd.h
* If @ref JackPortCanMonitor is set for this @a port, turn input * If @ref JackPortCanMonitor is set for this @a port, turn input
* monitoring on or off. Otherwise, do nothing. * monitoring on or off. Otherwise, do nothing.
if (!(fFlags & JackPortCanMonitor)) if (!(fFlags & JackPortCanMonitor))
return -1; return -1;
*/ */
@@ -123,10 +167,10 @@ int JackPort::RequestMonitor(bool onoff)
int JackPort::EnsureMonitor(bool onoff) int JackPort::EnsureMonitor(bool onoff)
{ {
/** /**
jackd.h
jackd.h
* If @ref JackPortCanMonitor is set for this @a port, turn input * If @ref JackPortCanMonitor is set for this @a port, turn input
* monitoring on or off. Otherwise, do nothing. * monitoring on or off. Otherwise, do nothing.
if (!(fFlags & JackPortCanMonitor)) if (!(fFlags & JackPortCanMonitor))
return -1; return -1;
*/ */
@@ -165,7 +209,7 @@ int JackPort::GetFlags() const
const char* JackPort::GetType() const const char* JackPort::GetType() const
{ {
const JackPortType* type = GetPortType(fTypeId); const JackPortType* type = GetPortType(fTypeId);
return type->name;
return type->fName;
} }


void JackPort::SetName(const char* new_name) void JackPort::SetName(const char* new_name)


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -51,12 +51,14 @@ class SERVER_EXPORT JackPort


jack_nframes_t fLatency; jack_nframes_t fLatency;
jack_nframes_t fTotalLatency; jack_nframes_t fTotalLatency;
jack_latency_range_t fPlaybackLatency;
jack_latency_range_t fCaptureLatency;
uint8_t fMonitorRequests; uint8_t fMonitorRequests;


bool fInUse; bool fInUse;
jack_port_id_t fTied; // Locally tied source port jack_port_id_t fTied; // Locally tied source port
float fBuffer[BUFFER_SIZE_MAX + 4]; float fBuffer[BUFFER_SIZE_MAX + 4];
bool IsUsed() const bool IsUsed() const
{ {
return fInUse; return fInUse;
@@ -88,9 +90,13 @@ class SERVER_EXPORT JackPort
int UnTie(); int UnTie();


jack_nframes_t GetLatency() const; jack_nframes_t GetLatency() const;
jack_nframes_t GetTotalLatency() const;
void SetLatency(jack_nframes_t latency); void SetLatency(jack_nframes_t latency);


void SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range);
void GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const;

jack_nframes_t GetTotalLatency() const;

int RequestMonitor(bool onoff); int RequestMonitor(bool onoff);
int EnsureMonitor(bool onoff); int EnsureMonitor(bool onoff);
bool MonitoringInput() bool MonitoringInput()
@@ -105,7 +111,7 @@ class SERVER_EXPORT JackPort
} }


int GetRefNum() const; int GetRefNum() const;
} POST_PACKED_STRUCTURE; } POST_PACKED_STRUCTURE;


} // end of namespace } // end of namespace


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -24,20 +24,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
namespace Jack namespace Jack
{ {


static const JackPortType* port_types[] =
static const JackPortType* gPortTypes[] =
{ {
&gAudioPortType, &gAudioPortType,
&gMidiPortType, &gMidiPortType,
}; };


jack_port_type_id_t PORT_TYPES_MAX = sizeof(port_types) / sizeof(port_types[0]);
jack_port_type_id_t PORT_TYPES_MAX = sizeof(gPortTypes) / sizeof(gPortTypes[0]);


jack_port_type_id_t GetPortTypeId(const char* port_type) jack_port_type_id_t GetPortTypeId(const char* port_type)
{ {
for (jack_port_type_id_t i = 0; i < PORT_TYPES_MAX; ++i) { for (jack_port_type_id_t i = 0; i < PORT_TYPES_MAX; ++i) {
const JackPortType* type = port_types[i];
const JackPortType* type = gPortTypes[i];
assert(type != 0); assert(type != 0);
if (strcmp(port_type, type->name) == 0)
if (strcmp(port_type, type->fName) == 0)
return i; return i;
} }
return PORT_TYPES_MAX; return PORT_TYPES_MAX;
@@ -46,7 +46,7 @@ jack_port_type_id_t GetPortTypeId(const char* port_type)
const JackPortType* GetPortType(jack_port_type_id_t type_id) const JackPortType* GetPortType(jack_port_type_id_t type_id)
{ {
assert(type_id >= 0 && type_id <= PORT_TYPES_MAX); assert(type_id >= 0 && type_id <= PORT_TYPES_MAX);
const JackPortType* type = port_types[type_id];
const JackPortType* type = gPortTypes[type_id];
assert(type != 0); assert(type != 0);
return type; return type;
} }


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -31,7 +31,8 @@ extern jack_port_type_id_t PORT_TYPES_MAX;


struct JackPortType struct JackPortType
{ {
const char* name;
const char* fName;
size_t (*size)();
void (*init)(void* buffer, size_t buffer_size, jack_nframes_t nframes); void (*init)(void* buffer, size_t buffer_size, jack_nframes_t nframes);
void (*mixdown)(void *mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes); void (*mixdown)(void *mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes);
}; };


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -71,7 +71,9 @@ struct JackRequest
kSessionReply = 34, kSessionReply = 34,
kGetClientByUUID = 35, kGetClientByUUID = 35,
kReserveClientName = 36, kReserveClientName = 36,
kGetUUIDByClient = 37
kGetUUIDByClient = 37,
kClientHasSessionCallback = 38,
kComputeTotalLatencies = 39
}; };


RequestType fType; RequestType fType;
@@ -122,7 +124,7 @@ struct JackResult
{ {
return trans->Write(&fResult, sizeof(int)); return trans->Write(&fResult, sizeof(int));
} }
}; };


/*! /*!
@@ -161,7 +163,7 @@ struct JackClientCheckRequest : public JackRequest
CheckRes(trans->Write(&fOptions, sizeof(int))); CheckRes(trans->Write(&fOptions, sizeof(int)));
return trans->Write(&fUUID, sizeof(int)); return trans->Write(&fUUID, sizeof(int));
} }
}; };


/*! /*!
@@ -197,7 +199,7 @@ struct JackClientCheckResult : public JackResult
CheckRes(trans->Write(&fStatus, sizeof(int))); CheckRes(trans->Write(&fStatus, sizeof(int)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -210,7 +212,7 @@ struct JackClientOpenRequest : public JackRequest
int fPID; int fPID;
int fUUID; int fUUID;
char fName[JACK_CLIENT_NAME_SIZE + 1]; char fName[JACK_CLIENT_NAME_SIZE + 1];
JackClientOpenRequest() JackClientOpenRequest()
{} {}
JackClientOpenRequest(const char* name, int pid, int uuid): JackRequest(JackRequest::kClientOpen) JackClientOpenRequest(const char* name, int pid, int uuid): JackRequest(JackRequest::kClientOpen)
@@ -234,7 +236,7 @@ struct JackClientOpenRequest : public JackRequest
CheckRes(trans->Write(&fUUID, sizeof(int))); CheckRes(trans->Write(&fUUID, sizeof(int)));
return trans->Write(&fName, sizeof(fName)); return trans->Write(&fName, sizeof(fName));
} }
}; };


/*! /*!
@@ -247,7 +249,7 @@ struct JackClientOpenResult : public JackResult
int fSharedEngine; int fSharedEngine;
int fSharedClient; int fSharedClient;
int fSharedGraph; int fSharedGraph;
JackClientOpenResult() JackClientOpenResult()
: JackResult(), fSharedEngine(-1), fSharedClient(-1), fSharedGraph(-1) : JackResult(), fSharedEngine(-1), fSharedClient(-1), fSharedGraph(-1)
{} {}
@@ -272,7 +274,7 @@ struct JackClientOpenResult : public JackResult
CheckRes(trans->Write(&fSharedGraph, sizeof(int))); CheckRes(trans->Write(&fSharedGraph, sizeof(int)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -299,7 +301,7 @@ struct JackClientCloseRequest : public JackRequest
CheckRes(JackRequest::Write(trans)); CheckRes(JackRequest::Write(trans));
return trans->Write(&fRefNum, sizeof(int)); return trans->Write(&fRefNum, sizeof(int));
} }
}; };


/*! /*!
@@ -402,7 +404,7 @@ struct JackPortRegisterRequest : public JackRequest
CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int))); CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -428,7 +430,7 @@ struct JackPortRegisterResult : public JackResult
CheckRes(JackResult::Write(trans)); CheckRes(JackResult::Write(trans));
return trans->Write(&fPortIndex, sizeof(jack_port_id_t)); return trans->Write(&fPortIndex, sizeof(jack_port_id_t));
} }
}; };


/*! /*!
@@ -461,7 +463,7 @@ struct JackPortUnRegisterRequest : public JackRequest
CheckRes(trans->Write(&fPortIndex, sizeof(jack_port_id_t))); CheckRes(trans->Write(&fPortIndex, sizeof(jack_port_id_t)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -501,7 +503,7 @@ struct JackPortConnectNameRequest : public JackRequest
CheckRes(trans->Write(&fDst, sizeof(fDst))); CheckRes(trans->Write(&fDst, sizeof(fDst)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -540,7 +542,7 @@ struct JackPortDisconnectNameRequest : public JackRequest
CheckRes(trans->Write(&fDst, sizeof(fDst))); CheckRes(trans->Write(&fDst, sizeof(fDst)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -576,7 +578,7 @@ struct JackPortConnectRequest : public JackRequest
CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -612,7 +614,7 @@ struct JackPortDisconnectRequest : public JackRequest
CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -651,7 +653,7 @@ struct JackPortRenameRequest : public JackRequest
return 0; return 0;


} }
}; };


/*! /*!
@@ -679,7 +681,7 @@ struct JackSetBufferSizeRequest : public JackRequest
CheckRes(JackRequest::Write(trans)); CheckRes(JackRequest::Write(trans));
return trans->Write(&fBufferSize, sizeof(jack_nframes_t)); return trans->Write(&fBufferSize, sizeof(jack_nframes_t));
} }
}; };


/*! /*!
@@ -707,7 +709,31 @@ struct JackSetFreeWheelRequest : public JackRequest
CheckRes(JackRequest::Write(trans)); CheckRes(JackRequest::Write(trans));
return trans->Write(&fOnOff, sizeof(int)); return trans->Write(&fOnOff, sizeof(int));
} }

};

/*!
\brief ComputeTotalLatencies request.
*/

struct JackComputeTotalLatenciesRequest : public JackRequest
{

JackComputeTotalLatenciesRequest()
: JackRequest(JackRequest::kComputeTotalLatencies)
{}

int Read(JackChannelTransaction* trans)
{
return 0;
}

int Write(JackChannelTransaction* trans)
{
CheckRes(JackRequest::Write(trans));
return 0;
}

}; };


/*! /*!
@@ -735,7 +761,7 @@ struct JackReleaseTimebaseRequest : public JackRequest
CheckRes(JackRequest::Write(trans)); CheckRes(JackRequest::Write(trans));
return trans->Write(&fRefNum, sizeof(int)); return trans->Write(&fRefNum, sizeof(int));
} }
}; };


/*! /*!
@@ -766,7 +792,7 @@ struct JackSetTimebaseCallbackRequest : public JackRequest
CheckRes(trans->Write(&fRefNum, sizeof(int))); CheckRes(trans->Write(&fRefNum, sizeof(int)));
return trans->Write(&fConditionnal, sizeof(int)); return trans->Write(&fConditionnal, sizeof(int));
} }
}; };


/*! /*!
@@ -797,7 +823,7 @@ struct JackGetInternalClientNameRequest : public JackRequest
CheckRes(trans->Write(&fRefNum, sizeof(int))); CheckRes(trans->Write(&fRefNum, sizeof(int)));
return trans->Write(&fIntRefNum, sizeof(int)); return trans->Write(&fIntRefNum, sizeof(int));
} }
}; };


/*! /*!
@@ -830,7 +856,7 @@ struct JackGetInternalClientNameResult : public JackResult
CheckRes(trans->Write(&fName, sizeof(fName))); CheckRes(trans->Write(&fName, sizeof(fName)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -863,7 +889,7 @@ struct JackInternalClientHandleRequest : public JackRequest
CheckRes(trans->Write(&fRefNum, sizeof(int))); CheckRes(trans->Write(&fRefNum, sizeof(int)));
return trans->Write(&fName, sizeof(fName)); return trans->Write(&fName, sizeof(fName));
} }
}; };


/*! /*!
@@ -897,7 +923,7 @@ struct JackInternalClientHandleResult : public JackResult
CheckRes(trans->Write(&fIntRefNum, sizeof(int))); CheckRes(trans->Write(&fIntRefNum, sizeof(int)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -949,7 +975,7 @@ struct JackInternalClientLoadRequest : public JackRequest
CheckRes(trans->Write(&fUUID, sizeof(int))); CheckRes(trans->Write(&fUUID, sizeof(int)));
return trans->Write(&fOptions, sizeof(int)); return trans->Write(&fOptions, sizeof(int));
} }
}; };


/*! /*!
@@ -983,7 +1009,7 @@ struct JackInternalClientLoadResult : public JackResult
CheckRes(trans->Write(&fIntRefNum, sizeof(int))); CheckRes(trans->Write(&fIntRefNum, sizeof(int)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -1044,7 +1070,7 @@ struct JackInternalClientUnloadResult : public JackResult
CheckRes(trans->Write(&fStatus, sizeof(int))); CheckRes(trans->Write(&fStatus, sizeof(int)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -1147,7 +1173,7 @@ struct JackSessionNotifyResult : public JackResult
CheckRes(trans->Write(terminator, sizeof(terminator))); CheckRes(trans->Write(terminator, sizeof(terminator)));
return 0; return 0;
} }
}; };


/*! /*!
@@ -1245,7 +1271,7 @@ struct JackClientNameResult : public JackResult
CheckRes(trans->Write(&fName, sizeof(fName))); CheckRes(trans->Write(&fName, sizeof(fName)));
return 0; return 0;
} }
}; };


struct JackUUIDResult : public JackResult struct JackUUIDResult : public JackResult
@@ -1274,7 +1300,7 @@ struct JackUUIDResult : public JackResult
CheckRes(trans->Write(&fUUID, sizeof(fUUID))); CheckRes(trans->Write(&fUUID, sizeof(fUUID)));
return 0; return 0;
} }
}; };


struct JackGetUUIDRequest : public JackRequest struct JackGetUUIDRequest : public JackRequest
@@ -1368,6 +1394,34 @@ struct JackReserveNameRequest : public JackRequest


}; };


struct JackClientHasSessionCallbackRequest : public JackRequest
{
char fName[JACK_CLIENT_NAME_SIZE + 1];

JackClientHasSessionCallbackRequest()
{}

JackClientHasSessionCallbackRequest(const char *name)
: JackRequest(JackRequest::kClientHasSessionCallback)
{
strncpy(fName, name, sizeof(fName));
}

int Read(JackChannelTransaction* trans)
{
CheckRes(trans->Read(&fName, sizeof(fName)));
return 0;
}

int Write(JackChannelTransaction* trans)
{
CheckRes(JackRequest::Write(trans));
CheckRes(trans->Write(&fName, sizeof(fName)));
return 0;
}

};

/*! /*!
\brief ClientNotification. \brief ClientNotification.
*/ */


+ 17
- 17
common/JackServer.cpp View File

@@ -45,7 +45,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio
} else { } else {
jack_info("JACK server starting in non-realtime mode"); jack_info("JACK server starting in non-realtime mode");
} }
fGraphManager = JackGraphManager::Allocate(port_max); fGraphManager = JackGraphManager::Allocate(port_max);
fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name);
fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl);
@@ -72,17 +72,17 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
{ {
// TODO: move that in reworked JackServerGlobals::Init() // TODO: move that in reworked JackServerGlobals::Init()
JackMessageBuffer::Create(); JackMessageBuffer::Create();
if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
jack_error("Cannot initialize driver"); jack_error("Cannot initialize driver");
goto fail_close1; goto fail_close1;
} }
if (fChannel.Open(fEngineControl->fServerName, this) < 0) { if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
jack_error("Server channel open error"); jack_error("Server channel open error");
goto fail_close2; goto fail_close2;
} }
if (fEngine->Open() < 0) { if (fEngine->Open() < 0) {
jack_error("Cannot open engine"); jack_error("Cannot open engine");
goto fail_close3; goto fail_close3;
@@ -92,12 +92,12 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
jack_error("Cannot open driver"); jack_error("Cannot open driver");
goto fail_close4; goto fail_close4;
} }
if (fAudioDriver->Attach() < 0) { if (fAudioDriver->Attach() < 0) {
jack_error("Cannot attach audio driver"); jack_error("Cannot attach audio driver");
goto fail_close5; goto fail_close5;
} }
fFreewheelDriver->SetMaster(false); fFreewheelDriver->SetMaster(false);
fAudioDriver->SetMaster(true); fAudioDriver->SetMaster(true);
fAudioDriver->AddSlave(fFreewheelDriver); // After ??? fAudioDriver->AddSlave(fFreewheelDriver); // After ???
@@ -113,11 +113,11 @@ fail_close4:


fail_close3: fail_close3:
fChannel.Close(); fChannel.Close();
fail_close2:
fail_close2:
fAudioDriver->Close(); fAudioDriver->Close();


fail_close1:
fail_close1:
JackMessageBuffer::Destroy(); JackMessageBuffer::Destroy();
return -1; return -1;
} }
@@ -190,7 +190,7 @@ int JackServer::SetBufferSize(jack_nframes_t buffer_size)
jack_log("SetBufferSize: requirement for new buffer size equals current value"); jack_log("SetBufferSize: requirement for new buffer size equals current value");
return 0; return 0;
} }
if (fAudioDriver->IsFixedBufferSize()) { if (fAudioDriver->IsFixedBufferSize()) {
jack_log("SetBufferSize: driver only supports a fixed buffer size"); jack_log("SetBufferSize: driver only supports a fixed buffer size");
return -1; return -1;
@@ -316,37 +316,37 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par
fAudioDriver->Stop(); fAudioDriver->Stop();
fAudioDriver->Detach(); fAudioDriver->Detach();
fAudioDriver->Close(); fAudioDriver->Close();
// Open new master // Open new master
JackDriverInfo* info = new JackDriverInfo(); JackDriverInfo* info = new JackDriverInfo();
JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
if (master == NULL || info == NULL) { if (master == NULL || info == NULL) {
delete info; delete info;
delete master; delete master;
return -1; return -1;
} else { } else {
// Get slaves list // Get slaves list
std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
std::list<JackDriverInterface*>::const_iterator it; std::list<JackDriverInterface*>::const_iterator it;
// Move slaves in new master // Move slaves in new master
for (it = slave_list.begin(); it != slave_list.end(); it++) { for (it = slave_list.begin(); it != slave_list.end(); it++) {
JackDriverInterface* slave = *it; JackDriverInterface* slave = *it;
master->AddSlave(slave); master->AddSlave(slave);
} }
// Delete old master // Delete old master
delete fAudioDriver; delete fAudioDriver;
delete fDriverInfo; delete fDriverInfo;
// Activate master // Activate master
fAudioDriver = master; fAudioDriver = master;
fDriverInfo = info; fDriverInfo = info;
fAudioDriver->Attach(); fAudioDriver->Attach();
fAudioDriver->SetMaster(true); fAudioDriver->SetMaster(true);
return fAudioDriver->Start();
return fAudioDriver->Start();
} }
} }




+ 6
- 4
common/JackServerGlobals.cpp View File

@@ -28,8 +28,10 @@ static char* server_name = NULL;
namespace Jack namespace Jack
{ {


JackServer* JackServerGlobals::fInstance;
JackServer* JackServerGlobals::fInstance;
unsigned int JackServerGlobals::fUserCount; unsigned int JackServerGlobals::fUserCount;
int JackServerGlobals::fRTNotificationSocket;

bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL;
void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL; void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL;


@@ -95,7 +97,7 @@ bool JackServerGlobals::Init()
int argc = 0; int argc = 0;
char* argv[32]; char* argv[32];
jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK;
// First user starts the server // First user starts the server
if (fUserCount++ == 0) { if (fUserCount++ == 0) {


@@ -158,7 +160,7 @@ bool JackServerGlobals::Init()
(opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) {


switch (opt) { switch (opt) {
case 'c': case 'c':
if (tolower (optarg[0]) == 'h') { if (tolower (optarg[0]) == 'h') {
clock_source = JACK_TIMER_HPET; clock_source = JACK_TIMER_HPET;
@@ -168,7 +170,7 @@ bool JackServerGlobals::Init()
clock_source = JACK_TIMER_SYSTEM_CLOCK; clock_source = JACK_TIMER_SYSTEM_CLOCK;
} else { } else {
jack_error("unknown option character %c", optopt); jack_error("unknown option character %c", optopt);
}
}
break; break;


case 'd': case 'd':


+ 4
- 3
common/JackServerGlobals.h View File

@@ -38,9 +38,10 @@ struct SERVER_EXPORT JackServerGlobals
{ {
static JackServer* fInstance; static JackServer* fInstance;
static unsigned int fUserCount; static unsigned int fUserCount;
static bool (* on_device_acquire)(const char * device_name);
static void (* on_device_release)(const char * device_name);
static int fRTNotificationSocket; // For debugging purpose
static bool (* on_device_acquire)(const char* device_name);
static void (* on_device_release)(const char* device_name);

JackServerGlobals(); JackServerGlobals();
~JackServerGlobals(); ~JackServerGlobals();




+ 28
- 28
common/JackThread.h View File

@@ -1,21 +1,21 @@
/* /*
Copyright (C) 2001 Paul Davis Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 Grame Copyright (C) 2004-2008 Grame
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */


#ifndef __JackThread__ #ifndef __JackThread__
@@ -26,23 +26,23 @@


namespace Jack namespace Jack
{ {
/*! /*!
\brief The base class for runnable objects, that have an <B> Init </B> and <B> Execute </B> method to be called in a thread. \brief The base class for runnable objects, that have an <B> Init </B> and <B> Execute </B> method to be called in a thread.
*/ */


class JackRunnableInterface class JackRunnableInterface
{ {
protected: protected:
JackRunnableInterface() JackRunnableInterface()
{} {}
virtual ~JackRunnableInterface() virtual ~JackRunnableInterface()
{} {}
public: public:
virtual bool Init() /*! Called once when the thread is started */ virtual bool Init() /*! Called once when the thread is started */
{ {
return true; return true;
@@ -61,23 +61,23 @@ class SERVER_EXPORT JackThreadInterface
{ {


public: public:
enum kThreadState {kIdle, kStarting, kIniting, kRunning}; enum kThreadState {kIdle, kStarting, kIniting, kRunning};
protected: protected:
JackRunnableInterface* fRunnable; JackRunnableInterface* fRunnable;
int fPriority; int fPriority;
bool fRealTime; bool fRealTime;
volatile kThreadState fStatus; volatile kThreadState fStatus;
int fCancellation; int fCancellation;
public: public:
JackThreadInterface(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation): JackThreadInterface(JackRunnableInterface* runnable, int priority, bool real_time, int cancellation):
fRunnable(runnable), fPriority(priority), fRealTime(real_time), fStatus(kIdle), fCancellation(cancellation) fRunnable(runnable), fPriority(priority), fRealTime(real_time), fStatus(kIdle), fCancellation(cancellation)
{} {}
kThreadState GetStatus() kThreadState GetStatus()
{ {
return fStatus; return fStatus;
@@ -86,10 +86,10 @@ class SERVER_EXPORT JackThreadInterface
{ {
fStatus = status; fStatus = status;
} }
void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX... void SetParams(UInt64 period, UInt64 computation, UInt64 constraint) // Empty implementation, will only make sense on OSX...
{} {}
int Start(); int Start();
int StartSync(); int StartSync();
int Kill(); int Kill();
@@ -98,24 +98,24 @@ class SERVER_EXPORT JackThreadInterface


int AcquireRealTime(); // Used when called from another thread int AcquireRealTime(); // Used when called from another thread
int AcquireSelfRealTime(); // Used when called from thread itself int AcquireSelfRealTime(); // Used when called from thread itself
int AcquireRealTime(int priority); // Used when called from another thread int AcquireRealTime(int priority); // Used when called from another thread
int AcquireSelfRealTime(int priority); // Used when called from thread itself int AcquireSelfRealTime(int priority); // Used when called from thread itself
int DropRealTime(); // Used when called from another thread int DropRealTime(); // Used when called from another thread
int DropSelfRealTime(); // Used when called from thread itself int DropSelfRealTime(); // Used when called from thread itself


pthread_t GetThreadID();
jack_native_thread_t GetThreadID();
bool IsThread(); bool IsThread();


static int AcquireRealTimeImp(pthread_t thread, int priority);
static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint);
static int DropRealTimeImp(pthread_t thread);
static int StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg);
static int StopImp(pthread_t thread);
static int KillImp(pthread_t thread);
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority);
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint);
static int DropRealTimeImp(jack_native_thread_t thread);
static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg);
static int StopImp(jack_native_thread_t thread);
static int KillImp(jack_native_thread_t thread);
}; };
} }


} // end of namespace } // end of namespace


+ 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__ #ifndef __JackTime__
#define __JackTime__ #define __JackTime__


#include "types.h"
#include "JackCompilerDeps.h" #include "JackCompilerDeps.h"
#include "JackTypes.h" #include "JackTypes.h"




+ 6
- 0
common/JackTypes.h View File

@@ -34,6 +34,12 @@ typedef signed long SInt32;


#include "JackTypes_os.h" #include "JackTypes_os.h"


/**
* Type used to represent the value of free running
* monotonic clock with units of microseconds.
*/
typedef uint64_t jack_time_t;

typedef uint16_t jack_int_t; // Internal type for ports and refnum typedef uint16_t jack_int_t; // Internal type for ports and refnum


typedef enum { typedef enum {


+ 19
- 19
common/Jackdmp.cpp View File

@@ -33,7 +33,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackDriverLoader.h" #include "JackDriverLoader.h"


#if defined(JACK_DBUS) && defined(__linux__) #if defined(JACK_DBUS) && defined(__linux__)
#include <dbus/dbus.h>
#include <dbus/dbus.h>
#include "audio_reserve.h" #include "audio_reserve.h"
#endif #endif


@@ -85,7 +85,7 @@ static void copyright(FILE* file)
{ {
fprintf(file, "jackdmp " VERSION "\n" fprintf(file, "jackdmp " VERSION "\n"
"Copyright 2001-2005 Paul Davis and others.\n" "Copyright 2001-2005 Paul Davis and others.\n"
"Copyright 2004-2010 Grame.\n"
"Copyright 2004-2011 Grame.\n"
"jackdmp comes with ABSOLUTELY NO WARRANTY\n" "jackdmp comes with ABSOLUTELY NO WARRANTY\n"
"This is free software, and you are welcome to redistribute it\n" "This is free software, and you are welcome to redistribute it\n"
"under certain conditions; see the file COPYING for details\n"); "under certain conditions; see the file COPYING for details\n");
@@ -114,10 +114,10 @@ static void usage(FILE* file)
" -d backend [ ... backend args ... ]\n" " -d backend [ ... backend args ... ]\n"
#ifdef __APPLE__ #ifdef __APPLE__
" Available backends may include: coreaudio, dummy or net.\n\n" " Available backends may include: coreaudio, dummy or net.\n\n"
#endif
#endif
#ifdef WIN32 #ifdef WIN32
" Available backends may include: portaudio, dummy or net.\n\n" " Available backends may include: portaudio, dummy or net.\n\n"
#endif
#endif
#ifdef __linux__ #ifdef __linux__
" Available backends may include: alsa, dummy, freebob, firewire or net\n\n" " Available backends may include: alsa, dummy, freebob, firewire or net\n\n"
#endif #endif
@@ -178,13 +178,13 @@ int main(int argc, char* argv[])
jackctl_driver_t * midi_driver_ctl; jackctl_driver_t * midi_driver_ctl;
jackctl_driver_t * loopback_driver_ctl; jackctl_driver_t * loopback_driver_ctl;
int replace_registry = 0; int replace_registry = 0;
const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:"
#ifdef __linux__ #ifdef __linux__
"c:" "c:"
#endif #endif
; ;
struct option long_options[] = { struct option long_options[] = {
#ifdef __linux__ #ifdef __linux__
{ "clock-source", 1, 0, 'c' }, { "clock-source", 1, 0, 'c' },
@@ -199,7 +199,7 @@ int main(int argc, char* argv[])
{ "name", 1, 0, 'n' }, { "name", 1, 0, 'n' },
{ "unlock", 0, 0, 'u' }, { "unlock", 0, 0, 'u' },
{ "realtime", 0, 0, 'R' }, { "realtime", 0, 0, 'R' },
{ "no-realtime", 0, 0, 'r' },
{ "no-realtime", 0, 0, 'r' },
{ "replace-registry", 0, &replace_registry, 0 }, { "replace-registry", 0, &replace_registry, 0 },
{ "loopback", 0, 0, 'L' }, { "loopback", 0, 0, 'L' },
{ "realtime-priority", 1, 0, 'P' }, { "realtime-priority", 1, 0, 'P' },
@@ -239,23 +239,23 @@ int main(int argc, char* argv[])
fprintf(stderr, "Failed to create server object\n"); fprintf(stderr, "Failed to create server object\n");
return -1; return -1;
} }
server_parameters = jackctl_server_get_parameters(server_ctl); server_parameters = jackctl_server_get_parameters(server_ctl);
// Default setting // Default setting
param = jackctl_get_parameter(server_parameters, "realtime"); param = jackctl_get_parameter(server_parameters, "realtime");
if (param != NULL) { if (param != NULL) {
value.b = true; value.b = true;
jackctl_parameter_set_value(param, &value); jackctl_parameter_set_value(param, &value);
} }
opterr = 0; opterr = 0;
while (!seen_audio_driver && while (!seen_audio_driver &&
(opt = getopt_long(argc, argv, options, (opt = getopt_long(argc, argv, options,
long_options, &option_index)) != EOF) { long_options, &option_index)) != EOF) {
switch (opt) { switch (opt) {


#ifdef __linux__
#ifdef __linux__
case 'c': case 'c':
param = jackctl_get_parameter(server_parameters, "clock-source"); param = jackctl_get_parameter(server_parameters, "clock-source");
if (param != NULL) { if (param != NULL) {
@@ -280,7 +280,7 @@ int main(int argc, char* argv[])
seen_audio_driver = true; seen_audio_driver = true;
audio_driver_name = optarg; audio_driver_name = optarg;
break; break;
case 'L': case 'L':
loopback = atoi(optarg); loopback = atoi(optarg);
break; break;
@@ -342,7 +342,7 @@ int main(int argc, char* argv[])
jackctl_parameter_set_value(param, &value); jackctl_parameter_set_value(param, &value);
} }
break; break;
case 'r': case 'r':
param = jackctl_get_parameter(server_parameters, "realtime"); param = jackctl_get_parameter(server_parameters, "realtime");
if (param != NULL) { if (param != NULL) {
@@ -388,14 +388,14 @@ int main(int argc, char* argv[])
goto fail_free1; goto fail_free1;
} }
} }
// Long option with no letter so treated separately // Long option with no letter so treated separately
param = jackctl_get_parameter(server_parameters, "replace-registry"); param = jackctl_get_parameter(server_parameters, "replace-registry");
if (param != NULL) { if (param != NULL) {
value.b = replace_registry; value.b = replace_registry;
jackctl_parameter_set_value(param, &value); jackctl_parameter_set_value(param, &value);
} }
if (show_version) { if (show_version) {
printf( "jackdmp version " VERSION printf( "jackdmp version " VERSION
" tmpdir " jack_server_dir " tmpdir " jack_server_dir
@@ -441,7 +441,7 @@ int main(int argc, char* argv[])


// Setup signals then start server // Setup signals then start server
signals = jackctl_setup_signals(0); signals = jackctl_setup_signals(0);
if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { if (!jackctl_server_start(server_ctl, audio_driver_ctl)) {
fprintf(stderr, "Failed to start server\n"); fprintf(stderr, "Failed to start server\n");
goto fail_free1; goto fail_free1;
@@ -458,7 +458,7 @@ int main(int argc, char* argv[])


jackctl_server_add_slave(server_ctl, midi_driver_ctl); jackctl_server_add_slave(server_ctl, midi_driver_ctl);
} }
// Loopback driver // Loopback driver
if (loopback > 0) { if (loopback > 0) {
loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback");
@@ -480,7 +480,7 @@ int main(int argc, char* argv[])


if (!jackctl_server_stop(server_ctl)) if (!jackctl_server_stop(server_ctl))
fprintf(stderr, "Cannot stop server...\n"); fprintf(stderr, "Cannot stop server...\n");
jackctl_server_destroy(server_ctl); jackctl_server_destroy(server_ctl);
notify_server_stop(server_name); notify_server_stop(server_name);
return 0; return 0;
@@ -488,7 +488,7 @@ int main(int argc, char* argv[])
fail_free1: fail_free1:
jackctl_server_destroy(server_ctl); jackctl_server_destroy(server_ctl);
return -1; return -1;
fail_free2: fail_free2:
jackctl_server_stop(server_ctl); jackctl_server_stop(server_ctl);
jackctl_server_destroy(server_ctl); jackctl_server_destroy(server_ctl);


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

@@ -1,19 +1,19 @@
/* /*
Copyright (C) 2001 Paul Davis Copyright (C) 2001 Paul Davis
Copyright (C) 2004 Jack O'Quin Copyright (C) 2004 Jack O'Quin
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -33,21 +33,21 @@ extern "C"
/** /**
* Note: More documentation can be found in jack/types.h. * Note: More documentation can be found in jack/types.h.
*/ */
/************************************************************* /*************************************************************
* NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function
* added to the JACK API after the 0.116.2 release. * added to the JACK API after the 0.116.2 release.
*
* Functions that predate this release are marked with
*
* Functions that predate this release are marked with
* JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile * JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile
* time in a variety of ways. The default definition is empty, * time in a variety of ways. The default definition is empty,
* so that these symbols get normal linkage. If you wish to * so that these symbols get normal linkage. If you wish to
* use all JACK symbols with weak linkage, include
* use all JACK symbols with weak linkage, include
* <jack/weakjack.h> before jack.h. * <jack/weakjack.h> before jack.h.
*************************************************************/ *************************************************************/
#include <jack/weakmacros.h> #include <jack/weakmacros.h>
/** /**
* Call this function to get version of the JACK, in form of several numbers * Call this function to get version of the JACK, in form of several numbers
* *
@@ -200,7 +200,7 @@ int jack_get_client_pid (const char *name) JACK_OPTIONAL_WEAK_EXPORT;
* @return the pthread ID of the thread running the JACK client side * @return the pthread ID of the thread running the JACK client side
* code. * code.
*/ */
pthread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT;
jack_native_thread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT;


/*@}*/ /*@}*/


@@ -228,7 +228,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_


/** /**
* Wait until this JACK client should process data. * Wait until this JACK client should process data.
*
*
* @param client - pointer to a JACK client structure * @param client - pointer to a JACK client structure
* *
* @return the number of frames of data to process * @return the number of frames of data to process
@@ -237,7 +237,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_


/** /**
* Signal next clients in the graph. * Signal next clients in the graph.
*
*
* @param client - pointer to a JACK client structure * @param client - pointer to a JACK client structure
* @param status - if non-zero, calling thread should exit * @param status - if non-zero, calling thread should exit
*/ */
@@ -254,7 +254,7 @@ void jack_cycle_signal (jack_client_t* client, int status) JACK_OPTIONAL_WEAK_EX
* http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000
* for more information. * for more information.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code. * @return 0 on success, otherwise a non-zero error code.
@@ -270,13 +270,13 @@ int jack_set_process_thread(jack_client_t* client, JackThreadCallback thread_cal


/** /**
* Tell JACK to call @a thread_init_callback once just after * Tell JACK to call @a thread_init_callback once just after
* the creation of the thread in which all other callbacks
* the creation of the thread in which all other callbacks
* will be handled. * will be handled.
* *
* The code in the supplied function does not need to be * The code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code, causing JACK * @return 0 on success, otherwise a non-zero error code, causing JACK
@@ -337,7 +337,7 @@ void jack_on_shutdown (jack_client_t *client,
*/ */
void jack_on_info_shutdown (jack_client_t *client, void jack_on_info_shutdown (jack_client_t *client,
JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT;
/** /**
* Tell the Jack server to call @a process_callback whenever there is * Tell the Jack server to call @a process_callback whenever there is
* work be done, passing @a arg as the second argument. * work be done, passing @a arg as the second argument.
@@ -350,7 +350,7 @@ void jack_on_info_shutdown (jack_client_t *client,
* http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000 * http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000
* for more information. * for more information.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code. * @return 0 on success, otherwise a non-zero error code.
@@ -370,7 +370,7 @@ int jack_set_process_callback (jack_client_t *client,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code. * @return 0 on success, otherwise a non-zero error code.
@@ -389,7 +389,7 @@ int jack_set_freewheel_callback (jack_client_t *client,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @param client pointer to JACK client structure. * @param client pointer to JACK client structure.
@@ -410,7 +410,7 @@ int jack_set_buffer_size_callback (jack_client_t *client,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
@@ -427,7 +427,7 @@ int jack_set_sample_rate_callback (jack_client_t *client,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
@@ -444,7 +444,7 @@ int jack_set_client_registration_callback (jack_client_t *,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
@@ -452,7 +452,7 @@ int jack_set_client_registration_callback (jack_client_t *,
int jack_set_port_registration_callback (jack_client_t *, int jack_set_port_registration_callback (jack_client_t *,
JackPortRegistrationCallback JackPortRegistrationCallback
registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT;
/** /**
* Tell the JACK server to call @a connect_callback whenever a * Tell the JACK server to call @a connect_callback whenever a
* port is connected or disconnected, passing @a arg as a parameter. * port is connected or disconnected, passing @a arg as a parameter.
@@ -461,7 +461,7 @@ int jack_set_client_registration_callback (jack_client_t *,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
@@ -478,7 +478,7 @@ int jack_set_port_connect_callback (jack_client_t *,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
@@ -495,7 +495,7 @@ int jack_set_port_rename_callback (jack_client_t *,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
@@ -512,39 +512,97 @@ int jack_set_graph_order_callback (jack_client_t *,
* the code in the supplied function does not need to be * the code in the supplied function does not need to be
* suitable for real-time execution. * suitable for real-time execution.
* *
* NOTE: this function cannot be called while the client is activated
* NOTE: this function cannot be called while the client is activated
* (after jack_activate has been called.) * (after jack_activate has been called.)
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
*/ */
int jack_set_xrun_callback (jack_client_t *, int jack_set_xrun_callback (jack_client_t *,
JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT;

/*@}*/

/**
* Tell the Jack server to call @a latency_callback whenever it
* is necessary to recompute the latencies for some or all
* Jack ports.
*
* @a latency_callback will be called twice each time it is
* needed, once being passed JackCaptureLatency and once
* JackPlaybackLatency. See @ref LatencyFunctions for
* the definition of each type of latency and related functions.
*
* <b>IMPORTANT: Most JACK clients do NOT need to register a latency
* callback.</b>
*
* Clients that meet any of the following conditions do NOT
* need to register a latency callback:
*
* - have only input ports
* - have only output ports
* - their output is totally unrelated to their input
* - their output is not delayed relative to their input
* (i.e. data that arrives in a given process()
* callback is processed and output again in the
* same callback)
*
* Clients NOT registering a latency callback MUST also
* satisfy this condition:
*
* - have no multiple distinct internal signal pathways
*
* This means that if your client has more than 1 input and
* output port, and considers them always "correlated"
* (e.g. as a stereo pair), then there is only 1 (e.g. stereo)
* signal pathway through the client. This would be true,
* for example, of a stereo FX rack client that has a
* left/right input pair and a left/right output pair.
*
* However, this is somewhat a matter of perspective. The
* same FX rack client could be connected so that its
* two input ports were connected to entirely separate
* sources. Under these conditions, the fact that the client
* does not register a latency callback MAY result
* in port latency values being incorrect.
*
* Clients that do not meet any of those conditions SHOULD
* register a latency callback.
*
* See the documentation for @ref jack_port_set_latency_range()
* on how the callback should operate. Remember that the @a mode
* argument given to the latency callback will need to be
* passed into @ref jack_port_set_latency_range()
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_set_latency_callback (jack_client_t *,
JackLatencyCallback latency_callback,
void *) JACK_WEAK_EXPORT;
/*@}*/ /*@}*/


/** /**
* @defgroup ServerClientControl Controlling & querying JACK server operation * @defgroup ServerClientControl Controlling & querying JACK server operation
* @{ * @{
*/ */
/** /**
* Start/Stop JACK's "freewheel" mode. * Start/Stop JACK's "freewheel" mode.
* *
* When in "freewheel" mode, JACK no longer waits for * When in "freewheel" mode, JACK no longer waits for
* any external event to begin the start of the next process * any external event to begin the start of the next process
* cycle.
* cycle.
* *
* As a result, freewheel mode causes "faster than realtime" * As a result, freewheel mode causes "faster than realtime"
* execution of a JACK graph. If possessed, real-time * execution of a JACK graph. If possessed, real-time
* scheduling is dropped when entering freewheel mode, and * scheduling is dropped when entering freewheel mode, and
* if appropriate it is reacquired when stopping. * if appropriate it is reacquired when stopping.
*
*
* IMPORTANT: on systems using capabilities to provide real-time * IMPORTANT: on systems using capabilities to provide real-time
* scheduling (i.e. Linux kernel 2.4), if onoff is zero, this function * scheduling (i.e. Linux kernel 2.4), if onoff is zero, this function
* must be called from the thread that originally called jack_activate().
* This restriction does not apply to other systems (e.g. Linux kernel 2.6
* must be called from the thread that originally called jack_activate().
* This restriction does not apply to other systems (e.g. Linux kernel 2.6
* or OS X). * or OS X).
*
*
* @param client pointer to JACK client structure * @param client pointer to JACK client structure
* @param onoff if non-zero, freewheel mode starts. Otherwise * @param onoff if non-zero, freewheel mode starts. Otherwise
* freewheel mode ends. * freewheel mode ends.
@@ -569,7 +627,7 @@ int jack_set_freewheel(jack_client_t* client, int onoff) JACK_OPTIONAL_WEAK_EXPO
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
*/ */
int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) JACK_OPTIONAL_WEAK_EXPORT; int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) JACK_OPTIONAL_WEAK_EXPORT;
/** /**
* @return the sample rate of the jack system, as set by the user when * @return the sample rate of the jack system, as set by the user when
* jackd was started. * jackd was started.
@@ -613,7 +671,7 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
* @defgroup PortFunctions Creating & manipulating ports * @defgroup PortFunctions Creating & manipulating ports
* @{ * @{
*/ */
/** /**
* Create a new port for the client. This is an object used for moving * Create a new port for the client. This is an object used for moving
* data of any type in or out of the client. Ports may be connected * data of any type in or out of the client. Ports may be connected
@@ -625,16 +683,16 @@ float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
* name. Exceeding that will cause the port registration to fail and * name. Exceeding that will cause the port registration to fail and
* return NULL. * return NULL.
* *
* The @a port_name must be unique among all ports owned by this client.
* If the name is not unique, the registration will fail.
*
* The @a port_name must be unique among all ports owned by this client.
* If the name is not unique, the registration will fail.
*
* All ports have a type, which may be any non-NULL and non-zero * All ports have a type, which may be any non-NULL and non-zero
* length string, passed as an argument. Some port types are built * length string, passed as an argument. Some port types are built
* into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE. * into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE.
* *
* @param client pointer to JACK client structure. * @param client pointer to JACK client structure.
* @param port_name non-empty short name for the new port (not * @param port_name non-empty short name for the new port (not
* including the leading @a "client_name:"). Must be unique.
* including the leading @a "client_name:"). Must be unique.
* @param port_type port type name. If longer than * @param port_type port type name. If longer than
* jack_port_type_size(), only that many characters are significant. * jack_port_type_size(), only that many characters are significant.
* @param flags @ref JackPortFlags bit mask. * @param flags @ref JackPortFlags bit mask.
@@ -663,7 +721,7 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP
* that can be written to; for an input port, it will be an area * that can be written to; for an input port, it will be an area
* containing the data from the port's connection(s), or * containing the data from the port's connection(s), or
* zero-filled. if there are multiple inbound connections, the data * zero-filled. if there are multiple inbound connections, the data
* will be mixed appropriately.
* will be mixed appropriately.
* *
* FOR OUTPUT PORTS ONLY : DEPRECATED in Jack 2.0 !! * FOR OUTPUT PORTS ONLY : DEPRECATED in Jack 2.0 !!
* --------------------------------------------------- * ---------------------------------------------------
@@ -672,9 +730,9 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP
* either never cache the return value or ensure you have * either never cache the return value or ensure you have
* a "blocksize" callback and be sure to invalidate the cached * a "blocksize" callback and be sure to invalidate the cached
* address from there. * address from there.
*
*
* Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). * Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining").
* Port buffers have to be retrieved in each callback for proper functionning.
* Port buffers have to be retrieved in each callback for proper functionning.
*/ */
void * jack_port_get_buffer (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; void * jack_port_get_buffer (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT;


@@ -759,7 +817,7 @@ const char ** jack_port_get_connections (const jack_port_t *port) JACK_OPTIONAL_
* you cannot use it in a GraphReordered handler. * you cannot use it in a GraphReordered handler.
* *
* 2) You need not be the owner of the port to get information * 2) You need not be the owner of the port to get information
* about its connections.
* about its connections.
* *
* @see jack_port_name_size() * @see jack_port_name_size()
*/ */
@@ -768,8 +826,8 @@ const char ** jack_port_get_all_connections (const jack_client_t *client,


/** /**
* *
* @deprecated This function will be removed from a future version
* of JACK. Do not use it. There is no replacement. It has
* @deprecated This function will be removed from a future version
* of JACK. Do not use it. There is no replacement. It has
* turned out to serve essentially no purpose in real-life * turned out to serve essentially no purpose in real-life
* JACK clients. * JACK clients.
*/ */
@@ -777,73 +835,13 @@ int jack_port_tie (jack_port_t *src, jack_port_t *dst) JACK_OPTIONAL_WEAK_DEPREC


/** /**
* *
* @deprecated This function will be removed from a future version
* of JACK. Do not use it. There is no replacement. It has
* @deprecated This function will be removed from a future version
* of JACK. Do not use it. There is no replacement. It has
* turned out to serve essentially no purpose in real-life * turned out to serve essentially no purpose in real-life
* JACK clients. * JACK clients.
*/ */
int jack_port_untie (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; int jack_port_untie (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT;


/**
* @return the time (in frames) between data being available or
* delivered at/to a port, and the time at which it arrived at or is
* delivered to the "other side" of the port. E.g. for a physical
* audio output port, this is the time between writing to the port and
* when the signal will leave the connector. For a physical audio
* input port, this is the time between the sound arriving at the
* connector and the corresponding frames being readable from the
* port.
*/
jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT;

/**
* The maximum of the sum of the latencies in every
* connection path that can be drawn between the port and other
* ports with the @ref JackPortIsTerminal flag set.
*/
jack_nframes_t jack_port_get_total_latency (jack_client_t *,
jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT;

/**
* The port latency is zero by default. Clients that control
* physical hardware with non-zero latency should call this
* to set the latency to its correct value. Note that the value
* should include any systemic latency present "outside" the
* physical hardware controlled by the client. For example,
* for a client controlling a digital audio interface connected
* to an external digital converter, the latency setting should
* include both buffering by the audio interface *and* the converter.
*/
void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT;

/**
* Request a complete recomputation of a port's total latency. This
* can be called by a client that has just changed the internal
* latency of its port using @function jack_port_set_latency
* and wants to ensure that all signal pathways in the graph
* are updated with respect to the values that will be returned
* by @function jack_port_get_total_latency.
*
* @return zero for successful execution of the request. non-zero
* otherwise.
*/
int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_EXPORT;

/**
* Request a complete recomputation of all port latencies. This
* can be called by a client that has just changed the internal
* latency of its port using @function jack_port_set_latency
* and wants to ensure that all signal pathways in the graph
* are updated with respect to the values that will be returned
* by @function jack_port_get_total_latency. It allows a client
* to change multiple port latencies without triggering a
* recompute for each change.
*
* @return zero for successful execution of the request. non-zero
* otherwise.
*/
int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT;

/** /**
* Modify a port's short name. May be called at any time. If the * Modify a port's short name. May be called at any time. If the
* resulting full name (including the @a "client_name:" prefix) is * resulting full name (including the @a "client_name:" prefix) is
@@ -856,12 +854,12 @@ int jack_port_set_name (jack_port_t *port, const char *port_name) JACK_OPTIONAL_
/** /**
* Set @a alias as an alias for @a port. May be called at any time. * Set @a alias as an alias for @a port. May be called at any time.
* If the alias is longer than jack_port_name_size(), it will be truncated. * If the alias is longer than jack_port_name_size(), it will be truncated.
*
*
* After a successful call, and until JACK exits or * After a successful call, and until JACK exits or
* @function jack_port_unset_alias() is called, @alias may be * @function jack_port_unset_alias() is called, @alias may be
* used as a alternate name for the port. * used as a alternate name for the port.
* *
* Ports can have up to two aliases - if both are already
* Ports can have up to two aliases - if both are already
* set, this function will return an error. * set, this function will return an error.
* *
* @return 0 on success, otherwise a non-zero error code. * @return 0 on success, otherwise a non-zero error code.
@@ -870,8 +868,8 @@ int jack_port_set_alias (jack_port_t *port, const char *alias) JACK_OPTIONAL_WEA


/** /**
* Remove @a alias as an alias for @a port. May be called at any time. * Remove @a alias as an alias for @a port. May be called at any time.
*
* After a successful call, @a alias can no longer be
*
* After a successful call, @a alias can no longer be
* used as a alternate name for the port. * used as a alternate name for the port.
* *
* @return 0 on success, otherwise a non-zero error code. * @return 0 on success, otherwise a non-zero error code.
@@ -981,6 +979,224 @@ int jack_port_name_size(void) JACK_OPTIONAL_WEAK_EXPORT;
*/ */
int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT; int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT;


/**
* @return the buffersize of a port of type @arg port_type.
*
* this function may only be called in a buffer_size callback.
*/
size_t jack_port_type_get_buffer_size (jack_client_t *client, const char *port_type) JACK_WEAK_EXPORT;

/*@}*/

/**
* @defgroup LatencyFunctions Managing and determining latency
*
* The purpose of JACK's latency API is to allow clients to
* easily answer two questions:
*
* - How long has it been since the data read from a port arrived
* at the edge of the JACK graph (either via a physical port
* or being synthesized from scratch)?
*
* - How long will it be before the data written to a port arrives
* at the edge of a JACK graph?

* To help answering these two questions, all JACK ports have two
* latency values associated with them, both measured in frames:
*
* <b>capture latency</b>: how long since the data read from
* the buffer of a port arrived at at
* a port marked with JackPortIsTerminal.
* The data will have come from the "outside
* world" if the terminal port is also
* marked with JackPortIsPhysical, or
* will have been synthesized by the client
* that owns the terminal port.
*
* <b>playback latency</b>: how long until the data
* written to the buffer of port will reach a port
* marked with JackPortIsTerminal.
*
* Both latencies might potentially have more than one value
* because there may be multiple pathways to/from a given port
* and a terminal port. Latency is therefore generally
* expressed a min/max pair.
*
* In most common setups, the minimum and maximum latency
* are the same, but this design accomodates more complex
* routing, and allows applications (and thus users) to
* detect cases where routing is creating an anomalous
* situation that may either need fixing or more
* sophisticated handling by clients that care about
* latency.
*
* See also @ref jack_set_latency_callback for details on how
* clients that add latency to the signal path should interact
* with JACK to ensure that the correct latency figures are
* used.
* @{
*/

/**
* The port latency is zero by default. Clients that control
* physical hardware with non-zero latency should call this
* to set the latency to its correct value. Note that the value
* should include any systemic latency present "outside" the
* physical hardware controlled by the client. For example,
* for a client controlling a digital audio interface connected
* to an external digital converter, the latency setting should
* include both buffering by the audio interface *and* the converter.
*
* @deprecated This method will be removed in the next major
* release of JACK. It should not be used in new code, and should
* be replaced by a latency callback that calls @ref
* jack_port_set_latency_range().
*/
void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT;

/**
* return the latency range defined by @a mode for
* @a port, in frames.
*
* See @ref LatencyFunctions for the definition of each latency value.
*
* This is normally used in the LatencyCallback.
* and therefor safe to execute from callbacks.
*/
void jack_port_get_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) JACK_WEAK_EXPORT;

/**
* set the minimum and maximum latencies defined by
* @a mode for @a port, in frames.
*
* See @ref LatencyFunctions for the definition of each latency value.
*
* This function should ONLY be used inside a latency
* callback. The client should determine the current
* value of the latency using @ref jack_port_get_latency_range()
* (called using the same mode as @a mode)
* and then add some number of frames to that reflects
* latency added by the client.
*
* How much latency a client adds will vary
* dramatically. For most clients, the answer is zero
* and there is no reason for them to register a latency
* callback and thus they should never call this
* function.
*
* More complex clients that take an input signal,
* transform it in some way and output the result but
* not during the same process() callback will
* generally know a single constant value to add
* to the value returned by @ref jack_port_get_latency_range().
*
* Such clients would register a latency callback (see
* @ref jack_set_latency_callback) and must know what input
* ports feed which output ports as part of their
* internal state. Their latency callback will update
* the ports' latency values appropriately.
*
* A pseudo-code example will help. The @a mode argument to the latency
* callback will determine whether playback or capture
* latency is being set. The callback will use
* @ref jack_port_set_latency_range() as follows:
*
* \code
* jack_latency_range_t range;
* if (mode == JackPlaybackLatency) {
* foreach input_port in (all self-registered port) {
* jack_port_get_latency_range (port_feeding_input_port, JackPlaybackLatency, &range);
* range.min += min_delay_added_as_signal_flows_from port_feeding to input_port;
* range.max += max_delay_added_as_signal_flows_from port_feeding to input_port;
* jack_port_set_latency_range (input_port, JackPlaybackLatency, &range);
* }
* } else if (mode == JackCaptureLatency) {
* foreach output_port in (all self-registered port) {
* jack_port_get_latency_range (port_fed_by_output_port, JackCaptureLatency, &range);
* range.min += min_delay_added_as_signal_flows_from_output_port_to_fed_by_port;
* range.max += max_delay_added_as_signal_flows_from_output_port_to_fed_by_port;
* jack_port_set_latency_range (output_port, JackCaptureLatency, &range);
* }
* }
* \endcode
*
* In this relatively simple pseudo-code example, it is assumed that
* each input port or output is connected to only 1 output or input
* port respectively.
*
* If a port is connected to more than 1 other port, then the
* range.min and range.max values passed to @ref
* jack_port_set_latency_range() should reflect the minimum and
* maximum values across all connected ports.
*
* See the description of @ref jack_set_latency_callback for more
* information.
*/
void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) JACK_WEAK_EXPORT;

/**
* Request a complete recomputation of all port latencies. This
* can be called by a client that has just changed the internal
* latency of its port using jack_port_set_latency
* and wants to ensure that all signal pathways in the graph
* are updated with respect to the values that will be returned
* by jack_port_get_total_latency. It allows a client
* to change multiple port latencies without triggering a
* recompute for each change.
*
* @return zero for successful execution of the request. non-zero
* otherwise.
*/
int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT;

/**
* @return the time (in frames) between data being available or
* delivered at/to a port, and the time at which it arrived at or is
* delivered to the "other side" of the port. E.g. for a physical
* audio output port, this is the time between writing to the port and
* when the signal will leave the connector. For a physical audio
* input port, this is the time between the sound arriving at the
* connector and the corresponding frames being readable from the
* port.
*
* @deprecated This method will be removed in the next major
* release of JACK. It should not be used in new code, and should
* be replaced by jack_port_get_latency_range() in any existing
* use cases.
*/
jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT;

/**
* The maximum of the sum of the latencies in every
* connection path that can be drawn between the port and other
* ports with the @ref JackPortIsTerminal flag set.
*
* @deprecated This method will be removed in the next major
* release of JACK. It should not be used in new code, and should
* be replaced by jack_port_get_latency_range() in any existing
* use cases.
*/
jack_nframes_t jack_port_get_total_latency (jack_client_t *,
jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT;

/**
* Request a complete recomputation of a port's total latency. This
* can be called by a client that has just changed the internal
* latency of its port using jack_port_set_latency
* and wants to ensure that all signal pathways in the graph
* are updated with respect to the values that will be returned
* by jack_port_get_total_latency.
*
* @return zero for successful execution of the request. non-zero
* otherwise.
*
* @deprecated This method will be removed in the next major
* release of JACK. It should not be used in new code, and should
* be replaced by jack_recompute_total_latencies() in any existing
* use cases.
*/
int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT;

/*@}*/ /*@}*/


/** /**
@@ -989,13 +1205,13 @@ int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT;
*/ */


/** /**
* @param port_name_pattern A regular expression used to select
* ports by name. If NULL or of zero length, no selection based
* @param port_name_pattern A regular expression used to select
* ports by name. If NULL or of zero length, no selection based
* on name will be carried out. * on name will be carried out.
* @param type_name_pattern A regular expression used to select
* ports by type. If NULL or of zero length, no selection based
* @param type_name_pattern A regular expression used to select
* ports by type. If NULL or of zero length, no selection based
* on type will be carried out. * on type will be carried out.
* @param flags A value used to select ports by their flags.
* @param flags A value used to select ports by their flags.
* If zero, no selection based on flags will be carried out. * If zero, no selection based on flags will be carried out.
* *
* @return a NULL-terminated array of ports that match the specified * @return a NULL-terminated array of ports that match the specified
@@ -1021,8 +1237,8 @@ jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name) JACK_OP
*/ */
jack_port_t * jack_port_by_id (jack_client_t *client, jack_port_t * jack_port_by_id (jack_client_t *client,
jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT; jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT;
/*@}*/
/*@}*/


/** /**
* @defgroup TimeFunctions Handling time * @defgroup TimeFunctions Handling time
@@ -1052,7 +1268,7 @@ jack_nframes_t jack_frame_time (const jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT
* This function may only be used from the process callback, and can * This function may only be used from the process callback, and can
* be used to interpret timestamps generated by jack_frame_time() in * be used to interpret timestamps generated by jack_frame_time() in
* other threads with respect to the current process cycle. * other threads with respect to the current process cycle.
*
*
* This is the only jack time function that returns exact time: * This is the only jack time function that returns exact time:
* when used during the process callback it always returns the same * when used during the process callback it always returns the same
* value (until the next process callback, where it will return * value (until the next process callback, where it will return
@@ -1075,8 +1291,8 @@ jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t) JAC


/** /**
* @return return JACK's current system time in microseconds, * @return return JACK's current system time in microseconds,
* using the JACK clock source.
*
* using the JACK clock source.
*
* The value returned is guaranteed to be monotonic, but not linear. * The value returned is guaranteed to be monotonic, but not linear.
*/ */
jack_time_t jack_get_time() JACK_OPTIONAL_WEAK_EXPORT; jack_time_t jack_get_time() JACK_OPTIONAL_WEAK_EXPORT;
@@ -1129,7 +1345,7 @@ void jack_set_info_function (void (*func)(const char *)) JACK_OPTIONAL_WEAK_EXPO
/*@}*/ /*@}*/


/** /**
* The free function to be used on memory returned by jack_port_get_connections,
* The free function to be used on memory returned by jack_port_get_connections,
* jack_port_get_all_connections and jack_get_ports functions. * jack_port_get_all_connections and jack_get_ports functions.
* This is MANDATORY on Windows when otherwise all nasty runtime version related crashes can occur. * This is MANDATORY on Windows when otherwise all nasty runtime version related crashes can occur.
* Developers are strongly encouraged to use this function instead of the standard "free" function in new code. * Developers are strongly encouraged to use this function instead of the standard "free" function in new code.


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

@@ -1,18 +1,18 @@
/* /*
Copyright (C) 2004 Ian Esten Copyright (C) 2004 Ian Esten
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -24,11 +24,12 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

#include <jack/weakmacros.h>
#include <jack/types.h> #include <jack/types.h>
#include <stdlib.h> #include <stdlib.h>
#include <jack/weakmacros.h>
/** Type for raw event data contained in @ref jack_midi_event_t. */ /** Type for raw event data contained in @ref jack_midi_event_t. */
typedef unsigned char jack_midi_data_t; typedef unsigned char jack_midi_data_t;


@@ -43,7 +44,7 @@ typedef struct _jack_midi_event




/** /**
* @defgroup MIDIAPI Reading and writing MIDI data
* @defgroup MIDIAPI Reading and writing MIDI data
* @{ * @{
*/ */


@@ -57,7 +58,7 @@ jack_midi_get_event_count(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT;




/** Get a MIDI event from an event port buffer. /** Get a MIDI event from an event port buffer.
*
*
* Jack MIDI is normalised, the MIDI event returned by this function is * Jack MIDI is normalised, the MIDI event returned by this function is
* guaranteed to be a complete MIDI event (the status byte will always be * guaranteed to be a complete MIDI event (the status byte will always be
* present, and no realtime events will interspered with the event). * present, and no realtime events will interspered with the event).
@@ -74,7 +75,7 @@ jack_midi_event_get(jack_midi_event_t *event,




/** Clear an event buffer. /** Clear an event buffer.
*
*
* This should be called at the beginning of each process cycle before calling * This should be called at the beginning of each process cycle before calling
* @ref jack_midi_event_reserve or @ref jack_midi_event_write. This * @ref jack_midi_event_reserve or @ref jack_midi_event_write. This
* function may not be called on an input port's buffer. * function may not be called on an input port's buffer.
@@ -105,10 +106,10 @@ jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT;
* messages interspersed with other messages (realtime messages are fine * messages interspersed with other messages (realtime messages are fine
* when they occur on their own, like other messages). * when they occur on their own, like other messages).
* *
* Events must be written in order, sorted by their sample offsets.
* JACK will not sort the events for you, and will refuse to store
* out-of-order events.
*
* Events must be written in order, sorted by their sample offsets.
* JACK will not sort the events for you, and will refuse to store
* out-of-order events.
*
* @param port_buffer Buffer to write event to. * @param port_buffer Buffer to write event to.
* @param time Sample offset of event. * @param time Sample offset of event.
* @param data_size Length of event's raw data in bytes. * @param data_size Length of event's raw data in bytes.
@@ -117,7 +118,7 @@ jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT;
*/ */
jack_midi_data_t* jack_midi_data_t*
jack_midi_event_reserve(void *port_buffer, jack_midi_event_reserve(void *port_buffer,
jack_nframes_t time,
jack_nframes_t time,
size_t data_size) JACK_OPTIONAL_WEAK_EXPORT; size_t data_size) JACK_OPTIONAL_WEAK_EXPORT;




@@ -125,18 +126,17 @@ jack_midi_event_reserve(void *port_buffer,
* *
* This function is simply a wrapper for @ref jack_midi_event_reserve * This function is simply a wrapper for @ref jack_midi_event_reserve
* which writes the event data into the space reserved in the buffer. * which writes the event data into the space reserved in the buffer.
* The same restrictions on the MIDI data apply.
*
* Clients must not write more than
* @a data_size bytes into this buffer. Clients must write normalised
* MIDI data to the port - no running status and no (1-byte) realtime
* messages interspersed with other messages (realtime messages are fine
* when they occur on their own, like other messages).
*
* Events must be written in order, sorted by their sample offsets.
* JACK will not sort the events for you, and will refuse to store
*
* Clients must not write more than
* @a data_size bytes into this buffer. Clients must write normalised
* MIDI data to the port - no running status and no (1-byte) realtime
* messages interspersed with other messages (realtime messages are fine
* when they occur on their own, like other messages).
*
* Events must be written in order, sorted by their sample offsets.
* JACK will not sort the events for you, and will refuse to store
* out-of-order events. * out-of-order events.
*
*
* @param port_buffer Buffer to write event to. * @param port_buffer Buffer to write event to.
* @param time Sample offset of event. * @param time Sample offset of event.
* @param data Message data to be written. * @param data Message data to be written.


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

@@ -2,21 +2,20 @@
Copyright (C) 2001 Paul Davis Copyright (C) 2001 Paul Davis
Copyright (C) 2004 Jack O'Quin Copyright (C) 2004 Jack O'Quin
Copyright (C) 2010 Torben Hohn Copyright (C) 2010 Torben Hohn
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/ */


#ifndef __jack_session_h__ #ifndef __jack_session_h__
@@ -36,80 +35,114 @@ extern "C" {




/** /**
* session event types.
* Session event type.
* *
* if a client cant save templates, i might just do a normal save. * if a client cant save templates, i might just do a normal save.
* *
* the rationale, why there is no quit without save, is that a client
* might refuse to quit when it has unsaved data.
* however some other clients might have already quit.
* this results in too much confusion, so we just dont support that.
* the session manager can check, if the saved state is different from a previous
* save, and just remove the saved stuff.
*
* (an inquiry function, whether a quit is ok, followed by a quit event
* would have a race)
* There is no "quit without saving" event because a client might refuse to
* quit when it has unsaved data, but other clients may have already quit.
* This results in too much confusion, so it is unsupported.
*/ */
enum JackSessionEventType { enum JackSessionEventType {
/**
* Save the session completely.
*
* The client may save references to data outside the provided directory,
* but it must do so by creating a link inside the provided directory and
* referring to that in any save files. The client must not refer to data
* files outside the provided directory directly in save files, because
* this makes it impossible for the session manager to create a session
* archive for distribution or archival.
*/
JackSessionSave = 1, JackSessionSave = 1,

/**
* Save the session completly, then quit.
*
* The rules for saving are exactly the same as for JackSessionSave.
*/
JackSessionSaveAndQuit = 2, JackSessionSaveAndQuit = 2,

/**
* Save a session template.
*
* A session template is a "skeleton" of the session, but without any data.
* Clients must save a session that, when restored, will create the same
* ports as a full save would have. However, the actual data contained in
* the session may not be saved (e.g. a DAW would create the necessary
* tracks, but not save the actual recorded data).
*/
JackSessionSaveTemplate = 3 JackSessionSaveTemplate = 3
}; };


typedef enum JackSessionEventType jack_session_event_type_t; typedef enum JackSessionEventType jack_session_event_type_t;


/**
* @ref jack_session_flags_t bits
*/
enum JackSessionFlags { enum JackSessionFlags {
/** /**
* an error occured while saving.
* An error occured while saving.
*/ */
JackSessionSaveError = 0x01, JackSessionSaveError = 0x01,


/** /**
* this reply indicates that a client is part of a multiclient application.
* the command reply is left empty. but the session manager should still
* consider this client part of a session. it will come up due to invocation of another
* client.
* Client needs to be run in a terminal.
*/ */
JackSessionChildClient = 0x02
JackSessionNeedTerminal = 0x02
}; };


/**
* Session flags.
*/
typedef enum JackSessionFlags jack_session_flags_t; typedef enum JackSessionFlags jack_session_flags_t;


struct _jack_session_event { struct _jack_session_event {
/** /**
* the actual type of this session event.
* The type of this session event.
*/ */
jack_session_event_type_t type; jack_session_event_type_t type;


/** /**
* session_directory with trailing separator
* this is per client. so the client can do whatever it likes in here.
* Session directory path, with trailing separator.
*
* This directory is exclusive to the client; when saving the client may
* create any files it likes in this directory.
*/ */
const char *session_dir; const char *session_dir;


/** /**
* client_uuid which must be specified to jack_client_open on session reload.
* client can specify it in the returned commandline as an option, or just save it
* with the state file.
* Client UUID which must be passed to jack_client_open on session load.
*
* The client can specify this in the returned command line, or save it
* in a state file within the session directory.
*/ */
const char *client_uuid; const char *client_uuid;


/** /**
* the command_line is the reply of the client.
* it specifies in a platform dependent way, how the client must be restarted upon session reload.
* Reply (set by client): the command line needed to restore the client.
* *
* probably it should contain ${SESSION_DIR} instead of the actual session dir.
* this would basically make the session dir moveable.
* This is a platform dependent command line. It must contain
* ${SESSION_DIR} instead of the actual session directory path. More
* generally, just as in session files, clients should not include any
* paths outside the session directory here as this makes
* archival/distribution impossible.
* *
* ownership of the memory is handed to jack.
* initially set to NULL by jack;
* This field is set to NULL by Jack when the event is delivered to the
* client. The client must set to allocated memory that is safe to
* free(). This memory will be freed by jack_session_event_free.
*/ */
char *command_line; char *command_line;


/** /**
* flags to be set by the client. normally left 0.
* Reply (set by client): Session flags.
*/ */
jack_session_flags_t flags; jack_session_flags_t flags;

/**
* Future flags. Set to zero for now.
*/
uint32_t future;
}; };


typedef struct _jack_session_event jack_session_event_t; typedef struct _jack_session_event jack_session_event_t;
@@ -118,35 +151,42 @@ typedef struct _jack_session_event jack_session_event_t;
* Prototype for the client supplied function that is called * Prototype for the client supplied function that is called
* whenever a session notification is sent via jack_session_notify(). * whenever a session notification is sent via jack_session_notify().
* *
* The session_id must be passed to jack_client_open on session reload (this can be
* done by specifying it somehow on the returned command line).
* Ownership of the memory of @a event is passed to the application.
* It must be freed using jack_session_event_free when its not used anymore.
*
* The client must promptly call jack_session_reply for this event.
* *
* @param event the event_structure.
* @param arg pointer to a client supplied structure
* @param event The event structure.
* @param arg Pointer to a client supplied structure.
*/ */
typedef void (*JackSessionCallback)(jack_session_event_t *event, void *arg);
typedef void (*JackSessionCallback)(jack_session_event_t *event,
void *arg);


/** /**
* Tell the JACK server to call @a save_callback the session handler wants
* to save.
* Tell the JACK server to call @a session_callback when a session event
* is to be delivered.
*
* setting more than one session_callback per process is probably a design
* error. if you have a multiclient application its more sensible to create
* a jack_client with only a session callback set.
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
*/ */
int jack_set_session_callback(jack_client_t *client,
JackSessionCallback session_callback,
void *arg) JACK_WEAK_EXPORT;
int jack_set_session_callback (jack_client_t *client,
JackSessionCallback session_callback,
void *arg) JACK_WEAK_EXPORT;


/** /**
* reply to a session_event
* Reply to a session event.
* *
* this can either be called directly from the callback, or later from a different thread.
* so its possible to just stick the event pointer into a pipe and execute the save code
* from the gui thread.
* This can either be called directly from the callback, or later from a
* different thread. For example, it is possible to push the event through a
* queue and execute the save code from the GUI thread.
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
*/ */
int jack_session_reply( jack_client_t *client, jack_session_event_t *event ) JACK_WEAK_EXPORT;
int jack_session_reply (jack_client_t *client,
jack_session_event_t *event) JACK_WEAK_EXPORT;




/** /**
@@ -154,74 +194,90 @@ int jack_session_reply( jack_client_t *client, jack_session_event_t *event ) JAC
* this also frees the memory used by the command_line pointer. * this also frees the memory used by the command_line pointer.
* if its non NULL. * if its non NULL.
*/ */
void jack_session_event_free (jack_session_event_t *event) JACK_WEAK_EXPORT;


void jack_session_event_free (jack_session_event_t *event);


/*@}*/
/**
* get the assigned uuid for client.
* safe to call from callback and all other threads.
* memory needs to be freed.
*/


char *jack_client_get_uuid (jack_client_t *client) JACK_WEAK_EXPORT;


/** /**
* @defgroup JackSessionManagerAPI this API is intended for a sessionmanager.
* this API could be server specific. if we dont reach consensus here,
* we can just drop it.
* i know its a bit clumsy.
* but this api isnt required to be as stable as the client api.
* @}
*/

/**
* @defgroup JackSessionManagerAPI API for a session manager.
*
* @{ * @{
*/ */


typedef struct { typedef struct {
const char *uuid;
const char *client_name;
const char *command;
jack_session_flags_t flags;
const char *uuid;
const char *client_name;
const char *command;
jack_session_flags_t flags;
} jack_session_command_t; } jack_session_command_t;


/** /**
* send a save or quit event, to all clients listening for session
* callbacks. the returned strings of the clients are accumulated and
* returned as an array of jack_session_command_t.
* its terminated by ret[i].uuid == NULL
* target == NULL means send to all interested clients. otherwise a clientname
* Send an event to all clients listening for session callbacks.
*
* The returned strings of the clients are accumulated and returned as an array
* of jack_session_command_t. its terminated by ret[i].uuid == NULL target ==
* NULL means send to all interested clients. otherwise a clientname
*/ */
jack_session_command_t *jack_session_notify (jack_client_t* client,
const char *target,
jack_session_event_type_t type,
const char *path ) JACK_WEAK_EXPORT;
jack_session_command_t *jack_session_notify (
jack_client_t* client,
const char *target,
jack_session_event_type_t type,
const char *path) JACK_WEAK_EXPORT;


/** /**
* free the memory allocated by a session command.
* Free the memory allocated by a session command.
*/ */

void jack_session_commands_free (jack_session_command_t *cmds) JACK_WEAK_EXPORT; void jack_session_commands_free (jack_session_command_t *cmds) JACK_WEAK_EXPORT;


/** /**
* get the sessionid for a client name.
* the sessionmanager needs this to reassociate a client_name to the session_id.
* Get the session ID for a client name.
* The session manager needs this to reassociate a client name to the session_id.
*/ */
char *jack_get_uuid_for_client_name( jack_client_t *client, const char *client_name ) JACK_WEAK_EXPORT;
char *jack_get_uuid_for_client_name (jack_client_t *client,
const char *client_name) JACK_WEAK_EXPORT;


/** /**
* get the client name for a session_id.
* in order to snapshot the graph connections, the sessionmanager needs to map
* Get the client name for a session_id.
*
* In order to snapshot the graph connections, the session manager needs to map
* session_ids to client names. * session_ids to client names.
*/ */
char *jack_get_client_name_by_uuid( jack_client_t *client, const char *client_uuid ) JACK_WEAK_EXPORT;
char *jack_get_client_name_by_uuid (jack_client_t *client,
const char *client_uuid ) JACK_WEAK_EXPORT;


/** /**
* reserve a client name and associate it to a uuid.
* when a client later call jack_client_open() and specifies the uuid,
* jackd will assign the reserved name.
* this allows a session manager to know in advance under which client name
* its managed clients will appear.
* Reserve a client name and associate it with a UUID.
*
* When a client later calls jack_client_open() and specifies the UUID, jackd
* will assign the reserved name. This allows a session manager to know in
* advance under which client name its managed clients will appear.
* *
* @return 0 on success, otherwise a non-zero error code * @return 0 on success, otherwise a non-zero error code
*/ */
int
jack_reserve_client_name (jack_client_t *client,
const char *name,
const char *uuid) JACK_WEAK_EXPORT;


/**
* Find out whether a client has set up a session callback.
*
* @return 0 when the client has no session callback, 1 when it has one.
* -1 on error.
*/
int int
jack_reserve_client_name( jack_client_t *client, const char *name, const char *uuid ) JACK_WEAK_EXPORT;
jack_client_has_session_callback (jack_client_t *client, const char *client_name) JACK_WEAK_EXPORT;


#ifdef __cplusplus #ifdef __cplusplus
} }


+ 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 LONGLONG int64_t;
typedef ULONGLONG uint64_t; typedef ULONGLONG uint64_t;
#endif #endif
#ifndef pthread_t
typedef HANDLE pthread_t;
#endif
/**
* to make jack API independent of different thread implementations,
* we define jack_native_thread_t to HANDLE here.
*/
typedef HANDLE jack_native_thread_t;
#elif __MINGW32__ /* MINGW */ #elif __MINGW32__ /* MINGW */
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#ifndef pthread_t
typedef HANDLE pthread_t;
#endif
/**
* to make jack API independent of different thread implementations,
* we define jack_native_thread_t to HANDLE here.
*/
typedef HANDLE jack_native_thread_t;
#else /* other compilers ...*/ #else /* other compilers ...*/
#include <inttypes.h> #include <inttypes.h>
#include <pthread.h> #include <pthread.h>
@@ -57,6 +61,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <inttypes.h> #include <inttypes.h>
#include <pthread.h> #include <pthread.h>
#include <sys/types.h> #include <sys/types.h>

/**
* to make jack API independent of different thread implementations,
* we define jack_native_thread_t to pthread_t here.
*/
typedef pthread_t jack_native_thread_t;

#endif /* __APPLE__ || __linux__ || __sun__ || sun */ #endif /* __APPLE__ || __linux__ || __sun__ || sun */


#endif #endif

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

@@ -28,6 +28,10 @@ extern "C"
#include <jack/systemdeps.h> #include <jack/systemdeps.h>
#include <jack/weakmacros.h> #include <jack/weakmacros.h>


/* use 512KB stack per thread - the default is way too high to be feasible
* with mlockall() on many systems */
#define THREAD_STACK 524288

/** @file thread.h /** @file thread.h
* *
* Library functions to standardize thread creation for JACK and its * Library functions to standardize thread creation for JACK and its
@@ -66,7 +70,7 @@ int jack_client_max_real_time_priority (jack_client_t*) JACK_OPTIONAL_WEAK_EXPOR
* @returns 0, if successful; EPERM, if the calling process lacks * @returns 0, if successful; EPERM, if the calling process lacks
* required realtime privileges; otherwise some other error number. * required realtime privileges; otherwise some other error number.
*/ */
int jack_acquire_real_time_scheduling (pthread_t thread, int priority) JACK_OPTIONAL_WEAK_EXPORT;
int jack_acquire_real_time_scheduling (jack_native_thread_t thread, int priority) JACK_OPTIONAL_WEAK_EXPORT;


/** /**
* Create a thread for JACK or one of its clients. The thread is * Create a thread for JACK or one of its clients. The thread is
@@ -85,7 +89,7 @@ int jack_acquire_real_time_scheduling (pthread_t thread, int priority) JACK_OPTI
* @returns 0, if successful; otherwise some error number. * @returns 0, if successful; otherwise some error number.
*/ */
int jack_client_create_thread (jack_client_t* client, int jack_client_create_thread (jack_client_t* client,
pthread_t *thread,
jack_native_thread_t *thread,
int priority, int priority,
int realtime, /* boolean */ int realtime, /* boolean */
void *(*start_routine)(void*), void *(*start_routine)(void*),
@@ -98,7 +102,7 @@ int jack_client_create_thread (jack_client_t* client,
* *
* @returns 0, if successful; otherwise an error number. * @returns 0, if successful; otherwise an error number.
*/ */
int jack_drop_real_time_scheduling (pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT;
int jack_drop_real_time_scheduling (jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT;


/** /**
* Stop the thread, waiting for the thread handler to terminate. * Stop the thread, waiting for the thread handler to terminate.
@@ -107,7 +111,7 @@ int jack_drop_real_time_scheduling (pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT;
* *
* @returns 0, if successful; otherwise an error number. * @returns 0, if successful; otherwise an error number.
*/ */
int jack_client_stop_thread(jack_client_t* client, pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT;
int jack_client_stop_thread(jack_client_t* client, jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT;


/** /**
* Cancel the thread then waits for the thread handler to terminate. * Cancel the thread then waits for the thread handler to terminate.
@@ -116,7 +120,7 @@ int jack_client_stop_thread(jack_client_t* client, pthread_t thread) JACK_OPTION
* *
* @returns 0, if successful; otherwise an error number. * @returns 0, if successful; otherwise an error number.
*/ */
int jack_client_kill_thread(jack_client_t* client, pthread_t thread) JACK_OPTIONAL_WEAK_EXPORT;
int jack_client_kill_thread(jack_client_t* client, jack_native_thread_t thread) JACK_OPTIONAL_WEAK_EXPORT;


#ifndef WIN32 #ifndef WIN32




+ 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; typedef uint32_t jack_port_type_id_t;


/**
* @ref jack_options_t bits
*/
enum JackOptions {

/**
* Null value to use when no option bits are needed.
*/
JackNullOption = 0x00,

/**
* Do not automatically start the JACK server when it is not
* already running. This option is always selected if
* \$JACK_NO_START_SERVER is defined in the calling process
* environment.
*/
JackNoStartServer = 0x01,

/**
* Use the exact client name requested. Otherwise, JACK
* automatically generates a unique one, if needed.
*/
JackUseExactName = 0x02,

/**
* Open with optional <em>(char *) server_name</em> parameter.
*/
JackServerName = 0x04,

/**
* Load internal client from optional <em>(char *)
* load_name</em>. Otherwise use the @a client_name.
*/
JackLoadName = 0x08,

/**
* Pass optional <em>(char *) load_init</em> string to the
* jack_initialize() entry point of an internal client.
*/
JackLoadInit = 0x10,

/**
* pass a SessionID Token this allows the sessionmanager to identify the client again.
*/
JackSessionID = 0x20
};

/** Valid options for opening an external client. */
#define JackOpenOptions (JackSessionID|JackServerName|JackNoStartServer|JackUseExactName)

/** Valid options for loading an internal client. */
#define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName)

/**
* Options for several JACK operations, formed by OR-ing together the
* relevant @ref JackOptions bits.
*/
typedef enum JackOptions jack_options_t;

/**
* @ref jack_status_t bits
*/
enum JackStatus {

/**
* Overall operation failed.
*/
JackFailure = 0x01,

/**
* The operation contained an invalid or unsupported option.
*/
JackInvalidOption = 0x02,

/**
* The desired client name was not unique. With the @ref
* JackUseExactName option this situation is fatal. Otherwise,
* the name was modified by appending a dash and a two-digit
* number in the range "-01" to "-99". The
* jack_get_client_name() function will return the exact string
* that was used. If the specified @a client_name plus these
* extra characters would be too long, the open fails instead.
*/
JackNameNotUnique = 0x04,

/**
* The JACK server was started as a result of this operation.
* Otherwise, it was running already. In either case the caller
* is now connected to jackd, so there is no race condition.
* When the server shuts down, the client will find out.
*/
JackServerStarted = 0x08,

/**
* Unable to connect to the JACK server.
*/
JackServerFailed = 0x10,

/**
* Communication error with the JACK server.
*/
JackServerError = 0x20,

/**
* Requested client does not exist.
*/
JackNoSuchClient = 0x40,

/**
* Unable to load internal client
*/
JackLoadFailure = 0x80,

/**
* Unable to initialize client
*/
JackInitFailure = 0x100,

/**
* Unable to access shared memory
*/
JackShmFailure = 0x200,

/**
* Client's protocol version does not match
*/
JackVersionError = 0x400,

/**
* Backend error
*/
JackBackendError = 0x800,

/**
* Client zombified failure
*/
JackClientZombie = 0x1000
};

/**
* Status word returned from several JACK operations, formed by
* OR-ing together the relevant @ref JackStatus bits.
*/
typedef enum JackStatus jack_status_t;

/**
* @ref jack_latency_callback_mode_t
*/
enum JackLatencyCallbackMode {

/**
* Latency Callback for Capture Latency.
* Input Ports have their latency value setup.
* In the Callback the client needs to set the latency of the output ports
*/
JackCaptureLatency,

/**
* Latency Callback for Playback Latency.
* Output Ports have their latency value setup.
* In the Callback the client needs to set the latency of the input ports
*/
JackPlaybackLatency

};

/**
* Type of Latency Callback (Capture or Playback)
*/
typedef enum JackLatencyCallbackMode jack_latency_callback_mode_t;

/**
* Prototype for the client supplied function that is called
* by the engine when port latencies need to be recalculated
*
* @param mode playback or capture latency
* @param arg pointer to a client supplied data
*
* @return zero on success, non-zero on error
*/
typedef void (*JackLatencyCallback)(jack_latency_callback_mode_t mode, void *arg);

/**
* the new latency API operates on Ranges.
*/
struct _jack_latency_range
{
/**
* minimum latency
*/
jack_nframes_t min;
/**
* maximum latency
*/
jack_nframes_t max;
};

typedef struct _jack_latency_range jack_latency_range_t;

/** /**
* Prototype for the client supplied function that is called * Prototype for the client supplied function that is called
* by the engine anytime there is work to be done. * by the engine anytime there is work to be done.
@@ -164,9 +363,12 @@ typedef int (*JackSampleRateCallback)(jack_nframes_t nframes, void *arg);
* Prototype for the client supplied function that is called * Prototype for the client supplied function that is called
* whenever a port is registered or unregistered. * whenever a port is registered or unregistered.
* *
* @param arg pointer to a client supplied structure
* @param port the ID of the port
* @param arg pointer to a client supplied data
* @param register non-zero if the port is being registered,
* zero if the port is being unregistered
*/ */
typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg);
typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int register, void *arg);


/** /**
* Prototype for the client supplied function that is called * Prototype for the client supplied function that is called
@@ -177,7 +379,7 @@ typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int, void *arg
* zero if the client is being unregistered * zero if the client is being unregistered
* @param arg pointer to a client supplied structure * @param arg pointer to a client supplied structure
*/ */
typedef void (*JackClientRegistrationCallback)(const char* name, int val, void *arg);
typedef void (*JackClientRegistrationCallback)(const char* name, int register, void *arg);


/** /**
* Prototype for the client supplied function that is called * Prototype for the client supplied function that is called
@@ -214,7 +416,7 @@ typedef void (*JackFreewheelCallback)(int starting, void *arg);


/** /**
* Prototype for the client supplied function that is called * Prototype for the client supplied function that is called
* whenever jackd is shutdown. Note that after server shutdown,
* whenever jackd is shutdown. Note that after server shutdown,
* the client pointer is *not* deallocated by libjack, * the client pointer is *not* deallocated by libjack,
* the application is responsible to properly use jack_client_close() * the application is responsible to properly use jack_client_close()
* to release client ressources. Warning: jack_client_close() cannot be * to release client ressources. Warning: jack_client_close() cannot be
@@ -225,6 +427,21 @@ typedef void (*JackFreewheelCallback)(int starting, void *arg);
*/ */
typedef void (*JackShutdownCallback)(void *arg); typedef void (*JackShutdownCallback)(void *arg);


/**
* Prototype for the client supplied function that is called
* whenever jackd is shutdown. Note that after server shutdown,
* the client pointer is *not* deallocated by libjack,
* the application is responsible to properly use jack_client_close()
* to release client ressources. Warning: jack_client_close() cannot be
* safely used inside the shutdown callback and has to be called outside of
* the callback context.

* @param code a status word, formed by OR-ing together the relevant @ref JackStatus bits.
* @param reason a string describing the shutdown reason (backend failure, server crash... etc...)
* @param arg pointer to a client supplied structure
*/
typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg);

/** /**
* Used for the type argument of jack_port_register() for default * Used for the type argument of jack_port_register() for default
* audio ports and midi ports. * audio ports and midi ports.
@@ -295,161 +512,9 @@ enum JackPortFlags {
* their ports. * their ports.
*/ */
JackPortIsTerminal = 0x10, JackPortIsTerminal = 0x10,
/**
* JackPortIsActive means the port has been registered and the
* client is "active", that is jack_activate has been called
*
* JackPortIsActive is on between jack_activate and jack_deactivate.
*/
JackPortIsActive = 0x20
};

/**
* @ref jack_options_t bits
*/
enum JackOptions {

/**
* Null value to use when no option bits are needed.
*/
JackNullOption = 0x00,

/**
* Do not automatically start the JACK server when it is not
* already running. This option is always selected if
* \$JACK_NO_START_SERVER is defined in the calling process
* environment.
*/
JackNoStartServer = 0x01,

/**
* Use the exact client name requested. Otherwise, JACK
* automatically generates a unique one, if needed.
*/
JackUseExactName = 0x02,

/**
* Open with optional <em>(char *) server_name</em> parameter.
*/
JackServerName = 0x04,

/**
* Load internal client from optional <em>(char *)
* load_name</em>. Otherwise use the @a client_name.
*/
JackLoadName = 0x08,

/**
* Pass optional <em>(char *) load_init</em> string to the
* jack_initialize() entry point of an internal client.
*/
JackLoadInit = 0x10,

/**
* pass a SessionID Token this allows the sessionmanager to identify the client again.
*/
JackSessionID = 0x20
};

/** Valid options for opening an external client. */
#define JackOpenOptions (JackSessionID|JackServerName|JackNoStartServer|JackUseExactName)

/** Valid options for loading an internal client. */
#define JackLoadOptions (JackLoadInit|JackLoadName|JackUseExactName)

/**
* Options for several JACK operations, formed by OR-ing together the
* relevant @ref JackOptions bits.
*/
typedef enum JackOptions jack_options_t;

/**
* @ref jack_status_t bits
*/
enum JackStatus {

/**
* Overall operation failed.
*/
JackFailure = 0x01,

/**
* The operation contained an invalid or unsupported option.
*/
JackInvalidOption = 0x02,

/**
* The desired client name was not unique. With the @ref
* JackUseExactName option this situation is fatal. Otherwise,
* the name was modified by appending a dash and a two-digit
* number in the range "-01" to "-99". The
* jack_get_client_name() function will return the exact string
* that was used. If the specified @a client_name plus these
* extra characters would be too long, the open fails instead.
*/
JackNameNotUnique = 0x04,

/**
* The JACK server was started as a result of this operation.
* Otherwise, it was running already. In either case the caller
* is now connected to jackd, so there is no race condition.
* When the server shuts down, the client will find out.
*/
JackServerStarted = 0x08,

/**
* Unable to connect to the JACK server.
*/
JackServerFailed = 0x10,

/**
* Communication error with the JACK server.
*/
JackServerError = 0x20,


/**
* Requested client does not exist.
*/
JackNoSuchClient = 0x40,

/**
* Unable to load internal client
*/
JackLoadFailure = 0x80,

/**
* Unable to initialize client
*/
JackInitFailure = 0x100,

/**
* Unable to access shared memory
*/
JackShmFailure = 0x200,

/**
* Client's protocol version does not match
*/
JackVersionError = 0x400,
/**
* Backend error
*/
JackBackendError = 0x800,
/**
* Client zombified failure
*/
JackClientZombie = 0x1000
}; };


/**
* Status word returned from several JACK operations, formed by
* OR-ing together the relevant @ref JackStatus bits.
*/
typedef enum JackStatus jack_status_t;

/** /**
* Transport states. * Transport states.
*/ */
@@ -476,7 +541,7 @@ typedef enum {
JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */ JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */
JackAudioVideoRatio = 0x80, /**< audio frames per video frame */ JackAudioVideoRatio = 0x80, /**< audio frames per video frame */
JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */ JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */
} jack_position_bits_t; } jack_position_bits_t;


/** all valid position bits */ /** all valid position bits */
@@ -666,19 +731,5 @@ typedef struct {


} jack_transport_info_t; } jack_transport_info_t;


/**
* Prototype for the client supplied function that is called
* whenever jackd is shutdown. Note that after server shutdown,
* the client pointer is *not* deallocated by libjack,
* the application is responsible to properly use jack_client_close()
* to release client ressources. Warning: jack_client_close() cannot be
* safely used inside the shutdown callback and has to be called outside of
* the callback context.
* @param code a status word, formed by OR-ing together the relevant @ref JackStatus bits.
* @param reason a string describing the shutdown reason (backend failure, server crash... etc...)
* @param arg pointer to a client supplied structure
*/
typedef void (*JackInfoShutdownCallback)(jack_status_t code, const char* reason, void *arg);


#endif /* __jack_types_h__ */ #endif /* __jack_types_h__ */

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

@@ -1,18 +1,18 @@
/* /*
Copyright (C) 2010 Paul Davis Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -20,10 +20,63 @@
#ifndef __weakjack_h__ #ifndef __weakjack_h__
#define __weakjack_h__ #define __weakjack_h__


/**
* @defgroup WeakLinkage managing support for newer/older versions of JACK
* @{ One challenge faced by developers is that of taking advantage of new features introduced in new versions of [ JACK ] while still
* supporting older versions of the system. Normally, if an application uses a new feature in a library/API, it is unable to run on
* earlier versions of the library/API that do not support that feature. Such applications would either fail to launch or crash when
* an attempt to use the feature was made. This problem cane be solved using weakly-linked symbols.
*
* When a symbol in a framework is defined as weakly linked, the symbol does not have to be present at runtime for a process to
* continue running. The static linker identifies a weakly linked symbol as such in any code module that references the symbol. The
* dynamic linker uses this same information at runtime to determine whether a process can continue running. If a weakly linked symbol
* is not present in the framework, the code module can continue to run as long as it does not reference the symbol. However, if the
* symbol is present, the code can use it normally.
*
* (adapted from: http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html)
*
* A concrete example will help. Suppose that someone uses a version
* of a JACK client we'll call "Jill". Jill was linked against a version
* of JACK that contains a newer part of the API (say, jack_set_latency_callback())
* and would like to use it if it is available.
*
* When Jill is run on a system that has a suitably "new" version of
* JACK, this function will be available entirely normally. But if Jill
* is run on a system with an old version of JACK, the function isn't
* available.
*
* With normal symbol linkage, this would create a startup error whenever
* someone tries to run Jill with the "old" version of JACK. However, functions
* added to JACK after version 0.116.2 are all declared to have "weak" linkage
* which means that their abscence doesn't cause an error during program
* startup. Instead, Jill can test whether or not the symbol jack_set_latency_callback
* is null or not. If its null, it means that the JACK installed on this machine
* is too old to support this function. If its not null, then Jill can use it
* just like any other function in the API. For example:
*
* \code
* if (jack_set_latency_callback) {
* jack_set_latency_callback (jill_client, jill_latency_callback, arg);
* }
* \endcode
*
* However, there are clients that may want to use this approach to parts of the
* the JACK API that predate 0.116.2. For example, they might want to see if even
* really old basic parts of the API like jack_client_open() exist at runtime.
*
* Such clients should include <jack/weakjack.h> before any other JACK header.
* This will make the \b entire JACK API be subject to weak linkage, so that any
* and all functions can be checked for existence at runtime. It is important
* to understand that very few clients need to do this - if you use this
* feature you should have a clear reason to do so.
*
*
*/

#ifndef JACK_OPTIONAL_WEAK_EXPORT #ifndef JACK_OPTIONAL_WEAK_EXPORT
/* JACK_OPTIONAL_WEAK_EXPORT needs to be a macro which /* JACK_OPTIONAL_WEAK_EXPORT needs to be a macro which
expands into a compiler directive. If non-null, the directive
must tell the compiler to arrange for weak linkage of
expands into a compiler directive. If non-null, the directive
must tell the compiler to arrange for weak linkage of
the symbol it used with. For this to work fully may the symbol it used with. For this to work fully may
require linker arguments for the client as well. require linker arguments for the client as well.
*/ */
@@ -49,4 +102,6 @@
#endif #endif
#endif #endif


/*@}*/

#endif /* weakjack */ #endif /* weakjack */

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

@@ -1,18 +1,18 @@
/* /*
Copyright (C) 2010 Paul Davis Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -23,27 +23,31 @@
/************************************************************* /*************************************************************
* NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function * NOTE: JACK_WEAK_EXPORT ***MUST*** be used on every function
* added to the JACK API after the 0.116.2 release. * added to the JACK API after the 0.116.2 release.
*
* Functions that predate this release are marked with
*
* Functions that predate this release are marked with
* JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile * JACK_WEAK_OPTIONAL_EXPORT which can be defined at compile
* time in a variety of ways. The default definition is empty, * time in a variety of ways. The default definition is empty,
* so that these symbols get normal linkage. If you wish to * so that these symbols get normal linkage. If you wish to
* use all JACK symbols with weak linkage, include
* use all JACK symbols with weak linkage, include
* <jack/weakjack.h> before jack.h. * <jack/weakjack.h> before jack.h.
*************************************************************/ *************************************************************/


#ifndef JACK_WEAK_EXPORT #ifndef JACK_WEAK_EXPORT
#ifdef __GNUC__ #ifdef __GNUC__
/* JACK_WEAK_EXPORT needs to be a macro which /* JACK_WEAK_EXPORT needs to be a macro which
expands into a compiler directive. If non-null, the directive
must tell the compiler to arrange for weak linkage of
expands into a compiler directive. If non-null, the directive
must tell the compiler to arrange for weak linkage of
the symbol it used with. For this to work full may the symbol it used with. For this to work full may
require linker arguments in the client as well. require linker arguments in the client as well.
*/ */
#define JACK_WEAK_EXPORT __attribute__((weak)) #define JACK_WEAK_EXPORT __attribute__((weak))
#else #else
/* Add other things here for non-gcc platforms */ /* Add other things here for non-gcc platforms */
#define JACK_WEAK_EXPORT
#ifdef WIN32
#define JACK_WEAK_EXPORT
#endif

#endif #endif
#endif #endif


@@ -54,9 +58,13 @@
#ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT #ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT
#ifdef __GNUC__ #ifdef __GNUC__
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__)) #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__))
#else
#else
/* Add other things here for non-gcc platforms */ /* Add other things here for non-gcc platforms */
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT
#ifdef WIN32
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT
#endif

#endif /* __GNUC__ */ #endif /* __GNUC__ */
#endif #endif




+ 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 $ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $
*/ */



#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <memory.h> #include <memory.h>
@@ -48,8 +47,6 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif


#include "netjack.h"

#ifdef __linux__ #ifdef __linux__
#include "config.h" #include "config.h"
#endif #endif
@@ -58,15 +55,11 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $
#include <samplerate.h> #include <samplerate.h>
#endif #endif


#if HAVE_CELT
#include <celt/celt.h>
#endif

#include "netjack.h" #include "netjack.h"
#include "netjack_packet.h" #include "netjack_packet.h"


// JACK2 // JACK2
#include "jack/control.h"
#include "control.h"


#define MIN(x,y) ((x)<(y) ? (x) : (y)) #define MIN(x,y) ((x)<(y) ? (x) : (y))


@@ -105,8 +98,8 @@ int netjack_wait( netjack_driver_state_t *netj )
netj->expected_framecnt += 1; netj->expected_framecnt += 1;
} else { } else {
// starting up.... lets look into the packetcache, and fetch the highest packet. // starting up.... lets look into the packetcache, and fetch the highest packet.
packet_cache_drain_socket( global_packcache, netj->sockfd );
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail ) ) {
packet_cache_drain_socket( netj->packcache, netj->sockfd );
if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail ) ) {
netj->expected_framecnt = next_frame_avail; netj->expected_framecnt = next_frame_avail;
netj->expected_framecnt_valid = 1; netj->expected_framecnt_valid = 1;
} else { } else {
@@ -122,7 +115,7 @@ int netjack_wait( netjack_driver_state_t *netj )
// then poll (have deadline calculated) // then poll (have deadline calculated)
// then drain socket, rinse and repeat. // then drain socket, rinse and repeat.
while(1) { while(1) {
if( packet_cache_get_next_available_framecnt( global_packcache, netj->expected_framecnt, &next_frame_avail) ) {
if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) ) {
if( next_frame_avail == netj->expected_framecnt ) { if( next_frame_avail == netj->expected_framecnt ) {
we_have_the_expected_frame = 1; we_have_the_expected_frame = 1;
if( !netj->always_deadline ) if( !netj->always_deadline )
@@ -133,13 +126,13 @@ int netjack_wait( netjack_driver_state_t *netj )
break; break;
} }


packet_cache_drain_socket( global_packcache, netj->sockfd );
packet_cache_drain_socket( netj->packcache, netj->sockfd );
} }


// check if we know who to send our packets too. // check if we know who to send our packets too.
if (!netj->srcaddress_valid) if (!netj->srcaddress_valid)
if( global_packcache->master_address_valid ) {
memcpy (&(netj->syncsource_address), &(global_packcache->master_address), sizeof( struct sockaddr_in ) );
if( netj->packcache->master_address_valid ) {
memcpy (&(netj->syncsource_address), &(netj->packcache->master_address), sizeof( struct sockaddr_in ) );
netj->srcaddress_valid = 1; netj->srcaddress_valid = 1;
} }


@@ -161,7 +154,7 @@ int netjack_wait( netjack_driver_state_t *netj )
else else
netj->time_to_deadline = 0; netj->time_to_deadline = 0;


packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp);
packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize , &packet_recv_time_stamp);
pkthdr = (jacknet_packet_header *) netj->rx_buf; pkthdr = (jacknet_packet_header *) netj->rx_buf;
packet_header_ntoh(pkthdr); packet_header_ntoh(pkthdr);
netj->deadline_goodness = (int)pkthdr->sync_state; netj->deadline_goodness = (int)pkthdr->sync_state;
@@ -203,7 +196,7 @@ int netjack_wait( netjack_driver_state_t *netj )
// lets check if we have the next packets, we will just run a cycle without data. // lets check if we have the next packets, we will just run a cycle without data.
// in that case. // in that case.


if( packet_cache_get_next_available_framecnt( global_packcache, netj->expected_framecnt, &next_frame_avail) )
if( packet_cache_get_next_available_framecnt( netj->packcache, netj->expected_framecnt, &next_frame_avail) )
{ {
jack_nframes_t offset = next_frame_avail - netj->expected_framecnt; jack_nframes_t offset = next_frame_avail - netj->expected_framecnt;


@@ -221,7 +214,7 @@ int netjack_wait( netjack_driver_state_t *netj )


// I also found this happening, when the packet queue, is too full. // I also found this happening, when the packet queue, is too full.
// but wtf ? use a smaller latency. this link can handle that ;S // but wtf ? use a smaller latency. this link can handle that ;S
if( packet_cache_get_fill( global_packcache, netj->expected_framecnt ) > 80.0 )
if( packet_cache_get_fill( netj->packcache, netj->expected_framecnt ) > 80.0 )
netj->next_deadline -= netj->period_usecs/2; netj->next_deadline -= netj->period_usecs/2;




@@ -229,7 +222,7 @@ int netjack_wait( netjack_driver_state_t *netj )
// the diff is too high. but we have a packet in the future. // the diff is too high. but we have a packet in the future.
// lets resync. // lets resync.
netj->expected_framecnt = next_frame_avail; netj->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL );
packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL );
pkthdr = (jacknet_packet_header *) netj->rx_buf; pkthdr = (jacknet_packet_header *) netj->rx_buf;
packet_header_ntoh(pkthdr); packet_header_ntoh(pkthdr);
//netj->deadline_goodness = 0; //netj->deadline_goodness = 0;
@@ -257,7 +250,7 @@ int netjack_wait( netjack_driver_state_t *netj )
// i will make the packet cache drop redundant packets, // i will make the packet cache drop redundant packets,
// that have already been retreived. // that have already been retreived.
// //
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) {
if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) {
if( next_frame_avail == (netj->expected_framecnt - 1) ) { if( next_frame_avail == (netj->expected_framecnt - 1) ) {
// Ok. the last packet is there now. // Ok. the last packet is there now.
// and it had not been retrieved. // and it had not been retrieved.
@@ -277,9 +270,9 @@ int netjack_wait( netjack_driver_state_t *netj )


// But now we can check for any new frame available. // But now we can check for any new frame available.
// //
if( packet_cache_get_highest_available_framecnt( global_packcache, &next_frame_avail) ) {
if( packet_cache_get_highest_available_framecnt( netj->packcache, &next_frame_avail) ) {
netj->expected_framecnt = next_frame_avail; netj->expected_framecnt = next_frame_avail;
packet_cache_retreive_packet_pointer( global_packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL );
packet_cache_retreive_packet_pointer( netj->packcache, netj->expected_framecnt, (char **) &(netj->rx_buf), netj->rx_bufsize, NULL );
pkthdr = (jacknet_packet_header *) netj->rx_buf; pkthdr = (jacknet_packet_header *) netj->rx_buf;
packet_header_ntoh(pkthdr); packet_header_ntoh(pkthdr);
netj->deadline_goodness = pkthdr->sync_state; netj->deadline_goodness = pkthdr->sync_state;
@@ -300,7 +293,7 @@ int netjack_wait( netjack_driver_state_t *netj )
// reply address changes port. // reply address changes port.
if (netj->num_lost_packets > 200 ) { if (netj->num_lost_packets > 200 ) {
netj->srcaddress_valid = 0; netj->srcaddress_valid = 0;
packet_cache_reset_master_address( global_packcache );
packet_cache_reset_master_address( netj->packcache );
} }
} }
} }
@@ -369,6 +362,21 @@ void netjack_attach( netjack_driver_state_t *netj )
int port_flags; int port_flags;




if( netj->bitdepth == CELT_MODE )
{
#if HAVE_CELT
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
celt_int32 lookahead;
netj->celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
#else
celt_int32_t lookahead;
netj->celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
#endif
celt_mode_info( netj->celt_mode, CELT_GET_LOOKAHEAD, &lookahead );
netj->codec_latency = 2*lookahead;
#endif
}

if (netj->handle_transport_sync) if (netj->handle_transport_sync)
jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL); jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL);


@@ -390,17 +398,11 @@ void netjack_attach( netjack_driver_state_t *netj )


if( netj->bitdepth == CELT_MODE ) { if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT #if HAVE_CELT
#if HAVE_CELT_API_0_7
celt_int32 lookahead;
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) );
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode, 1, NULL ) );
#else #else
celt_int32_t lookahead;
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( celt_mode ) );
netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode ) );
#endif #endif
celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead );
netj->codec_latency = 2*lookahead;
#endif #endif
} else { } else {
#if HAVE_SAMPLERATE #if HAVE_SAMPLERATE
@@ -408,6 +410,7 @@ void netjack_attach( netjack_driver_state_t *netj )
#endif #endif
} }
} }

for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) { for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) {
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1); snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);


@@ -441,7 +444,7 @@ void netjack_attach( netjack_driver_state_t *netj )
jack_slist_append (netj->playback_ports, port); jack_slist_append (netj->playback_ports, port);
if( netj->bitdepth == CELT_MODE ) { if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT #if HAVE_CELT
#if HAVE_CELT_API_0_7
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) );
#else #else
@@ -479,7 +482,6 @@ void netjack_detach( netjack_driver_state_t *netj )
{ {
JSList * node; JSList * node;



for (node = netj->capture_ports; node; node = jack_slist_next (node)) for (node = netj->capture_ports; node; node = jack_slist_next (node))
jack_port_unregister (netj->client, jack_port_unregister (netj->client,
((jack_port_t *) node->data)); ((jack_port_t *) node->data));
@@ -487,12 +489,57 @@ void netjack_detach( netjack_driver_state_t *netj )
jack_slist_free (netj->capture_ports); jack_slist_free (netj->capture_ports);
netj->capture_ports = NULL; netj->capture_ports = NULL;


for (node = netj->capture_srcs; node; node = jack_slist_next (node))
{
#if HAVE_CELT
if( netj->bitdepth == CELT_MODE )
{
CELTDecoder * decoder = node->data;
celt_decoder_destroy(decoder);
}
else
#endif
{
#if HAVE_SAMPLERATE
SRC_STATE * src = node->data;
src_delete(src);
#endif
}
}
jack_slist_free (netj->capture_srcs);
netj->playback_srcs = NULL;

for (node = netj->playback_ports; node; node = jack_slist_next (node)) for (node = netj->playback_ports; node; node = jack_slist_next (node))
jack_port_unregister (netj->client, jack_port_unregister (netj->client,
((jack_port_t *) node->data)); ((jack_port_t *) node->data));


jack_slist_free (netj->playback_ports); jack_slist_free (netj->playback_ports);
netj->playback_ports = NULL; netj->playback_ports = NULL;

for (node = netj->playback_srcs; node; node = jack_slist_next (node))
{
#if HAVE_CELT
if( netj->bitdepth == CELT_MODE )
{
CELTEncoder * encoder = node->data;
celt_encoder_destroy(encoder);
}
else
#endif
{
#if HAVE_SAMPLERATE
SRC_STATE * src = node->data;
src_delete(src);
#endif
}
}
jack_slist_free (netj->playback_srcs);
netj->playback_srcs = NULL;

#if HAVE_CELT
if( netj->bitdepth == CELT_MODE )
celt_mode_destroy(netj->celt_mode);
#endif
} }




@@ -574,8 +621,8 @@ void netjack_release( netjack_driver_state_t *netj )
close( netj->sockfd ); close( netj->sockfd );
close( netj->outsockfd ); close( netj->outsockfd );


packet_cache_free( global_packcache );
global_packcache = NULL;
packet_cache_free( netj->packcache );
netj->packcache = NULL;
} }


int int
@@ -585,13 +632,7 @@ netjack_startup( netjack_driver_state_t *netj )
struct sockaddr_in address; struct sockaddr_in address;
// Now open the socket, and wait for the first packet to arrive... // Now open the socket, and wait for the first packet to arrive...
netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0);

#ifdef WIN32 #ifdef WIN32
u_long parm = 1;
DWORD bufsize = 262144;
//ioctlsocket( netj->sockfd, FIONBIO, &parm );
setsockopt( netj->sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize) );
setsockopt( netj->sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize) );
if (netj->sockfd == INVALID_SOCKET) if (netj->sockfd == INVALID_SOCKET)
#else #else
if (netj->sockfd == -1) if (netj->sockfd == -1)
@@ -632,6 +673,10 @@ netjack_startup( netjack_driver_state_t *netj )
//jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!");


while(1) { while(1) {
if( ! netjack_poll( netj->sockfd, 1000 ) ) {
jack_info ("Waiting aborted");
return -1;
}
first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size);
#ifdef WIN32 #ifdef WIN32
if( first_pack_len == -1 ) { if( first_pack_len == -1 ) {
@@ -735,7 +780,7 @@ netjack_startup( netjack_driver_state_t *netj )
} }


netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth); netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth);
global_packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu);
netj->packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu);


netj->expected_framecnt_valid = 0; netj->expected_framecnt_valid = 0;
netj->num_lost_packets = 0; netj->num_lost_packets = 0;


+ 10
- 0
common/netjack.h View File

@@ -30,6 +30,10 @@


#include "jack/jslist.h" #include "jack/jslist.h"


#if HAVE_CELT
#include <celt/celt.h>
#endif

//#include <netinet/in.h> //#include <netinet/in.h>


#ifdef __cplusplus #ifdef __cplusplus
@@ -37,6 +41,8 @@ extern "C"
{ {
#endif #endif


struct _packet_cache;

typedef struct _netjack_driver_state netjack_driver_state_t; typedef struct _netjack_driver_state netjack_driver_state_t;


struct _netjack_driver_state { struct _netjack_driver_state {
@@ -106,6 +112,10 @@ struct _netjack_driver_state {
unsigned int resample_factor; unsigned int resample_factor;
unsigned int resample_factor_up; unsigned int resample_factor_up;
int jitter_val; int jitter_val;
struct _packet_cache * packcache;
#if HAVE_CELT
CELTMode *celt_mode;
#endif
}; };


int netjack_wait( netjack_driver_state_t *netj ); int netjack_wait( netjack_driver_state_t *netj );


+ 14
- 60
common/netjack_packet.c View File

@@ -75,7 +75,7 @@
#include "netjack_packet.h" #include "netjack_packet.h"


// JACK2 specific. // JACK2 specific.
#include "jack/control.h"
#include "control.h"


#ifdef NO_JACK_ERROR #ifdef NO_JACK_ERROR
#define jack_error printf #define jack_error printf
@@ -83,8 +83,6 @@


int fraggo = 0; int fraggo = 0;


packet_cache *global_packcache = NULL;

void void
packet_header_hton (jacknet_packet_header *pkthdr) packet_header_hton (jacknet_packet_header *pkthdr)
{ {
@@ -388,7 +386,7 @@ netjack_poll_deadline (int sockfd, jack_time_t deadline)
#if HAVE_PPOLL #if HAVE_PPOLL
timeout_spec.tv_nsec = (deadline - now) * 1000; timeout_spec.tv_nsec = (deadline - now) * 1000;
#else #else
timeout = (deadline - now + 500) / 1000;
timeout = lrintf( (float)(deadline - now) / 1000.0 );
#endif #endif




@@ -565,7 +563,7 @@ packet_cache_drain_socket( packet_cache *pcache, int sockfd )
if( pcache->last_framecnt_retreived_valid && (framecnt <= pcache->last_framecnt_retreived )) if( pcache->last_framecnt_retreived_valid && (framecnt <= pcache->last_framecnt_retreived ))
continue; continue;


cpack = packet_cache_get_packet (global_packcache, framecnt);
cpack = packet_cache_get_packet (pcache, framecnt);
cache_packet_add_fragment (cpack, rx_packet, rcv_len); cache_packet_add_fragment (cpack, rx_packet, rcv_len);
cpack->recv_timestamp = jack_get_time(); cpack->recv_timestamp = jack_get_time();
} }
@@ -774,61 +772,6 @@ packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecn
return retval; return retval;
} }
// fragmented packet IO // fragmented packet IO
int
netjack_recvfrom (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, size_t *addr_size, int mtu)
{
int retval;
socklen_t from_len = *addr_size;
if (pkt_size <= mtu) {
retval = recvfrom (sockfd, packet_buf, pkt_size, flags, addr, &from_len);
*addr_size = from_len;
return retval;
}

char *rx_packet = alloca (mtu);
jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet;
int rcv_len;
jack_nframes_t framecnt;
cache_packet *cpack;
do
{
rcv_len = recvfrom (sockfd, rx_packet, mtu, 0, addr, &from_len);
if (rcv_len < 0)
return rcv_len;
framecnt = ntohl (pkthdr->framecnt);
cpack = packet_cache_get_packet (global_packcache, framecnt);
cache_packet_add_fragment (cpack, rx_packet, rcv_len);
} while (!cache_packet_is_complete (cpack));
memcpy (packet_buf, cpack->packet_buf, pkt_size);
cache_packet_reset (cpack);
*addr_size = from_len;
return pkt_size;
}

int
netjack_recv (int sockfd, char *packet_buf, int pkt_size, int flags, int mtu)
{
if (pkt_size <= mtu)
return recv (sockfd, packet_buf, pkt_size, flags);
char *rx_packet = alloca (mtu);
jacknet_packet_header *pkthdr = (jacknet_packet_header *) rx_packet;
int rcv_len;
jack_nframes_t framecnt;
cache_packet *cpack;
do
{
rcv_len = recv (sockfd, rx_packet, mtu, flags);
if (rcv_len < 0)
return rcv_len;
framecnt = ntohl (pkthdr->framecnt);
cpack = packet_cache_get_packet (global_packcache, framecnt);
cache_packet_add_fragment (cpack, rx_packet, rcv_len);
} while (!cache_packet_is_complete (cpack));
memcpy (packet_buf, cpack->packet_buf, pkt_size);
cache_packet_reset (cpack);
return pkt_size;
}

void void
netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu) netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, int addr_size, int mtu)
{ {
@@ -1427,10 +1370,17 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri
// audio port, decode celt data. // audio port, decode celt data.


CELTDecoder *decoder = src_node->data; CELTDecoder *decoder = src_node->data;
#if HAVE_CELT_API_0_8
if( !packet_payload )
celt_decode_float( decoder, NULL, net_period_down, buf, nframes );
else
celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes );
#else
if( !packet_payload ) if( !packet_payload )
celt_decode_float( decoder, NULL, net_period_down, buf ); celt_decode_float( decoder, NULL, net_period_down, buf );
else else
celt_decode_float( decoder, packet_bufX, net_period_down, buf ); celt_decode_float( decoder, packet_bufX, net_period_down, buf );
#endif


src_node = jack_slist_next (src_node); src_node = jack_slist_next (src_node);
} }
@@ -1472,7 +1422,11 @@ render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs
float *floatbuf = alloca (sizeof(float) * nframes ); float *floatbuf = alloca (sizeof(float) * nframes );
memcpy( floatbuf, buf, nframes*sizeof(float) ); memcpy( floatbuf, buf, nframes*sizeof(float) );
CELTEncoder *encoder = src_node->data; CELTEncoder *encoder = src_node->data;
#if HAVE_CELT_API_0_8
encoded_bytes = celt_encode_float( encoder, floatbuf, nframes, packet_bufX, net_period_up );
#else
encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up );
#endif
if( encoded_bytes != net_period_up ) if( encoded_bytes != net_period_up )
printf( "something in celt changed. netjack needs to be changed to handle this.\n" ); printf( "something in celt changed. netjack needs to be changed to handle this.\n" );
src_node = jack_slist_next( src_node ); src_node = jack_slist_next( src_node );


+ 0
- 6
common/netjack_packet.h View File

@@ -107,8 +107,6 @@ struct _packet_cache
int last_framecnt_retreived_valid; int last_framecnt_retreived_valid;
}; };


extern packet_cache *global_packcache;

// fragment cache function prototypes // fragment cache function prototypes
// XXX: Some of these are private. // XXX: Some of these are private.
packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu); packet_cache *packet_cache_new(int num_packets, int pkt_size, int mtu);
@@ -152,10 +150,6 @@ void render_jack_ports_to_payload(int bitdepth, JSList *playback_ports, JSList *
// This one waits forever. an is not using ppoll // This one waits forever. an is not using ppoll
int netjack_poll(int sockfd, int timeout); int netjack_poll(int sockfd, int timeout);


// TODO: these are deprecated.
//int netjack_recvfrom(int sockfd, char *packet_buf, int pkt_size, int flags, struct sockaddr *addr, socklen_t *addr_size, int mtu);
//int netjack_recv(int sockfd, char *packet_buf, int pkt_size, int flags, int mtu);

void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf);
void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf); void encode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf);
#ifdef __cplusplus #ifdef __cplusplus


+ 6
- 5
common/timestamps.c View File

@@ -1,24 +1,25 @@
/* /*
Copyright (C) 2002-2003 Paul Davis Copyright (C) 2002-2003 Paul Davis
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */


#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <inttypes.h>
#include "timestamps.h" #include "timestamps.h"
#include "JackTime.h" #include "JackTime.h"


@@ -60,7 +61,7 @@ jack_dump_timestamps (FILE *out)
unsigned long i; unsigned long i;


for (i = 0; i < timestamp_index; ++i) { for (i = 0; i < timestamp_index; ++i) {
fprintf (out, "%-.32s %" PRIu64 " %" PRIu64,
fprintf (out, "%-.32s %" PRIu64 " %" PRIu64,
timestamps[i].what, timestamps[i].when, timestamps[i].what, timestamps[i].when,
timestamps[i].when - timestamps[0].when); timestamps[i].when - timestamps[0].when);
if (i > 0) { if (i > 0) {


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

@@ -11,12 +11,11 @@
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>


#include <alloca.h>
#include <math.h> #include <math.h>


#include <jack/jack.h> #include <jack/jack.h>
#include <jack/jslist.h> #include <jack/jslist.h>
#include <memops.h>
#include <jack/memops.h>


#include "alsa/asoundlib.h" #include "alsa/asoundlib.h"


@@ -77,6 +76,12 @@ volatile float output_diff = 0.0;
snd_pcm_uframes_t real_buffer_size; snd_pcm_uframes_t real_buffer_size;
snd_pcm_uframes_t real_period_size; snd_pcm_uframes_t real_period_size;


// buffers

char *tmpbuf;
char *outbuf;
float *resampbuf;

// format selection, and corresponding functions from memops in a nice set of structs. // format selection, and corresponding functions from memops in a nice set of structs.


typedef struct alsa_format { typedef struct alsa_format {
@@ -307,8 +312,6 @@ double hann( double x )
*/ */
int process (jack_nframes_t nframes, void *arg) { int process (jack_nframes_t nframes, void *arg) {


char *outbuf;
float *resampbuf;
int rlen; int rlen;
int err; int err;
snd_pcm_sframes_t delay = target_delay; snd_pcm_sframes_t delay = target_delay;
@@ -322,10 +325,15 @@ int process (jack_nframes_t nframes, void *arg) {
// this is for compensating xruns etc... // this is for compensating xruns etc...


if( delay > (target_delay+max_diff) ) { if( delay > (target_delay+max_diff) ) {
char *tmp = alloca( (delay-target_delay) * formats[format].sample_size * num_channels );
snd_pcm_readi( alsa_handle, tmp, delay-target_delay );

output_new_delay = (int) delay; output_new_delay = (int) delay;


while ((delay-target_delay) > 0) {
snd_pcm_uframes_t to_read = ((delay-target_delay) > 512) ? 512 : (delay-target_delay);
snd_pcm_readi( alsa_handle, tmpbuf, to_read );
delay -= to_read;
}

delay = target_delay; delay = target_delay;


// Set the resample_rate... we need to adjust the offset integral, to do this. // Set the resample_rate... we need to adjust the offset integral, to do this.
@@ -399,13 +407,6 @@ int process (jack_nframes_t nframes, void *arg) {


// Calculate resample_mean so we can init ourselves to saner values. // Calculate resample_mean so we can init ourselves to saner values.
resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
/*
* now this should do it...
*/

outbuf = alloca( rlen * formats[format].sample_size * num_channels );

resampbuf = alloca( rlen * sizeof( float ) );


// get the data... // get the data...
again: again:
@@ -465,6 +466,32 @@ again:
return 0; return 0;
} }


/**
* the latency callback.
* sets up the latencies on the ports.
*/

void
latency_cb (jack_latency_callback_mode_t mode, void *arg)
{
jack_latency_range_t range;
JSList *node;

range.min = range.max = target_delay;

if (mode == JackCaptureLatency) {
for (node = capture_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
} else {
for (node = playback_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
}
}



/** /**
* Allocate the necessary jack ports... * Allocate the necessary jack ports...
@@ -661,6 +688,8 @@ int main (int argc, char *argv[]) {


jack_on_shutdown (client, jack_shutdown, 0); jack_on_shutdown (client, jack_shutdown, 0);


if (jack_set_latency_callback)
jack_set_latency_callback (client, latency_cb, 0);


// get jack sample_rate // get jack sample_rate
@@ -716,6 +745,17 @@ int main (int argc, char *argv[]) {
// alloc input ports, which are blasted out to alsa... // alloc input ports, which are blasted out to alsa...
alloc_ports( num_channels, 0 ); alloc_ports( num_channels, 0 );


outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels );
resampbuf = malloc( num_periods * period_size * sizeof( float ) );
tmpbuf = malloc( 512 * formats[format].sample_size * num_channels );

if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL))
{
fprintf( stderr, "no memory for buffers.\n" );
exit(20);
}

memset( tmpbuf, 0, 512 * formats[format].sample_size * num_channels);


/* tell the JACK server that we are ready to roll */ /* tell the JACK server that we are ready to roll */




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

@@ -11,12 +11,11 @@
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>


#include <alloca.h>
#include <math.h> #include <math.h>


#include <jack/jack.h> #include <jack/jack.h>
#include <jack/jslist.h> #include <jack/jslist.h>
#include <memops.h>
#include <jack/memops.h>


#include "alsa/asoundlib.h" #include "alsa/asoundlib.h"


@@ -35,6 +34,7 @@ snd_pcm_t *alsa_handle;
int jack_sample_rate; int jack_sample_rate;
int jack_buffer_size; int jack_buffer_size;


int quit = 0;
double resample_mean = 1.0; double resample_mean = 1.0;
double static_resample_factor = 1.0; double static_resample_factor = 1.0;
double resample_lower_limit = 0.25; double resample_lower_limit = 0.25;
@@ -45,7 +45,6 @@ double *window_array;
int offset_differential_index = 0; int offset_differential_index = 0;


double offset_integral = 0; double offset_integral = 0;
int quit = 0;


// ------------------------------------------------------ commandline parameters // ------------------------------------------------------ commandline parameters


@@ -77,6 +76,12 @@ volatile float output_diff = 0.0;
snd_pcm_uframes_t real_buffer_size; snd_pcm_uframes_t real_buffer_size;
snd_pcm_uframes_t real_period_size; snd_pcm_uframes_t real_period_size;


// buffers

char *tmpbuf;
char *outbuf;
float *resampbuf;

// format selection, and corresponding functions from memops in a nice set of structs. // format selection, and corresponding functions from memops in a nice set of structs.


typedef struct alsa_format { typedef struct alsa_format {
@@ -90,6 +95,7 @@ typedef struct alsa_format {
alsa_format_t formats[] = { alsa_format_t formats[] = {
{ SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" },
{ SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" },
{ SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" },
{ SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" },
{ SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" }
}; };
@@ -311,8 +317,6 @@ double hann( double x )
*/ */
int process (jack_nframes_t nframes, void *arg) { int process (jack_nframes_t nframes, void *arg) {


char *outbuf;
float *resampbuf;
int rlen; int rlen;
int err; int err;
snd_pcm_sframes_t delay = target_delay; snd_pcm_sframes_t delay = target_delay;
@@ -321,7 +325,6 @@ int process (jack_nframes_t nframes, void *arg) {
delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ;


delay -= jack_frames_since_cycle_start( client ); delay -= jack_frames_since_cycle_start( client );
delay += jack_get_buffer_size( client ) / 2;
// Do it the hard way. // Do it the hard way.
// this is for compensating xruns etc... // this is for compensating xruns etc...


@@ -340,12 +343,15 @@ int process (jack_nframes_t nframes, void *arg) {
offset_array[i] = 0.0; offset_array[i] = 0.0;
} }
if( delay < (target_delay-max_diff) ) { if( delay < (target_delay-max_diff) ) {
char *tmp = alloca( (target_delay-delay) * formats[format].sample_size * num_channels );
memset( tmp, 0, formats[format].sample_size * num_channels * (target_delay-delay) );
snd_pcm_writei( alsa_handle, tmp, target_delay-delay );


output_new_delay = (int) delay; output_new_delay = (int) delay;


while ((target_delay-delay) > 0) {
snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay);
snd_pcm_writei( alsa_handle, tmpbuf, to_write );
delay += to_write;
}

delay = target_delay; delay = target_delay;


// Set the resample_rate... we need to adjust the offset integral, to do this. // Set the resample_rate... we need to adjust the offset integral, to do this.
@@ -463,6 +469,32 @@ again:
return 0; return 0;
} }


/**
* the latency callback.
* sets up the latencies on the ports.
*/

void
latency_cb (jack_latency_callback_mode_t mode, void *arg)
{
jack_latency_range_t range;
JSList *node;

range.min = range.max = target_delay;

if (mode == JackCaptureLatency) {
for (node = capture_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
} else {
for (node = playback_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
}
}



/** /**
* Allocate the necessary jack ports... * Allocate the necessary jack ports...
@@ -659,6 +691,8 @@ int main (int argc, char *argv[]) {


jack_on_shutdown (client, jack_shutdown, 0); jack_on_shutdown (client, jack_shutdown, 0);


if (jack_set_latency_callback)
jack_set_latency_callback (client, latency_cb, 0);


// get jack sample_rate // get jack sample_rate
@@ -714,6 +748,16 @@ int main (int argc, char *argv[]) {
// alloc input ports, which are blasted out to alsa... // alloc input ports, which are blasted out to alsa...
alloc_ports( 0, num_channels ); alloc_ports( 0, num_channels );


outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels );
resampbuf = malloc( num_periods * period_size * sizeof( float ) );
tmpbuf = malloc( 512 * formats[format].sample_size * num_channels );

if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL))
{
fprintf( stderr, "no memory for buffers.\n" );
exit(20);
}



/* tell the JACK server that we are ready to roll */ /* tell the JACK server that we are ready to roll */




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

@@ -2,7 +2,7 @@
* bufsize.c -- change JACK buffer size. * bufsize.c -- change JACK buffer size.
* *
* Copyright (C) 2003 Jack O'Quin. * Copyright (C) 2003 Jack O'Quin.
*
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@@ -64,12 +64,23 @@ void parse_arguments(int argc, char *argv[])
exit(9); exit(9);
} }


if (strspn (argv[1], "0123456789") != strlen (argv[1])) {
fprintf(stderr, "usage: %s <bufsize>\n", package);
exit(8);
}

nframes = strtoul(argv[1], NULL, 0); nframes = strtoul(argv[1], NULL, 0);
if (errno == ERANGE) { if (errno == ERANGE) {
fprintf(stderr, "%s: invalid buffer size: %s\n",
fprintf(stderr, "%s: invalid buffer size: %s (range is 1-8182)\n",
package, argv[1]); package, argv[1]);
exit(2); exit(2);
} }

if (nframes < 1 || nframes > 8182) {
fprintf(stderr, "%s: invalid buffer size: %s (range is 1-8182)\n",
package, argv[1]);
exit(3);
}
} }


int main(int argc, char *argv[]) int main(int argc, char *argv[])


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

@@ -24,7 +24,9 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <getopt.h>
#include <jack/jack.h> #include <jack/jack.h>
#include <jack/session.h>


jack_port_t *input_port; jack_port_t *input_port;
jack_port_t *output_port; jack_port_t *output_port;
@@ -33,17 +35,84 @@ int done = 0;
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0



void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
{ {
done = 1; done = 1;
} }


void
show_version (char *my_name)
{
//fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name);
}

void
show_usage (char *my_name)
{
show_version (my_name);
fprintf (stderr, "\nusage: %s [options] port1 port2\n", my_name);
fprintf (stderr, "Connects two JACK ports together.\n\n");
fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n");
fprintf (stderr, " -v, --version Output version information and exit\n");
fprintf (stderr, " -h, --help Display this help message\n\n");
fprintf (stderr, "For more information see http://jackaudio.org/\n");
}


int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
jack_client_t* client = NULL;
jack_client_t *client;
jack_status_t status;
char *server_name = NULL;
int c;
int option_index;
jack_options_t options = JackNoStartServer;
char *my_name = strrchr(argv[0], '/'); char *my_name = strrchr(argv[0], '/');
jack_port_t *src_port = 0;
jack_port_t *dst_port = 0;
jack_port_t *port1 = 0;
jack_port_t *port2 = 0;
char portA[300];
char portB[300];
int use_uuid=0;
int connecting, disconnecting;
int port1_flags, port2_flags;
int rc = 1;

struct option long_options[] = {
{ "server", 1, 0, 's' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "uuid", 0, 0, 'u' },
{ 0, 0, 0, 0 }
};

while ((c = getopt_long (argc, argv, "s:hvu", long_options, &option_index)) >= 0) {
switch (c) {
case 's':
server_name = (char *) malloc (sizeof (char) * strlen(optarg));
strcpy (server_name, optarg);
options |= JackServerName;
break;
case 'u':
use_uuid = 1;
break;
case 'h':
show_usage (my_name);
return 1;
break;
case 'v':
show_version (my_name);
return 1;
break;
default:
show_usage (my_name);
return 1;
break;
}
}

connecting = disconnecting = FALSE; connecting = disconnecting = FALSE;
if (my_name == 0) { if (my_name == 0) {
my_name = argv[0]; my_name = argv[0];
@@ -51,90 +120,121 @@ main (int argc, char *argv[])
my_name ++; my_name ++;
} }


printf("name %s\n", my_name);

if (strstr(my_name, "jack_disconnect")) {
disconnecting = TRUE;
} else
if (strstr(my_name, "jack_connect")) {
connecting = TRUE;
if (strstr(my_name, "disconnect")) {
disconnecting = 1;
} else if (strstr(my_name, "connect")) {
connecting = 1;
} else { } else {
fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name);
return 1; return 1;
} }


if (argc != 3) {
fprintf (stderr, "usage: %s <src_port> <dst_port>\n", my_name);
fprintf(stderr, "The source port must be an output port of the source client.\n");
fprintf (stderr, "The destination port must be an input port of the destination client.\n");
return 1;
}
if (argc < 3) show_usage(my_name);


/* try to become a client of the JACK server */ /* try to become a client of the JACK server */


if ((client = jack_client_open (my_name, JackNullOption, NULL)) == 0) {
if ((client = jack_client_open (my_name, options, &status, server_name)) == 0) {
fprintf (stderr, "jack server not running?\n"); fprintf (stderr, "jack server not running?\n");
return 1; return 1;
} }


jack_set_port_connect_callback(client, port_connect_callback, NULL); jack_set_port_connect_callback(client, port_connect_callback, NULL);


/* display the current sample rate. once the client is activated
(see below), you should rely on your own sample rate
callback (see above) for this value.
*/

/* find the two ports */ /* find the two ports */


if ((input_port = jack_port_by_name(client, argv[1])) == 0) {
fprintf (stderr, "ERROR %s not a valid port\n", argv[1]);
goto error;
if( use_uuid ) {
char *tmpname;
char *clientname;
char *portname;
tmpname = strdup( argv[argc-1] );
portname = strchr( tmpname, ':' );
portname[0] = '\0';
portname+=1;
clientname = jack_get_client_name_by_uuid( client, tmpname );
if( clientname ) {

snprintf( portA, sizeof(portA), "%s:%s", clientname, portname );
jack_free( clientname );
} else {
snprintf( portA, sizeof(portA), "%s", argv[argc-1] );
}
free( tmpname );

tmpname = strdup( argv[argc-2] );
portname = strchr( tmpname, ':' );
portname[0] = '\0';
portname+=1;
clientname = jack_get_client_name_by_uuid( client, tmpname );
if( clientname ) {
snprintf( portB, sizeof(portB), "%s:%s", clientname, portname );
jack_free( clientname );
} else {
snprintf( portB, sizeof(portB), "%s", argv[argc-2] );
}

free( tmpname );

} else {
snprintf( portA, sizeof(portA), "%s", argv[argc-1] );
snprintf( portB, sizeof(portB), "%s", argv[argc-2] );
} }
if ((output_port = jack_port_by_name(client, argv[2])) == 0) {
fprintf (stderr, "ERROR %s not a valid port\n", argv[2]);
goto error;
if ((port1 = jack_port_by_name(client, portA)) == 0) {
fprintf (stderr, "ERROR %s not a valid port\n", portA);
goto exit;
}
if ((port2 = jack_port_by_name(client, portB)) == 0) {
fprintf (stderr, "ERROR %s not a valid port\n", portB);
goto exit;
}

port1_flags = jack_port_flags (port1);
port2_flags = jack_port_flags (port2);

if (port1_flags & JackPortIsInput) {
if (port2_flags & JackPortIsOutput) {
src_port = port2;
dst_port = port1;
}
} else {
if (port2_flags & JackPortIsInput) {
src_port = port1;
dst_port = port2;
}
} }


/* tell the JACK server that we are ready to roll */

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
goto error;
if (!src_port || !dst_port) {
fprintf (stderr, "arguments must include 1 input port and 1 output port\n");
goto exit;
} }


/* connect the ports. Note: you can't do this before /* connect the ports. Note: you can't do this before
the client is activated (this may change in the future). the client is activated (this may change in the future).
*/ */


if (connecting) {
if (jack_connect(client, jack_port_name(input_port), jack_port_name(output_port))) {
fprintf (stderr, "cannot connect ports\n");
goto error;
}
if (connecting) {
if (jack_connect(client, jack_port_name(src_port), jack_port_name(dst_port))) {
goto exit;
}
} }
if (disconnecting) { if (disconnecting) {
if (jack_disconnect(client, jack_port_name(input_port), jack_port_name(output_port))) {
fprintf (stderr, "cannot disconnect ports\n");
goto error;
}
if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) {
goto exit;
}
} }


// Wait for connection/disconnection to be effective // Wait for connection/disconnection to be effective
while(!done) {
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
while(!done) {
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
} }


jack_deactivate (client);
jack_client_close (client);
return 0;
/* everything was ok, so setting exitcode to 0 */
rc = 0;


error:
if (client)
jack_client_close (client);
return 1;
exit:
jack_client_close (client);
exit (rc);
} }


+ 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> #include <unistd.h>
#endif #endif
#include <string.h> #include <string.h>
#include <getopt.h>
#include <getopt.h>
#include <inttypes.h>
#include <jack/jack.h> #include <jack/jack.h>


char * my_name; char * my_name;
@@ -39,6 +40,7 @@ show_usage (void)
fprintf (stderr, "List active Jack ports, and optionally display extra information.\n"); fprintf (stderr, "List active Jack ports, and optionally display extra information.\n");
fprintf (stderr, "Optionally filter ports which match ALL strings provided after any options.\n\n"); fprintf (stderr, "Optionally filter ports which match ALL strings provided after any options.\n\n");
fprintf (stderr, "Display options:\n"); fprintf (stderr, "Display options:\n");
fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n");
fprintf (stderr, " -A, --aliases List aliases for each port\n"); fprintf (stderr, " -A, --aliases List aliases for each port\n");
fprintf (stderr, " -c, --connections List connections to/from each port\n"); fprintf (stderr, " -c, --connections List connections to/from each port\n");
fprintf (stderr, " -l, --latency Display per-port latency in frames at each port\n"); fprintf (stderr, " -l, --latency Display per-port latency in frames at each port\n");
@@ -56,6 +58,7 @@ main (int argc, char *argv[])
{ {
jack_client_t *client; jack_client_t *client;
jack_status_t status; jack_status_t status;
jack_options_t options = JackNoStartServer;
const char **ports, **connections; const char **ports, **connections;
unsigned int i, j, k; unsigned int i, j, k;
int skip_port; int skip_port;
@@ -68,9 +71,11 @@ main (int argc, char *argv[])
int c; int c;
int option_index; int option_index;
char* aliases[2]; char* aliases[2];
char *server_name = NULL;
jack_port_t *port; jack_port_t *port;
struct option long_options[] = { struct option long_options[] = {
{ "server", 1, 0, 's' },
{ "aliases", 0, 0, 'A' }, { "aliases", 0, 0, 'A' },
{ "connections", 0, 0, 'c' }, { "connections", 0, 0, 'c' },
{ "port-latency", 0, 0, 'l' }, { "port-latency", 0, 0, 'l' },
@@ -89,8 +94,13 @@ main (int argc, char *argv[])
my_name ++; my_name ++;
} }


while ((c = getopt_long (argc, argv, "AclLphvt", long_options, &option_index)) >= 0) {
while ((c = getopt_long (argc, argv, "s:AclLphvt", long_options, &option_index)) >= 0) {
switch (c) { switch (c) {
case 's':
server_name = (char *) malloc (sizeof (char) * strlen(optarg));
strcpy (server_name, optarg);
options |= JackServerName;
break;
case 'A': case 'A':
aliases[0] = (char *) malloc (jack_port_name_size()); aliases[0] = (char *) malloc (jack_port_name_size());
aliases[1] = (char *) malloc (jack_port_name_size()); aliases[1] = (char *) malloc (jack_port_name_size());
@@ -131,7 +141,7 @@ main (int argc, char *argv[])
* specify JackNoStartServer. */ * specify JackNoStartServer. */
//JOQ: need a new server name option //JOQ: need a new server name option


client = jack_client_open ("lsp", JackNoStartServer, &status);
client = jack_client_open ("lsp", options, &status, server_name);
if (client == NULL) { if (client == NULL) {
if (status & JackServerFailed) { if (status & JackServerFailed) {
fprintf (stderr, "JACK server not running\n"); fprintf (stderr, "JACK server not running\n");
@@ -143,7 +153,7 @@ main (int argc, char *argv[])
} }


ports = jack_get_ports (client, NULL, NULL, 0); ports = jack_get_ports (client, NULL, NULL, 0);
if (!ports)
if (!ports)
goto error; goto error;


for (i = 0; ports && ports[i]; ++i) { for (i = 0; ports && ports[i]; ++i) {
@@ -168,19 +178,28 @@ main (int argc, char *argv[])
printf (" %s\n", aliases[i]); printf (" %s\n", aliases[i]);
} }
} }
if (show_con) { if (show_con) {
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) {
for (j = 0; connections[j]; j++) { for (j = 0; connections[j]; j++) {
printf (" %s\n", connections[j]); printf (" %s\n", connections[j]);
} }
free (connections); free (connections);
}
}
} }
if (show_port_latency) { if (show_port_latency) {
if (port) { if (port) {
printf (" port latency = %d frames\n",
jack_latency_range_t range;
printf (" port latency = %" PRIu32 " frames\n",
jack_port_get_latency (port)); jack_port_get_latency (port));

jack_port_get_latency_range (port, JackPlaybackLatency, &range);
printf (" port playback latency = [ %" PRIu32 " %" PRIu32 " ] frames\n",
range.min, range.max);

jack_port_get_latency_range (port, JackCaptureLatency, &range);
printf (" port capture latency = [ %" PRIu32 " %" PRIu32 " ] frames\n",
range.min, range.max);
} }
} }
if (show_total_latency) { if (show_total_latency) {
@@ -208,12 +227,7 @@ main (int argc, char *argv[])
if (flags & JackPortIsTerminal) { if (flags & JackPortIsTerminal) {
fputs ("terminal,", stdout); fputs ("terminal,", stdout);
} }
if (flags & JackPortIsActive) {
fputs ("active,", stdout);
} else {
fputs ("non-active,", stdout);
}

putc ('\n', stdout); putc ('\n', stdout);
} }
} }
@@ -225,7 +239,7 @@ main (int argc, char *argv[])
} }
} }
} }
error: error:
if (ports) if (ports)
jack_free (ports); jack_free (ports);


+ 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 bind_port = 0;
int redundancy = 1; int redundancy = 1;
jack_client_t *client; jack_client_t *client;
packet_cache * packcache = 0;


int state_connected = 0; int state_connected = 0;
int state_latency = 0; int state_latency = 0;
@@ -140,7 +141,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int
} }
if( bitdepth == 1000 ) { if( bitdepth == 1000 ) {
#if HAVE_CELT #if HAVE_CELT
#if HAVE_CELT_API_0_7
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL ); CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL );
capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) );
#else #else
@@ -183,7 +184,7 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int
} }
if( bitdepth == 1000 ) { if( bitdepth == 1000 ) {
#if HAVE_CELT #if HAVE_CELT
#if HAVE_CELT_API_0_7
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL ); CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL );
playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) );
#else #else
@@ -224,6 +225,9 @@ sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg)
static int latency_count = 0; static int latency_count = 0;
int retval = sync_state; int retval = sync_state;


if (! state_connected) {
return 1;
}
if (latency_count) { if (latency_count) {
latency_count--; latency_count--;
retval = 0; retval = 0;
@@ -329,7 +333,7 @@ process (jack_nframes_t nframes, void *arg)
else if (cont_miss > 50+5*latency) else if (cont_miss > 50+5*latency)
{ {
state_connected = 0; state_connected = 0;
packet_cache_reset_master_address( global_packcache );
packet_cache_reset_master_address( packcache );
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
cont_miss = 0; cont_miss = 0;
} }
@@ -355,19 +359,19 @@ process (jack_nframes_t nframes, void *arg)
if ( ! netjack_poll_deadline( input_fd, deadline ) ) if ( ! netjack_poll_deadline( input_fd, deadline ) )
break; break;


packet_cache_drain_socket(global_packcache, input_fd);
packet_cache_drain_socket(packcache, input_fd);


if (packet_cache_get_next_available_framecnt( global_packcache, framecnt - latency, &got_frame ))
if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame ))
if( got_frame == (framecnt - latency) ) if( got_frame == (framecnt - latency) )
break; break;
} }
} else { } else {
// normally: // normally:
// only drain socket. // only drain socket.
packet_cache_drain_socket(global_packcache, input_fd);
packet_cache_drain_socket(packcache, input_fd);
} }


size = packet_cache_retreive_packet_pointer( global_packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp );
size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp );
/* First alternative : we received what we expected. Render the data /* First alternative : we received what we expected. Render the data
* to the JACK ports so it can be played. */ * to the JACK ports so it can be played. */
if (size == rx_bufsize) if (size == rx_bufsize)
@@ -394,7 +398,7 @@ process (jack_nframes_t nframes, void *arg)
state_recv_packet_queue_time = recv_time_offset; state_recv_packet_queue_time = recv_time_offset;
state_connected = 1; state_connected = 1;
sync_state = pkthdr_rx->sync_state; sync_state = pkthdr_rx->sync_state;
packet_cache_release_packet( global_packcache, framecnt - latency );
packet_cache_release_packet( packcache, framecnt - latency );
} }
/* Second alternative : we've received something that's not /* Second alternative : we've received something that's not
* as big as expected or we missed a packet. We render silence * as big as expected or we missed a packet. We render silence
@@ -402,7 +406,7 @@ process (jack_nframes_t nframes, void *arg)
else else
{ {
jack_nframes_t latency_estimate; jack_nframes_t latency_estimate;
if( packet_cache_find_latency( global_packcache, framecnt, &latency_estimate ) )
if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) )
//if( (state_latency == 0) || (latency_estimate < state_latency) ) //if( (state_latency == 0) || (latency_estimate < state_latency) )
state_latency = latency_estimate; state_latency = latency_estimate;


@@ -468,7 +472,7 @@ process (jack_nframes_t nframes, void *arg)
else if (cont_miss > 50+5*latency) else if (cont_miss > 50+5*latency)
{ {
state_connected = 0; state_connected = 0;
packet_cache_reset_master_address( global_packcache );
packet_cache_reset_master_address( packcache );
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
cont_miss = 0; cont_miss = 0;
} }
@@ -501,12 +505,11 @@ init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t por
if (hostinfo == NULL) { if (hostinfo == NULL) {
fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname); fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname);
fflush( stderr ); fflush( stderr );
return;
} }
#ifdef WIN32 #ifdef WIN32
name->sin_addr.s_addr = inet_addr( hostname );
name->sin_addr.s_addr = inet_addr( hostname );
#else #else
name->sin_addr = *(struct in_addr *) hostinfo->h_addr ;
name->sin_addr = *(struct in_addr *) hostinfo->h_addr ;
#endif #endif
} }
else else
@@ -621,15 +624,15 @@ main (int argc, char *argv[])
case 'b': case 'b':
bitdepth = atoi (optarg); bitdepth = atoi (optarg);
break; break;
case 'c':
#if HAVE_CELT
bitdepth = 1000;
case 'c':
#if HAVE_CELT
bitdepth = 1000;
factor = atoi (optarg); factor = atoi (optarg);
#else
#else
printf( "not built with celt supprt\n" ); printf( "not built with celt supprt\n" );
exit(10); exit(10);
#endif
break;
#endif
break;
case 'm': case 'm':
mtu = atoi (optarg); mtu = atoi (optarg);
break; break;
@@ -676,17 +679,18 @@ main (int argc, char *argv[])
} }


init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port);
if (bind_port) {
if(bind_port) {
init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port);
if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) {
fprintf (stderr, "bind failure\n" );
}
fprintf (stderr, "bind failure\n" );
}
} }
if (reply_port) {
if(reply_port)
{
init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port);
if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) {
fprintf (stderr, "bind failure\n" );
}
fprintf (stderr, "bind failure\n" );
}
} }


/* try to become a client of the JACK server */ /* try to become a client of the JACK server */
@@ -712,7 +716,7 @@ main (int argc, char *argv[])
net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor); net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor);


int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
global_packcache = packet_cache_new (latency + 50, rx_bufsize, mtu);
packcache = packet_cache_new (latency + 50, rx_bufsize, mtu);


/* tell the JACK server that we are ready to roll */ /* tell the JACK server that we are ready to roll */
if (jack_activate (client)) if (jack_activate (client))
@@ -778,6 +782,6 @@ main (int argc, char *argv[])
} }


jack_client_close (client); jack_client_close (client);
packet_cache_free (global_packcache);
packet_cache_free (packcache);
exit (0); exit (0);
} }

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

@@ -25,12 +25,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <jack/jack.h> #include <jack/jack.h>
#include <jack/types.h>
#include <jack/jslist.h> #include <jack/jslist.h>
#include <jack/transport.h> #include <jack/transport.h>
#include <jack/session.h> #include <jack/session.h>


char *package; /* program name */
char *package; /* program name */
jack_client_t *client; jack_client_t *client;


jack_session_event_type_t notify_type; jack_session_event_type_t notify_type;
@@ -38,147 +37,145 @@ char *save_path = NULL;


void jack_shutdown(void *arg) void jack_shutdown(void *arg)
{ {
fprintf(stderr, "JACK shut down, exiting ...\n");
exit(1);
fprintf(stderr, "JACK shut down, exiting ...\n");
exit(1);
} }


void signal_handler(int sig) void signal_handler(int sig)
{ {
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
} }


void parse_arguments(int argc, char *argv[]) void parse_arguments(int argc, char *argv[])
{ {


/* basename $0 */
package = strrchr(argv[0], '/');
if (package == 0)
package = argv[0];
else
package++;
if (argc==2) {
if( !strcmp( argv[1], "quit" ) ) {
notify_type = JackSessionSaveAndQuit;
return;
}
}
if (argc==3) {
if( !strcmp( argv[1], "save" ) ) {
notify_type = JackSessionSave;
save_path = argv[2];
return;
}
}
fprintf(stderr, "usage: %s quit|save [path]\n", package);
exit(9);
/* basename $0 */
package = strrchr(argv[0], '/');
if (package == 0)
package = argv[0];
else
package++;
if (argc==2) {
if( !strcmp( argv[1], "quit" ) ) {
notify_type = JackSessionSaveAndQuit;
return;
}
}
if (argc==3) {
if( !strcmp( argv[1], "save" ) ) {
notify_type = JackSessionSave;
save_path = argv[2];
return;
}
}
fprintf(stderr, "usage: %s quit|save [path]\n", package);
exit(9);
} }


typedef struct { typedef struct {
char name[32];
char uuid[16];
char name[32];
char uuid[16];
} uuid_map_t; } uuid_map_t;


JSList *uuid_map = NULL; JSList *uuid_map = NULL;


void add_uuid_mapping( const char *uuid ) { void add_uuid_mapping( const char *uuid ) {
char *clientname = jack_get_client_name_by_uuid( client, uuid );
if( !clientname ) {
printf( "error... cant find client for uuid %s", uuid );

return;
}

uuid_map_t *mapping = malloc( sizeof(uuid_map_t) );
snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid );
snprintf( mapping->name, sizeof(mapping->name), "%s", clientname );
uuid_map = jack_slist_append( uuid_map, mapping );
char *clientname = jack_get_client_name_by_uuid( client, uuid );
if( !clientname ) {
printf( "error... cant find client for uuid" );
return;
}

uuid_map_t *mapping = malloc( sizeof(uuid_map_t) );
snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid );
snprintf( mapping->name, sizeof(mapping->name), "%s", clientname );
uuid_map = jack_slist_append( uuid_map, mapping );
} }


char *map_port_name_to_uuid_port( const char *port_name ) char *map_port_name_to_uuid_port( const char *port_name )
{ {
JSList *node;
char retval[300];
char *port_component = strchr( port_name,':' );
char *client_component = strdup( port_name );
strchr( client_component, ':' )[0] = '\0';
sprintf( retval, "%s", port_name );
for( node=uuid_map; node; node=jack_slist_next(node) ) {
uuid_map_t *mapping = node->data;
if( !strcmp( mapping->name, client_component ) ) {
sprintf( retval, "%s%s", mapping->uuid, port_component );
break;
}
}
return strdup(retval);
JSList *node;
char retval[300];
char *port_component = strchr( port_name,':' );
char *client_component = strdup( port_name );
strchr( client_component, ':' )[0] = '\0';
sprintf( retval, "%s", port_name );
for( node=uuid_map; node; node=jack_slist_next(node) ) {
uuid_map_t *mapping = node->data;
if( !strcmp( mapping->name, client_component ) ) {
sprintf( retval, "%s%s", mapping->uuid, port_component );
break;
}
}
return strdup(retval);
} }


int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
parse_arguments(argc, argv);
jack_session_command_t *retval;
int k,i,j;


/* become a JACK client */
if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) {
fprintf(stderr, "JACK server not running?\n");
exit(1);
}

signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);

jack_on_shutdown(client, jack_shutdown, 0);

jack_activate(client);


retval = jack_session_notify( client, NULL, notify_type, save_path );
printf( "retval = %p\n", retval );
for(i=0; retval[i].uuid; i++ ) {
printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name );
printf( "%s &\n", retval[i].command );
add_uuid_mapping(retval[i].uuid);
}

printf( "sleep 10\n" );

for(k=0; retval[k].uuid; k++ ) {

char* port_regexp = alloca( jack_client_name_size()+3 );
char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid );
snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name );
jack_free(client_name);
const char **ports = jack_get_ports( client, port_regexp, NULL, 0 );
if( !ports ) {
continue;
}
for (i = 0; ports[i]; ++i) {
const char **connections;
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) {
for (j = 0; connections[j]; j++) {
char *src = map_port_name_to_uuid_port( ports[i] );
char *dst = map_port_name_to_uuid_port( connections[j] );
printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst );
}
jack_free (connections);
}
}
jack_free(ports);

}
jack_session_commands_free(retval);

jack_client_close(client);

return 0;
parse_arguments(argc, argv);
jack_session_command_t *retval;
int k,i,j;


/* become a JACK client */
if ((client = jack_client_open(package, JackNullOption, NULL)) == 0) {
fprintf(stderr, "JACK server not running?\n");
exit(1);
}

signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);

jack_on_shutdown(client, jack_shutdown, 0);

jack_activate(client);


retval = jack_session_notify( client, NULL, notify_type, save_path );
for(i=0; retval[i].uuid; i++ ) {
printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name );
printf( "%s &\n", retval[i].command );
add_uuid_mapping(retval[i].uuid);
}

printf( "sleep 10\n" );

for(k=0; retval[k].uuid; k++ ) {

char* port_regexp = alloca( jack_client_name_size()+3 );
char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid );
snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name );
jack_free(client_name);
const char **ports = jack_get_ports( client, port_regexp, NULL, 0 );
if( !ports ) {
continue;
}
for (i = 0; ports[i]; ++i) {
const char **connections;
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) {
for (j = 0; connections[j]; j++) {
char *src = map_port_name_to_uuid_port( ports[i] );
char *dst = map_port_name_to_uuid_port( connections[j] );
printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst );
}
jack_free (connections);
}
}
jack_free(ports);

}
jack_session_commands_free(retval);

jack_client_close(client);

return 0;
} }

+ 2
- 6
example-clients/wscript View File

@@ -27,6 +27,8 @@ example_programs = {
'jack_server_control' : 'server_control.cpp', 'jack_server_control' : 'server_control.cpp',
'jack_net_slave' : 'netslave.c', 'jack_net_slave' : 'netslave.c',
'jack_net_master' : 'netmaster.c', 'jack_net_master' : 'netmaster.c',
'jack_latent_client' : 'latent_client.c',
'jack_midi_dump' : 'midi_dump.c',
} }


example_libs = { example_libs = {
@@ -130,12 +132,6 @@ def build(bld):
prog.includes = os_incdir + ['../common/jack', '../common'] prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = ['netsource.c', '../common/netjack_packet.c'] prog.source = ['netsource.c', '../common/netjack_packet.c']
prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR")
# Seems uneeded here...
#if bld.env['HAVE_CELT']:
#if bld.env['HAVE_CELT_API_0_5']:
# prog.defines = ['HAVE_CELT', 'HAVE_CELT_API_0_5']
#elif bld.env['HAVE_CELT_API_0_7']:
# prog.defines = ['HAVE_CELT', 'HAVE_CELT_API_0_7']
prog.uselib = 'CELT SAMPLERATE' prog.uselib = 'CELT SAMPLERATE'
prog.uselib_local = 'clientlib' prog.uselib_local = 'clientlib'
prog.target = 'jack_netsource' prog.target = 'jack_netsource'


+ 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 #endif





#if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__) #if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__)
#warning using builtin gcc (version > 4.1) atomic


static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
{ {
return __sync_bool_compare_and_swap (&addr, value, newvalue);
return __sync_bool_compare_and_swap ((UInt32*)addr, value, newvalue);
} }
#endif #endif




+ 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 <string.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h>


static jack_time_t __jack_cpu_mhz = 0; static jack_time_t __jack_cpu_mhz = 0;
jack_time_t (*_jack_get_microseconds)(void) = 0; jack_time_t (*_jack_get_microseconds)(void) = 0;


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

@@ -276,7 +276,7 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
} else { } else {
driver->channel_copy = memcpy_fake; driver->channel_copy = memcpy_fake;
} }
switch (driver->dither) { switch (driver->dither) {
case Rectangular: case Rectangular:
jack_info("Rectangular dithering at 16 bits"); jack_info("Rectangular dithering at 16 bits");
@@ -284,42 +284,42 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
sample_move_dither_rect_d16_sSs: sample_move_dither_rect_d16_sSs:
sample_move_dither_rect_d16_sS; sample_move_dither_rect_d16_sS;
break; break;
case Triangular: case Triangular:
jack_info("Triangular dithering at 16 bits"); jack_info("Triangular dithering at 16 bits");
driver->write_via_copy = driver->quirk_bswap? driver->write_via_copy = driver->quirk_bswap?
sample_move_dither_tri_d16_sSs: sample_move_dither_tri_d16_sSs:
sample_move_dither_tri_d16_sS; sample_move_dither_tri_d16_sS;
break; break;
case Shaped: case Shaped:
jack_info("Noise-shaped dithering at 16 bits"); jack_info("Noise-shaped dithering at 16 bits");
driver->write_via_copy = driver->quirk_bswap? driver->write_via_copy = driver->quirk_bswap?
sample_move_dither_shaped_d16_sSs: sample_move_dither_shaped_d16_sSs:
sample_move_dither_shaped_d16_sS; sample_move_dither_shaped_d16_sS;
break; break;
default: default:
driver->write_via_copy = driver->quirk_bswap? driver->write_via_copy = driver->quirk_bswap?
sample_move_d16_sSs :
sample_move_d16_sSs :
sample_move_d16_sS; sample_move_d16_sS;
break; break;
} }
break; break;
case 3: /* NO DITHER */ case 3: /* NO DITHER */
if (driver->playback_interleaved) { if (driver->playback_interleaved) {
driver->channel_copy = memcpy_interleave_d24_s24; driver->channel_copy = memcpy_interleave_d24_s24;
} else { } else {
driver->channel_copy = memcpy_fake; driver->channel_copy = memcpy_fake;
} }
driver->write_via_copy = driver->quirk_bswap? driver->write_via_copy = driver->quirk_bswap?
sample_move_d24_sSs:
sample_move_d24_sSs:
sample_move_d24_sS; sample_move_d24_sS;


break; break;
case 4: /* NO DITHER */ case 4: /* NO DITHER */
if (driver->playback_interleaved) { if (driver->playback_interleaved) {
driver->channel_copy = memcpy_interleave_d32_s32; driver->channel_copy = memcpy_interleave_d32_s32;
@@ -328,7 +328,7 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
} }


driver->write_via_copy = driver->quirk_bswap? driver->write_via_copy = driver->quirk_bswap?
sample_move_d32u24_sSs:
sample_move_d32u24_sSs:
sample_move_d32u24_sS; sample_move_d32u24_sS;
break; break;


@@ -339,27 +339,27 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
} }
} }
} }
if (driver->capture_handle) { if (driver->capture_handle) {
switch (driver->capture_sample_bytes) { switch (driver->capture_sample_bytes) {
case 2: case 2:
driver->read_via_copy = driver->quirk_bswap? driver->read_via_copy = driver->quirk_bswap?
sample_move_dS_s16s:
sample_move_dS_s16s:
sample_move_dS_s16; sample_move_dS_s16;
break; break;
case 3: case 3:
driver->read_via_copy = driver->quirk_bswap? driver->read_via_copy = driver->quirk_bswap?
sample_move_dS_s24s:
sample_move_dS_s24s:
sample_move_dS_s24; sample_move_dS_s24;
break; break;
case 4: case 4:
driver->read_via_copy = driver->quirk_bswap? driver->read_via_copy = driver->quirk_bswap?
sample_move_dS_s32u24s:
sample_move_dS_s32u24s:
sample_move_dS_s32u24; sample_move_dS_s32u24;
break; break;
} }
} }
return 0; return 0;
} }


@@ -418,7 +418,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
} }
} }
} }
format = (sample_width == 4) ? 0 : NUMFORMATS - 1; format = (sample_width == 4) ? 0 : NUMFORMATS - 1;


while (1) { while (1) {
@@ -444,7 +444,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name);
break; break;
} }
}
}


frame_rate = driver->frame_rate ; frame_rate = driver->frame_rate ;
err = snd_pcm_hw_params_set_rate_near (handle, hw_params, err = snd_pcm_hw_params_set_rate_near (handle, hw_params,
@@ -464,7 +464,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
&channels_max); &channels_max);
*nchns = channels_max ; *nchns = channels_max ;


if (*nchns > 1024) {
if (*nchns > 1024) {


/* the hapless user is an unwitting victim of /* the hapless user is an unwitting victim of
the "default" ALSA PCM device, which can the "default" ALSA PCM device, which can
@@ -481,9 +481,9 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
"instead rather than using the plug layer. Usually the name of the\n" "instead rather than using the plug layer. Usually the name of the\n"
"hardware device that corresponds to the first sound card is hw:0\n" "hardware device that corresponds to the first sound card is hw:0\n"
); );
*nchns = 2;
*nchns = 2;
} }
}
}


if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, if ((err = snd_pcm_hw_params_set_channels (handle, hw_params,
*nchns)) < 0) { *nchns)) < 0) {
@@ -491,7 +491,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
*nchns, stream_name); *nchns, stream_name);
return -1; return -1;
} }
if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params,
driver->frames_per_cycle, driver->frames_per_cycle,
0)) 0))
@@ -520,7 +520,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
return -1; return -1;
} }
jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name);
#if 0
#if 0
if (!jack_power_of_two(driver->frames_per_cycle)) { if (!jack_power_of_two(driver->frames_per_cycle)) {
jack_error("JACK: frames must be a power of two " jack_error("JACK: frames must be a power of two "
"(64, 512, 1024, ...)\n"); "(64, 512, 1024, ...)\n");
@@ -557,7 +557,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
if (driver->soft_mode) { if (driver->soft_mode) {
stop_th = (snd_pcm_uframes_t)-1; stop_th = (snd_pcm_uframes_t)-1;
} }
if ((err = snd_pcm_sw_params_set_stop_threshold ( if ((err = snd_pcm_sw_params_set_stop_threshold (
handle, sw_params, stop_th)) < 0) { handle, sw_params, stop_th)) < 0) {
jack_error ("ALSA: cannot set stop mode for %s", jack_error ("ALSA: cannot set stop mode for %s",
@@ -594,7 +594,7 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic
else else
err = snd_pcm_sw_params_set_avail_min ( err = snd_pcm_sw_params_set_avail_min (
handle, sw_params, driver->frames_per_cycle); handle, sw_params, driver->frames_per_cycle);
if (err < 0) { if (err < 0) {
jack_error ("ALSA: cannot set avail min for %s", stream_name); jack_error ("ALSA: cannot set avail min for %s", stream_name);
return -1; return -1;
@@ -1158,7 +1158,7 @@ int
JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver)
{ {
int res; int res;
driver->xrun_recovery = 1; driver->xrun_recovery = 1;
if ((res = Stop()) == 0) if ((res = Stop()) == 0)
res = Start(); res = Start();
@@ -1189,11 +1189,24 @@ JackAlsaDriver::alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed
} }
} }


if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SUSPENDED) {
jack_error("**** alsa_pcm: pcm in suspended state, resuming it" );
if (driver->capture_handle) {
if ((res = snd_pcm_prepare(driver->capture_handle)) < 0) {
jack_error("error preparing after suspend: %s", snd_strerror(res));
}
} else {
if ((res = snd_pcm_prepare(driver->playback_handle)) < 0) {
jack_error("error preparing after suspend: %s", snd_strerror(res));
}
}
}

if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN
&& driver->process_count > XRUN_REPORT_DELAY) { && driver->process_count > XRUN_REPORT_DELAY) {
struct timeval now, diff, tstamp; struct timeval now, diff, tstamp;
driver->xrun_count++; driver->xrun_count++;
snd_pcm_status_get_tstamp(status,&now);
snd_pcm_status_get_tstamp(status,&now);
snd_pcm_status_get_trigger_tstamp(status, &tstamp); snd_pcm_status_get_trigger_tstamp(status, &tstamp);
timersub(&now, &tstamp, &diff); timersub(&now, &tstamp, &diff);
*delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec;
@@ -1253,7 +1266,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
} }


again: again:
while (need_playback || need_capture) { while (need_playback || need_capture) {


int poll_result; int poll_result;
@@ -1269,7 +1282,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
driver->playback_nfds); driver->playback_nfds);
nfds += driver->playback_nfds; nfds += driver->playback_nfds;
} }
if (need_capture) { if (need_capture) {
snd_pcm_poll_descriptors (driver->capture_handle, snd_pcm_poll_descriptors (driver->capture_handle,
&driver->pfd[nfds], &driver->pfd[nfds],
@@ -1279,7 +1292,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
} }


/* ALSA doesn't set POLLERR in some versions of 0.9.X */ /* ALSA doesn't set POLLERR in some versions of 0.9.X */
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
driver->pfd[i].events |= POLLERR; driver->pfd[i].events |= POLLERR;
} }
@@ -1316,12 +1329,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
*status = -2; *status = -2;
return 0; return 0;
} }
jack_error ("ALSA: poll call failed (%s)", jack_error ("ALSA: poll call failed (%s)",
strerror (errno)); strerror (errno));
*status = -3; *status = -3;
return 0; return 0;
} }


poll_ret = jack_get_microseconds (); poll_ret = jack_get_microseconds ();
@@ -1332,12 +1345,12 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
if (extra_fd < 0) { if (extra_fd < 0) {
if (driver->poll_next && poll_ret > driver->poll_next) { if (driver->poll_next && poll_ret > driver->poll_next) {
*delayed_usecs = poll_ret - driver->poll_next; *delayed_usecs = poll_ret - driver->poll_next;
}
}
driver->poll_last = poll_ret; driver->poll_last = poll_ret;
driver->poll_next = poll_ret + driver->period_usecs; driver->poll_next = poll_ret + driver->period_usecs;
// steph // steph
/* /*
driver->engine->transport_cycle_start (driver->engine,
driver->engine->transport_cycle_start (driver->engine,
poll_ret); poll_ret);
*/ */
} }
@@ -1358,7 +1371,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat


*status = -4; *status = -4;
return -1; return -1;
}
}


/* if POLLIN was the only bit set, we're OK */ /* if POLLIN was the only bit set, we're OK */


@@ -1414,14 +1427,14 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
#endif #endif
} }
} }
if (poll_result == 0) { if (poll_result == 0) {
jack_error ("ALSA: poll time out, polled for %" PRIu64 jack_error ("ALSA: poll time out, polled for %" PRIu64
" usecs", " usecs",
poll_ret - poll_enter); poll_ret - poll_enter);
*status = -5; *status = -5;
return 0; return 0;
}
}


} }


@@ -1437,7 +1450,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
} }
} else { } else {
/* odd, but see min() computation below */ /* odd, but see min() computation below */
capture_avail = INT_MAX;
capture_avail = INT_MAX;
} }


if (driver->playback_handle) { if (driver->playback_handle) {
@@ -1452,7 +1465,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat
} }
} else { } else {
/* odd, but see min() computation below */ /* odd, but see min() computation below */
playback_avail = INT_MAX;
playback_avail = INT_MAX;
} }


if (xrun_detected) { if (xrun_detected) {
@@ -1531,7 +1544,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
if (!driver->capture_handle) { if (!driver->capture_handle) {
return 0; return 0;
} }
nread = 0; nread = 0;
contiguous = 0; contiguous = 0;
orig_nframes = nframes; orig_nframes = nframes;
@@ -1559,11 +1572,11 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
/* // steph /* // steph
for (chn = 0, node = driver->capture_ports; node; for (chn = 0, node = driver->capture_ports; node;
node = jack_slist_next (node), chn++) { node = jack_slist_next (node), chn++) {
port = (jack_port_t *) node->data; port = (jack_port_t *) node->data;
if (!jack_port_connected (port)) { if (!jack_port_connected (port)) {
// no-copy optimization
// no-copy optimization
continue; continue;
} }
buf = jack_port_get_buffer (port, orig_nframes); buf = jack_port_get_buffer (port, orig_nframes);
@@ -1574,7 +1587,7 @@ JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)


if ((err = snd_pcm_mmap_commit (driver->capture_handle, if ((err = snd_pcm_mmap_commit (driver->capture_handle,
offset, contiguous)) < 0) { offset, contiguous)) < 0) {
jack_error ("ALSA: could not complete read of %" jack_error ("ALSA: could not complete read of %"
PRIu32 " frames: error = %d\n", contiguous, err); PRIu32 " frames: error = %d\n", contiguous, err);
return -1; return -1;
@@ -1702,7 +1715,7 @@ JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes
} }
monbuf = jack_port_get_buffer (port, orig_nframes); monbuf = jack_port_get_buffer (port, orig_nframes);
memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t));
mon_node = jack_slist_next (mon_node);
mon_node = jack_slist_next (mon_node);
} }
} }
*/ */
@@ -1716,7 +1729,7 @@ JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes
offset, contiguous)) < 0) { offset, contiguous)) < 0) {
jack_error ("ALSA: could not complete playback of %" jack_error ("ALSA: could not complete playback of %"
PRIu32 " frames: error = %d", contiguous, err); PRIu32 " frames: error = %d", contiguous, err);
if (err != EPIPE && err != ESTRPIPE)
if (err != -EPIPE && err != -ESTRPIPE)
return -1; return -1;
} }


@@ -1739,11 +1752,11 @@ JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver)
free (node->data); free (node->data);
} }
jack_slist_free (driver->clock_sync_listeners); jack_slist_free (driver->clock_sync_listeners);
if (driver->ctl_handle) { if (driver->ctl_handle) {
snd_ctl_close (driver->ctl_handle); snd_ctl_close (driver->ctl_handle);
driver->ctl_handle = 0; driver->ctl_handle = 0;
}
}


if (driver->capture_handle) { if (driver->capture_handle) {
snd_pcm_close (driver->capture_handle); snd_pcm_close (driver->capture_handle);
@@ -1821,14 +1834,14 @@ JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device,
jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32
"|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s",
playing ? playback_alsa_device : "-", playing ? playback_alsa_device : "-",
capturing ? capture_alsa_device : "-",
capturing ? capture_alsa_device : "-",
frames_per_cycle, user_nperiods, rate, frames_per_cycle, user_nperiods, rate,
user_capture_nchnls,user_playback_nchnls, user_capture_nchnls,user_playback_nchnls,
hw_monitoring ? "hwmon": "nomon", hw_monitoring ? "hwmon": "nomon",
hw_metering ? "hwmeter":"swmeter", hw_metering ? "hwmeter":"swmeter",
soft_mode ? "soft-mode":"-", soft_mode ? "soft-mode":"-",
shorts_first ? "16bit":"32bit"); shorts_first ? "16bit":"32bit");
driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t));


jack_driver_nt_init ((jack_driver_nt_t *) driver); jack_driver_nt_init ((jack_driver_nt_t *) driver);
@@ -1862,8 +1875,8 @@ JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device,


driver->playback_addr = 0; driver->playback_addr = 0;
driver->capture_addr = 0; driver->capture_addr = 0;
driver->playback_interleave_skip = NULL;
driver->capture_interleave_skip = NULL;
driver->playback_interleave_skip = NULL;
driver->capture_interleave_skip = NULL;


driver->silent = 0; driver->silent = 0;
driver->all_monitor_in = FALSE; driver->all_monitor_in = FALSE;
@@ -2071,6 +2084,7 @@ int JackAlsaDriver::Attach()
unsigned long port_flags; unsigned long port_flags;
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
jack_latency_range_t range;


assert(fCaptureChannels < DRIVER_PORT_NUM); assert(fCaptureChannels < DRIVER_PORT_NUM);
assert(fPlaybackChannels < DRIVER_PORT_NUM); assert(fPlaybackChannels < DRIVER_PORT_NUM);
@@ -2097,7 +2111,8 @@ int JackAlsaDriver::Attach()
} }
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetAlias(alias); port->SetAlias(alias);
port->SetLatency(alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency);
range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency;
port->SetLatencyRange(JackCaptureLatency, &range);
fCapturePortList[i] = port_index; fCapturePortList[i] = port_index;
jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index); jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index);
} }
@@ -2114,8 +2129,10 @@ int JackAlsaDriver::Attach()
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetAlias(alias); port->SetAlias(alias);
// Add one buffer more latency if "async" mode is used... // Add one buffer more latency if "async" mode is used...
port->SetLatency((alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) +
((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency);
range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) +
((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency;

port->SetLatencyRange(JackPlaybackLatency, &range);
fPlaybackPortList[i] = port_index; fPlaybackPortList[i] = port_index;
jack_log("JackAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index); jack_log("JackAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index);


@@ -2127,7 +2144,8 @@ int JackAlsaDriver::Attach()
jack_error ("ALSA: cannot register monitor port for %s", name); jack_error ("ALSA: cannot register monitor port for %s", name);
} else { } else {
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetLatency(alsa_driver->frames_per_cycle);
range.min = range.max = alsa_driver->frames_per_cycle;
port->SetLatencyRange(JackCaptureLatency, &range);
fMonitorPortList[i] = port_index; fMonitorPortList[i] = port_index;
} }
} }
@@ -2151,7 +2169,7 @@ int JackAlsaDriver::Detach()
return JackAudioDriver::Detach(); return JackAudioDriver::Detach();
} }


static int card_to_num(const char* device)
static int card_to_num(const char* device)
{ {
int err; int err;
char* ctl_name; char* ctl_name;
@@ -2316,13 +2334,13 @@ int JackAlsaDriver::Read()
retry: retry:


nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs);
if (wait_status < 0) if (wait_status < 0)
return -1; /* driver failed */ return -1; /* driver failed */


if (nframes == 0) { if (nframes == 0) {
/* we detected an xrun and restarted: notify /* we detected an xrun and restarted: notify
* clients about the delay.
* clients about the delay.
*/ */
jack_log("ALSA XRun wait_status = %d", wait_status); jack_log("ALSA XRun wait_status = %d", wait_status);
NotifyXRun(fBeginDateUst, fDelayedUsecs); NotifyXRun(fBeginDateUst, fDelayedUsecs);
@@ -2331,7 +2349,7 @@ retry:


if (nframes != fEngineControl->fBufferSize) if (nframes != fEngineControl->fBufferSize)
jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes); jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes);
// Has to be done before read // Has to be done before read
JackDriver::CycleIncTime(); JackDriver::CycleIncTime();


@@ -2619,7 +2637,7 @@ get_dither_constraint()
} }


static int static int
dither_opt (char c, DitherAlgorithm* dither)
dither_opt (char c, DitherAlgorithm* dither)
{ {
switch (c) { switch (c) {
case '-': case '-':
@@ -2646,17 +2664,17 @@ dither_opt (char c, DitherAlgorithm* dither)
return 0; return 0;
} }


SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
{ {
jack_driver_desc_t * desc; jack_driver_desc_t * desc;
jack_driver_param_desc_t * params; jack_driver_param_desc_t * params;
unsigned int i; unsigned int i;


desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
strcpy(desc->name, "alsa"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy(desc->name, "alsa"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "Linux ALSA API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 strcpy(desc->desc, "Linux ALSA API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
desc->nparams = 18; desc->nparams = 18;
params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));


@@ -2825,7 +2843,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
return desc; return desc;
} }


SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
{ {
jack_nframes_t srate = 48000; jack_nframes_t srate = 48000;
jack_nframes_t frames_per_interrupt = 1024; jack_nframes_t frames_per_interrupt = 1024;


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

@@ -104,7 +104,7 @@ typedef struct input_port_t {


// jack // jack
midi_unpack_t unpack; midi_unpack_t unpack;
// midi // midi
int overruns; int overruns;
} input_port_t; } input_port_t;
@@ -114,7 +114,7 @@ typedef struct output_port_t {


// jack // jack
midi_pack_t packer; midi_pack_t packer;
// midi // midi
event_head_t next_event; event_head_t next_event;
int todo; int todo;
@@ -425,16 +425,16 @@ static
inline int midi_port_open_jack(alsa_rawmidi_t *midi, midi_port_t *port, int type, const char *alias) inline int midi_port_open_jack(alsa_rawmidi_t *midi, midi_port_t *port, int type, const char *alias)
{ {
char name[128]; char name[128];
if (type & JackPortIsOutput) if (type & JackPortIsOutput)
snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++midi->midi_in_cnt); snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++midi->midi_in_cnt);
else
else
snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++midi->midi_out_cnt); snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++midi->midi_out_cnt);


port->jack = jack_port_register(midi->client, name, JACK_DEFAULT_MIDI_TYPE, port->jack = jack_port_register(midi->client, name, JACK_DEFAULT_MIDI_TYPE,
type | JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive, 0);
if (port->jack)
type | JackPortIsPhysical | JackPortIsTerminal, 0);
if (port->jack)
jack_port_set_alias(port->jack, alias); jack_port_set_alias(port->jack, alias);
return port->jack == NULL; return port->jack == NULL;
} }
@@ -455,7 +455,7 @@ int midi_port_open(alsa_rawmidi_t *midi, midi_port_t *port)
out = &port->rawmidi; out = &port->rawmidi;
type = JackPortIsInput; type = JackPortIsInput;
} }
if ((err = snd_rawmidi_open(in, out, port->dev, SND_RAWMIDI_NONBLOCK))<0) if ((err = snd_rawmidi_open(in, out, port->dev, SND_RAWMIDI_NONBLOCK))<0)
return err; return err;


@@ -749,7 +749,7 @@ void* scan_thread(void *arg)
return NULL; return NULL;
} }


/*
/*
* ------------------------------- Input/Output ------------------------------ * ------------------------------- Input/Output ------------------------------
*/ */


@@ -836,7 +836,7 @@ void *midi_thread(void *arg)
npfds = 1; npfds = 1;


if (jack_is_realtime(midi->client)) if (jack_is_realtime(midi->client))
set_threaded_log_function();
set_threaded_log_function();


//debug_log("midi_thread(%s): enter", str->name); //debug_log("midi_thread(%s): enter", str->name);


@@ -978,7 +978,7 @@ int midi_update_pfds(process_midi_t *proc)
return 1; return 1;
} }


/*
/*
* ------------------------------------ Input ------------------------------ * ------------------------------------ Input ------------------------------
*/ */


@@ -1083,7 +1083,7 @@ int do_midi_input(process_midi_t *proc)
return 1; return 1;
} }


/*
/*
* ------------------------------------ Output ------------------------------ * ------------------------------------ Output ------------------------------
*/ */


@@ -1149,7 +1149,7 @@ int do_midi_output(process_midi_t *proc)
} else } else
debug_log("midi_out: at %ld got %d bytes for %ld", (long)proc->cur_time, (int)port->next_event.size, (long)port->next_event.time); debug_log("midi_out: at %ld got %d bytes for %ld", (long)proc->cur_time, (int)port->next_event.size, (long)port->next_event.time);
} }
if (port->todo) if (port->todo)
debug_log("midi_out: todo = %d at %ld", (int)port->todo, (long)proc->cur_time); debug_log("midi_out: todo = %d at %ld", (int)port->todo, (long)proc->cur_time);




+ 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->client_id = snd_seq_client_id(self->seq);


self->queue = snd_seq_alloc_queue(self->seq); self->queue = snd_seq_alloc_queue(self->seq);
snd_seq_start_queue(self->seq, self->queue, 0);
snd_seq_start_queue(self->seq, self->queue, 0);


stream_attach(self, PORT_INPUT); stream_attach(self, PORT_INPUT);
stream_attach(self, PORT_OUTPUT); stream_attach(self, PORT_OUTPUT);
@@ -488,14 +488,14 @@ port_t* port_create(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, const s
/* mark anything that looks like a hardware port as physical&terminal */ /* mark anything that looks like a hardware port as physical&terminal */


if (snd_seq_port_info_get_type (info) & (SND_SEQ_PORT_TYPE_HARDWARE|SND_SEQ_PORT_TYPE_PORT|SND_SEQ_PORT_TYPE_SPECIFIC)) { if (snd_seq_port_info_get_type (info) & (SND_SEQ_PORT_TYPE_HARDWARE|SND_SEQ_PORT_TYPE_PORT|SND_SEQ_PORT_TYPE_SPECIFIC)) {
jack_caps |= (JackPortIsPhysical | JackPortIsTerminal | JackPortIsActive);
jack_caps |= (JackPortIsPhysical | JackPortIsTerminal);
} }


if (jack_caps & JackPortIsOutput) if (jack_caps & JackPortIsOutput)
snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt); snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt);
else
else
snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt); snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt);
port->jack_port = jack_port_register(self->jack, port->jack_port = jack_port_register(self->jack,
name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0); name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0);
if (!port->jack_port) if (!port->jack_port)
@@ -588,7 +588,7 @@ void update_ports(alsa_seqmidi_t *self)
snd_seq_port_info_alloca(&info); snd_seq_port_info_alloca(&info);


while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) { while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) {
int err; int err;


assert (size == sizeof(addr)); assert (size == sizeof(addr));
@@ -666,7 +666,7 @@ void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir,
info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec; info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec;


if (info->period_start + info->nframes < info->cur_frames) { if (info->period_start + info->nframes < info->cur_frames) {
int periods_lost = (info->cur_frames - info->period_start) / info->nframes;
int periods_lost = (info->cur_frames - info->period_start) / info->nframes;
info->period_start += periods_lost * info->nframes; info->period_start += periods_lost * info->nframes;
debug_log("xrun detected: %d periods lost\n", periods_lost); debug_log("xrun detected: %d periods lost\n", periods_lost);
} }
@@ -805,7 +805,7 @@ void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct proce
ev.size = size; ev.size = size;
jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev));
jack_ringbuffer_write(port->early_events, (char*)data, size); jack_ringbuffer_write(port->early_events, (char*)data, size);
debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes));
debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes));
return; return;
} }


@@ -829,7 +829,7 @@ void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes)
return; return;


set_process_info(&info, self, PORT_INPUT, nframes); set_process_info(&info, self, PORT_INPUT, nframes);
jack_process(self, &info);
jack_process(self, &info);


while ((res = snd_seq_event_input(self->seq, &event))>0) { while ((res = snd_seq_event_input(self->seq, &event))>0) {
if (event->source.client == SND_SEQ_CLIENT_SYSTEM) if (event->source.client == SND_SEQ_CLIENT_SYSTEM)


+ 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 Copyright (C) 2005 Karsten Wiese, Rui Nuno Capela


This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@@ -33,14 +33,14 @@
int dbg_offset; int dbg_offset;
char dbg_buffer[8096]; char dbg_buffer[8096];
#endif #endif
static
static
int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask)
{ {
return -1; return -1;
} }


static static
int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode)
int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode)
{ {
return -1; return -1;
} }
@@ -52,7 +52,7 @@ usx2y_release (jack_hardware_t *hw)


if (h == 0) if (h == 0)
return; return;
if (h->hwdep_handle) if (h->hwdep_handle)
snd_hwdep_close(h->hwdep_handle); snd_hwdep_close(h->hwdep_handle);


@@ -622,7 +622,7 @@ usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes)
offset, nframes_)) < 0) { offset, nframes_)) < 0) {
jack_error ("ALSA/USX2Y: could not complete playback of %" jack_error ("ALSA/USX2Y: could not complete playback of %"
PRIu32 " frames: error = %d", nframes_, err); PRIu32 " frames: error = %d", nframes_, err);
if (err != EPIPE && err != ESTRPIPE)
if (err != -EPIPE && err != -ESTRPIPE)
return -1; return -1;
} }




+ 0
- 18
linux/cycles.h View File

@@ -37,8 +37,6 @@
* regardless of how fast the machine is. * regardless of how fast the machine is.
*/ */


#ifdef __linux__

#ifdef __x86_64__ #ifdef __x86_64__


typedef unsigned long cycles_t; typedef unsigned long cycles_t;
@@ -127,21 +125,5 @@ static inline cycles_t get_cycles(void)


#endif /* everything else but x86, amd64, sparcv9 or ppc */ #endif /* everything else but x86, amd64, sparcv9 or ppc */


#endif /* __linux__ */


#if defined(__FreeBSD_kernel__)

#warning No suitable get_cycles() implementation. Returning 0 instead

typedef unsigned long long cycles_t;

static inline cycles_t get_cycles(void)
{
return 0;
}

#endif /* __FreeBSD_kernel__ */



#endif /* __jack_cycles_h__ */ #endif /* __jack_cycles_h__ */

+ 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!!!"); printError("Buffer size change requested but not supported!!!");


/* /*
driver->period_size = nframes;
driver->period_size = nframes;
driver->period_usecs = driver->period_usecs =
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) (jack_time_t) floor ((((float) nframes) / driver->sample_rate)
* 1000000.0f); * 1000000.0f);
@@ -362,6 +362,7 @@ int JackFFADODriver::Attach()
int port_index; int port_index;
char buf[JACK_PORT_NAME_SIZE]; char buf[JACK_PORT_NAME_SIZE];
char portname[JACK_PORT_NAME_SIZE]; char portname[JACK_PORT_NAME_SIZE];
jack_latency_range_t range;


ffado_driver_t* driver = (ffado_driver_t*)fDriver; ffado_driver_t* driver = (ffado_driver_t*)fDriver;


@@ -447,7 +448,8 @@ int JackFFADODriver::Attach()
ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); ffado_streaming_capture_stream_onoff(driver->dev, chn, 0);


port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetLatency(driver->period_size + driver->capture_frame_latency);
range.min = range.max = driver->period_size + driver->capture_frame_latency;
port->SetLatencyRange(JackCaptureLatency, &range);
// capture port aliases (jackd1 style port names) // capture port aliases (jackd1 style port names)
snprintf(buf, sizeof(buf) - 1, "%s:capture_%i", fClientControl.fName, (int) chn + 1); snprintf(buf, sizeof(buf) - 1, "%s:capture_%i", fClientControl.fName, (int) chn + 1);
port->SetAlias(buf); port->SetAlias(buf);
@@ -479,7 +481,8 @@ int JackFFADODriver::Attach()
driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t));


port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetLatency(driver->period_size + driver->capture_frame_latency);
range.min = range.max = driver->period_size + driver->capture_frame_latency;
port->SetLatencyRange(JackCaptureLatency, &range);
fCapturePortList[chn] = port_index; fCapturePortList[chn] = port_index;
jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index);
fCaptureChannels++; fCaptureChannels++;
@@ -523,7 +526,8 @@ int JackFFADODriver::Attach()


port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
// Add one buffer more latency if "async" mode is used... // Add one buffer more latency if "async" mode is used...
port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency);
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency
port->SetLatencyRange(JackPlaybackLatency, &range);
// playback port aliases (jackd1 style port names) // playback port aliases (jackd1 style port names)
snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1); snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1);
port->SetAlias(buf); port->SetAlias(buf);
@@ -549,7 +553,7 @@ int JackFFADODriver::Attach()
printError(" cannot enable port %s", buf); printError(" cannot enable port %s", buf);
} }
// setup the midi buffer // setup the midi buffer
// This constructor optionally accepts arguments for the // This constructor optionally accepts arguments for the
// non-realtime buffer size and the realtime buffer size. Ideally, // non-realtime buffer size and the realtime buffer size. Ideally,
// these would become command-line options for the FFADO driver. // these would become command-line options for the FFADO driver.
@@ -558,7 +562,8 @@ int JackFFADODriver::Attach()
driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t));


port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency);
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency;
port->SetLatencyRange(JackPlaybackLatency, &range);
fPlaybackPortList[chn] = port_index; fPlaybackPortList[chn] = port_index;
jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index);
fPlaybackChannels++; fPlaybackChannels++;
@@ -676,7 +681,7 @@ retry:


if (nframes == 0) { if (nframes == 0) {
/* we detected an xrun and restarted: notify /* we detected an xrun and restarted: notify
* clients about the delay.
* clients about the delay.
*/ */
jack_log("FFADO XRun"); jack_log("FFADO XRun");
NotifyXRun(fBeginDateUst, fDelayedUsecs); NotifyXRun(fBeginDateUst, fDelayedUsecs);
@@ -685,7 +690,7 @@ retry:


if (nframes != fEngineControl->fBufferSize) if (nframes != fEngineControl->fBufferSize)
jack_log("JackFFADODriver::Read warning nframes = %ld", nframes); jack_log("JackFFADODriver::Read warning nframes = %ld", nframes);
// Has to be done before read // Has to be done before read
JackDriver::CycleIncTime(); JackDriver::CycleIncTime();


@@ -755,7 +760,7 @@ extern "C"


strcpy (desc->name, "firewire"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy (desc->name, "firewire"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "Linux FFADO API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 strcpy(desc->desc, "Linux FFADO API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
desc->nparams = 13; desc->nparams = 13;


params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));


+ 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!!!"); printError("Buffer size change requested but not supported!!!");


/* /*
driver->period_size = nframes;
driver->period_size = nframes;
driver->period_usecs = driver->period_usecs =
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) (jack_time_t) floor ((((float) nframes) / driver->sample_rate)
* 1000000.0f); * 1000000.0f);
@@ -667,9 +667,10 @@ int JackFreebobDriver::Attach()
{ {
JackPort* port; JackPort* port;
int port_index; int port_index;
char buf[JACK_PORT_NAME_SIZE]; char buf[JACK_PORT_NAME_SIZE];
char portname[JACK_PORT_NAME_SIZE]; char portname[JACK_PORT_NAME_SIZE];
jack_latency_range_t range;


freebob_driver_t* driver = (freebob_driver_t*)fDriver; freebob_driver_t* driver = (freebob_driver_t*)fDriver;


@@ -737,7 +738,8 @@ int JackFreebobDriver::Attach()
return -1; return -1;
} }
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
port->SetLatency(driver->period_size + driver->capture_frame_latency);
range.min = range.max = driver->period_size + driver->capture_frame_latency;
port->SetLatencyRange(JackCaptureLatency, &range);
fCapturePortList[i] = port_index; fCapturePortList[i] = port_index;
jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index); jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index);
driver->capture_nchannels_audio++; driver->capture_nchannels_audio++;
@@ -766,7 +768,8 @@ int JackFreebobDriver::Attach()
} }
port = fGraphManager->GetPort(port_index); port = fGraphManager->GetPort(port_index);
// Add one buffer more latency if "async" mode is used... // Add one buffer more latency if "async" mode is used...
port->SetLatency((driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency);
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency);
port->SetLatencyRange(JackPlaybackLatency, &range);
fPlaybackPortList[i] = port_index; fPlaybackPortList[i] = port_index;
jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index); jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index);
driver->playback_nchannels_audio++; driver->playback_nchannels_audio++;
@@ -866,7 +869,7 @@ retry:


if (nframes == 0) { if (nframes == 0) {
/* we detected an xrun and restarted: notify /* we detected an xrun and restarted: notify
* clients about the delay.
* clients about the delay.
*/ */
jack_log("FreeBoB XRun"); jack_log("FreeBoB XRun");
NotifyXRun(fBeginDateUst, fDelayedUsecs); NotifyXRun(fBeginDateUst, fDelayedUsecs);
@@ -878,7 +881,7 @@ retry:


// Has to be done before read // Has to be done before read
JackDriver::CycleIncTime(); JackDriver::CycleIncTime();
printExit(); printExit();
return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize); return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize);
} }
@@ -944,7 +947,7 @@ extern "C"


strcpy (desc->name, "freebob"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy (desc->name, "freebob"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "Linux FreeBob API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 strcpy(desc->desc, "Linux FreeBob API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
desc->nparams = 11; desc->nparams = 11;


params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); params = (jack_driver_param_desc_t *)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));


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

@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>Jackservermp</string> <string>Jackservermp</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>Jackdmp 1.9.7, @03-10 Paul Davis, Grame</string>
<string>Jackdmp 1.9.7, @03-11 Paul Davis, Grame</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.grame.Jackmp</string> <string>com.grame.Jackmp</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>


+ 13
- 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
namespace Jack namespace Jack
{ {


int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint)
int JackMachThread::SetThreadToPriority(jack_native_thread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint)
{ {
if (inPriority == 96) { if (inPriority == 96) {
// REAL-TIME / TIME-CONSTRAINT THREAD // REAL-TIME / TIME-CONSTRAINT THREAD
@@ -73,18 +73,18 @@ int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boo
} }


// returns the thread's priority as it was last set by the API // returns the thread's priority as it was last set by the API
UInt32 JackMachThread::GetThreadSetPriority(pthread_t thread)
UInt32 JackMachThread::GetThreadSetPriority(jack_native_thread_t thread)
{ {
return GetThreadPriority(thread, THREAD_SET_PRIORITY); return GetThreadPriority(thread, THREAD_SET_PRIORITY);
} }


// returns the thread's priority as it was last scheduled by the Kernel // returns the thread's priority as it was last scheduled by the Kernel
UInt32 JackMachThread::GetThreadScheduledPriority(pthread_t thread)
UInt32 JackMachThread::GetThreadScheduledPriority(jack_native_thread_t thread)
{ {
return GetThreadPriority(thread, THREAD_SCHEDULED_PRIORITY); return GetThreadPriority(thread, THREAD_SCHEDULED_PRIORITY);
} }


UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority)
UInt32 JackMachThread::GetThreadPriority(jack_native_thread_t thread, int inWhichPriority)
{ {
thread_basic_info_data_t threadInfo; thread_basic_info_data_t threadInfo;
policy_info_data_t thePolicyInfo; policy_info_data_t thePolicyInfo;
@@ -127,7 +127,7 @@ UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority)
return 0; return 0;
} }


int JackMachThread::GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint)
int JackMachThread::GetParams(jack_native_thread_t thread, UInt64* period, UInt64* computation, UInt64* constraint)
{ {
thread_time_constraint_policy_data_t theTCPolicy; thread_time_constraint_policy_data_t theTCPolicy;
mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT; mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
@@ -160,11 +160,11 @@ int JackMachThread::Kill()
{ {
// pthread_cancel still not yet implemented in Darwin (TO CHECK ON TIGER) // pthread_cancel still not yet implemented in Darwin (TO CHECK ON TIGER)
jack_log("JackMachThread::Kill"); jack_log("JackMachThread::Kill");
if (fThread != (pthread_t)NULL) { // If thread has been started
if (fThread != (jack_native_thread_t)NULL) { // If thread has been started
mach_port_t machThread = pthread_mach_thread_np(fThread); mach_port_t machThread = pthread_mach_thread_np(fThread);
int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1; int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1;
fThread = (pthread_t)NULL;
fThread = (jack_native_thread_t)NULL;
return res; return res;
} else { } else {
return -1; return -1;
@@ -175,7 +175,7 @@ int JackMachThread::AcquireRealTime()
{ {
jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld", jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld",
long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000)); long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000));
return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1;
return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1;
} }


int JackMachThread::AcquireSelfRealTime() int JackMachThread::AcquireSelfRealTime()
@@ -197,7 +197,7 @@ int JackMachThread::AcquireSelfRealTime(int priority)
return AcquireSelfRealTime(); return AcquireSelfRealTime();
} }


int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint)
int JackMachThread::AcquireRealTimeImp(jack_native_thread_t thread, UInt64 period, UInt64 computation, UInt64 constraint)
{ {
SetThreadToPriority(thread, 96, true, period, computation, constraint); SetThreadToPriority(thread, 96, true, period, computation, constraint);
return 0; return 0;
@@ -205,7 +205,7 @@ int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 c


int JackMachThread::DropRealTime() int JackMachThread::DropRealTime()
{ {
return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1;
return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1;
} }


int JackMachThread::DropSelfRealTime() int JackMachThread::DropSelfRealTime()
@@ -213,7 +213,7 @@ int JackMachThread::DropSelfRealTime()
return DropRealTimeImp(pthread_self()); return DropRealTimeImp(pthread_self());
} }


int JackMachThread::DropRealTimeImp(pthread_t thread)
int JackMachThread::DropRealTimeImp(jack_native_thread_t thread)
{ {
SetThreadToPriority(thread, 63, false, 0, 0, 0); SetThreadToPriority(thread, 63, false, 0, 0, 0);
return 0; return 0;


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -98,9 +98,9 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread
UInt64 fComputation; UInt64 fComputation;
UInt64 fConstraint; UInt64 fConstraint;


static UInt32 GetThreadSetPriority(pthread_t thread);
static UInt32 GetThreadScheduledPriority(pthread_t thread);
static UInt32 GetThreadPriority(pthread_t thread, int inWhichPriority);
static UInt32 GetThreadSetPriority(jack_native_thread_t thread);
static UInt32 GetThreadScheduledPriority(jack_native_thread_t thread);
static UInt32 GetThreadPriority(jack_native_thread_t thread, int inWhichPriority);


public: public:


@@ -116,23 +116,23 @@ class SERVER_EXPORT JackMachThread : public JackPosixThread


int AcquireRealTime(); // Used when called from another thread int AcquireRealTime(); // Used when called from another thread
int AcquireSelfRealTime(); // Used when called from thread itself int AcquireSelfRealTime(); // Used when called from thread itself
int AcquireRealTime(int priority); // Used when called from another thread int AcquireRealTime(int priority); // Used when called from another thread
int AcquireSelfRealTime(int priority); // Used when called from thread itself int AcquireSelfRealTime(int priority); // Used when called from thread itself
int DropRealTime(); // Used when called from another thread int DropRealTime(); // Used when called from another thread
int DropSelfRealTime(); // Used when called from thread itself int DropSelfRealTime(); // Used when called from thread itself
void SetParams(UInt64 period, UInt64 computation, UInt64 constraint); void SetParams(UInt64 period, UInt64 computation, UInt64 constraint);
static int GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint);
static int SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint);
static int GetParams(jack_native_thread_t thread, UInt64* period, UInt64* computation, UInt64* constraint);
static int SetThreadToPriority(jack_native_thread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint);


static int AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint);
static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint)
{
return JackMachThread::AcquireRealTimeImp(thread, period, computation, constraint);
static int AcquireRealTimeImp(jack_native_thread_t thread, UInt64 period, UInt64 computation, UInt64 constraint);
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint)
{
return JackMachThread::AcquireRealTimeImp(thread, period, computation, constraint);
} }
static int DropRealTimeImp(pthread_t thread);
static int DropRealTimeImp(jack_native_thread_t thread);
}; };


} // end of namespace } // end of namespace


+ 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, AudioDevicePropertyID inPropertyID,
void* inClientData) void* inClientData)
{ {
switch (inPropertyID) { switch (inPropertyID) {
case kAudioDeviceProcessorOverload: { case kAudioDeviceProcessorOverload: {
jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload"); jack_error("JackCoreAudioAdapter::DeviceNotificationCallback kAudioDeviceProcessorOverload");
break; break;
@@ -196,12 +196,12 @@ OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice
jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration"); jack_error("Cannot handle kAudioDevicePropertyStreamConfiguration");
return kAudioHardwareUnsupportedOperationError; return kAudioHardwareUnsupportedOperationError;
} }
case kAudioDevicePropertyNominalSampleRate: { case kAudioDevicePropertyNominalSampleRate: {
jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate"); jack_error("Cannot handle kAudioDevicePropertyNominalSampleRate");
return kAudioHardwareUnsupportedOperationError; return kAudioHardwareUnsupportedOperationError;
} }
} }
return noErr; return noErr;
} }
@@ -217,7 +217,7 @@ int JackCoreAudioAdapter::AddListeners()
printError(err); printError(err);
return -1; return -1;
} }
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this);
if (err != noErr) { if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
@@ -275,17 +275,17 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
{ {
JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon); JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon);
AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData);
float* inputBuffer[adapter->fCaptureChannels]; float* inputBuffer[adapter->fCaptureChannels];
float* outputBuffer[adapter->fPlaybackChannels]; float* outputBuffer[adapter->fPlaybackChannels];
for (int i = 0; i < adapter->fCaptureChannels; i++) { for (int i = 0; i < adapter->fCaptureChannels; i++) {
inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData; inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData;
} }
for (int i = 0; i < adapter->fPlaybackChannels; i++) { for (int i = 0; i < adapter->fPlaybackChannels; i++) {
outputBuffer[i] = (float*)ioData->mBuffers[i].mData; outputBuffer[i] = (float*)ioData->mBuffers[i].mData;
} }
adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames); adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames);
return noErr; return noErr;
} }
@@ -302,16 +302,16 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra
fCaptureUID[0] = 0; fCaptureUID[0] = 0;
fPlaybackUID[0] = 0; fPlaybackUID[0] = 0;
fClockDriftCompensate = false; fClockDriftCompensate = false;
// Default values // Default values
fCaptureChannels = -1; fCaptureChannels = -1;
fPlaybackChannels = -1; fPlaybackChannels = -1;
SInt32 major; SInt32 major;
SInt32 minor; SInt32 minor;
Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMajor, &major);
Gestalt(gestaltSystemVersionMinor, &minor); Gestalt(gestaltSystemVersionMinor, &minor);
// Starting with 10.6 systems, the HAL notification thread is created internally // Starting with 10.6 systems, the HAL notification thread is created internally
if (major == 10 && minor >= 6) { if (major == 10 && minor >= 6) {
CFRunLoopRef theRunLoop = NULL; CFRunLoopRef theRunLoop = NULL;
@@ -321,7 +321,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra
jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error"); jack_error("JackCoreAudioAdapter::Open kAudioHardwarePropertyRunLoop error");
} }
} }
for (node = params; node; node = jack_slist_next(node)) { for (node = params; node; node = jack_slist_next(node)) {
param = (const jack_driver_param_t*) node->data; param = (const jack_driver_param_t*) node->data;


@@ -348,7 +348,7 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra
fPlaying = true; fPlaying = true;
strncpy(fPlaybackUID, param->value.str, 256); strncpy(fPlaybackUID, param->value.str, 256);
break; break;
case 'd': case 'd':
strncpy(fCaptureUID, param->value.str, 256); strncpy(fCaptureUID, param->value.str, 256);
strncpy(fPlaybackUID, param->value.str, 256); strncpy(fPlaybackUID, param->value.str, 256);
@@ -365,51 +365,51 @@ JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nfra
case 'p': case 'p':
SetAdaptedBufferSize(param->value.ui); SetAdaptedBufferSize(param->value.ui);
break; break;
case 'l': case 'l':
DisplayDeviceNames(); DisplayDeviceNames();
break; break;
case 'q': case 'q':
fQuality = param->value.ui; fQuality = param->value.ui;
break; break;
case 'g': case 'g':
fRingbufferCurSize = param->value.ui; fRingbufferCurSize = param->value.ui;
fAdaptative = false; fAdaptative = false;
break; break;
case 's': case 's':
fClockDriftCompensate = true; fClockDriftCompensate = true;
break; break;
} }
} }
/* duplex is the default */ /* duplex is the default */
if (!fCapturing && !fPlaying) { if (!fCapturing && !fPlaying) {
fCapturing = true; fCapturing = true;
fPlaying = true; fPlaying = true;
} }
if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0) if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName, fAdaptedSampleRate) < 0)
throw -1; throw -1;
if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0) if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0)
throw -1; throw -1;
if (SetupBufferSize(fAdaptedBufferSize) < 0) if (SetupBufferSize(fAdaptedBufferSize) < 0)
throw -1; throw -1;
if (SetupSampleRate(fAdaptedSampleRate) < 0) if (SetupSampleRate(fAdaptedSampleRate) < 0)
throw -1; throw -1;
if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0)
if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate) < 0)
throw -1; throw -1;
if (fCapturing && fCaptureChannels > 0) if (fCapturing && fCaptureChannels > 0)
if (SetupBuffers(fCaptureChannels) < 0) if (SetupBuffers(fCaptureChannels) < 0)
throw -1; throw -1;
if (AddListeners() < 0) if (AddListeners() < 0)
throw -1; throw -1;
} }
@@ -488,6 +488,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultInputDevice(AudioDeviceID* id)
if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr) if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
return res; return res;


if (inDefault == 0) {
jack_error("Error : input device is 0, please select a correct one !!");
return -1;
}
jack_log("GetDefaultInputDevice: input = %ld ", inDefault); jack_log("GetDefaultInputDevice: input = %ld ", inDefault);
*id = inDefault; *id = inDefault;
return noErr; return noErr;
@@ -502,6 +506,10 @@ OSStatus JackCoreAudioAdapter::GetDefaultOutputDevice(AudioDeviceID* id)
if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr) if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
return res; return res;


if (outDefault == 0) {
jack_error("Error : output device is 0, please select a correct one !!");
return -1;
}
jack_log("GetDefaultOutputDevice: output = %ld", outDefault); jack_log("GetDefaultOutputDevice: output = %ld", outDefault);
*id = outDefault; *id = outDefault;
return noErr; return noErr;
@@ -525,10 +533,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,


// Duplex // Duplex
if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) { if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
// Same device for capture and playback... // Same device for capture and playback...
if (strcmp(capture_driver_uid, playback_driver_uid) == 0) { if (strcmp(capture_driver_uid, playback_driver_uid) == 0) {
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) { if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
jack_log("Will take default in/out"); jack_log("Will take default in/out");
if (GetDefaultDevice(&fDeviceID) != noErr) { if (GetDefaultDevice(&fDeviceID) != noErr) {
@@ -540,12 +548,12 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
jack_error("Cannot get device name from device ID"); jack_error("Cannot get device name from device ID");
return -1; return -1;
} }
} else { } else {
// Creates aggregate device // Creates aggregate device
AudioDeviceID captureID, playbackID; AudioDeviceID captureID, playbackID;
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
jack_log("Will take default input"); jack_log("Will take default input");
if (GetDefaultInputDevice(&captureID) != noErr) { if (GetDefaultInputDevice(&captureID) != noErr) {
@@ -553,7 +561,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
return -1; return -1;
} }
} }
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
jack_log("Will take default output"); jack_log("Will take default output");
if (GetDefaultOutputDevice(&playbackID) != noErr) { if (GetDefaultOutputDevice(&playbackID) != noErr) {
@@ -561,7 +569,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
return -1; return -1;
} }
} }
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr)
return -1; return -1;
} }
@@ -599,10 +607,10 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
jack_log("JackCoreAudioDriver::Open default driver"); jack_log("JackCoreAudioDriver::Open default driver");
if (GetDefaultDevice(&fDeviceID) != noErr) { if (GetDefaultDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); jack_error("Cannot open default device in duplex mode, so aggregate default input and default output");
// Creates aggregate device // Creates aggregate device
AudioDeviceID captureID, playbackID; AudioDeviceID captureID, playbackID;
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) {
jack_log("Will take default input"); jack_log("Will take default input");
if (GetDefaultInputDevice(&captureID) != noErr) { if (GetDefaultInputDevice(&captureID) != noErr) {
@@ -610,7 +618,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
return -1; return -1;
} }
} }
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) { if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr) {
jack_log("Will take default output"); jack_log("Will take default output");
if (GetDefaultOutputDevice(&playbackID) != noErr) { if (GetDefaultOutputDevice(&playbackID) != noErr) {
@@ -618,7 +626,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
return -1; return -1;
} }
} }
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr)
return -1; return -1;
} }
@@ -680,7 +688,7 @@ int JackCoreAudioAdapter::SetupChannels(bool capturing,
jack_log("Setup max out channels = %ld", out_nChannels); jack_log("Setup max out channels = %ld", out_nChannels);
outchannels = out_nChannels; outchannels = out_nChannels;
} }
return 0; return 0;
} }


@@ -694,7 +702,7 @@ int JackCoreAudioAdapter::SetupBufferSize(jack_nframes_t buffer_size)
printError(err); printError(err);
return -1; return -1;
} }
return 0; return 0;
} }


@@ -708,7 +716,7 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe
OSStatus err = noErr; OSStatus err = noErr;
UInt32 outSize; UInt32 outSize;
Float64 sampleRate; Float64 sampleRate;
// Get sample rate // Get sample rate
outSize = sizeof(Float64); outSize = sizeof(Float64);
err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate); err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
@@ -716,12 +724,14 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe
jack_error("Cannot get current sample rate"); jack_error("Cannot get current sample rate");
printError(err); printError(err);
return -1; return -1;
} else {
jack_log("Current sample rate = %f", sampleRate);
} }
// If needed, set new sample rate // If needed, set new sample rate
if (samplerate != (jack_nframes_t)sampleRate) { if (samplerate != (jack_nframes_t)sampleRate) {
sampleRate = (Float64)samplerate; sampleRate = (Float64)samplerate;
// To get SR change notification // To get SR change notification
err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this); err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
if (err != noErr) { if (err != noErr) {
@@ -735,18 +745,18 @@ int JackCoreAudioAdapter::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframe
printError(err); printError(err);
return -1; return -1;
} }
// Waiting for SR change notification // Waiting for SR change notification
int count = 0; int count = 0;
while (!fState && count++ < WAIT_COUNTER) { while (!fState && count++ < WAIT_COUNTER) {
usleep(100000); usleep(100000);
jack_log("Wait count = %d", count); jack_log("Wait count = %d", count);
} }
// Remove SR change notification // Remove SR change notification
AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback); AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
} }
return 0; return 0;
} }


@@ -796,7 +806,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
jack_error("No input and output channels..."); jack_error("No input and output channels...");
return -1; return -1;
} }
// AUHAL // AUHAL
ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
Component HALOutput = FindNextComponent(NULL, &cd); Component HALOutput = FindNextComponent(NULL, &cd);
@@ -823,7 +833,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
enableIO = 0; enableIO = 0;
jack_log("Setup AUHAL input off"); jack_log("Setup AUHAL input off");
} }
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
if (err1 != noErr) { if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"); jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
@@ -838,14 +848,14 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
enableIO = 0; enableIO = 0;
jack_log("Setup AUHAL output off"); jack_log("Setup AUHAL output off");
} }
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
if (err1 != noErr) { if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
printError(err1); printError(err1);
goto error; goto error;
} }
size = sizeof(AudioDeviceID); size = sizeof(AudioDeviceID);
err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size); err1 = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &size);
if (err1 != noErr) { if (err1 != noErr) {
@@ -863,7 +873,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
printError(err1); printError(err1);
goto error; goto error;
} }
// Set buffer size // Set buffer size
if (capturing && inchannels > 0) { if (capturing && inchannels > 0) {
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32)); err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&buffer_size, sizeof(UInt32));
@@ -918,7 +928,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,


// Setup stream converters // Setup stream converters
if (capturing && inchannels > 0) { if (capturing && inchannels > 0) {
size = sizeof(AudioStreamBasicDescription); size = sizeof(AudioStreamBasicDescription);
err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size); err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size);
if (err1 != noErr) { if (err1 != noErr) {
@@ -927,7 +937,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
goto error; goto error;
} }
PrintStreamDesc(&srcFormat); PrintStreamDesc(&srcFormat);
jack_log("Setup AUHAL input stream converter SR = %ld", samplerate); jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
srcFormat.mSampleRate = samplerate; srcFormat.mSampleRate = samplerate;
srcFormat.mFormatID = kAudioFormatLinearPCM; srcFormat.mFormatID = kAudioFormatLinearPCM;
@@ -938,9 +948,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
srcFormat.mChannelsPerFrame = inchannels; srcFormat.mChannelsPerFrame = inchannels;
srcFormat.mBitsPerChannel = 32; srcFormat.mBitsPerChannel = 32;
PrintStreamDesc(&srcFormat); PrintStreamDesc(&srcFormat);
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
if (err1 != noErr) { if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input"); jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
printError(err1); printError(err1);
@@ -949,7 +959,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
} }


if (playing && outchannels > 0) { if (playing && outchannels > 0) {
size = sizeof(AudioStreamBasicDescription); size = sizeof(AudioStreamBasicDescription);
err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size); err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &dstFormat, &size);
if (err1 != noErr) { if (err1 != noErr) {
@@ -958,7 +968,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
goto error; goto error;
} }
PrintStreamDesc(&dstFormat); PrintStreamDesc(&dstFormat);
jack_log("Setup AUHAL output stream converter SR = %ld", samplerate); jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
dstFormat.mSampleRate = samplerate; dstFormat.mSampleRate = samplerate;
dstFormat.mFormatID = kAudioFormatLinearPCM; dstFormat.mFormatID = kAudioFormatLinearPCM;
@@ -969,9 +979,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
dstFormat.mChannelsPerFrame = outchannels; dstFormat.mChannelsPerFrame = outchannels;
dstFormat.mBitsPerChannel = 32; dstFormat.mBitsPerChannel = 32;
PrintStreamDesc(&dstFormat); PrintStreamDesc(&dstFormat);
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
if (err1 != noErr) { if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output"); jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
printError(err1); printError(err1);
@@ -1003,13 +1013,13 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
} }


return 0; return 0;
error: error:
CloseAUHAL(); CloseAUHAL();
return -1; return -1;
} }


OSStatus JackCoreAudioAdapter::DestroyAggregateDevice()
OSStatus JackCoreAudioAdapter::DestroyAggregateDevice()
{ {
OSStatus osErr = noErr; OSStatus osErr = noErr;
AudioObjectPropertyAddress pluginAOPA; AudioObjectPropertyAddress pluginAOPA;
@@ -1017,21 +1027,21 @@ OSStatus JackCoreAudioAdapter::DestroyAggregateDevice()
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
UInt32 outDataSize; UInt32 outDataSize;
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
printError(osErr); printError(osErr);
return osErr; return osErr;
} }
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error");
printError(osErr); printError(osErr);
return osErr; return osErr;
} }
return noErr; return noErr;
} }


@@ -1043,15 +1053,15 @@ static CFStringRef GetDeviceName(AudioDeviceID id)
return (err == noErr) ? UIname : NULL; return (err == noErr) ? UIname : NULL;
} }


OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
{ {
OSStatus err = noErr; OSStatus err = noErr;
AudioObjectID sub_device[32]; AudioObjectID sub_device[32];
UInt32 outSize = sizeof(sub_device); UInt32 outSize = sizeof(sub_device);
err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
vector<AudioDeviceID> captureDeviceIDArray; vector<AudioDeviceID> captureDeviceIDArray;
if (err != noErr) { if (err != noErr) {
jack_log("Input device does not have subdevices"); jack_log("Input device does not have subdevices");
captureDeviceIDArray.push_back(captureDeviceID); captureDeviceIDArray.push_back(captureDeviceID);
@@ -1062,10 +1072,10 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice
captureDeviceIDArray.push_back(sub_device[i]); captureDeviceIDArray.push_back(sub_device[i]);
} }
} }
err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
vector<AudioDeviceID> playbackDeviceIDArray; vector<AudioDeviceID> playbackDeviceIDArray;
if (err != noErr) { if (err != noErr) {
jack_log("Output device does not have subdevices"); jack_log("Output device does not have subdevices");
playbackDeviceIDArray.push_back(playbackDeviceID); playbackDeviceIDArray.push_back(playbackDeviceID);
@@ -1076,16 +1086,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice
playbackDeviceIDArray.push_back(sub_device[i]); playbackDeviceIDArray.push_back(sub_device[i]);
} }
} }
return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice); return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
} }
OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice)
{ {
OSStatus osErr = noErr; OSStatus osErr = noErr;
UInt32 outSize; UInt32 outSize;
Boolean outWritable; Boolean outWritable;
// Prepare sub-devices for clock drift compensation // Prepare sub-devices for clock drift compensation
// Workaround for bug in the HAL : until 10.6.2 // Workaround for bug in the HAL : until 10.6.2
AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
@@ -1094,7 +1104,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
AudioClassID inClass = kAudioSubDeviceClassID; AudioClassID inClass = kAudioSubDeviceClassID;
void* theQualifierData = &inClass; void* theQualifierData = &inClass;
UInt32 subDevicesNum = 0; UInt32 subDevicesNum = 0;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Setup SR of both devices otherwise creating AD may fail... // Setup SR of both devices otherwise creating AD may fail...
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -1102,18 +1112,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
UInt32 clockdomain = 0; UInt32 clockdomain = 0;
outSize = sizeof(UInt32); outSize = sizeof(UInt32);
bool need_clock_drift_compensation = false; bool need_clock_drift_compensation = false;
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device");
} else { } else {
// Check clock domain // Check clock domain
osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
if (osErr != 0) { if (osErr != 0) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
printError(osErr); printError(osErr);
} else { } else {
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain);
if (clockdomain != 0 && clockdomain != keptclockdomain) { if (clockdomain != 0 && clockdomain != keptclockdomain) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
@@ -1122,18 +1132,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
} }
} }
} }
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device");
} else { } else {
// Check clock domain // Check clock domain
osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
if (osErr != 0) { if (osErr != 0) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error");
printError(osErr); printError(osErr);
} else { } else {
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain);
if (clockdomain != 0 && clockdomain != keptclockdomain) { if (clockdomain != 0 && clockdomain != keptclockdomain) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...");
@@ -1142,74 +1152,74 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
} }
} }
} }
// If no valid clock domain was found, then assume we have to compensate... // If no valid clock domain was found, then assume we have to compensate...
if (keptclockdomain == 0) { if (keptclockdomain == 0) {
need_clock_drift_compensation = true; need_clock_drift_compensation = true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Start to create a new aggregate by getting the base audio hardware plugin // Start to create a new aggregate by getting the base audio hardware plugin
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
char device_name[256]; char device_name[256];
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
GetDeviceNameFromID(captureDeviceID[i], device_name); GetDeviceNameFromID(captureDeviceID[i], device_name);
jack_info("Separated input = '%s' ", device_name); jack_info("Separated input = '%s' ", device_name);
} }
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
GetDeviceNameFromID(playbackDeviceID[i], device_name); GetDeviceNameFromID(playbackDeviceID[i], device_name);
jack_info("Separated output = '%s' ", device_name); jack_info("Separated output = '%s' ", device_name);
} }
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error");
printError(osErr); printError(osErr);
return osErr; return osErr;
} }
AudioValueTranslation pluginAVT; AudioValueTranslation pluginAVT;
CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio"); CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
pluginAVT.mInputData = &inBundleRef; pluginAVT.mInputData = &inBundleRef;
pluginAVT.mInputDataSize = sizeof(inBundleRef); pluginAVT.mInputDataSize = sizeof(inBundleRef);
pluginAVT.mOutputData = &fPluginID; pluginAVT.mOutputData = &fPluginID;
pluginAVT.mOutputDataSize = sizeof(fPluginID); pluginAVT.mOutputDataSize = sizeof(fPluginID);
osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error");
printError(osErr); printError(osErr);
return osErr; return osErr;
} }
//------------------------------------------------- //-------------------------------------------------
// Create a CFDictionary for our aggregate device // Create a CFDictionary for our aggregate device
//------------------------------------------------- //-------------------------------------------------
CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex"); CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex"); CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
// add the name of the device to the dictionary // add the name of the device to the dictionary
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef); CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
// add our choice of UID for the aggregate device to the dictionary // add our choice of UID for the aggregate device to the dictionary
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
// add a "private aggregate key" to the dictionary // add a "private aggregate key" to the dictionary
int value = 1; int value = 1;
CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
SInt32 system; SInt32 system;
Gestalt(gestaltSystemVersion, &system); Gestalt(gestaltSystemVersion, &system);
jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054);
// Starting with 10.5.4 systems, the AD can be internal... (better) // Starting with 10.5.4 systems, the AD can be internal... (better)
if (system < 0x00001054) { if (system < 0x00001054) {
jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device....");
@@ -1217,16 +1227,16 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device....");
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
} }
// Prepare sub-devices for clock drift compensation // Prepare sub-devices for clock drift compensation
CFMutableArrayRef subDevicesArrayClock = NULL; CFMutableArrayRef subDevicesArrayClock = NULL;
/* /*
if (fClockDriftCompensate) { if (fClockDriftCompensate) {
if (need_clock_drift_compensation) { if (need_clock_drift_compensation) {
jack_info("Clock drift compensation activated..."); jack_info("Clock drift compensation activated...");
subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
CFStringRef UID = GetDeviceName(captureDeviceID[i]); CFStringRef UID = GetDeviceName(captureDeviceID[i]);
if (UID) { if (UID) {
@@ -1237,7 +1247,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
} }
} }
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
CFStringRef UID = GetDeviceName(playbackDeviceID[i]); CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
if (UID) { if (UID) {
@@ -1248,7 +1258,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict); CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
} }
} }
// add sub-device clock array for the aggregate device to the dictionary // add sub-device clock array for the aggregate device to the dictionary
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock); CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
} else { } else {
@@ -1256,14 +1266,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
} }
} }
*/ */
//------------------------------------------------- //-------------------------------------------------
// Create a CFMutableArray for our sub-device list // Create a CFMutableArray for our sub-device list
//------------------------------------------------- //-------------------------------------------------
// we need to append the UID for each device to a CFMutableArray, so create one here // we need to append the UID for each device to a CFMutableArray, so create one here
CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
vector<CFStringRef> captureDeviceUID; vector<CFStringRef> captureDeviceUID;
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
CFStringRef ref = GetDeviceName(captureDeviceID[i]); CFStringRef ref = GetDeviceName(captureDeviceID[i]);
@@ -1273,7 +1283,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
// input sub-devices in this example, so append the sub-device's UID to the CFArray // input sub-devices in this example, so append the sub-device's UID to the CFArray
CFArrayAppendValue(subDevicesArray, ref); CFArrayAppendValue(subDevicesArray, ref);
} }
vector<CFStringRef> playbackDeviceUID; vector<CFStringRef> playbackDeviceUID;
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
CFStringRef ref = GetDeviceName(playbackDeviceID[i]); CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
@@ -1283,39 +1293,39 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
// output sub-devices in this example, so append the sub-device's UID to the CFArray // output sub-devices in this example, so append the sub-device's UID to the CFArray
CFArrayAppendValue(subDevicesArray, ref); CFArrayAppendValue(subDevicesArray, ref);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// Feed the dictionary to the plugin, to create a blank aggregate device // Feed the dictionary to the plugin, to create a blank aggregate device
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
AudioObjectPropertyAddress pluginAOPA; AudioObjectPropertyAddress pluginAOPA;
pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice; pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
UInt32 outDataSize; UInt32 outDataSize;
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error");
printError(osErr); printError(osErr);
goto error; goto error;
} }
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error");
printError(osErr); printError(osErr);
goto error; goto error;
} }
// pause for a bit to make sure that everything completed correctly // pause for a bit to make sure that everything completed correctly
// this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
//------------------------- //-------------------------
// Set the sub-device list // Set the sub-device list
//------------------------- //-------------------------
pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList; pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal; pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster; pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
@@ -1326,14 +1336,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
printError(osErr); printError(osErr);
goto error; goto error;
} }
// pause again to give the changes time to take effect // pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
//----------------------- //-----------------------
// Set the master device // Set the master device
//----------------------- //-----------------------
// set the master device manually (this is the device which will act as the master clock for the aggregate device) // set the master device manually (this is the device which will act as the master clock for the aggregate device)
// pass in the UID of the device you want to use // pass in the UID of the device you want to use
pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice; pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
@@ -1346,36 +1356,36 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
printError(osErr); printError(osErr);
goto error; goto error;
} }
// pause again to give the changes time to take effect // pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
// Prepare sub-devices for clock drift compensation // Prepare sub-devices for clock drift compensation
// Workaround for bug in the HAL : until 10.6.2 // Workaround for bug in the HAL : until 10.6.2
if (fClockDriftCompensate) { if (fClockDriftCompensate) {
if (need_clock_drift_compensation) { if (need_clock_drift_compensation) {
jack_info("Clock drift compensation activated..."); jack_info("Clock drift compensation activated...");
// Get the property data size // Get the property data size
osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
printError(osErr); printError(osErr);
} }
// Calculate the number of object IDs // Calculate the number of object IDs
subDevicesNum = outSize / sizeof(AudioObjectID); subDevicesNum = outSize / sizeof(AudioObjectID);
jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum);
AudioObjectID subDevices[subDevicesNum]; AudioObjectID subDevices[subDevicesNum];
outSize = sizeof(subDevices); outSize = sizeof(subDevices);
osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
if (osErr != noErr) { if (osErr != noErr) {
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error");
printError(osErr); printError(osErr);
} }
// Set kAudioSubDevicePropertyDriftCompensation property... // Set kAudioSubDevicePropertyDriftCompensation property...
for (UInt32 index = 0; index < subDevicesNum; ++index) { for (UInt32 index = 0; index < subDevicesNum; ++index) {
UInt32 theDriftCompensationValue = 1; UInt32 theDriftCompensationValue = 1;
@@ -1388,50 +1398,50 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector<AudioDeviceID> ca
} else { } else {
jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)"); jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
} }
}
}
// pause again to give the changes time to take effect // pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
//---------- //----------
// Clean up // Clean up
//---------- //----------
// release the private AD key // release the private AD key
CFRelease(AggregateDeviceNumberRef); CFRelease(AggregateDeviceNumberRef);
// release the CF objects we have created - we don't need them any more // release the CF objects we have created - we don't need them any more
CFRelease(aggDeviceDict); CFRelease(aggDeviceDict);
CFRelease(subDevicesArray); CFRelease(subDevicesArray);
if (subDevicesArrayClock) if (subDevicesArrayClock)
CFRelease(subDevicesArrayClock); CFRelease(subDevicesArrayClock);
// release the device UID // release the device UID
for (UInt32 i = 0; i < captureDeviceUID.size(); i++) { for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
CFRelease(captureDeviceUID[i]); CFRelease(captureDeviceUID[i]);
} }
for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) { for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
CFRelease(playbackDeviceUID[i]); CFRelease(playbackDeviceUID[i]);
} }
jack_log("New aggregate device %ld", *outAggregateDevice); jack_log("New aggregate device %ld", *outAggregateDevice);
return noErr; return noErr;
error: error:
DestroyAggregateDevice(); DestroyAggregateDevice();
return -1; return -1;
} }
bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device) bool JackCoreAudioAdapter::IsAggregateDevice(AudioDeviceID device)
{ {
OSStatus err = noErr; OSStatus err = noErr;
AudioObjectID sub_device[32]; AudioObjectID sub_device[32];
UInt32 outSize = sizeof(sub_device); UInt32 outSize = sizeof(sub_device);
err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); err = AudioDeviceGetProperty(device, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
if (err != noErr) { if (err != noErr) {
jack_log("Device does not have subdevices"); jack_log("Device does not have subdevices");
return false; return false;
@@ -1494,7 +1504,7 @@ extern "C"


strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
desc->nparams = 13; desc->nparams = 13;
desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));


@@ -1574,7 +1584,7 @@ extern "C"
desc->params[i].value.i = TRUE; desc->params[i].value.i = TRUE;
strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); strcpy(desc->params[i].short_desc, "Display available CoreAudio devices");
strcpy(desc->params[i].long_desc, desc->params[i].short_desc); strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
i++; i++;
strcpy(desc->params[i].name, "quality"); strcpy(desc->params[i].name, "quality");
desc->params[i].character = 'q'; desc->params[i].character = 'q';
@@ -1582,7 +1592,7 @@ extern "C"
desc->params[i].value.ui = 0; desc->params[i].value.ui = 0;
strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)");
strcpy(desc->params[i].long_desc, desc->params[i].short_desc); strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
i++; i++;
strcpy(desc->params[i].name, "ring-buffer"); strcpy(desc->params[i].name, "ring-buffer");
desc->params[i].character = 'g'; desc->params[i].character = 'g';
@@ -1590,7 +1600,7 @@ extern "C"
desc->params[i].value.ui = 32768; desc->params[i].value.ui = 32768;
strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); strcpy(desc->params[i].short_desc, "Fixed ringbuffer size");
strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)");
i++; i++;
strcpy(desc->params[i].name, "clock-drift"); strcpy(desc->params[i].name, "clock-drift");
desc->params[i].character = 's'; desc->params[i].character = 's';
@@ -1598,7 +1608,7 @@ extern "C"
desc->params[i].value.i = FALSE; desc->params[i].value.i = FALSE;
strcpy(desc->params[i].short_desc, "Clock drift compensation"); strcpy(desc->params[i].short_desc, "Clock drift compensation");
strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device"); strcpy(desc->params[i].long_desc, "Whether to compensate clock drift in dynamically created aggregate device");
return desc; return desc;
} }




+ 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.features.append('cc')
driver.env['shlib_PATTERN'] = 'jack_%s.so' driver.env['shlib_PATTERN'] = 'jack_%s.so'
driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE']
# Seems uneeded here...
#if bld.env['HAVE_CELT']:
#if bld.env['HAVE_CELT_API_0_5']:
# driver.defines += ['HAVE_CELT', 'HAVE_CELT_API_0_5']
#elif bld.env['HAVE_CELT_API_0_7']:
# driver.defines += ['HAVE_CELT', 'HAVE_CELT_API_0_7']
driver.includes = ['.', '../macosx', '../posix', '../common', '../common/jack'] driver.includes = ['.', '../macosx', '../posix', '../common', '../common/jack']
driver.target = target driver.target = target
driver.source = sources driver.source = sources


+ 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. \brief Mutex abstraction.
*/ */


class JackBasePosixMutex class JackBasePosixMutex
{ {
protected: protected:
pthread_mutex_t fMutex; pthread_mutex_t fMutex;
public: public:
JackBasePosixMutex() JackBasePosixMutex()
{ {
pthread_mutex_init(&fMutex, NULL);
pthread_mutex_init(&fMutex, NULL);
} }
virtual ~JackBasePosixMutex() virtual ~JackBasePosixMutex()
{ {
pthread_mutex_destroy(&fMutex); pthread_mutex_destroy(&fMutex);
} }
void Lock() void Lock()
{ {
int res = pthread_mutex_lock(&fMutex); int res = pthread_mutex_lock(&fMutex);
if (res != 0) if (res != 0)
jack_error("JackBasePosixMutex::Lock res = %d", res);
jack_log("JackBasePosixMutex::Lock res = %d", res);
} }
bool Trylock() bool Trylock()
{ {
return (pthread_mutex_trylock(&fMutex) == 0); return (pthread_mutex_trylock(&fMutex) == 0);
} }
void Unlock() void Unlock()
{ {
int res = pthread_mutex_unlock(&fMutex); int res = pthread_mutex_unlock(&fMutex);
if (res != 0) if (res != 0)
jack_error("JackBasePosixMutex::Unlock res = %d", res);
jack_log("JackBasePosixMutex::Unlock res = %d", res);
} }
}; };
class JackPosixMutex class JackPosixMutex
{ {


@@ -97,7 +97,7 @@ class JackPosixMutex
res = pthread_mutexattr_destroy(&mutex_attr); res = pthread_mutexattr_destroy(&mutex_attr);
assert(res == 0); assert(res == 0);
} }
virtual ~JackPosixMutex() virtual ~JackPosixMutex()
{ {
pthread_mutex_destroy(&fMutex); pthread_mutex_destroy(&fMutex);
@@ -107,7 +107,7 @@ class JackPosixMutex
{ {
int res = pthread_mutex_lock(&fMutex); int res = pthread_mutex_lock(&fMutex);
if (res != 0) if (res != 0)
jack_error("JackPosixMutex::Lock res = %d", res);
jack_log("JackPosixMutex::Lock res = %d", res);
return (res == 0); return (res == 0);
} }


@@ -120,7 +120,7 @@ class JackPosixMutex
{ {
int res = pthread_mutex_unlock(&fMutex); int res = pthread_mutex_unlock(&fMutex);
if (res != 0) if (res != 0)
jack_error("JackPosixMutex::Unlock res = %d", res);
jack_log("JackPosixMutex::Unlock res = %d", res);
return (res == 0); return (res == 0);
} }




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -40,19 +40,19 @@ void* JackPosixThread::ThreadHandler(void* arg)
if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) { if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) {
jack_error("pthread_setcanceltype err = %s", strerror(err)); jack_error("pthread_setcanceltype err = %s", strerror(err));
} }
// Signal creation thread when started with StartSync // Signal creation thread when started with StartSync
jack_log("ThreadHandler: start"); jack_log("ThreadHandler: start");
obj->fStatus = kIniting; obj->fStatus = kIniting;
// Call Init method // Call Init method
if (!runnable->Init()) { if (!runnable->Init()) {
jack_error("Thread init fails: thread quits"); jack_error("Thread init fails: thread quits");
return 0; return 0;
} }
obj->fStatus = kRunning; obj->fStatus = kRunning;
// If Init succeed, start the thread loop // If Init succeed, start the thread loop
bool res = true; bool res = true;
while (obj->fStatus == kRunning && res) { while (obj->fStatus == kRunning && res) {
@@ -76,11 +76,11 @@ int JackPosixThread::Start()
return 0; return 0;
} }
} }
int JackPosixThread::StartSync() int JackPosixThread::StartSync()
{ {
fStatus = kStarting; fStatus = kStarting;
if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) {
fStatus = kIdle; fStatus = kIdle;
return -1; return -1;
@@ -90,10 +90,10 @@ int JackPosixThread::StartSync()
JackSleep(1000); JackSleep(1000);
} }
return (count == 1000) ? -1 : 0; return (count == 1000) ? -1 : 0;
}
}
} }
int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg)
int JackPosixThread::StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg)
{ {
pthread_attr_t attributes; pthread_attr_t attributes;
struct sched_param rt_param; struct sched_param rt_param;
@@ -111,19 +111,19 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi
} }


if (realtime) { if (realtime) {
jack_log("Create RT thread"); jack_log("Create RT thread");


if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) { if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
jack_error("Cannot request explicit scheduling for RT thread res = %d", res); jack_error("Cannot request explicit scheduling for RT thread res = %d", res);
return -1; return -1;
} }
if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) {
jack_error("Cannot set RR scheduling class for RT thread res = %d", res); jack_error("Cannot set RR scheduling class for RT thread res = %d", res);
return -1; return -1;
} }
memset(&rt_param, 0, sizeof(rt_param)); memset(&rt_param, 0, sizeof(rt_param));
rt_param.sched_priority = priority; rt_param.sched_priority = priority;


@@ -152,13 +152,13 @@ int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, voi


int JackPosixThread::Kill() int JackPosixThread::Kill()
{ {
if (fThread != (pthread_t)NULL) { // If thread has been started
if (fThread != (jack_native_thread_t)NULL) { // If thread has been started
jack_log("JackPosixThread::Kill"); jack_log("JackPosixThread::Kill");
void* status; void* status;
pthread_cancel(fThread); pthread_cancel(fThread);
pthread_join(fThread, &status); pthread_join(fThread, &status);
fStatus = kIdle; fStatus = kIdle;
fThread = (pthread_t)NULL;
fThread = (jack_native_thread_t)NULL;
return 0; return 0;
} else { } else {
return -1; return -1;
@@ -167,21 +167,21 @@ int JackPosixThread::Kill()


int JackPosixThread::Stop() int JackPosixThread::Stop()
{ {
if (fThread != (pthread_t)NULL) { // If thread has been started
if (fThread != (jack_native_thread_t)NULL) { // If thread has been started
jack_log("JackPosixThread::Stop"); jack_log("JackPosixThread::Stop");
void* status; void* status;
fStatus = kIdle; // Request for the thread to stop fStatus = kIdle; // Request for the thread to stop
pthread_join(fThread, &status); pthread_join(fThread, &status);
fThread = (pthread_t)NULL;
fThread = (jack_native_thread_t)NULL;
return 0; return 0;
} else { } else {
return -1; return -1;
} }
} }


int JackPosixThread::KillImp(pthread_t thread)
int JackPosixThread::KillImp(jack_native_thread_t thread)
{ {
if (thread != (pthread_t)NULL) { // If thread has been started
if (thread != (jack_native_thread_t)NULL) { // If thread has been started
jack_log("JackPosixThread::Kill"); jack_log("JackPosixThread::Kill");
void* status; void* status;
pthread_cancel(thread); pthread_cancel(thread);
@@ -192,9 +192,9 @@ int JackPosixThread::KillImp(pthread_t thread)
} }
} }


int JackPosixThread::StopImp(pthread_t thread)
int JackPosixThread::StopImp(jack_native_thread_t thread)
{ {
if (thread != (pthread_t)NULL) { // If thread has been started
if (thread != (jack_native_thread_t)NULL) { // If thread has been started
jack_log("JackPosixThread::Stop"); jack_log("JackPosixThread::Stop");
void* status; void* status;
pthread_join(thread, &status); pthread_join(thread, &status);
@@ -206,7 +206,7 @@ int JackPosixThread::StopImp(pthread_t thread)


int JackPosixThread::AcquireRealTime() int JackPosixThread::AcquireRealTime()
{ {
return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1;
return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1;
} }


int JackPosixThread::AcquireSelfRealTime() int JackPosixThread::AcquireSelfRealTime()
@@ -225,7 +225,7 @@ int JackPosixThread::AcquireSelfRealTime(int priority)
fPriority = priority; fPriority = priority;
return AcquireSelfRealTime(); return AcquireSelfRealTime();
} }
int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority)
int JackPosixThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority)
{ {
struct sched_param rtparam; struct sched_param rtparam;
int res; int res;
@@ -243,7 +243,7 @@ int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority)


int JackPosixThread::DropRealTime() int JackPosixThread::DropRealTime()
{ {
return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1;
return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1;
} }


int JackPosixThread::DropSelfRealTime() int JackPosixThread::DropSelfRealTime()
@@ -251,7 +251,7 @@ int JackPosixThread::DropSelfRealTime()
return DropRealTimeImp(pthread_self()); return DropRealTimeImp(pthread_self());
} }


int JackPosixThread::DropRealTimeImp(pthread_t thread)
int JackPosixThread::DropRealTimeImp(jack_native_thread_t thread)
{ {
struct sched_param rtparam; struct sched_param rtparam;
int res; int res;
@@ -265,7 +265,7 @@ int JackPosixThread::DropRealTimeImp(pthread_t thread)
return 0; return 0;
} }


pthread_t JackPosixThread::GetThreadID()
jack_native_thread_t JackPosixThread::GetThreadID()
{ {
return fThread; return fThread;
} }
@@ -320,42 +320,42 @@ bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr)
bool jack_tls_allocate_key(jack_tls_key *key_ptr) bool jack_tls_allocate_key(jack_tls_key *key_ptr)
{ {
int ret; int ret;
ret = pthread_key_create(key_ptr, NULL); ret = pthread_key_create(key_ptr, NULL);
if (ret != 0) if (ret != 0)
{ {
jack_error("pthread_key_create() failed with error %d", ret); jack_error("pthread_key_create() failed with error %d", ret);
return false; return false;
} }
return true; return true;
} }


bool jack_tls_free_key(jack_tls_key key) bool jack_tls_free_key(jack_tls_key key)
{ {
int ret; int ret;
ret = pthread_key_delete(key); ret = pthread_key_delete(key);
if (ret != 0) if (ret != 0)
{ {
jack_error("pthread_key_delete() failed with error %d", ret); jack_error("pthread_key_delete() failed with error %d", ret);
return false; return false;
} }
return true; return true;
} }


bool jack_tls_set(jack_tls_key key, void *data_ptr) bool jack_tls_set(jack_tls_key key, void *data_ptr)
{ {
int ret; int ret;
ret = pthread_setspecific(key, (const void *)data_ptr); ret = pthread_setspecific(key, (const void *)data_ptr);
if (ret != 0) if (ret != 0)
{ {
jack_error("pthread_setspecific() failed with error %d", ret); jack_error("pthread_setspecific() failed with error %d", ret);
return false; return false;
} }
return true; return true;
} }




+ 13
- 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -40,16 +40,16 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface


protected: protected:


pthread_t fThread;
jack_native_thread_t fThread;
static void* ThreadHandler(void* arg); static void* ThreadHandler(void* arg);


public: public:


JackPosixThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation) JackPosixThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation)
: JackThreadInterface(runnable, priority, real_time, cancellation), fThread((pthread_t)NULL)
: JackThreadInterface(runnable, priority, real_time, cancellation), fThread((jack_native_thread_t)NULL)
{} {}
JackPosixThread(JackRunnableInterface* runnable, int cancellation = PTHREAD_CANCEL_ASYNCHRONOUS) JackPosixThread(JackRunnableInterface* runnable, int cancellation = PTHREAD_CANCEL_ASYNCHRONOUS)
: JackThreadInterface(runnable, 0, false, cancellation), fThread((pthread_t)NULL)
: JackThreadInterface(runnable, 0, false, cancellation), fThread((jack_native_thread_t)NULL)
{} {}


int Start(); int Start();
@@ -60,23 +60,23 @@ class SERVER_EXPORT JackPosixThread : public detail::JackThreadInterface


int AcquireRealTime(); // Used when called from another thread int AcquireRealTime(); // Used when called from another thread
int AcquireSelfRealTime(); // Used when called from thread itself int AcquireSelfRealTime(); // Used when called from thread itself
int AcquireRealTime(int priority); // Used when called from another thread int AcquireRealTime(int priority); // Used when called from another thread
int AcquireSelfRealTime(int priority); // Used when called from thread itself int AcquireSelfRealTime(int priority); // Used when called from thread itself
int DropRealTime(); // Used when called from another thread int DropRealTime(); // Used when called from another thread
int DropSelfRealTime(); // Used when called from thread itself int DropSelfRealTime(); // Used when called from thread itself


pthread_t GetThreadID();
jack_native_thread_t GetThreadID();
bool IsThread(); bool IsThread();


static int AcquireRealTimeImp(pthread_t thread, int priority);
static int AcquireRealTimeImp(pthread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint)
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority);
static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint)
{ return JackPosixThread::AcquireRealTimeImp(thread, priority); } { return JackPosixThread::AcquireRealTimeImp(thread, priority); }
static int DropRealTimeImp(pthread_t thread);
static int StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg);
static int StopImp(pthread_t thread);
static int KillImp(pthread_t thread);
static int DropRealTimeImp(jack_native_thread_t thread);
static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg);
static int StopImp(jack_native_thread_t thread);
static int KillImp(jack_native_thread_t thread);
}; };


SERVER_EXPORT void ThreadExit(); SERVER_EXPORT void ThreadExit();


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -45,12 +45,12 @@ void JackClientSocket::SetReadTimeOut(long sec)
{ {
int flags; int flags;
fTimeOut = sec; fTimeOut = sec;
if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) {
jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL"); jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL");
return; return;
} }
flags |= O_NONBLOCK; flags |= O_NONBLOCK;
if (fcntl(fSocket, F_SETFL, flags) < 0) { if (fcntl(fSocket, F_SETFL, flags) < 0) {
jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL"); jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL");
@@ -62,12 +62,12 @@ void JackClientSocket::SetWriteTimeOut(long sec)
{ {
int flags; int flags;
fTimeOut = sec; fTimeOut = sec;
if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) { if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) {
jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL"); jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL");
return; return;
} }
flags |= O_NONBLOCK; flags |= O_NONBLOCK;
if (fcntl(fSocket, F_SETFL, flags) < 0) { if (fcntl(fSocket, F_SETFL, flags) < 0) {
jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL"); jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL");
@@ -100,7 +100,7 @@ void JackClientSocket::SetWriteTimeOut(long sec)
#endif #endif


void JackClientSocket::SetNonBlocking(bool onoff) void JackClientSocket::SetNonBlocking(bool onoff)
{
{
if (onoff) { if (onoff) {
long flags = 0; long flags = 0;
if (fcntl(fSocket, F_SETFL, flags | O_NONBLOCK) < 0) { if (fcntl(fSocket, F_SETFL, flags | O_NONBLOCK) < 0) {
@@ -140,7 +140,7 @@ int JackClientSocket::Connect(const char* dir, const char* name, int which) // A


int JackClientSocket::Close() int JackClientSocket::Close()
{ {
jack_log("JackClientSocket::Close");
jack_log("JackClientSocket::Close");
if (fSocket > 0) { if (fSocket > 0) {
shutdown(fSocket, SHUT_RDWR); shutdown(fSocket, SHUT_RDWR);
close(fSocket); close(fSocket);
@@ -161,17 +161,17 @@ int JackClientSocket::Read(void* data, int len)
struct timeval tv; struct timeval tv;
fd_set fdset; fd_set fdset;
ssize_t res; ssize_t res;
tv.tv_sec = fTimeOut; tv.tv_sec = fTimeOut;
tv.tv_usec = 0; tv.tv_usec = 0;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(fSocket, &fdset); FD_SET(fSocket, &fdset);
do { do {
res = select(fSocket + 1, &fdset, NULL, NULL, &tv); res = select(fSocket + 1, &fdset, NULL, NULL, &tv);
} while (res < 0 && errno == EINTR); } while (res < 0 && errno == EINTR);
if (res < 0) { if (res < 0) {
return res; return res;
} else if (res == 0) { } else if (res == 0) {
@@ -179,9 +179,9 @@ int JackClientSocket::Read(void* data, int len)
} }
} }
#endif #endif
if ((res = read(fSocket, data, len)) != len) { if ((res = read(fSocket, data, len)) != len) {
if (errno == EWOULDBLOCK) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
jack_error("JackClientSocket::Read time out"); jack_error("JackClientSocket::Read time out");
return 0; // For a non blocking socket, a read failure is not considered as an error return 0; // For a non blocking socket, a read failure is not considered as an error
} else if (res != 0) { } else if (res != 0) {
@@ -201,21 +201,21 @@ int JackClientSocket::Write(void* data, int len)


#if defined(__sun__) || defined(sun) #if defined(__sun__) || defined(sun)
if (fTimeOut > 0) { if (fTimeOut > 0) {
struct timeval tv; struct timeval tv;
fd_set fdset; fd_set fdset;
ssize_t res; ssize_t res;
tv.tv_sec = fTimeOut; tv.tv_sec = fTimeOut;
tv.tv_usec = 0; tv.tv_usec = 0;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(fSocket, &fdset); FD_SET(fSocket, &fdset);
do { do {
res = select(fSocket + 1, NULL, &fdset, NULL, &tv); res = select(fSocket + 1, NULL, &fdset, NULL, &tv);
} while (res < 0 && errno == EINTR); } while (res < 0 && errno == EINTR);
if (res < 0) { if (res < 0) {
return res; return res;
} else if (res == 0) { } else if (res == 0) {
@@ -225,7 +225,7 @@ int JackClientSocket::Write(void* data, int len)
#endif #endif


if ((res = write(fSocket, data, len)) != len) { if ((res = write(fSocket, data, len)) != len) {
if (errno == EWOULDBLOCK) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
jack_log("JackClientSocket::Write time out"); jack_log("JackClientSocket::Write time out");
return 0; // For a non blocking socket, a write failure is not considered as an error return 0; // For a non blocking socket, a write failure is not considered as an error
} else if (res != 0) { } else if (res != 0) {
@@ -251,7 +251,7 @@ int JackServerSocket::Bind(const char* dir, const char* name, int which) // A re
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
BuildName(name, fName, dir, which); BuildName(name, fName, dir, which);
strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1);
jack_log("Bind: addr.sun_path %s", addr.sun_path); jack_log("Bind: addr.sun_path %s", addr.sun_path);
unlink(fName); // Security... unlink(fName); // Security...




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -108,7 +108,6 @@ int JackSocketClientChannel::Start()
} }
} }



void JackSocketClientChannel::Stop() void JackSocketClientChannel::Stop()
{ {
jack_log("JackSocketClientChannel::Stop"); jack_log("JackSocketClientChannel::Stop");
@@ -246,61 +245,73 @@ void JackSocketClientChannel::SetFreewheel(int onoff, int* result)
ServerSyncCall(&req, &res, result); ServerSyncCall(&req, &res, result);
} }


void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t ** result)
void JackSocketClientChannel::ComputeTotalLatencies(int* result)
{
JackComputeTotalLatenciesRequest req;
JackResult res;
ServerSyncCall(&req, &res, result);
}

void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result)
{ {
JackSessionNotifyRequest req(refnum, path, type, target); JackSessionNotifyRequest req(refnum, path, type, target);
JackSessionNotifyResult res;
JackSessionNotifyResult res;
int intresult; int intresult;
ServerSyncCall(&req, &res, &intresult); ServerSyncCall(&req, &res, &intresult);


jack_session_command_t *session_command = (jack_session_command_t *)malloc( sizeof(jack_session_command_t) * (res.fCommandList.size()+1) );
int i=0;
jack_session_command_t* session_command = (jack_session_command_t *)malloc(sizeof(jack_session_command_t) * (res.fCommandList.size() + 1));
int i = 0;
for (std::list<JackSessionCommand>::iterator ci=res.fCommandList.begin(); ci!=res.fCommandList.end(); ci++) { for (std::list<JackSessionCommand>::iterator ci=res.fCommandList.begin(); ci!=res.fCommandList.end(); ci++) {
session_command[i].uuid = strdup( ci->fUUID );
session_command[i].client_name = strdup( ci->fClientName );
session_command[i].command = strdup( ci->fCommand );
session_command[i].flags = ci->fFlags;

i+=1;
}
session_command[i].uuid = strdup( ci->fUUID );
session_command[i].client_name = strdup( ci->fClientName );
session_command[i].command = strdup( ci->fCommand );
session_command[i].flags = ci->fFlags;
i += 1;
}

session_command[i].uuid = NULL; session_command[i].uuid = NULL;
session_command[i].client_name = NULL; session_command[i].client_name = NULL;
session_command[i].command = NULL; session_command[i].command = NULL;
session_command[i].flags = (jack_session_flags_t)0; session_command[i].flags = (jack_session_flags_t)0;



*result = session_command; *result = session_command;
} }


void JackSocketClientChannel::SessionReply(int refnum, int* result) void JackSocketClientChannel::SessionReply(int refnum, int* result)
{ {
JackSessionReplyRequest req(refnum); JackSessionReplyRequest req(refnum);
JackResult res;
JackResult res;
ServerSyncCall(&req, &res, result); ServerSyncCall(&req, &res, result);
} }


void JackSocketClientChannel::GetUUIDForClientName( int refnum, const char *client_name, char *uuid_res, int *result )
void JackSocketClientChannel::GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result)
{ {
JackGetUUIDRequest req(client_name); JackGetUUIDRequest req(client_name);
JackUUIDResult res;
JackUUIDResult res;
ServerSyncCall(&req, &res, result); ServerSyncCall(&req, &res, result);
strncpy( uuid_res, res.fUUID, JACK_UUID_SIZE );
strncpy(uuid_res, res.fUUID, JACK_UUID_SIZE);
} }


void JackSocketClientChannel::GetClientNameForUUID( int refnum, const char *uuid, char *name_res, int *result )
void JackSocketClientChannel::GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result)
{ {
JackGetClientNameRequest req(uuid); JackGetClientNameRequest req(uuid);
JackClientNameResult res;
JackClientNameResult res;
ServerSyncCall(&req, &res, result);
strncpy(name_res, res.fName, JACK_CLIENT_NAME_SIZE);
}

void JackSocketClientChannel::ClientHasSessionCallback(const char* client_name, int* result)
{
JackClientHasSessionCallbackRequest req(client_name);
JackResult res;
ServerSyncCall(&req, &res, result); ServerSyncCall(&req, &res, result);
strncpy( name_res, res.fName, JACK_CLIENT_NAME_SIZE );
} }


void JackSocketClientChannel::ReserveClientName( int refnum, const char *client_name, const char *uuid, int *result )
void JackSocketClientChannel::ReserveClientName(int refnum, const char* client_name, const char* uuid, int* result)
{ {
JackReserveNameRequest req(refnum, client_name, uuid); JackReserveNameRequest req(refnum, client_name, uuid);
JackResult res;
JackResult res;
ServerSyncCall(&req, &res, result); ServerSyncCall(&req, &res, result);
} }


@@ -363,7 +374,7 @@ bool JackSocketClientChannel::Init()
jack_error("JackSocketClientChannel: cannot establish notication socket"); jack_error("JackSocketClientChannel: cannot establish notication socket");
return false; return false;
} else { } else {
return fClient->Init();
return true;
} }
} }




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -38,11 +38,11 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi


private: private:


JackClientSocket fRequestSocket; // Socket to communicate with the server
JackServerSocket fNotificationListenSocket; // Socket listener for server notification
JackClientSocket* fNotificationSocket; // Socket for server notification
JackClientSocket fRequestSocket; // Socket to communicate with the server
JackServerSocket fNotificationListenSocket; // Socket listener for server notification
JackClientSocket* fNotificationSocket; // Socket for server notification
JackThread fThread; // Thread to execute the event loop JackThread fThread; // Thread to execute the event loop
JackClient* fClient;
JackClient* fClient;


void ServerSyncCall(JackRequest* req, JackResult* res, int* result); void ServerSyncCall(JackRequest* req, JackResult* res, int* result);
void ServerAsyncCall(JackRequest* req, JackResult* res, int* result); void ServerAsyncCall(JackRequest* req, JackResult* res, int* result);
@@ -77,12 +77,14 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi


void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result);
void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result);
void PortRename(int refnum, jack_port_id_t port, const char* name, int* result); void PortRename(int refnum, jack_port_id_t port, const char* name, int* result);


void SetBufferSize(jack_nframes_t buffer_size, int* result); void SetBufferSize(jack_nframes_t buffer_size, int* result);
void SetFreewheel(int onoff, int* result); void SetFreewheel(int onoff, int* result);


void ComputeTotalLatencies(int* result);

void ReleaseTimebase(int refnum, int* result); void ReleaseTimebase(int refnum, int* result);
void SetTimebaseCallback(int refnum, int conditional, int* result); void SetTimebaseCallback(int refnum, int conditional, int* result);


@@ -91,18 +93,18 @@ class JackSocketClientChannel : public detail::JackClientChannelInterface, publi
void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result); void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result);
void InternalClientUnload(int refnum, int int_ref, int* status, int* result); void InternalClientUnload(int refnum, int int_ref, int* status, int* result);


// Session Stuff
// Session API
void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result); void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result);
void SessionReply(int refnum, int* result); void SessionReply(int refnum, int* result);
void GetUUIDForClientName( int refnum, const char *client_name, char *uuid_res, int *result );
void GetClientNameForUUID( int refnum, const char *uuid, char *name_res, int *result );
void ReserveClientName( int refnum, const char *client_name, const char *uuid, int *result );
void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result);
void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result);
void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result);
void ClientHasSessionCallback(const char* client_name, int* result);


// JackRunnableInterface interface // JackRunnableInterface interface
bool Init(); bool Init();
bool Execute(); bool Execute();



bool IsChannelThread() { return fThread.IsThread(); } bool IsChannelThread() { return fThread.IsThread(); }
}; };




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -51,7 +51,7 @@ JackSocketServerChannel::~JackSocketServerChannel()
int JackSocketServerChannel::Open(const char* server_name, JackServer* server) int JackSocketServerChannel::Open(const char* server_name, JackServer* server)
{ {
jack_log("JackSocketServerChannel::Open"); jack_log("JackSocketServerChannel::Open");
// Prepare request socket // Prepare request socket
if (fRequestListenSocket.Bind(jack_server_dir, server_name, 0) < 0) { if (fRequestListenSocket.Bind(jack_server_dir, server_name, 0) < 0) {
jack_log("JackSocketServerChannel::Open : cannot create result listen socket"); jack_log("JackSocketServerChannel::Open : cannot create result listen socket");
@@ -79,14 +79,14 @@ void JackSocketServerChannel::Close()
delete socket; delete socket;
} }
} }
int JackSocketServerChannel::Start() int JackSocketServerChannel::Start()
{ {
if (fThread.Start() != 0) { if (fThread.Start() != 0) {
jack_error("Cannot start Jack server listener"); jack_error("Cannot start Jack server listener");
return -1; return -1;
}
}
return 0; return 0;
} }


@@ -168,6 +168,12 @@ bool JackSocketServerChannel::HandleRequest(int fd)
return false; return false;
} }


if (fd == JackServerGlobals::fRTNotificationSocket && header.fType != JackRequest::kNotification) {
jack_error("fRTNotificationSocket = %d", JackServerGlobals::fRTNotificationSocket);
jack_error("JackSocketServerChannel::HandleRequest : incorrect notification !!");
return true;
}

// Read data // Read data
switch (header.fType) { switch (header.fType) {


@@ -292,7 +298,7 @@ bool JackSocketServerChannel::HandleRequest(int fd)
jack_error("JackRequest::DisconnectPorts write error ref = %d", req.fRefNum); jack_error("JackRequest::DisconnectPorts write error ref = %d", req.fRefNum);
break; break;
} }
case JackRequest::kPortRename: { case JackRequest::kPortRename: {
jack_log("JackRequest::PortRename"); jack_log("JackRequest::PortRename");
JackPortRenameRequest req; JackPortRenameRequest req;
@@ -326,6 +332,17 @@ bool JackSocketServerChannel::HandleRequest(int fd)
break; break;
} }


case JackRequest::kComputeTotalLatencies: {
jack_log("JackRequest::ComputeTotalLatencies");
JackComputeTotalLatenciesRequest req;
JackResult res;
if (req.Read(socket) == 0)
res.fResult = fServer->GetEngine()->ComputeTotalLatencies();
if (res.Write(socket) < 0)
jack_error("JackRequest::ComputeTotalLatencies write error");
break;
}

case JackRequest::kReleaseTimebase: { case JackRequest::kReleaseTimebase: {
jack_log("JackRequest::ReleaseTimebase"); jack_log("JackRequest::ReleaseTimebase");
JackReleaseTimebaseRequest req; JackReleaseTimebaseRequest req;
@@ -430,27 +447,26 @@ bool JackSocketServerChannel::HandleRequest(int fd)
} }


case JackRequest::kGetClientByUUID: { case JackRequest::kGetClientByUUID: {
jack_log("JackRequest::GetClientNameForUUID");
jack_log("JackRequest::GetClientByUUID");
JackGetClientNameRequest req; JackGetClientNameRequest req;
JackClientNameResult res; JackClientNameResult res;
if (req.Read(socket) == 0) { if (req.Read(socket) == 0) {
fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult); fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult);
} }
if (res.Write(socket) < 0) if (res.Write(socket) < 0)
jack_error("JackRequest::GetClientNameForUUID write error");
jack_error("JackRequest::GetClientByUUID write error");
break; break;
} }


case JackRequest::kGetUUIDByClient: { case JackRequest::kGetUUIDByClient: {
jack_log("JackRequest::GetUUIDForClientName");
jack_log("JackRequest::GetUUIDByClient");
JackGetUUIDRequest req; JackGetUUIDRequest req;
JackUUIDResult res; JackUUIDResult res;
if (req.Read(socket) == 0) { if (req.Read(socket) == 0) {
fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult); fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult);
res.fResult = 0;
} }
if (res.Write(socket) < 0) if (res.Write(socket) < 0)
jack_error("JackRequest::GetUUIDForClientName write error");
jack_error("JackRequest::GetUUIDByClient write error");
break; break;
} }


@@ -466,11 +482,23 @@ bool JackSocketServerChannel::HandleRequest(int fd)
break; break;
} }


case JackRequest::kClientHasSessionCallback: {
jack_log("JackRequest::ClientHasSessionCallback");
JackClientHasSessionCallbackRequest req;
JackResult res;
if (req.Read(socket) == 0) {
fServer->GetEngine()->ClientHasSessionCallbackRequest(req.fName, &res.fResult);
}
if (res.Write(socket) < 0)
jack_error("JackRequest::ClientHasSessionCallback write error");
break;
}

default: default:
jack_error("Unknown request %ld", header.fType); jack_error("Unknown request %ld", header.fType);
break; break;
} }
return true; return true;
} }


@@ -511,7 +539,7 @@ bool JackSocketServerChannel::Init()
bool JackSocketServerChannel::Execute() bool JackSocketServerChannel::Execute()
{ {
try { try {
// Global poll // Global poll
if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) { if ((poll(fPollTable, fSocketTable.size() + 1, 10000) < 0) && (errno != EINTR)) {
jack_error("Engine poll failed err = %s request thread quits...", strerror(errno)); jack_error("Engine poll failed err = %s request thread quits...", strerror(errno));
@@ -526,22 +554,22 @@ bool JackSocketServerChannel::Execute()
jack_log("Poll client error err = %s", strerror(errno)); jack_log("Poll client error err = %s", strerror(errno));
ClientKill(fd); ClientKill(fd);
} else if (fPollTable[i].revents & POLLIN) { } else if (fPollTable[i].revents & POLLIN) {
if (!HandleRequest(fd))
if (!HandleRequest(fd))
jack_log("Could not handle external client request"); jack_log("Could not handle external client request");
} }
} }


// Check the server request socket */ // Check the server request socket */
if (fPollTable[0].revents & POLLERR)
if (fPollTable[0].revents & POLLERR)
jack_error("Error on server request socket err = %s", strerror(errno)); jack_error("Error on server request socket err = %s", strerror(errno));
if (fPollTable[0].revents & POLLIN)
if (fPollTable[0].revents & POLLIN)
ClientCreate(); ClientCreate();
} }


BuildPoolTable(); BuildPoolTable();
return true; return true;
} catch (JackQuitException& e) { } catch (JackQuitException& e) {
jack_log("JackMachServerChannel::Execute JackQuitException"); jack_log("JackMachServerChannel::Execute JackQuitException");
return false; return false;


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -41,7 +41,7 @@ class JackSocketServerChannel : public JackRunnableInterface


JackServerSocket fRequestListenSocket; // Socket to create request socket for the client JackServerSocket fRequestListenSocket; // Socket to create request socket for the client
JackThread fThread; // Thread to execute the event loop JackThread fThread; // Thread to execute the event loop
JackServer* fServer;
JackServer* fServer;
pollfd* fPollTable; pollfd* fPollTable;
bool fRebuild; bool fRebuild;
std::map<int, std::pair<int, JackClientSocket*> > fSocketTable; std::map<int, std::pair<int, JackClientSocket*> > fSocketTable;
@@ -61,7 +61,7 @@ class JackSocketServerChannel : public JackRunnableInterface


int Open(const char* server_name, JackServer* server); // Open the Server/Client connection int Open(const char* server_name, JackServer* server); // Open the Server/Client connection
void Close(); // Close the Server/Client connection void Close(); // Close the Server/Client connection
int Start(); int Start();


// JackRunnableInterface interface // JackRunnableInterface interface


+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackRequest.h" #include "JackRequest.h"
#include "JackConstants.h" #include "JackConstants.h"
#include "JackNotification.h" #include "JackNotification.h"
#include "JackServerGlobals.h"


namespace Jack namespace Jack
{ {
@@ -33,6 +34,7 @@ int JackSocketServerNotifyChannel::Open(const char* server_name)
return -1; return -1;
} else { } else {
fRequestSocket.SetNonBlocking(true); fRequestSocket.SetNonBlocking(true);
JackServerGlobals::fRTNotificationSocket = fRequestSocket.GetFd();
return 0; return 0;
} }
} }
@@ -63,7 +65,7 @@ void JackSocketServerNotifyChannel::NotifyQuit()
jack_error("Could not write request ref = %d notify = %d", -1, kQUIT); jack_error("Could not write request ref = %d notify = %d", -1, kQUIT);
} }
} }


} // end of namespace } // end of namespace




+ 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. GNU Lesser General Public License for more details.


You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


*/ */


+ 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 <signal.h>
#include <dlfcn.h> #include <dlfcn.h>


#define UINT32_MAX 4294967295U

#define DRIVER_HANDLE void* #define DRIVER_HANDLE void*
#define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) #define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL)
#define UnloadDriverModule(handle) dlclose((handle)) #define UnloadDriverModule(handle) dlclose((handle))


+ 2
- 0
posix/JackTypes_os.h View File

@@ -26,6 +26,8 @@
typedef unsigned long long UInt64; typedef unsigned long long UInt64;
typedef pthread_key_t jack_tls_key; typedef pthread_key_t jack_tls_key;


typedef pthread_t jack_native_thread_t;

typedef int (*jack_thread_creator_t)(pthread_t*, const pthread_attr_t*, void* (*function)(void*), void* arg); typedef int (*jack_thread_creator_t)(pthread_t*, const pthread_attr_t*, void* (*function)(void*), void* arg);


#endif #endif

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

@@ -1,6 +1,6 @@
/* /*
Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net> Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
@@ -95,14 +95,14 @@ int MTDM::process (size_t len, float *ip, float *op)
vip = *ip++; vip = *ip++;
for (i = 0, F = _freq; i < 5; i++, F++) for (i = 0, F = _freq; i < 5; i++, F++)
{ {
a = 2 * (float) M_PI * (F->p & 65535) / 65536.0;
a = 2 * (float) M_PI * (F->p & 65535) / 65536.0;
F->p += F->f; F->p += F->f;
c = cosf (a);
s = -sinf (a);
c = cosf (a);
s = -sinf (a);
vop += F->a * s; vop += F->a * s;
F->xa += s * vip; F->xa += s * vip;
F->ya += c * vip; F->ya += c * vip;
}
}
*op++ = vop; *op++ = vop;
if (++_cnt == 16) if (++_cnt == 16)
{ {
@@ -142,10 +142,10 @@ int MTDM::resolve (void)
k = (int)(floor (p + 0.5)); k = (int)(floor (p + 0.5));
e = fabs (p - k); e = fabs (p - k);
if (e > _err) _err = e; if (e > _err) _err = e;
if (e > 0.4) return 1;
if (e > 0.4) return 1;
d += m * (k & 7); d += m * (k & 7);
m *= 8; m *= 8;
}
}
_del = 16 * d; _del = 16 * d;


return 0; return 0;
@@ -158,6 +158,34 @@ static jack_client_t *jack_handle;
static jack_port_t *jack_capt; static jack_port_t *jack_capt;
static jack_port_t *jack_play; static jack_port_t *jack_play;


jack_latency_range_t capture_latency = {-1, -1};
jack_latency_range_t playback_latency = {-1, -1};

void
latency_cb (jack_latency_callback_mode_t mode, void *arg)
{
jack_latency_range_t range;

range.min = range.max = 0;

if (mode == JackCaptureLatency) {
jack_port_set_latency_range (jack_play, mode, &range);
jack_port_get_latency_range (jack_capt, mode, &range);
if ((range.min != capture_latency.min) || (range.max != capture_latency.max)) {
capture_latency = range;
printf ("new capture latency: [%d, %d]\n", range.min, range.max);
}
} else {
jack_port_set_latency_range (jack_capt, mode, &range);
jack_port_get_latency_range (jack_play, mode, &range);
if ((range.min != playback_latency.min) || (range.max != playback_latency.max)) {
playback_latency = range;
printf ("new playback latency: [%d, %d]\n", range.min, range.max);
}
}

}

int jack_callback (jack_nframes_t nframes, void *arg) int jack_callback (jack_nframes_t nframes, void *arg)
{ {
float *ip, *op; float *ip, *op;
@@ -182,14 +210,12 @@ int main (int ac, char *av [])


jack_set_process_callback (jack_handle, jack_callback, 0); jack_set_process_callback (jack_handle, jack_callback, 0);


if (jack_set_latency_callback)
jack_set_latency_callback (jack_handle, latency_cb, 0);

jack_capt = jack_port_register (jack_handle, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); jack_capt = jack_port_register (jack_handle, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
jack_play = jack_port_register (jack_handle, "out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); jack_play = jack_port_register (jack_handle, "out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);


printf ("capture latency = %d\n",
jack_port_get_latency (jack_port_by_name (jack_handle, "system:capture_1")));
printf ("playback_latency = %d\n",
jack_port_get_latency (jack_port_by_name (jack_handle, "system:playback_1")));

t = 1000.0f / jack_get_sample_rate (jack_handle); t = 1000.0f / jack_get_sample_rate (jack_handle);


if (jack_activate (jack_handle)) if (jack_activate (jack_handle))
@@ -200,16 +226,16 @@ int main (int ac, char *av [])


while (1) while (1)
{ {
#ifdef WIN32
Sleep (250);
#else
usleep (250000);
#endif
#ifdef WIN32
Sleep (250);
#else
usleep (250000);
#endif
if (mtdm.resolve () < 0) printf ("Signal below threshold...\n"); if (mtdm.resolve () < 0) printf ("Signal below threshold...\n");
else
else
{ {
if (mtdm.err () > 0.3)
if (mtdm.err () > 0.3)
{ {
mtdm.invert (); mtdm.invert ();
mtdm.resolve (); mtdm.resolve ();

+ 1
- 1
tests/wscript View File

@@ -9,7 +9,7 @@ test_programs = {
#'testSem': ['testSem.cpp'], #'testSem': ['testSem.cpp'],
'jack_test': ['test.cpp'], 'jack_test': ['test.cpp'],
'jack_cpu': ['cpu.c'], 'jack_cpu': ['cpu.c'],
'jack_delay': ['jdelay.cpp'],
'jack_iodelay': ['iodelay.cpp'],
'jack_multiple_metro' : ['external_metro.cpp'], 'jack_multiple_metro' : ['external_metro.cpp'],
} }




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

@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"


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

Loading…
Cancel
Save