jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

531 lines
13KB

  1. /*
  2. JACK transport client interface -- runs in the client process.
  3. Copyright (C) 2001-2003 Paul Davis
  4. Copyright (C) 2003 Jack O'Quin
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public License
  7. as published by the Free Software Foundation; either version 2.1
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this program; if not, write to the Free
  15. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  16. 02111-1307, USA.
  17. */
  18. #include <config.h>
  19. #include <errno.h>
  20. #include <math.h>
  21. #include <stdio.h>
  22. #include <jack/internal.h>
  23. #include "local.h"
  24. /********************* Internal functions *********************/
  25. /* generate a unique non-zero ID, different for each call */
  26. jack_unique_t
  27. jack_generate_unique_id (jack_control_t *ectl)
  28. {
  29. /* The jack_unique_t is an opaque type. Its structure is only
  30. * known here. We use the least significant word of the CPU
  31. * cycle counter. For SMP, I would like to include the
  32. * current thread ID, since only one thread runs on a CPU at a
  33. * time.
  34. *
  35. * But, pthread_self() is broken on my Debian GNU/Linux
  36. * system, it always seems to return 16384. That's useless.
  37. * So, I'm using the process ID instead. With Linux 2.4 and
  38. * Linuxthreads there is an LWP for each thread so this works,
  39. * but is not portable. :-(
  40. */
  41. volatile union {
  42. jack_unique_t unique;
  43. struct {
  44. pid_t pid;
  45. unsigned long cycle;
  46. } field;
  47. } id;
  48. id.field.cycle = (unsigned long) get_cycles();
  49. id.field.pid = getpid();
  50. // JOQ: Alternatively, we could keep a sequence number in
  51. // shared memory, using <asm/atomic.h> to increment it. I
  52. // really like the simplicity of that approach. But I hate
  53. // forcing JACK to either depend on that pesky header file, or
  54. // maintain its own like ardour does.
  55. // fprintf (stderr, "unique ID 0x%" PRIx64
  56. // ", process %d, cycle 0x%" PRIx32 "\n",
  57. // id.unique, id.field.pid, id.field.cycle);
  58. return id.unique;
  59. }
  60. static inline void
  61. jack_read_frame_time (const jack_client_t *client, jack_frame_timer_t *copy)
  62. {
  63. int tries = 0;
  64. do {
  65. /* throttle the busy wait if we don't get
  66. the answer very quickly.
  67. */
  68. if (tries > 10) {
  69. usleep (20);
  70. tries = 0;
  71. }
  72. *copy = client->engine->frame_timer;
  73. tries++;
  74. } while (copy->guard1 != copy->guard2);
  75. }
  76. /* copy a JACK transport position structure (thread-safe) */
  77. void
  78. jack_transport_copy_position (jack_position_t *from, jack_position_t *to)
  79. {
  80. int tries = 0;
  81. long timeout = 1000;
  82. do {
  83. /* throttle the busy wait if we don't get the answer
  84. * very quickly. */
  85. if (tries > 10) {
  86. usleep (20);
  87. tries = 0;
  88. /* debug code to avoid system hangs... */
  89. if (--timeout == 0) {
  90. jack_error("hung in loop copying position");
  91. abort();
  92. }
  93. }
  94. *to = *from;
  95. tries++;
  96. } while (to->unique_1 != to->unique_2);
  97. }
  98. static inline int
  99. jack_transport_request_new_pos (jack_client_t *client, jack_position_t *pos)
  100. {
  101. jack_control_t *ectl = client->engine;
  102. /* distinguish this request from all others */
  103. pos->unique_1 = pos->unique_2 = jack_generate_unique_id(ectl);
  104. /* clients may not set these fields */
  105. pos->usecs = ectl->current_time.usecs;
  106. pos->frame_rate = ectl->current_time.frame_rate;
  107. /* carefully copy requested postion into shared memory */
  108. jack_transport_copy_position (pos, &ectl->request_time);
  109. return 0;
  110. }
  111. /******************** Callback invocations ********************/
  112. void
  113. jack_call_sync_client (jack_client_t *client)
  114. {
  115. jack_client_control_t *control = client->control;
  116. jack_control_t *ectl = client->engine;
  117. /* Make sure still active and slow-sync; active_slowsync is
  118. * set in a critical section; sync_cb is not. */
  119. if ((ectl->new_pos || control->sync_poll || control->sync_new) &&
  120. control->active_slowsync) {
  121. if (control->sync_cb (ectl->transport_state,
  122. &ectl->current_time,
  123. control->sync_arg)) {
  124. if (control->sync_poll) {
  125. control->sync_poll = 0;
  126. ectl->sync_remain--;
  127. }
  128. }
  129. control->sync_new = 0;
  130. }
  131. }
  132. void
  133. jack_call_timebase_master (jack_client_t *client)
  134. {
  135. jack_client_control_t *control = client->control;
  136. jack_control_t *ectl = client->engine;
  137. int new_pos = (int) ectl->pending_pos;
  138. /* Make sure this is still the master; is_timebase is set in a
  139. * critical section; timebase_cb is not. */
  140. if (control->is_timebase) {
  141. if (control->timebase_new) { /* first callback? */
  142. control->timebase_new = 0;
  143. new_pos = 1;
  144. }
  145. if ((ectl->transport_state == JackTransportRolling) ||
  146. new_pos) {
  147. control->timebase_cb (ectl->transport_state,
  148. control->nframes,
  149. &ectl->pending_time,
  150. new_pos,
  151. control->timebase_arg);
  152. }
  153. } else {
  154. /* another master took over, so resign */
  155. control->timebase_cb = NULL;
  156. control->timebase_arg = NULL;
  157. }
  158. }
  159. /************************* API functions *************************/
  160. jack_nframes_t
  161. jack_get_current_transport_frame (const jack_client_t *client)
  162. {
  163. jack_position_t position;
  164. float usecs;
  165. jack_nframes_t elapsed;
  166. jack_transport_state_t tstate;
  167. /* get the current transport position information.
  168. this is thread-safe and atomic with respect
  169. to the structure contents.
  170. */
  171. tstate = jack_transport_query (client, &position);
  172. if (tstate != JackTransportRolling) {
  173. return position.frame;
  174. }
  175. /* compute the elapsed usecs then audio frames since
  176. the transport info was last updated
  177. */
  178. usecs = jack_get_microseconds() - position.usecs;
  179. elapsed = (jack_nframes_t) floor ((((float) position.frame_rate) / 1000000.0f) * usecs);
  180. /* return the estimated transport frame position
  181. */
  182. return position.frame + elapsed;
  183. }
  184. jack_nframes_t
  185. jack_frames_since_cycle_start (const jack_client_t *client)
  186. {
  187. float usecs;
  188. jack_control_t *ectl = client->engine;
  189. usecs = jack_get_microseconds() - ectl->current_time.usecs;
  190. return (jack_nframes_t) floor ((((float) ectl->current_time.frame_rate)
  191. / 1000000.0f) * usecs);
  192. }
  193. jack_nframes_t
  194. jack_frame_time (const jack_client_t *client)
  195. {
  196. jack_frame_timer_t current;
  197. float usecs;
  198. jack_nframes_t elapsed;
  199. jack_control_t *ectl = client->engine;
  200. jack_read_frame_time (client, &current);
  201. usecs = jack_get_microseconds() - current.stamp;
  202. elapsed = (jack_nframes_t)
  203. floor ((((float) ectl->current_time.frame_rate)
  204. / 1000000.0f) * usecs);
  205. return current.frames + elapsed;
  206. }
  207. jack_nframes_t
  208. jack_get_sample_rate (jack_client_t *client)
  209. {
  210. return client->engine->current_time.frame_rate;
  211. }
  212. int
  213. jack_set_sample_rate_callback (jack_client_t *client,
  214. JackSampleRateCallback callback, void *arg)
  215. {
  216. if (client->control->active) {
  217. jack_error ("You cannot set callbacks on an active client.");
  218. return -1;
  219. }
  220. client->control->srate_arg = arg;
  221. client->control->srate = callback;
  222. /* Now invoke it */
  223. callback (client->engine->current_time.frame_rate, arg);
  224. return 0;
  225. }
  226. int
  227. jack_release_timebase (jack_client_t *client)
  228. {
  229. int rc;
  230. jack_request_t req;
  231. jack_client_control_t *ctl = client->control;
  232. req.type = ResetTimeBaseClient;
  233. req.x.client_id = ctl->id;
  234. rc = jack_client_deliver_request (client, &req);
  235. if (rc == 0) {
  236. ctl->timebase_cb = NULL;
  237. ctl->timebase_arg = NULL;
  238. }
  239. return rc;
  240. }
  241. int
  242. jack_set_sync_callback (jack_client_t *client,
  243. JackSyncCallback sync_callback, void *arg)
  244. {
  245. jack_client_control_t *ctl = client->control;
  246. jack_request_t req;
  247. int rc;
  248. if (sync_callback)
  249. req.type = SetSyncClient;
  250. else
  251. req.type = ResetSyncClient;
  252. req.x.client_id = ctl->id;
  253. rc = jack_client_deliver_request (client, &req);
  254. if (rc == 0) {
  255. ctl->sync_cb = sync_callback;
  256. ctl->sync_arg = arg;
  257. }
  258. return rc;
  259. }
  260. int
  261. jack_set_sync_timeout (jack_client_t *client, jack_time_t usecs)
  262. {
  263. jack_request_t req;
  264. req.type = SetSyncTimeout;
  265. req.x.timeout = usecs;
  266. return jack_client_deliver_request (client, &req);
  267. }
  268. int
  269. jack_set_timebase_callback (jack_client_t *client, int conditional,
  270. JackTimebaseCallback timebase_cb, void *arg)
  271. {
  272. int rc;
  273. jack_request_t req;
  274. jack_client_control_t *ctl = client->control;
  275. req.type = SetTimeBaseClient;
  276. req.x.timebase.client_id = ctl->id;
  277. req.x.timebase.conditional = conditional;
  278. rc = jack_client_deliver_request (client, &req);
  279. if (rc == 0) {
  280. ctl->timebase_arg = arg;
  281. ctl->timebase_cb = timebase_cb;
  282. }
  283. return rc;
  284. }
  285. int
  286. jack_transport_locate (jack_client_t *client, jack_nframes_t frame)
  287. {
  288. jack_position_t pos;
  289. pos.frame = frame;
  290. pos.valid = 0;
  291. return jack_transport_request_new_pos (client, &pos);
  292. }
  293. jack_transport_state_t
  294. jack_transport_query (const jack_client_t *client, jack_position_t *pos)
  295. {
  296. jack_control_t *ectl = client->engine;
  297. if (pos) {
  298. /* the guarded copy makes this function work in any
  299. * thread
  300. */
  301. jack_transport_copy_position (&ectl->current_time, pos);
  302. }
  303. return ectl->transport_state;
  304. }
  305. int
  306. jack_transport_reposition (jack_client_t *client, jack_position_t *pos)
  307. {
  308. /* copy the input, to avoid modifying its contents */
  309. jack_position_t tmp = *pos;
  310. /* validate input */
  311. if (tmp.valid & ~JACK_POSITION_MASK) /* unknown field present? */
  312. return EINVAL;
  313. return jack_transport_request_new_pos (client, &tmp);
  314. }
  315. void
  316. jack_transport_start (jack_client_t *client)
  317. {
  318. client->engine->transport_cmd = TransportCommandStart;
  319. }
  320. void
  321. jack_transport_stop (jack_client_t *client)
  322. {
  323. client->engine->transport_cmd = TransportCommandStop;
  324. }
  325. #ifdef OLD_TRANSPORT
  326. /************* Compatibility with old transport API. *************/
  327. #define OLD_TIMEBASE_BROKEN
  328. int
  329. jack_engine_takeover_timebase (jack_client_t *client)
  330. {
  331. #ifdef OLD_TIMEBASE_BROKEN
  332. return ENOSYS;
  333. #else
  334. jack_request_t req;
  335. req.type = SetTimeBaseClient;
  336. req.x.timebase.client_id = client->control->id;
  337. req.x.timebase.conditional = 0;
  338. return jack_client_deliver_request (client, &req);
  339. #endif /* OLD_TIMEBASE_BROKEN */
  340. }
  341. void
  342. jack_get_transport_info (jack_client_t *client,
  343. jack_transport_info_t *info)
  344. {
  345. jack_control_t *ectl = client->engine;
  346. /* check that this is the process thread */
  347. if (!pthread_equal(client->thread_id, pthread_self())) {
  348. jack_error("Invalid thread for jack_get_transport_info().");
  349. abort(); /* kill this client */
  350. }
  351. info->usecs = ectl->current_time.usecs;
  352. info->frame_rate = ectl->current_time.frame_rate;
  353. info->transport_state = ectl->transport_state;
  354. info->frame = ectl->current_time.frame;
  355. info->valid = (ectl->current_time.valid |
  356. JackTransportState | JackTransportPosition);
  357. if (info->valid & JackTransportBBT) {
  358. info->bar = ectl->current_time.bar;
  359. info->beat = ectl->current_time.beat;
  360. info->tick = ectl->current_time.tick;
  361. info->bar_start_tick = ectl->current_time.bar_start_tick;
  362. info->beats_per_bar = ectl->current_time.beats_per_bar;
  363. info->beat_type = ectl->current_time.beat_type;
  364. info->ticks_per_beat = ectl->current_time.ticks_per_beat;
  365. info->beats_per_minute = ectl->current_time.beats_per_minute;
  366. }
  367. }
  368. void
  369. jack_set_transport_info (jack_client_t *client,
  370. jack_transport_info_t *info)
  371. {
  372. static int first_error = 1;
  373. #ifdef OLD_TIMEBASE_BROKEN
  374. if (first_error)
  375. jack_error ("jack_set_transport_info() no longer supported.");
  376. first_error = 0;
  377. #else
  378. jack_control_t *ectl = client->engine;
  379. if (!client->control->is_timebase) { /* not timebase master? */
  380. if (first_error)
  381. jack_error ("Called jack_set_transport_info(), "
  382. "but not timebase master.");
  383. first_error = 0;
  384. /* JOQ: I would prefer to ignore this request, but
  385. * that would break ardour 0.9-beta2. So, let's allow
  386. * it for now. */
  387. // return;
  388. }
  389. /* check that this is the process thread */
  390. if (!pthread_equal(client->thread_id, pthread_self())) {
  391. jack_error ("Invalid thread for jack_set_transport_info().");
  392. abort(); /* kill this client */
  393. }
  394. /* is there a new state? */
  395. if ((info->valid & JackTransportState) &&
  396. (info->transport_state != ectl->transport_state)) {
  397. if (info->transport_state == JackTransportStopped)
  398. ectl->transport_cmd = TransportCommandStop;
  399. else if ((info->transport_state == JackTransportRolling) &&
  400. (ectl->transport_state != JackTransportStarting))
  401. ectl->transport_cmd = TransportCommandStart;
  402. /* silently ignore anything else */
  403. }
  404. if (info->valid & JackTransportPosition)
  405. ectl->pending_time.frame = info->frame;
  406. else
  407. ectl->pending_time.frame = ectl->current_time.frame;
  408. ectl->pending_time.valid = (info->valid & JACK_POSITION_MASK);
  409. if (info->valid & JackTransportBBT) {
  410. ectl->pending_time.bar = info->bar;
  411. ectl->pending_time.beat = info->beat;
  412. ectl->pending_time.tick = info->tick;
  413. ectl->pending_time.bar_start_tick = info->bar_start_tick;
  414. ectl->pending_time.beats_per_bar = info->beats_per_bar;
  415. ectl->pending_time.beat_type = info->beat_type;
  416. ectl->pending_time.ticks_per_beat = info->ticks_per_beat;
  417. ectl->pending_time.beats_per_minute = info->beats_per_minute;
  418. }
  419. #endif /* OLD_TIMEBASE_BROKEN */
  420. }
  421. #endif /* OLD_TRANSPORT */