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.

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