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.

519 lines
14KB

  1. /*
  2. JACK transport engine -- runs in the server 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 General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. 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 General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #include <config.h>
  18. #include <errno.h>
  19. #include <assert.h>
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <jack/internal.h>
  23. #include <jack/engine.h>
  24. #include "transengine.h"
  25. /********************** internal functions **********************/
  26. /* initiate polling a new slow-sync client
  27. *
  28. * precondition: caller holds the graph lock. */
  29. static inline void
  30. jack_sync_poll_new (jack_engine_t *engine, jack_client_internal_t *client)
  31. {
  32. /* force sync_cb callback to run in its first cycle */
  33. engine->control->sync_time_left = engine->control->sync_timeout;
  34. client->control->sync_new = 1;
  35. if (!client->control->sync_poll) {
  36. client->control->sync_poll = 1;
  37. engine->control->sync_remain++;
  38. }
  39. // JOQ: I don't like doing this here...
  40. if (engine->control->transport_state == JackTransportRolling) {
  41. engine->control->transport_state = JackTransportStarting;
  42. VERBOSE (engine, "force transport state to Starting\n");
  43. }
  44. VERBOSE (engine, "polling sync client %" PRIu32 "\n",
  45. client->control->id);
  46. }
  47. /* stop polling a specific slow-sync client
  48. *
  49. * precondition: caller holds the graph lock. */
  50. static inline void
  51. jack_sync_poll_deactivate (jack_engine_t *engine,
  52. jack_client_internal_t *client)
  53. {
  54. if (client->control->sync_poll) {
  55. client->control->sync_poll = 0;
  56. client->control->sync_new = 0;
  57. engine->control->sync_remain--;
  58. VERBOSE (engine, "sync poll interrupted for client %"
  59. PRIu32 "\n", client->control->id);
  60. }
  61. client->control->active_slowsync = 0;
  62. engine->control->sync_clients--;
  63. assert(engine->control->sync_clients >= 0);
  64. }
  65. /* stop polling all the slow-sync clients
  66. *
  67. * precondition: caller holds the graph lock. */
  68. static void
  69. jack_sync_poll_stop (jack_engine_t *engine)
  70. {
  71. JSList *node;
  72. long poll_count = 0; /* count sync_poll clients */
  73. for (node = engine->clients; node; node = jack_slist_next (node)) {
  74. jack_client_internal_t *client =
  75. (jack_client_internal_t *) node->data;
  76. if (client->control->active_slowsync &&
  77. client->control->sync_poll) {
  78. client->control->sync_poll = 0;
  79. poll_count++;
  80. }
  81. }
  82. //JOQ: check invariant for debugging...
  83. assert (poll_count == engine->control->sync_remain);
  84. VERBOSE (engine,
  85. "sync poll halted with %" PRIu32
  86. " clients and %8.6f secs remaining\n",
  87. engine->control->sync_remain,
  88. (double) (engine->control->sync_time_left / 1000000.0));
  89. engine->control->sync_remain = 0;
  90. engine->control->sync_time_left = 0;
  91. }
  92. /* start polling all the slow-sync clients
  93. *
  94. * precondition: caller holds the graph lock. */
  95. static void
  96. jack_sync_poll_start (jack_engine_t *engine)
  97. {
  98. JSList *node;
  99. long sync_count = 0; /* count slow-sync clients */
  100. for (node = engine->clients; node; node = jack_slist_next (node)) {
  101. jack_client_internal_t *client =
  102. (jack_client_internal_t *) node->data;
  103. if (client->control->active_slowsync) {
  104. client->control->sync_poll = 1;
  105. sync_count++;
  106. }
  107. }
  108. //JOQ: check invariant for debugging...
  109. assert (sync_count == engine->control->sync_clients);
  110. engine->control->sync_remain = sync_count;
  111. engine->control->sync_time_left = engine->control->sync_timeout;
  112. VERBOSE (engine, "transport Starting, sync poll of %" PRIu32
  113. " clients for %8.6f secs\n", engine->control->sync_remain,
  114. (double) (engine->control->sync_time_left / 1000000.0));
  115. }
  116. /* check for sync timeout */
  117. static inline int
  118. jack_sync_timeout (jack_engine_t *engine)
  119. {
  120. jack_control_t *ectl = engine->control;
  121. jack_time_t buf_usecs =
  122. ((ectl->buffer_size * (jack_time_t) 1000000) /
  123. ectl->current_time.frame_rate);
  124. /* compare carefully, jack_time_t is unsigned */
  125. if (ectl->sync_time_left > buf_usecs) {
  126. ectl->sync_time_left -= buf_usecs;
  127. return FALSE;
  128. }
  129. /* timed out */
  130. VERBOSE (engine, "transport sync timeout\n");
  131. ectl->sync_time_left = 0;
  132. return TRUE;
  133. }
  134. /**************** subroutines used by engine.c ****************/
  135. /* driver callback */
  136. int
  137. jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes)
  138. {
  139. jack_control_t *ectl = engine->control;
  140. ectl->current_time.frame_rate = nframes;
  141. ectl->pending_time.frame_rate = nframes;
  142. return 0;
  143. }
  144. /* on ResetTimeBaseClient request */
  145. int
  146. jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id)
  147. {
  148. int ret;
  149. struct _jack_client_internal *client;
  150. jack_control_t *ectl = engine->control;
  151. jack_lock_graph (engine);
  152. client = jack_client_internal_by_id (engine, client_id);
  153. if (client && (client == engine->timebase_client)) {
  154. client->control->is_timebase = 0;
  155. client->control->timebase_new = 0;
  156. engine->timebase_client = NULL;
  157. ectl->pending_time.valid = 0;
  158. VERBOSE (engine, "%s resigned as timebase master\n",
  159. client->control->name);
  160. ret = 0;
  161. } else
  162. ret = EINVAL;
  163. jack_unlock_graph (engine);
  164. return ret;
  165. }
  166. /* on SetTimeBaseClient request */
  167. int
  168. jack_timebase_set (jack_engine_t *engine,
  169. jack_client_id_t client_id, int conditional)
  170. {
  171. int ret = 0;
  172. struct _jack_client_internal *client;
  173. jack_lock_graph (engine);
  174. client = jack_client_internal_by_id (engine, client_id);
  175. if (client == NULL) {
  176. VERBOSE (engine, " %" PRIu32 " no longer exists\n", client_id);
  177. jack_unlock_graph (engine);
  178. return EINVAL;
  179. }
  180. if (conditional && engine->timebase_client) {
  181. /* see if timebase master is someone else */
  182. if (client != engine->timebase_client) {
  183. VERBOSE (engine, "conditional timebase for %s failed\n"
  184. " %s is already the master\n",
  185. client->control->name,
  186. engine->timebase_client->control->name);
  187. ret = EBUSY;
  188. } else
  189. VERBOSE (engine, " %s was already timebase master:\n",
  190. client->control->name);
  191. } else {
  192. if (engine->timebase_client) {
  193. engine->timebase_client->control->is_timebase = 0;
  194. engine->timebase_client->control->timebase_new = 0;
  195. }
  196. engine->timebase_client = client;
  197. client->control->is_timebase = 1;
  198. if (client->control->active)
  199. client->control->timebase_new = 1;
  200. VERBOSE (engine, "new timebase master: %s\n",
  201. client->control->name);
  202. }
  203. jack_unlock_graph (engine);
  204. return ret;
  205. }
  206. /* for client activation
  207. *
  208. * precondition: caller holds the graph lock. */
  209. void
  210. jack_transport_activate (jack_engine_t *engine, jack_client_internal_t *client)
  211. {
  212. if (client->control->is_slowsync) {
  213. assert(!client->control->active_slowsync);
  214. client->control->active_slowsync = 1;
  215. engine->control->sync_clients++;
  216. jack_sync_poll_new (engine, client);
  217. }
  218. if (client->control->is_timebase) {
  219. client->control->timebase_new = 1;
  220. }
  221. }
  222. /* for engine initialization */
  223. void
  224. jack_transport_init (jack_engine_t *engine)
  225. {
  226. jack_control_t *ectl = engine->control;
  227. engine->timebase_client = NULL;
  228. ectl->transport_state = JackTransportStopped;
  229. ectl->transport_cmd = TransportCommandStop;
  230. ectl->previous_cmd = TransportCommandStop;
  231. memset (&ectl->current_time, 0, sizeof(ectl->current_time));
  232. memset (&ectl->pending_time, 0, sizeof(ectl->pending_time));
  233. memset (&ectl->request_time, 0, sizeof(ectl->request_time));
  234. ectl->prev_request = 0;
  235. ectl->seq_number = 1; /* can't start at 0 */
  236. ectl->new_pos = 0;
  237. ectl->pending_pos = 0;
  238. ectl->pending_frame = 0;
  239. ectl->sync_clients = 0;
  240. ectl->sync_remain = 0;
  241. ectl->sync_timeout = 2000000; /* 2 second default */
  242. ectl->sync_time_left = 0;
  243. }
  244. /* when any client exits the graph (either dead or not active)
  245. *
  246. * precondition: caller holds the graph lock */
  247. void
  248. jack_transport_client_exit (jack_engine_t *engine,
  249. jack_client_internal_t *client)
  250. {
  251. if (client == engine->timebase_client) {
  252. if (client->control->dead) {
  253. engine->timebase_client->control->is_timebase = 0;
  254. engine->timebase_client->control->timebase_new = 0;
  255. engine->timebase_client = NULL;
  256. VERBOSE (engine, "timebase master exit\n");
  257. }
  258. engine->control->current_time.valid = 0;
  259. engine->control->pending_time.valid = 0;
  260. }
  261. if (client->control->is_slowsync) {
  262. if (client->control->active_slowsync)
  263. jack_sync_poll_deactivate (engine, client);
  264. if (client->control->dead)
  265. client->control->is_slowsync = 0;
  266. }
  267. }
  268. /* when a new client is being created */
  269. void
  270. jack_transport_client_new (jack_client_internal_t *client)
  271. {
  272. client->control->is_timebase = 0;
  273. client->control->timebase_new = 0;
  274. client->control->is_slowsync = 0;
  275. client->control->active_slowsync = 0;
  276. client->control->sync_poll = 0;
  277. client->control->sync_new = 0;
  278. client->control->sync_cb = NULL;
  279. client->control->sync_arg = NULL;
  280. client->control->timebase_cb = NULL;
  281. client->control->timebase_arg = NULL;
  282. }
  283. /* on ResetSyncClient request */
  284. int
  285. jack_transport_client_reset_sync (jack_engine_t *engine,
  286. jack_client_id_t client_id)
  287. {
  288. int ret;
  289. jack_client_internal_t *client;
  290. jack_lock_graph (engine);
  291. client = jack_client_internal_by_id (engine, client_id);
  292. if (client && (client->control->is_slowsync)) {
  293. if (client->control->active_slowsync)
  294. jack_sync_poll_deactivate (engine, client);
  295. client->control->is_slowsync = 0;
  296. ret = 0;
  297. } else
  298. ret = EINVAL;
  299. jack_unlock_graph (engine);
  300. return ret;
  301. }
  302. /* on SetSyncClient request */
  303. int
  304. jack_transport_client_set_sync (jack_engine_t *engine,
  305. jack_client_id_t client_id)
  306. {
  307. int ret;
  308. jack_client_internal_t *client;
  309. /* The process cycle runs with this lock. */
  310. jack_lock_graph (engine);
  311. client = jack_client_internal_by_id (engine, client_id);
  312. if (client) {
  313. if (!client->control->is_slowsync) {
  314. client->control->is_slowsync = 1;
  315. if (client->control->active) {
  316. client->control->active_slowsync = 1;
  317. engine->control->sync_clients++;
  318. }
  319. }
  320. /* force poll of the new slow-sync client, if active */
  321. if (client->control->active_slowsync)
  322. jack_sync_poll_new (engine, client);
  323. ret = 0;
  324. } else
  325. ret = EINVAL;
  326. jack_unlock_graph (engine);
  327. return ret;
  328. }
  329. /* at process cycle end, set transport parameters for the next cycle
  330. *
  331. * precondition: caller holds the graph lock.
  332. */
  333. void
  334. jack_transport_cycle_end (jack_engine_t *engine)
  335. {
  336. jack_control_t *ectl = engine->control;
  337. transport_command_t cmd; /* latest transport command */
  338. /* Promote pending_time to current_time. Maintain the usecs,
  339. * frame_rate and frame values, clients may not set them. */
  340. ectl->pending_time.usecs = ectl->current_time.usecs;
  341. ectl->pending_time.frame_rate = ectl->current_time.frame_rate;
  342. ectl->pending_time.frame = ectl->pending_frame;
  343. ectl->current_time = ectl->pending_time;
  344. ectl->new_pos = ectl->pending_pos;
  345. /* check sync results from previous cycle */
  346. if (ectl->transport_state == JackTransportStarting) {
  347. if ((ectl->sync_remain == 0) ||
  348. (jack_sync_timeout(engine))) {
  349. ectl->transport_state = JackTransportRolling;
  350. VERBOSE (engine, "transport Rolling, %8.6f sec"
  351. " left for poll\n",
  352. (double) (ectl->sync_time_left / 1000000.0));
  353. }
  354. }
  355. /* Handle any new transport command from the last cycle. */
  356. cmd = ectl->transport_cmd;
  357. if (cmd != ectl->previous_cmd) {
  358. ectl->previous_cmd = cmd;
  359. VERBOSE (engine, "transport command: %s\n",
  360. (cmd == TransportCommandStart? "START": "STOP"));
  361. } else
  362. cmd = TransportCommandNone;
  363. /* state transition switch */
  364. switch (ectl->transport_state) {
  365. case JackTransportStopped:
  366. if (cmd == TransportCommandStart) {
  367. if (ectl->sync_clients) {
  368. ectl->transport_state = JackTransportStarting;
  369. jack_sync_poll_start(engine);
  370. } else {
  371. ectl->transport_state = JackTransportRolling;
  372. VERBOSE (engine, "transport Rolling\n");
  373. }
  374. }
  375. break;
  376. case JackTransportStarting:
  377. if (cmd == TransportCommandStop) {
  378. ectl->transport_state = JackTransportStopped;
  379. VERBOSE (engine, "transport Stopped\n");
  380. if (ectl->sync_remain)
  381. jack_sync_poll_stop(engine);
  382. } else if (ectl->new_pos) {
  383. if (ectl->sync_clients) {
  384. ectl->transport_state = JackTransportStarting;
  385. jack_sync_poll_start(engine);
  386. } else {
  387. ectl->transport_state = JackTransportRolling;
  388. VERBOSE (engine, "transport Rolling\n");
  389. }
  390. }
  391. break;
  392. case JackTransportRolling:
  393. if (cmd == TransportCommandStop) {
  394. ectl->transport_state = JackTransportStopped;
  395. VERBOSE (engine, "transport Stopped\n");
  396. if (ectl->sync_remain)
  397. jack_sync_poll_stop(engine);
  398. } else if (ectl->new_pos) {
  399. if (ectl->sync_clients) {
  400. ectl->transport_state = JackTransportStarting;
  401. jack_sync_poll_start(engine);
  402. }
  403. }
  404. break;
  405. default:
  406. jack_error ("invalid JACK transport state: %d",
  407. ectl->transport_state);
  408. }
  409. /* update timebase, if needed */
  410. if (ectl->transport_state == JackTransportRolling) {
  411. ectl->pending_time.frame =
  412. ectl->current_time.frame + ectl->buffer_size;
  413. }
  414. /* See if an asynchronous position request arrived during the
  415. * last cycle. The request_time could change during the
  416. * guarded copy. If so, we use the newest request. */
  417. ectl->pending_pos = 0;
  418. if (ectl->request_time.unique_1 != ectl->prev_request) {
  419. jack_transport_copy_position(&ectl->request_time,
  420. &ectl->pending_time);
  421. VERBOSE (engine, "new transport position: %" PRIu32
  422. ", id=0x%" PRIx64 "\n", ectl->pending_time.frame,
  423. ectl->pending_time.unique_1);
  424. ectl->prev_request = ectl->pending_time.unique_1;
  425. ectl->pending_pos = 1;
  426. }
  427. /* clients can't set pending frame number, so save it here */
  428. ectl->pending_frame = ectl->pending_time.frame;
  429. }
  430. /* driver callback at start of cycle */
  431. void
  432. jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time)
  433. {
  434. engine->control->current_time.usecs = time;
  435. }
  436. /* on SetSyncTimeout request */
  437. int
  438. jack_transport_set_sync_timeout (jack_engine_t *engine,
  439. jack_time_t usecs)
  440. {
  441. engine->control->sync_timeout = usecs;
  442. VERBOSE (engine, "new sync timeout: %8.6f secs\n",
  443. (double) (usecs / 1000000.0));
  444. return 0;
  445. }