2 JACK transport engine -- runs in the server process.
4 Copyright (C) 2001-2003 Paul Davis
5 Copyright (C) 2003 Jack O'Quin
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <jack/internal.h>
28 #include <jack/engine.h>
29 #include <jack/messagebuffer.h>
30 #include "transengine.h"
32 /********************** internal functions **********************/
34 /* initiate polling a new slow-sync client
36 * precondition: caller holds the graph lock. */
38 jack_sync_poll_new (jack_engine_t
*engine
, jack_client_internal_t
*client
)
40 /* force sync_cb callback to run in its first cycle */
41 engine
->control
->sync_time_left
= engine
->control
->sync_timeout
;
42 client
->control
->sync_new
= 1;
43 if (!client
->control
->sync_poll
) {
44 client
->control
->sync_poll
= 1;
45 engine
->control
->sync_remain
++;
48 // JOQ: I don't like doing this here...
49 if (engine
->control
->transport_state
== JackTransportRolling
) {
50 engine
->control
->transport_state
= JackTransportStarting
;
51 VERBOSE (engine
, "force transport state to Starting");
54 VERBOSE (engine
, "polling sync client %" PRIu32
,
58 /* stop polling a specific slow-sync client
60 * precondition: caller holds the graph lock. */
62 jack_sync_poll_deactivate (jack_engine_t
*engine
,
63 jack_client_internal_t
*client
)
65 if (client
->control
->sync_poll
) {
66 client
->control
->sync_poll
= 0;
67 client
->control
->sync_new
= 0;
68 engine
->control
->sync_remain
--;
69 VERBOSE (engine
, "sync poll interrupted for client %"
70 PRIu32
, client
->control
->id
);
72 client
->control
->active_slowsync
= 0;
73 engine
->control
->sync_clients
--;
74 assert(engine
->control
->sync_clients
>= 0);
77 /* stop polling all the slow-sync clients
79 * precondition: caller holds the graph lock. */
81 jack_sync_poll_stop (jack_engine_t
*engine
)
84 long poll_count
= 0; /* count sync_poll clients */
86 for (node
= engine
->clients
; node
; node
= jack_slist_next (node
)) {
87 jack_client_internal_t
*client
=
88 (jack_client_internal_t
*) node
->data
;
89 if (client
->control
->active_slowsync
&&
90 client
->control
->sync_poll
) {
91 client
->control
->sync_poll
= 0;
96 //JOQ: check invariant for debugging...
97 assert (poll_count
== engine
->control
->sync_remain
);
99 "sync poll halted with %" PRIu32
100 " clients and %8.6f secs remaining",
101 engine
->control
->sync_remain
,
102 (double) (engine
->control
->sync_time_left
/ 1000000.0));
103 engine
->control
->sync_remain
= 0;
104 engine
->control
->sync_time_left
= 0;
107 /* start polling all the slow-sync clients
109 * precondition: caller holds the graph lock. */
111 jack_sync_poll_start (jack_engine_t
*engine
)
114 long sync_count
= 0; /* count slow-sync clients */
116 for (node
= engine
->clients
; node
; node
= jack_slist_next (node
)) {
117 jack_client_internal_t
*client
=
118 (jack_client_internal_t
*) node
->data
;
119 if (client
->control
->active_slowsync
) {
120 client
->control
->sync_poll
= 1;
125 //JOQ: check invariant for debugging...
126 assert (sync_count
== engine
->control
->sync_clients
);
127 engine
->control
->sync_remain
= sync_count
;
128 engine
->control
->sync_time_left
= engine
->control
->sync_timeout
;
129 VERBOSE (engine
, "transport Starting, sync poll of %" PRIu32
130 " clients for %8.6f secs", engine
->control
->sync_remain
,
131 (double) (engine
->control
->sync_time_left
/ 1000000.0));
134 /* check for sync timeout */
136 jack_sync_timeout (jack_engine_t
*engine
)
138 jack_control_t
*ectl
= engine
->control
;
139 jack_time_t buf_usecs
=
140 ((ectl
->buffer_size
* (jack_time_t
) 1000000) /
141 ectl
->current_time
.frame_rate
);
143 /* compare carefully, jack_time_t is unsigned */
144 if (ectl
->sync_time_left
> buf_usecs
) {
145 ectl
->sync_time_left
-= buf_usecs
;
150 VERBOSE (engine
, "transport sync timeout");
151 ectl
->sync_time_left
= 0;
156 /**************** subroutines used by engine.c ****************/
158 /* driver callback */
160 jack_set_sample_rate (jack_engine_t
*engine
, jack_nframes_t nframes
)
162 jack_control_t
*ectl
= engine
->control
;
164 ectl
->current_time
.frame_rate
= nframes
;
165 ectl
->pending_time
.frame_rate
= nframes
;
169 /* on ResetTimeBaseClient request */
171 jack_timebase_reset (jack_engine_t
*engine
, jack_client_id_t client_id
)
174 struct _jack_client_internal
*client
;
175 jack_control_t
*ectl
= engine
->control
;
177 jack_lock_graph (engine
);
179 client
= jack_client_internal_by_id (engine
, client_id
);
180 if (client
&& (client
== engine
->timebase_client
)) {
181 client
->control
->is_timebase
= 0;
182 client
->control
->timebase_new
= 0;
183 engine
->timebase_client
= NULL
;
184 ectl
->pending_time
.valid
= 0;
185 VERBOSE (engine
, "%s resigned as timebase master",
186 client
->control
->name
);
191 jack_unlock_graph (engine
);
196 /* on SetTimeBaseClient request */
198 jack_timebase_set (jack_engine_t
*engine
,
199 jack_client_id_t client_id
, int conditional
)
202 struct _jack_client_internal
*client
;
204 jack_lock_graph (engine
);
206 client
= jack_client_internal_by_id (engine
, client_id
);
208 if (client
== NULL
) {
209 VERBOSE (engine
, " %" PRIu32
" no longer exists", client_id
);
210 jack_unlock_graph (engine
);
214 if (conditional
&& engine
->timebase_client
) {
216 /* see if timebase master is someone else */
217 if (client
!= engine
->timebase_client
) {
218 VERBOSE (engine
, "conditional timebase for %s failed",
219 client
->control
->name
);
220 VERBOSE (engine
, " %s is already the master",
221 engine
->timebase_client
->control
->name
);
224 VERBOSE (engine
, " %s was already timebase master:",
225 client
->control
->name
);
229 if (engine
->timebase_client
) {
230 engine
->timebase_client
->control
->is_timebase
= 0;
231 engine
->timebase_client
->control
->timebase_new
= 0;
233 engine
->timebase_client
= client
;
234 client
->control
->is_timebase
= 1;
235 if (client
->control
->active
)
236 client
->control
->timebase_new
= 1;
237 VERBOSE (engine
, "new timebase master: %s",
238 client
->control
->name
);
241 jack_unlock_graph (engine
);
246 /* for client activation
248 * precondition: caller holds the graph lock. */
250 jack_transport_activate (jack_engine_t
*engine
, jack_client_internal_t
*client
)
252 if (client
->control
->is_slowsync
) {
253 assert(!client
->control
->active_slowsync
);
254 client
->control
->active_slowsync
= 1;
255 engine
->control
->sync_clients
++;
256 jack_sync_poll_new (engine
, client
);
259 if (client
->control
->is_timebase
) {
260 client
->control
->timebase_new
= 1;
264 /* for engine initialization */
266 jack_transport_init (jack_engine_t
*engine
)
268 jack_control_t
*ectl
= engine
->control
;
270 engine
->timebase_client
= NULL
;
271 ectl
->transport_state
= JackTransportStopped
;
272 ectl
->transport_cmd
= TransportCommandStop
;
273 ectl
->previous_cmd
= TransportCommandStop
;
274 memset (&ectl
->current_time
, 0, sizeof(ectl
->current_time
));
275 memset (&ectl
->pending_time
, 0, sizeof(ectl
->pending_time
));
276 memset (&ectl
->request_time
, 0, sizeof(ectl
->request_time
));
277 ectl
->prev_request
= 0;
278 ectl
->seq_number
= 1; /* can't start at 0 */
280 ectl
->pending_pos
= 0;
281 ectl
->pending_frame
= 0;
282 ectl
->sync_clients
= 0;
283 ectl
->sync_remain
= 0;
284 ectl
->sync_timeout
= 2000000; /* 2 second default */
285 ectl
->sync_time_left
= 0;
288 /* when any client exits the graph (either dead or not active)
290 * precondition: caller holds the graph lock */
292 jack_transport_client_exit (jack_engine_t
*engine
,
293 jack_client_internal_t
*client
)
295 if (client
== engine
->timebase_client
) {
296 if (client
->control
->dead
) {
297 engine
->timebase_client
->control
->is_timebase
= 0;
298 engine
->timebase_client
->control
->timebase_new
= 0;
299 engine
->timebase_client
= NULL
;
300 VERBOSE (engine
, "timebase master exit");
302 engine
->control
->current_time
.valid
= 0;
303 engine
->control
->pending_time
.valid
= 0;
306 if (client
->control
->is_slowsync
) {
307 if (client
->control
->active_slowsync
)
308 jack_sync_poll_deactivate (engine
, client
);
309 if (client
->control
->dead
)
310 client
->control
->is_slowsync
= 0;
314 /* when a new client is being created */
316 jack_transport_client_new (jack_client_internal_t
*client
)
318 client
->control
->is_timebase
= 0;
319 client
->control
->timebase_new
= 0;
320 client
->control
->is_slowsync
= 0;
321 client
->control
->active_slowsync
= 0;
322 client
->control
->sync_poll
= 0;
323 client
->control
->sync_new
= 0;
325 client
->control
->sync_cb_cbset
= FALSE
;
326 client
->control
->timebase_cb_cbset
= FALSE
;
329 if (client
->control
->type
!= ClientExternal
) {
330 client
->sync_cb
= NULL
;
331 client
->sync_arg
= NULL
;
332 client
->timebase_cb
= NULL
;
333 client
->timebase_arg
= NULL
;
338 /* on ResetSyncClient request */
340 jack_transport_client_reset_sync (jack_engine_t
*engine
,
341 jack_client_id_t client_id
)
344 jack_client_internal_t
*client
;
346 jack_lock_graph (engine
);
348 client
= jack_client_internal_by_id (engine
, client_id
);
350 if (client
&& (client
->control
->is_slowsync
)) {
351 if (client
->control
->active_slowsync
)
352 jack_sync_poll_deactivate (engine
, client
);
353 client
->control
->is_slowsync
= 0;
358 jack_unlock_graph (engine
);
363 /* on SetSyncClient request */
365 jack_transport_client_set_sync (jack_engine_t
*engine
,
366 jack_client_id_t client_id
)
369 jack_client_internal_t
*client
;
371 DEBUG ("set sync client");
373 /* The process cycle runs with this lock. */
374 jack_lock_graph (engine
);
376 DEBUG ("got write lock");
378 client
= jack_client_internal_by_id (engine
, client_id
);
380 DEBUG ("client was %p");
383 if (!client
->control
->is_slowsync
) {
384 client
->control
->is_slowsync
= 1;
385 if (client
->control
->active
) {
386 client
->control
->active_slowsync
= 1;
387 engine
->control
->sync_clients
++;
391 /* force poll of the new slow-sync client, if active */
392 if (client
->control
->active_slowsync
) {
393 DEBUG ("sync poll new");
394 jack_sync_poll_new (engine
, client
);
400 DEBUG ("unlocking write lock for set_sync");
401 jack_unlock_graph (engine
);
407 /* at process cycle end, set transport parameters for the next cycle
409 * precondition: caller holds the graph lock.
412 jack_transport_cycle_end (jack_engine_t
*engine
)
414 jack_control_t
*ectl
= engine
->control
;
415 transport_command_t cmd
; /* latest transport command */
417 /* Promote pending_time to current_time. Maintain the usecs,
418 * frame_rate and frame values, clients may not set them. */
419 ectl
->pending_time
.usecs
= ectl
->current_time
.usecs
;
420 ectl
->pending_time
.frame_rate
= ectl
->current_time
.frame_rate
;
421 ectl
->pending_time
.frame
= ectl
->pending_frame
;
422 ectl
->current_time
= ectl
->pending_time
;
423 ectl
->new_pos
= ectl
->pending_pos
;
425 /* check sync results from previous cycle */
426 if (ectl
->transport_state
== JackTransportStarting
) {
427 if ((ectl
->sync_remain
== 0) ||
428 (jack_sync_timeout(engine
))) {
429 ectl
->transport_state
= JackTransportRolling
;
430 VERBOSE (engine
, "transport Rolling, %8.6f sec"
432 (double) (ectl
->sync_time_left
/ 1000000.0));
436 /* Handle any new transport command from the last cycle. */
437 cmd
= ectl
->transport_cmd
;
438 if (cmd
!= ectl
->previous_cmd
) {
439 ectl
->previous_cmd
= cmd
;
440 VERBOSE (engine
, "transport command: %s",
441 (cmd
== TransportCommandStart
? "START": "STOP"));
443 cmd
= TransportCommandNone
;
445 /* state transition switch */
447 switch (ectl
->transport_state
) {
449 case JackTransportStopped
:
450 if (cmd
== TransportCommandStart
) {
451 if (ectl
->sync_clients
) {
452 ectl
->transport_state
= JackTransportStarting
;
453 jack_sync_poll_start(engine
);
455 ectl
->transport_state
= JackTransportRolling
;
456 VERBOSE (engine
, "transport Rolling");
461 case JackTransportStarting
:
462 if (cmd
== TransportCommandStop
) {
463 ectl
->transport_state
= JackTransportStopped
;
464 VERBOSE (engine
, "transport Stopped");
465 if (ectl
->sync_remain
)
466 jack_sync_poll_stop(engine
);
467 } else if (ectl
->new_pos
) {
468 if (ectl
->sync_clients
) {
469 ectl
->transport_state
= JackTransportStarting
;
470 jack_sync_poll_start(engine
);
472 ectl
->transport_state
= JackTransportRolling
;
473 VERBOSE (engine
, "transport Rolling");
478 case JackTransportRolling
:
479 if (cmd
== TransportCommandStop
) {
480 ectl
->transport_state
= JackTransportStopped
;
481 VERBOSE (engine
, "transport Stopped");
482 if (ectl
->sync_remain
)
483 jack_sync_poll_stop(engine
);
484 } else if (ectl
->new_pos
) {
485 if (ectl
->sync_clients
) {
486 ectl
->transport_state
= JackTransportStarting
;
487 jack_sync_poll_start(engine
);
493 jack_error ("invalid JACK transport state: %d",
494 ectl
->transport_state
);
497 /* Update timebase, if needed. */
498 if (ectl
->transport_state
== JackTransportRolling
) {
499 ectl
->pending_time
.frame
=
500 ectl
->current_time
.frame
+ ectl
->buffer_size
;
503 /* See if an asynchronous position request arrived during the
504 * last cycle. The request_time could change during the
505 * guarded copy. If so, we use the newest request. */
506 ectl
->pending_pos
= 0;
507 if (ectl
->request_time
.unique_1
!= ectl
->prev_request
) {
508 jack_transport_copy_position(&ectl
->request_time
,
509 &ectl
->pending_time
);
510 VERBOSE (engine
, "new transport position: %" PRIu32
511 ", id=0x%" PRIx64
, ectl
->pending_time
.frame
,
512 ectl
->pending_time
.unique_1
);
513 ectl
->prev_request
= ectl
->pending_time
.unique_1
;
514 ectl
->pending_pos
= 1;
517 /* clients can't set pending frame number, so save it here */
518 ectl
->pending_frame
= ectl
->pending_time
.frame
;
521 /* driver callback at start of cycle */
523 jack_transport_cycle_start (jack_engine_t
*engine
, jack_time_t time
)
525 engine
->control
->current_time
.usecs
= time
;
528 /* on SetSyncTimeout request */
530 jack_transport_set_sync_timeout (jack_engine_t
*engine
,
533 engine
->control
->sync_timeout
= usecs
;
534 VERBOSE (engine
, "new sync timeout: %8.6f secs",
535 (double) (usecs
/ 1000000.0));