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.

261 lines
6.6KB

  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 Lesser General Public License
  7. as published by the Free Software Foundation; either version 2.1
  8. of the 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 <jack/internal.h>
  20. #include <jack/engine.h>
  21. #include "transengine.h"
  22. /*********************** driver functions ***********************/
  23. int
  24. jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes)
  25. {
  26. jack_control_t *ectl = engine->control;
  27. ectl->current_time.frame_rate = nframes;
  28. ectl->pending_time.frame_rate = nframes;
  29. return 0;
  30. }
  31. void
  32. jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time)
  33. {
  34. engine->control->current_time.guard_usecs =
  35. engine->control->current_time.usecs = time;
  36. }
  37. /********************* RPC request handlers *********************/
  38. /* for SetSyncClient */
  39. int
  40. jack_set_sync_client (jack_engine_t *engine, jack_client_id_t client)
  41. {
  42. int ret;
  43. jack_client_internal_t *clintl;
  44. jack_lock_graph (engine);
  45. clintl = jack_client_internal_by_id (engine, client);
  46. if (clintl) {
  47. clintl->control->sync_ready = 0;
  48. engine->control->sync_clients++;
  49. ret = 0;
  50. } else
  51. ret = EINVAL;
  52. jack_unlock_graph (engine);
  53. return ret;
  54. }
  55. /* for ResetTimeBaseClient */
  56. int
  57. jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client)
  58. {
  59. int ret;
  60. jack_lock_graph (engine);
  61. if ((engine->timebase_client =
  62. jack_client_internal_by_id (engine, client)) != 0) {
  63. engine->timebase_client = 0;
  64. engine->control->pending_time.valid = 0;
  65. ret = 0;
  66. } else
  67. ret = EINVAL;
  68. jack_unlock_graph (engine);
  69. return ret;
  70. }
  71. /* for SetTimeBaseClient */
  72. int
  73. jack_timebase_set (jack_engine_t *engine,
  74. jack_client_id_t client, int conditional)
  75. {
  76. int ret;
  77. jack_lock_graph (engine);
  78. if (conditional && engine->timebase_client)
  79. ret = EBUSY;
  80. else if ((engine->timebase_client =
  81. jack_client_internal_by_id (engine, client)) != 0)
  82. ret = 0;
  83. else
  84. ret = -1;
  85. jack_unlock_graph (engine);
  86. return ret;
  87. }
  88. /******************** engine.c subroutines ********************/
  89. /* start polling slow-sync clients */
  90. void
  91. jack_start_sync_poll(jack_engine_t *engine)
  92. {
  93. jack_control_t *ectl = engine->control;
  94. JSList *node;
  95. long sync_count = 0; /* number of slow-sync clients */
  96. jack_lock_graph (engine);
  97. for (node = engine->clients; node; node = jack_slist_next (node)) {
  98. jack_client_internal_t *clintl =
  99. (jack_client_internal_t *) node->data;
  100. if (clintl->control->sync_cb) {
  101. clintl->control->sync_ready = 0;
  102. sync_count++;
  103. }
  104. }
  105. ectl->sync_remain = ectl->sync_clients = sync_count;
  106. ectl->sync_cycle = 0;
  107. jack_unlock_graph (engine);
  108. }
  109. /* when timebase master exits the graph */
  110. void
  111. jack_timebase_exit (jack_engine_t *engine)
  112. {
  113. jack_control_t *ectl = engine->control;
  114. ectl->current_time.valid = 0;
  115. ectl->pending_time.valid = 0;
  116. }
  117. /* engine initialization */
  118. void
  119. jack_timebase_init (jack_engine_t *engine)
  120. {
  121. jack_control_t *ectl = engine->control;
  122. ectl->transport_state = JackTransportStopped;
  123. ectl->transport_cmd = TransportCommandNone;
  124. memset (&ectl->current_time, 0, sizeof(ectl->current_time));
  125. memset (&ectl->pending_time, 0, sizeof(ectl->pending_time));
  126. memset (&ectl->request_time, 0, sizeof(ectl->request_time));
  127. ectl->new_pos = 0;
  128. ectl->sync_remain = 0;
  129. ectl->sync_cycle = 0;
  130. ectl->sync_clients = 0;
  131. }
  132. /* This is the heart of the transport control. It runs at the end of
  133. * every process cycle.
  134. */
  135. void
  136. jack_transport_cycle_end (jack_engine_t *engine)
  137. {
  138. jack_control_t *ectl = engine->control;
  139. transport_command_t cmd; /* latest transport command */
  140. jack_time_t repos; /* nonzero if reposition requested */
  141. /* update timebase, if needed */
  142. if ((engine->timebase_client == 0) &&
  143. (ectl->transport_state == JackTransportRolling)) {
  144. ectl->pending_time.frame =
  145. ectl->current_time.frame + ectl->buffer_size;
  146. }
  147. /* Handle latest asynchronous requests from the last cycle.
  148. *
  149. * This should ideally use an atomic swap, since commands can
  150. * arrive at any time. There is a small timing window during
  151. * which a request could be ignored inadvertently. Since
  152. * another could have arrived in the previous moment and
  153. * replaced it anyway, we won't bother with <asm/atomic.h>.
  154. */
  155. cmd = ectl->transport_cmd;
  156. ectl->transport_cmd = TransportCommandNone;
  157. repos = ectl->request_time.usecs;
  158. if (repos) {
  159. /* request_time could change during this copy */
  160. jack_transport_copy_position(&ectl->request_time,
  161. &ectl->pending_time);
  162. ectl->request_time.usecs = 0; /* empty request buffer */
  163. ectl->new_pos = 1;
  164. } else
  165. ectl->new_pos = 0;
  166. /* Promote pending_time to current_time. Maintain the usecs
  167. * and frame_rate values, clients may not set them. */
  168. ectl->pending_time.guard_usecs =
  169. ectl->pending_time.usecs = ectl->current_time.usecs;
  170. ectl->pending_time.frame_rate = ectl->current_time.frame_rate;
  171. ectl->current_time = ectl->pending_time;
  172. /* accumulate sync results from previous cycle */
  173. if (ectl->sync_remain) {
  174. ectl->sync_remain -= ectl->sync_cycle;
  175. if ((ectl->sync_remain == 0) &&
  176. (ectl->transport_state == JackTransportStarting))
  177. ectl->transport_state = JackTransportRolling;
  178. ectl->sync_cycle = 0;
  179. }
  180. /* state transition switch */
  181. switch (ectl->transport_state) {
  182. case JackTransportStopped:
  183. if (cmd == TransportCommandPlay) {
  184. if (ectl->sync_clients) {
  185. ectl->transport_state = JackTransportStarting;
  186. jack_start_sync_poll(engine);
  187. } else
  188. ectl->transport_state = JackTransportRolling;
  189. }
  190. break;
  191. case JackTransportStarting:
  192. case JackTransportRolling:
  193. if (cmd == TransportCommandStop) {
  194. ectl->transport_state = JackTransportStopped;
  195. ectl->sync_remain = 0; /* halt polling */
  196. } else if (repos) {
  197. if (ectl->sync_clients) {
  198. ectl->transport_state = JackTransportStarting;
  199. jack_start_sync_poll(engine);
  200. }
  201. else
  202. ectl->transport_state = JackTransportRolling;
  203. }
  204. break;
  205. default:
  206. jack_error ("invalid JACK transport state: %d",
  207. ectl->transport_state);
  208. }
  209. return;
  210. }