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.

477 lines
13KB

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