~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
JACK/jackd/transengine.c


** Warning: Cannot open xref database.

1 /* 2 JACK transport engine -- runs in the server process. 3 4 Copyright (C) 2001-2003 Paul Davis 5 Copyright (C) 2003 Jack O'Quin 6 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. 11 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. 16 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. 20 */ 21 22 #include <config.h> 23 #include <errno.h> 24 #include <assert.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <jack/internal.h> 28 #include <jack/engine.h> 29 #include "transengine.h" 30 31 32 /********************** internal functions **********************/ 33 34 /* initiate polling a new slow-sync client 35 * 36 * precondition: caller holds the graph lock. */ 37 static inline void 38 jack_sync_poll_new (jack_engine_t *engine, jack_client_internal_t *client) 39 { 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++; 46 } 47 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\n"); 52 } 53 54 VERBOSE (engine, "polling sync client %" PRIu32 "\n", 55 client->control->id); 56 } 57 58 /* stop polling a specific slow-sync client 59 * 60 * precondition: caller holds the graph lock. */ 61 static inline void 62 jack_sync_poll_deactivate (jack_engine_t *engine, 63 jack_client_internal_t *client) 64 { 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 "\n", client->control->id); 71 } 72 client->control->active_slowsync = 0; 73 engine->control->sync_clients--; 74 assert(engine->control->sync_clients >= 0); 75 } 76 77 /* stop polling all the slow-sync clients 78 * 79 * precondition: caller holds the graph lock. */ 80 static void 81 jack_sync_poll_stop (jack_engine_t *engine) 82 { 83 JSList *node; 84 long poll_count = 0; /* count sync_poll clients */ 85 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; 92 poll_count++; 93 } 94 } 95 96 //JOQ: check invariant for debugging... 97 assert (poll_count == engine->control->sync_remain); 98 VERBOSE (engine, 99 "sync poll halted with %" PRIu32 100 " clients and %8.6f secs remaining\n", 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; 105 } 106 107 /* start polling all the slow-sync clients 108 * 109 * precondition: caller holds the graph lock. */ 110 static void 111 jack_sync_poll_start (jack_engine_t *engine) 112 { 113 JSList *node; 114 long sync_count = 0; /* count slow-sync clients */ 115 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; 121 sync_count++; 122 } 123 } 124 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\n", engine->control->sync_remain, 131 (double) (engine->control->sync_time_left / 1000000.0)); 132 } 133 134 /* check for sync timeout */ 135 static inline int 136 jack_sync_timeout (jack_engine_t *engine) 137 { 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); 142 143 /* compare carefully, jack_time_t is unsigned */ 144 if (ectl->sync_time_left > buf_usecs) { 145 ectl->sync_time_left -= buf_usecs; 146 return FALSE; 147 } 148 149 /* timed out */ 150 VERBOSE (engine, "transport sync timeout\n"); 151 ectl->sync_time_left = 0; 152 return TRUE; 153 } 154 155 156 /**************** subroutines used by engine.c ****************/ 157 158 /* driver callback */ 159 int 160 jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes) 161 { 162 jack_control_t *ectl = engine->control; 163 164 ectl->current_time.frame_rate = nframes; 165 ectl->pending_time.frame_rate = nframes; 166 return 0; 167 } 168 169 /* on ResetTimeBaseClient request */ 170 int 171 jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id) 172 { 173 int ret; 174 struct _jack_client_internal *client; 175 jack_control_t *ectl = engine->control; 176 177 jack_lock_graph (engine); 178 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\n", 186 client->control->name); 187 ret = 0; 188 } else 189 ret = EINVAL; 190 191 jack_unlock_graph (engine); 192 193 return ret; 194 } 195 196 /* on SetTimeBaseClient request */ 197 int 198 jack_timebase_set (jack_engine_t *engine, 199 jack_client_id_t client_id, int conditional) 200 { 201 int ret = 0; 202 struct _jack_client_internal *client; 203 204 jack_lock_graph (engine); 205 206 client = jack_client_internal_by_id (engine, client_id); 207 208 if (client == NULL) { 209 VERBOSE (engine, " %" PRIu32 " no longer exists\n", client_id); 210 jack_unlock_graph (engine); 211 return EINVAL; 212 } 213 214 if (conditional && engine->timebase_client) { 215 216 /* see if timebase master is someone else */ 217 if (client != engine->timebase_client) { 218 VERBOSE (engine, "conditional timebase for %s failed\n" 219 " %s is already the master\n", 220 client->control->name, 221 engine->timebase_client->control->name); 222 ret = EBUSY; 223 } else 224 VERBOSE (engine, " %s was already timebase master:\n", 225 client->control->name); 226 227 } else { 228 229 if (engine->timebase_client) { 230 engine->timebase_client->control->is_timebase = 0; 231 engine->timebase_client->control->timebase_new = 0; 232 } 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\n", 238 client->control->name); 239 } 240 241 jack_unlock_graph (engine); 242 243 return ret; 244 } 245 246 /* for client activation 247 * 248 * precondition: caller holds the graph lock. */ 249 void 250 jack_transport_activate (jack_engine_t *engine, jack_client_internal_t *client) 251 { 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); 257 } 258 259 if (client->control->is_timebase) { 260 client->control->timebase_new = 1; 261 } 262 } 263 264 /* for engine initialization */ 265 void 266 jack_transport_init (jack_engine_t *engine) 267 { 268 jack_control_t *ectl = engine->control; 269 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 */ 279 ectl->new_pos = 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; 286 } 287 288 /* when any client exits the graph (either dead or not active) 289 * 290 * precondition: caller holds the graph lock */ 291 void 292 jack_transport_client_exit (jack_engine_t *engine, 293 jack_client_internal_t *client) 294 { 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\n"); 301 } 302 engine->control->current_time.valid = 0; 303 engine->control->pending_time.valid = 0; 304 } 305 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; 311 } 312 } 313 314 /* when a new client is being created */ 315 void 316 jack_transport_client_new (jack_client_internal_t *client) 317 { 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; 324 client->control->sync_cb = NULL; 325 client->control->sync_arg = NULL; 326 client->control->timebase_cb = NULL; 327 client->control->timebase_arg = NULL; 328 } 329 330 /* on ResetSyncClient request */ 331 int 332 jack_transport_client_reset_sync (jack_engine_t *engine, 333 jack_client_id_t client_id) 334 { 335 int ret; 336 jack_client_internal_t *client; 337 338 jack_lock_graph (engine); 339 340 client = jack_client_internal_by_id (engine, client_id); 341 342 if (client && (client->control->is_slowsync)) { 343 if (client->control->active_slowsync) 344 jack_sync_poll_deactivate (engine, client); 345 client->control->is_slowsync = 0; 346 ret = 0; 347 } else 348 ret = EINVAL; 349 350 jack_unlock_graph (engine); 351 352 return ret; 353 } 354 355 /* on SetSyncClient request */ 356 int 357 jack_transport_client_set_sync (jack_engine_t *engine, 358 jack_client_id_t client_id) 359 { 360 int ret; 361 jack_client_internal_t *client; 362 363 /* The process cycle runs with this lock. */ 364 jack_lock_graph (engine); 365 366 client = jack_client_internal_by_id (engine, client_id); 367 368 if (client) { 369 if (!client->control->is_slowsync) { 370 client->control->is_slowsync = 1; 371 if (client->control->active) { 372 client->control->active_slowsync = 1; 373 engine->control->sync_clients++; 374 } 375 } 376 377 /* force poll of the new slow-sync client, if active */ 378 if (client->control->active_slowsync) 379 jack_sync_poll_new (engine, client); 380 ret = 0; 381 } else 382 ret = EINVAL; 383 384 jack_unlock_graph (engine); 385 386 return ret; 387 } 388 389 /* at process cycle end, set transport parameters for the next cycle 390 * 391 * precondition: caller holds the graph lock. 392 */ 393 void 394 jack_transport_cycle_end (jack_engine_t *engine) 395 { 396 jack_control_t *ectl = engine->control; 397 transport_command_t cmd; /* latest transport command */ 398 399 /* Promote pending_time to current_time. Maintain the usecs, 400 * frame_rate and frame values, clients may not set them. */ 401 ectl->pending_time.usecs = ectl->current_time.usecs; 402 ectl->pending_time.frame_rate = ectl->current_time.frame_rate; 403 ectl->pending_time.frame = ectl->pending_frame; 404 ectl->current_time = ectl->pending_time; 405 ectl->new_pos = ectl->pending_pos; 406 407 /* check sync results from previous cycle */ 408 if (ectl->transport_state == JackTransportStarting) { 409 if ((ectl->sync_remain == 0) || 410 (jack_sync_timeout(engine))) { 411 ectl->transport_state = JackTransportRolling; 412 VERBOSE (engine, "transport Rolling, %8.6f sec" 413 " left for poll\n", 414 (double) (ectl->sync_time_left / 1000000.0)); 415 } 416 } 417 418 /* Handle any new transport command from the last cycle. */ 419 cmd = ectl->transport_cmd; 420 if (cmd != ectl->previous_cmd) { 421 ectl->previous_cmd = cmd; 422 VERBOSE (engine, "transport command: %s\n", 423 (cmd == TransportCommandStart? "START": "STOP")); 424 } else 425 cmd = TransportCommandNone; 426 427 /* state transition switch */ 428 switch (ectl->transport_state) { 429 430 case JackTransportStopped: 431 if (cmd == TransportCommandStart) { 432 if (ectl->sync_clients) { 433 ectl->transport_state = JackTransportStarting; 434 jack_sync_poll_start(engine); 435 } else { 436 ectl->transport_state = JackTransportRolling; 437 VERBOSE (engine, "transport Rolling\n"); 438 } 439 } 440 break; 441 442 case JackTransportStarting: 443 if (cmd == TransportCommandStop) { 444 ectl->transport_state = JackTransportStopped; 445 VERBOSE (engine, "transport Stopped\n"); 446 if (ectl->sync_remain) 447 jack_sync_poll_stop(engine); 448 } else if (ectl->new_pos) { 449 if (ectl->sync_clients) { 450 ectl->transport_state = JackTransportStarting; 451 jack_sync_poll_start(engine); 452 } else { 453 ectl->transport_state = JackTransportRolling; 454 VERBOSE (engine, "transport Rolling\n"); 455 } 456 } 457 break; 458 459 case JackTransportRolling: 460 if (cmd == TransportCommandStop) { 461 ectl->transport_state = JackTransportStopped; 462 VERBOSE (engine, "transport Stopped\n"); 463 if (ectl->sync_remain) 464 jack_sync_poll_stop(engine); 465 } else if (ectl->new_pos) { 466 if (ectl->sync_clients) { 467 ectl->transport_state = JackTransportStarting; 468 jack_sync_poll_start(engine); 469 } 470 } 471 break; 472 473 default: 474 jack_error ("invalid JACK transport state: %d", 475 ectl->transport_state); 476 } 477 478 /* update timebase, if needed */ 479 if (ectl->transport_state == JackTransportRolling) { 480 ectl->pending_time.frame = 481 ectl->current_time.frame + ectl->buffer_size; 482 } 483 484 /* See if an asynchronous position request arrived during the 485 * last cycle. The request_time could change during the 486 * guarded copy. If so, we use the newest request. */ 487 ectl->pending_pos = 0; 488 if (ectl->request_time.unique_1 != ectl->prev_request) { 489 jack_transport_copy_position(&ectl->request_time, 490 &ectl->pending_time); 491 VERBOSE (engine, "new transport position: %" PRIu32 492 ", id=0x%" PRIx64 "\n", ectl->pending_time.frame, 493 ectl->pending_time.unique_1); 494 ectl->prev_request = ectl->pending_time.unique_1; 495 ectl->pending_pos = 1; 496 } 497 498 /* clients can't set pending frame number, so save it here */ 499 ectl->pending_frame = ectl->pending_time.frame; 500 } 501 502 /* driver callback at start of cycle */ 503 void 504 jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time) 505 { 506 engine->control->current_time.usecs = time; 507 } 508 509 /* on SetSyncTimeout request */ 510 int 511 jack_transport_set_sync_timeout (jack_engine_t *engine, 512 jack_time_t usecs) 513 { 514 engine->control->sync_timeout = usecs; 515 VERBOSE (engine, "new sync timeout: %8.6f secs\n", 516 (double) (usecs / 1000000.0)); 517 return 0; 518 } 519

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.