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.

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