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.

456 lines
12KB

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