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.

411 lines
11KB

  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 <jack/internal.h>
  21. #include <jack/engine.h>
  22. #include "transengine.h"
  23. /********************** internal functions **********************/
  24. /* stop polling a specific slow-sync client
  25. *
  26. * precondition: caller holds the graph lock. */
  27. static inline void
  28. jack_sync_poll_exit(jack_engine_t *engine, jack_client_internal_t *client)
  29. {
  30. if (client->control->sync_poll) {
  31. client->control->sync_poll = 0;
  32. client->control->sync_new = 0;
  33. engine->control->sync_remain--;
  34. }
  35. client->control->is_slowsync = 0;
  36. engine->control->sync_clients--;
  37. }
  38. /* stop polling all the slow-sync clients
  39. *
  40. * precondition: caller holds the graph lock. */
  41. static void
  42. jack_sync_poll_stop(jack_engine_t *engine)
  43. {
  44. JSList *node;
  45. long poll_count = 0; /* count sync_poll clients */
  46. for (node = engine->clients; node; node = jack_slist_next (node)) {
  47. jack_client_internal_t *client =
  48. (jack_client_internal_t *) node->data;
  49. if (client->control->is_slowsync &&
  50. client->control->sync_poll) {
  51. client->control->sync_poll = 0;
  52. poll_count++;
  53. }
  54. }
  55. //JOQ: check invariant for debugging...
  56. assert (poll_count == engine->control->sync_remain);
  57. engine->control->sync_remain = 0;
  58. engine->control->sync_time_left = 0;
  59. }
  60. /* start polling all the slow-sync clients
  61. *
  62. * precondition: caller holds the graph lock. */
  63. static void
  64. jack_sync_poll_start(jack_engine_t *engine)
  65. {
  66. JSList *node;
  67. long sync_count = 0; /* count slow-sync clients */
  68. for (node = engine->clients; node; node = jack_slist_next (node)) {
  69. jack_client_internal_t *client =
  70. (jack_client_internal_t *) node->data;
  71. if (client->control->is_slowsync) {
  72. client->control->sync_poll = 1;
  73. sync_count++;
  74. }
  75. }
  76. //JOQ: check invariant for debugging...
  77. assert (sync_count == engine->control->sync_clients);
  78. engine->control->sync_remain = engine->control->sync_clients;
  79. engine->control->sync_time_left = engine->control->sync_timeout;
  80. }
  81. /* check for sync timeout */
  82. static inline int
  83. jack_sync_timeout(jack_engine_t *engine)
  84. {
  85. jack_control_t *ectl = engine->control;
  86. jack_time_t buf_usecs =
  87. ((ectl->buffer_size * (jack_time_t) 1000000000) /
  88. ectl->current_time.frame_rate);
  89. /* compare carefully, jack_time_t is unsigned */
  90. if (ectl->sync_time_left <= buf_usecs) {
  91. ectl->sync_time_left = 0;
  92. return 1; /* timed out */
  93. } else {
  94. ectl->sync_time_left -= buf_usecs;
  95. return 0; /* continue */
  96. }
  97. }
  98. /**************** subroutines used by engine.c ****************/
  99. /* driver callback */
  100. int
  101. jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes)
  102. {
  103. jack_control_t *ectl = engine->control;
  104. ectl->current_time.frame_rate = nframes;
  105. ectl->pending_time.frame_rate = nframes;
  106. return 0;
  107. }
  108. /* on ResetTimeBaseClient request */
  109. int
  110. jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id)
  111. {
  112. int ret;
  113. struct _jack_client_internal *client;
  114. jack_control_t *ectl = engine->control;
  115. jack_lock_graph (engine);
  116. client = jack_client_internal_by_id (engine, client_id);
  117. if (client && (client == engine->timebase_client)) {
  118. client->control->is_timebase = 0;
  119. engine->timebase_client = NULL;
  120. ectl->pending_time.valid = 0;
  121. ret = 0;
  122. } else
  123. ret = EINVAL;
  124. jack_unlock_graph (engine);
  125. return ret;
  126. }
  127. /* on SetTimeBaseClient request */
  128. int
  129. jack_timebase_set (jack_engine_t *engine,
  130. jack_client_id_t client_id, int conditional)
  131. {
  132. int ret = 0;
  133. struct _jack_client_internal *client;
  134. jack_lock_graph (engine);
  135. client = jack_client_internal_by_id (engine, client_id);
  136. if (conditional && engine->timebase_client) {
  137. /* see if timebase master is someone else */
  138. if (client && (client != engine->timebase_client))
  139. ret = EBUSY;
  140. } else {
  141. if (client) {
  142. if (engine->timebase_client)
  143. engine->timebase_client->
  144. control->is_timebase = 0;
  145. engine->timebase_client = client;
  146. client->control->is_timebase = 1;
  147. } else
  148. ret = EINVAL;
  149. }
  150. jack_unlock_graph (engine);
  151. return ret;
  152. }
  153. /* for engine initialization */
  154. void
  155. jack_transport_init (jack_engine_t *engine)
  156. {
  157. jack_control_t *ectl = engine->control;
  158. engine->timebase_client = NULL;
  159. ectl->transport_state = JackTransportStopped;
  160. ectl->transport_cmd = TransportCommandNone;
  161. memset (&ectl->current_time, 0, sizeof(ectl->current_time));
  162. memset (&ectl->pending_time, 0, sizeof(ectl->pending_time));
  163. memset (&ectl->request_time, 0, sizeof(ectl->request_time));
  164. ectl->new_pos = 0;
  165. ectl->sync_remain = 0;
  166. ectl->sync_clients = 0;
  167. ectl->sync_timeout = 2000000000; /* 2 second default */
  168. ectl->sync_time_left = 0;
  169. }
  170. /* when any client exits the graph
  171. *
  172. * precondition: caller holds the graph lock */
  173. void
  174. jack_transport_client_exit (jack_engine_t *engine,
  175. jack_client_internal_t *client)
  176. {
  177. if (client == engine->timebase_client) {
  178. engine->timebase_client->control->is_timebase = 0;
  179. engine->timebase_client = NULL;
  180. engine->control->current_time.valid = 0;
  181. engine->control->pending_time.valid = 0;
  182. }
  183. if (client->control->is_slowsync)
  184. jack_sync_poll_exit(engine, client);
  185. }
  186. /* when a new client is being created */
  187. void
  188. jack_transport_client_new (jack_client_internal_t *client)
  189. {
  190. client->control->is_timebase = 0;
  191. client->control->is_slowsync = 0;
  192. client->control->sync_poll = 0;
  193. client->control->sync_new = 0;
  194. client->control->sync_cb = NULL;
  195. client->control->sync_arg = NULL;
  196. client->control->timebase_cb = NULL;
  197. client->control->timebase_arg = NULL;
  198. }
  199. /* on ResetSyncClient request */
  200. int
  201. jack_transport_client_reset_sync (jack_engine_t *engine,
  202. jack_client_id_t client_id)
  203. {
  204. int ret;
  205. jack_client_internal_t *client;
  206. jack_lock_graph (engine);
  207. client = jack_client_internal_by_id (engine, client_id);
  208. if (client && (client->control->is_slowsync)) {
  209. jack_sync_poll_exit(engine, client);
  210. ret = 0;
  211. } else
  212. ret = EINVAL;
  213. jack_unlock_graph (engine);
  214. return ret;
  215. }
  216. /* on SetSyncClient request */
  217. int
  218. jack_transport_client_set_sync (jack_engine_t *engine,
  219. jack_client_id_t client_id)
  220. {
  221. int ret;
  222. jack_client_internal_t *client;
  223. // JOQ: I am assuming the process cycle is serialized with
  224. // respect to this lock...
  225. jack_lock_graph (engine);
  226. client = jack_client_internal_by_id (engine, client_id);
  227. if (client) {
  228. if (!client->control->is_slowsync) {
  229. /* force poll of the new slow-sync client */
  230. client->control->is_slowsync = 1;
  231. engine->control->sync_clients++;
  232. // JOQ: I don't like doing this here...
  233. client->control->sync_poll = 1;
  234. engine->control->sync_remain++;
  235. engine->control->sync_time_left =
  236. engine->control->sync_timeout;
  237. if (engine->control->transport_state ==
  238. JackTransportRolling)
  239. engine->control->transport_state =
  240. JackTransportStarting;
  241. }
  242. client->control->sync_new = 1;
  243. ret = 0;
  244. } else
  245. ret = EINVAL;
  246. jack_unlock_graph (engine);
  247. return ret;
  248. }
  249. /* at the end of every process cycle
  250. *
  251. * Determines the transport parameters for the following cycle.
  252. * precondition: caller holds the graph lock.
  253. */
  254. void
  255. jack_transport_cycle_end (jack_engine_t *engine)
  256. {
  257. jack_control_t *ectl = engine->control;
  258. transport_command_t cmd; /* latest transport command */
  259. /* update timebase, if needed */
  260. if ((engine->timebase_client == NULL) &&
  261. (ectl->transport_state == JackTransportRolling)) {
  262. ectl->pending_time.frame =
  263. ectl->current_time.frame + ectl->buffer_size;
  264. }
  265. /* Handle latest asynchronous requests from the last cycle.
  266. *
  267. * This should ideally use an atomic swap, since commands can
  268. * arrive at any time. There is a small timing window during
  269. * which a request could be ignored inadvertently. Since
  270. * another could have arrived in the previous moment and
  271. * replaced it anyway, we won't bother with <asm/atomic.h>.
  272. */
  273. cmd = ectl->transport_cmd;
  274. // JOQ: may be able to close the window by eliminating this
  275. // store, but watch out below...
  276. ectl->transport_cmd = TransportCommandNone;
  277. if (ectl->request_time.usecs) {
  278. /* request_time could change during this copy */
  279. jack_transport_copy_position(&ectl->request_time,
  280. &ectl->pending_time);
  281. ectl->request_time.usecs = 0; /* empty request buffer */
  282. ectl->new_pos = 1;
  283. } else
  284. ectl->new_pos = 0;
  285. /* Promote pending_time to current_time. Maintain the usecs
  286. * and frame_rate values, clients may not set them. */
  287. ectl->pending_time.guard_usecs =
  288. ectl->pending_time.usecs = ectl->current_time.usecs;
  289. ectl->pending_time.frame_rate = ectl->current_time.frame_rate;
  290. ectl->current_time = ectl->pending_time;
  291. /* check sync results from previous cycle */
  292. if (ectl->transport_state == JackTransportStarting) {
  293. if ((ectl->sync_remain == 0) ||
  294. (jack_sync_timeout(engine)))
  295. ectl->transport_state = JackTransportRolling;
  296. }
  297. /* state transition switch */
  298. switch (ectl->transport_state) {
  299. case JackTransportStopped:
  300. if (cmd == TransportCommandStart) {
  301. if (ectl->sync_clients) {
  302. ectl->transport_state = JackTransportStarting;
  303. jack_sync_poll_start(engine);
  304. } else {
  305. ectl->transport_state = JackTransportRolling;
  306. }
  307. }
  308. break;
  309. case JackTransportStarting:
  310. case JackTransportRolling:
  311. if (cmd == TransportCommandStop) {
  312. ectl->transport_state = JackTransportStopped;
  313. jack_sync_poll_stop(engine);
  314. } else if (ectl->new_pos) {
  315. if (ectl->sync_clients) {
  316. ectl->transport_state = JackTransportStarting;
  317. jack_sync_poll_start(engine);
  318. } else {
  319. ectl->transport_state = JackTransportRolling;
  320. }
  321. }
  322. break;
  323. default:
  324. jack_error ("invalid JACK transport state: %d",
  325. ectl->transport_state);
  326. }
  327. return;
  328. }
  329. /* driver callback at start of cycle */
  330. void
  331. jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time)
  332. {
  333. engine->control->current_time.guard_usecs =
  334. engine->control->current_time.usecs = time;
  335. }
  336. /* on SetSyncTimeout request */
  337. int
  338. jack_transport_set_sync_timeout (jack_engine_t *engine,
  339. jack_time_t usecs)
  340. {
  341. engine->control->sync_timeout = usecs;
  342. return 0;
  343. }