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.

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