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.

275 lines
7.1KB

  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 callbacks ***********************/
  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. struct _jack_client_internal *clint;
  61. jack_control_t *ectl = engine->control;
  62. jack_lock_graph (engine);
  63. clint = jack_client_internal_by_id (engine, client);
  64. if (clint && (clint == engine->timebase_client)) {
  65. clint->control->is_timebase = 0;
  66. engine->timebase_client = NULL;
  67. ectl->pending_time.valid = 0;
  68. ret = 0;
  69. } else
  70. ret = EINVAL;
  71. jack_unlock_graph (engine);
  72. return ret;
  73. }
  74. /* for SetTimeBaseClient */
  75. int
  76. jack_timebase_set (jack_engine_t *engine,
  77. jack_client_id_t client, int conditional)
  78. {
  79. int ret = 0;
  80. struct _jack_client_internal *clint;
  81. jack_lock_graph (engine);
  82. clint = jack_client_internal_by_id (engine, client);
  83. if (conditional && engine->timebase_client) {
  84. /* see if timebase master is someone else */
  85. if (clint && (clint != engine->timebase_client))
  86. ret = EBUSY;
  87. } else {
  88. if (clint) {
  89. if (engine->timebase_client)
  90. engine->timebase_client->
  91. control->is_timebase = 0;
  92. engine->timebase_client = clint;
  93. clint->control->is_timebase = 1;
  94. } else
  95. ret = EINVAL;
  96. }
  97. jack_unlock_graph (engine);
  98. return ret;
  99. }
  100. /******************** engine.c subroutines ********************/
  101. /* start polling slow-sync clients */
  102. void
  103. jack_start_sync_poll(jack_engine_t *engine)
  104. {
  105. /* precondition: caller holds the graph lock. */
  106. jack_control_t *ectl = engine->control;
  107. JSList *node;
  108. long sync_count = 0; /* number of slow-sync clients */
  109. for (node = engine->clients; node; node = jack_slist_next (node)) {
  110. jack_client_internal_t *clintl =
  111. (jack_client_internal_t *) node->data;
  112. if (clintl->control->sync_cb) {
  113. clintl->control->sync_ready = 0;
  114. sync_count++;
  115. }
  116. }
  117. ectl->sync_remain = ectl->sync_clients = sync_count;
  118. ectl->sync_cycle = 0;
  119. }
  120. /* when timebase master exits the graph */
  121. void
  122. jack_timebase_exit (jack_engine_t *engine)
  123. {
  124. jack_control_t *ectl = engine->control;
  125. engine->timebase_client->control->is_timebase = 0;
  126. engine->timebase_client = NULL;
  127. ectl->current_time.valid = 0;
  128. ectl->pending_time.valid = 0;
  129. }
  130. /* engine initialization */
  131. void
  132. jack_timebase_init (jack_engine_t *engine)
  133. {
  134. jack_control_t *ectl = engine->control;
  135. engine->timebase_client = NULL;
  136. ectl->transport_state = JackTransportStopped;
  137. ectl->transport_cmd = TransportCommandNone;
  138. memset (&ectl->current_time, 0, sizeof(ectl->current_time));
  139. memset (&ectl->pending_time, 0, sizeof(ectl->pending_time));
  140. memset (&ectl->request_time, 0, sizeof(ectl->request_time));
  141. ectl->new_pos = 0;
  142. ectl->sync_remain = 0;
  143. ectl->sync_cycle = 0;
  144. ectl->sync_clients = 0;
  145. }
  146. /* This runs at the end of every process cycle. It determines the
  147. * transport parameters for the next cycle.
  148. */
  149. void
  150. jack_transport_cycle_end (jack_engine_t *engine)
  151. {
  152. /* precondition: caller holds the graph lock. */
  153. jack_control_t *ectl = engine->control;
  154. transport_command_t cmd; /* latest transport command */
  155. /* update timebase, if needed */
  156. if ((engine->timebase_client == NULL) &&
  157. (ectl->transport_state == JackTransportRolling)) {
  158. ectl->pending_time.frame =
  159. ectl->current_time.frame + ectl->buffer_size;
  160. }
  161. /* Handle latest asynchronous requests from the last cycle.
  162. *
  163. * This should ideally use an atomic swap, since commands can
  164. * arrive at any time. There is a small timing window during
  165. * which a request could be ignored inadvertently. Since
  166. * another could have arrived in the previous moment and
  167. * replaced it anyway, we won't bother with <asm/atomic.h>.
  168. */
  169. cmd = ectl->transport_cmd;
  170. ectl->transport_cmd = TransportCommandNone;
  171. if (ectl->request_time.usecs) {
  172. /* request_time could change during this copy */
  173. jack_transport_copy_position(&ectl->request_time,
  174. &ectl->pending_time);
  175. ectl->request_time.usecs = 0; /* empty request buffer */
  176. ectl->new_pos = 1;
  177. } else
  178. ectl->new_pos = 0;
  179. /* Promote pending_time to current_time. Maintain the usecs
  180. * and frame_rate values, clients may not set them. */
  181. ectl->pending_time.guard_usecs =
  182. ectl->pending_time.usecs = ectl->current_time.usecs;
  183. ectl->pending_time.frame_rate = ectl->current_time.frame_rate;
  184. ectl->current_time = ectl->pending_time;
  185. /* accumulate sync results from previous cycle */
  186. if (ectl->sync_remain) {
  187. ectl->sync_remain -= ectl->sync_cycle;
  188. if ((ectl->sync_remain == 0) &&
  189. (ectl->transport_state == JackTransportStarting))
  190. ectl->transport_state = JackTransportRolling;
  191. ectl->sync_cycle = 0;
  192. }
  193. /* state transition switch */
  194. switch (ectl->transport_state) {
  195. case JackTransportStopped:
  196. if (cmd == TransportCommandPlay) {
  197. if (ectl->sync_clients) {
  198. ectl->transport_state = JackTransportStarting;
  199. jack_start_sync_poll(engine);
  200. } else
  201. ectl->transport_state = JackTransportRolling;
  202. }
  203. break;
  204. case JackTransportStarting:
  205. case JackTransportRolling:
  206. if (cmd == TransportCommandStop) {
  207. ectl->transport_state = JackTransportStopped;
  208. ectl->sync_remain = 0; /* halt polling */
  209. } else if (ectl->new_pos) {
  210. if (ectl->sync_clients) {
  211. ectl->transport_state = JackTransportStarting;
  212. jack_start_sync_poll(engine);
  213. }
  214. else
  215. ectl->transport_state = JackTransportRolling;
  216. }
  217. break;
  218. default:
  219. jack_error ("invalid JACK transport state: %d",
  220. ectl->transport_state);
  221. }
  222. return;
  223. }