Browse Source

[0.76.6] transport sync improvements, timeout

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@451 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
joq 22 years ago
parent
commit
a3f7d60349
8 changed files with 347 additions and 166 deletions
  1. +1
    -1
      configure.in
  2. +1
    -1
      doc/transport.dox
  3. +11
    -5
      jack/internal.h
  4. +24
    -29
      jack/transport.h
  5. +19
    -7
      jackd/engine.c
  6. +237
    -101
      jackd/transengine.c
  7. +14
    -6
      jackd/transengine.h
  8. +40
    -16
      libjack/transclient.c

+ 1
- 1
configure.in View File

@@ -14,7 +14,7 @@ dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=76
JACK_MICRO_VERSION=5
JACK_MICRO_VERSION=6


dnl ---


+ 1
- 1
doc/transport.dox View File

@@ -145,7 +145,7 @@ to NULL.

@code
int jack_set_sync_timeout (jack_client_t *client,
jack_nframes_t timeout);
jack_time_t usecs);
@endcode

There must be a @a timeout to prevent unresponsive slow-sync clients


+ 11
- 5
jack/internal.h View File

@@ -75,7 +75,7 @@ typedef struct {

typedef enum {
TransportCommandNone = 0,
TransportCommandPlay = 1,
TransportCommandStart = 1,
TransportCommandStop = 2,
} transport_command_t;

@@ -102,9 +102,10 @@ typedef struct {
jack_position_t pending_time; /* position for next cycle */
jack_position_t request_time; /* latest requested position */
int new_pos; /* new position this cycle */
unsigned long sync_remain; /* remaining sync count */
unsigned long sync_cycle; /* number ready this cycle */
unsigned long sync_clients; /* number of slow-sync clients */
unsigned long sync_clients; /* number of is_slowsync clients */
unsigned long sync_remain; /* number of them with sync_poll */
jack_time_t sync_timeout;
jack_time_t sync_time_left;
jack_frame_timer_t frame_timer;
int internal;
jack_nframes_t frames_at_cycle_start;
@@ -177,8 +178,10 @@ typedef volatile struct {
volatile char active : 1; /* w: engine r: engine and client */
volatile char dead : 1; /* r/w: engine */
volatile char timed_out : 1; /* r/w: engine */
volatile char sync_ready : 1; /* w: engine and client, r: engine */
volatile char is_timebase : 1; /* w: engine, r: engine and client */
volatile char is_slowsync : 1; /* w: engine, r: engine and client */
volatile char sync_poll : 1; /* w: engine and client, r: engine */
volatile char sync_new : 1; /* w: engine and client, r: engine */
volatile pid_t pid; /* w: client r: engine; client pid */
volatile unsigned long long signalled_at;
volatile unsigned long long awake_at;
@@ -281,6 +284,8 @@ typedef enum {
GetPortNConnections = 11,
ResetTimeBaseClient = 12,
SetSyncClient = 13,
ResetSyncClient = 14,
SetSyncTimeout = 15,
} RequestType;

struct _jack_request {
@@ -309,6 +314,7 @@ struct _jack_request {
} timebase;
jack_client_id_t client_id;
jack_nframes_t nframes;
jack_time_t timeout;
} x;
int status;
};


+ 24
- 29
jack/transport.h View File

@@ -50,6 +50,7 @@ typedef enum {

} jack_position_bits_t;

#define JACK_POSITION_MASK (JackPositionBBT) /**< all valid position bits */
#define EXTENDED_TIME_INFO

/**
@@ -105,17 +106,18 @@ typedef struct {
int jack_release_timebase (jack_client_t *client);

/**
* Prototype for the sync callback defined by slow-sync clients.
* Called just before process() in the same thread when some client
* has requested a new position. This realtime function must not
* wait.
* Prototype for the @a sync_callback defined by slow-sync clients.
* Called just before process() in the same thread on the first cycle
* after being registered, whenever some client requests a new
* position, or when the transport enters the ::JackTransportStarting
* state. This realtime function must not wait.
*
* The transport @a state will be:
*
* - ::JackTransportStopped some client just requested a new position;
* - ::JackTransportStarting the transport is waiting to start;
* - ::JackTransportRolling the timeout has expired, and the position
* is now a moving target.
* - ::JackTransportStopped when a new position is requested;
* - ::JackTransportStarting when the transport is waiting to start;
* - ::JackTransportRolling when the timeout has expired, and the
* position is now a moving target.
*
* @param state current transport state.
* @param pos new transport position.
@@ -131,18 +133,11 @@ typedef int (*JackSyncCallback)(jack_transport_state_t state,
* Register (or unregister) as a slow-sync client, one that cannot
* respond immediately to transport position changes.
*
* When there are slow-sync clients and the JACK transport starts
* playing in a new postion, it first enters the
* ::JackTransportStarting state. The @a sync_callback function for
* each slow-sync client will be invoked in the JACK process thread
* while the transport is starting. If it has not already done so,
* the client needs to initiate a seek to reach the starting position.
* The @a sync_callback returns false until the seek completes and the
* client is ready to play. When all slow-sync clients are ready, the
* state changes to ::JackTransportRolling.
*
* Clients that don't set a @a sync_callback are assumed to be ready
* immediately, any time the transport wants to start.
* The @a sync_callback will be invoked on the first process cycle
* after its registration is complete. After that, it runs according
* to the ::JackSyncCallback rules. Clients that don't set a @a
* sync_callback are assumed to be ready immediately any time the
* transport wants to start.
*
* @param client the JACK client structure.
* @param sync_callback is a realtime function that returns true when
@@ -162,24 +157,24 @@ int jack_set_sync_callback (jack_client_t *client,
* This timeout prevents unresponsive slow-sync clients from
* completely halting the transport mechanism. The default is two
* seconds. When the timeout expires, the transport starts rolling,
* even if some slow-sync clients are still unready. The
* sync_callbacksof these clients continue being invoked, giving them
* even if some slow-sync clients are still unready. The @a
* sync_callbacks of these clients continue being invoked, giving them
* a chance to catch up.
*
* @see jack_set_sync_callback
*
* @param client the JACK client structure.
* @param timeout is delay (in frames) before the timeout expires.
* @param timeout is delay (in microseconds) before the timeout expires.
*
* @return 0 on success, otherwise a non-zero error code.
*/
int jack_set_sync_timeout (jack_client_t *client,
jack_nframes_t timeout);
jack_time_t timeout);

/**
* Prototype for the timebase master callback used to continuously
* update position information. Without extended information, there
* is no need for this function, JACK can count frames automatically.
* Prototype for the @a timebase_callback used to continuously update
* position information. Without extended information, there is no
* need for this function, JACK will count frames automatically.
*
* This function is called immediately after process() in the same
* thread whenever the transport is rolling, or when any client has
@@ -252,7 +247,7 @@ int jack_set_timebase_callback (jack_client_t *client,
* @param client the JACK client structure.
* @param frame frame number of new transport position.
*
* @return 0 if valid request, otherwise a non-zero error code.
* @return 0 if valid request, non-zero otherwise.
*/
int jack_transport_locate (jack_client_t *client,
jack_nframes_t frame);
@@ -288,7 +283,7 @@ jack_transport_state_t jack_transport_query (jack_client_t *client,
* @param client the JACK client structure.
* @param pos requested new transport position.
*
* @return 0 if valid request, otherwise a non-zero error code.
* @return 0 if valid request, EINVAL if position structure rejected.
*/
int jack_transport_reposition (jack_client_t *client,
jack_position_t *pos);


+ 19
- 7
jackd/engine.c View File

@@ -1322,8 +1322,7 @@ jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id)
JSList *portnode;
jack_port_internal_t *port;

if (client == engine->timebase_client)
jack_timebase_exit (engine);
jack_transport_client_exit (engine, client);
for (portnode = client->ports; portnode; portnode = jack_slist_next (portnode)) {
port = (jack_port_internal_t *) portnode->data;
@@ -1446,7 +1445,20 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd)
break;

case SetSyncClient:
req->status = jack_set_sync_client (engine, req->x.client_id);
req->status =
jack_transport_client_set_sync (engine,
req->x.client_id);
break;

case ResetSyncClient:
req->status =
jack_transport_client_reset_sync (engine,
req->x.client_id);
break;

case SetSyncTimeout:
req->status = jack_transport_set_sync_timeout (engine,
req->x.timeout);
break;

#ifdef USE_CAPABILITIES
@@ -1782,7 +1794,7 @@ jack_engine_new (int realtime, int rtpriority, int verbose, int client_timeout)
engine->control->buffer_size = 0;
jack_set_sample_rate (engine, 0);
jack_timebase_init (engine);
jack_transport_init (engine);
engine->control->internal = 0;

engine->control->has_capabilities = 0;
@@ -2239,6 +2251,8 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req
client->control->port_register_arg = NULL;
client->control->graph_order = NULL;
client->control->graph_order_arg = NULL;

jack_transport_client_new (client);
#if defined(__APPLE__) && defined(__POWERPC__)
/* specific ressources for server/client real-time thread communication */
@@ -2287,9 +2301,7 @@ jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)

client->control->dead = TRUE;
if (client == engine->timebase_client)
jack_timebase_exit (engine);

jack_transport_client_exit (engine, client);
jack_client_disconnect (engine, client);
jack_client_do_deactivate (engine, client, FALSE);
}


+ 237
- 101
jackd/transengine.c View File

@@ -5,9 +5,9 @@
Copyright (C) 2003 Jack O'Quin
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1
of the License, or (at your option) any later version.
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -21,69 +21,123 @@

#include <config.h>
#include <errno.h>
#include <assert.h>
#include <jack/internal.h>
#include <jack/engine.h>
#include "transengine.h"


/*********************** driver callbacks ***********************/
/********************** internal functions **********************/

int
jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes)
/* stop polling a specific slow-sync client
*
* precondition: caller holds the graph lock. */
static inline void
jack_sync_poll_exit(jack_engine_t *engine, jack_client_internal_t *client)
{
jack_control_t *ectl = engine->control;

ectl->current_time.frame_rate = nframes;
ectl->pending_time.frame_rate = nframes;
return 0;
if (client->control->sync_poll) {
client->control->sync_poll = 0;
client->control->sync_new = 0;
engine->control->sync_remain--;
}
client->control->is_slowsync = 0;
engine->control->sync_clients--;
}

void
jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time)
/* stop polling all the slow-sync clients
*
* precondition: caller holds the graph lock. */
static void
jack_sync_poll_stop(jack_engine_t *engine)
{
engine->control->current_time.guard_usecs =
engine->control->current_time.usecs = time;
}
JSList *node;
long poll_count = 0; /* count sync_poll clients */

for (node = engine->clients; node; node = jack_slist_next (node)) {
jack_client_internal_t *client =
(jack_client_internal_t *) node->data;
if (client->control->is_slowsync &&
client->control->sync_poll) {
client->control->sync_poll = 0;
poll_count++;
}
}

/********************* RPC request handlers *********************/
//JOQ: check invariant for debugging...
assert (poll_count == engine->control->sync_remain);
engine->control->sync_remain = 0;
engine->control->sync_time_left = 0;
}

/* for SetSyncClient */
int
jack_set_sync_client (jack_engine_t *engine, jack_client_id_t client)
/* start polling all the slow-sync clients
*
* precondition: caller holds the graph lock. */
static void
jack_sync_poll_start(jack_engine_t *engine)
{
int ret;
jack_client_internal_t *clintl;
JSList *node;
long sync_count = 0; /* count slow-sync clients */

jack_lock_graph (engine);
for (node = engine->clients; node; node = jack_slist_next (node)) {
jack_client_internal_t *client =
(jack_client_internal_t *) node->data;
if (client->control->is_slowsync) {
client->control->sync_poll = 1;
sync_count++;
}
}

clintl = jack_client_internal_by_id (engine, client);
//JOQ: check invariant for debugging...
assert (sync_count == engine->control->sync_clients);
engine->control->sync_remain = engine->control->sync_clients;
engine->control->sync_time_left = engine->control->sync_timeout;
}

if (clintl) {
clintl->control->sync_ready = 0;
engine->control->sync_clients++;
ret = 0;
} else
ret = EINVAL;
/* check for sync timeout */
static inline int
jack_sync_timeout(jack_engine_t *engine)
{
jack_control_t *ectl = engine->control;
jack_time_t buf_usecs =
((ectl->buffer_size * (jack_time_t) 1000000000) /
ectl->current_time.frame_rate);

/* compare carefully, jack_time_t is unsigned */
if (ectl->sync_time_left <= buf_usecs) {
ectl->sync_time_left = 0;
return 1; /* timed out */
} else {
ectl->sync_time_left -= buf_usecs;
return 0; /* continue */
}
}

jack_unlock_graph (engine);
/**************** subroutines used by engine.c ****************/

return ret;
/* driver callback */
int
jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes)
{
jack_control_t *ectl = engine->control;

ectl->current_time.frame_rate = nframes;
ectl->pending_time.frame_rate = nframes;
return 0;
}

/* for ResetTimeBaseClient */
/* on ResetTimeBaseClient request */
int
jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client)
jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id)
{
int ret;
struct _jack_client_internal *clint;
struct _jack_client_internal *client;
jack_control_t *ectl = engine->control;

jack_lock_graph (engine);

clint = jack_client_internal_by_id (engine, client);
if (clint && (clint == engine->timebase_client)) {
clint->control->is_timebase = 0;
client = jack_client_internal_by_id (engine, client_id);
if (client && (client == engine->timebase_client)) {
client->control->is_timebase = 0;
engine->timebase_client = NULL;
ectl->pending_time.valid = 0;
ret = 0;
@@ -95,32 +149,32 @@ jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client)
return ret;
}

/* for SetTimeBaseClient */
/* on SetTimeBaseClient request */
int
jack_timebase_set (jack_engine_t *engine,
jack_client_id_t client, int conditional)
jack_client_id_t client_id, int conditional)
{
int ret = 0;
struct _jack_client_internal *clint;
struct _jack_client_internal *client;

jack_lock_graph (engine);

clint = jack_client_internal_by_id (engine, client);
client = jack_client_internal_by_id (engine, client_id);

if (conditional && engine->timebase_client) {

/* see if timebase master is someone else */
if (clint && (clint != engine->timebase_client))
if (client && (client != engine->timebase_client))
ret = EBUSY;

} else {

if (clint) {
if (client) {
if (engine->timebase_client)
engine->timebase_client->
control->is_timebase = 0;
engine->timebase_client = clint;
clint->control->is_timebase = 1;
engine->timebase_client = client;
client->control->is_timebase = 1;
} else
ret = EINVAL;
}
@@ -130,68 +184,129 @@ jack_timebase_set (jack_engine_t *engine,
return ret;
}


/******************** engine.c subroutines ********************/

/* start polling slow-sync clients */
/* for engine initialization */
void
jack_start_sync_poll(jack_engine_t *engine)
jack_transport_init (jack_engine_t *engine)
{
/* precondition: caller holds the graph lock. */
jack_control_t *ectl = engine->control;
JSList *node;
long sync_count = 0; /* number of slow-sync clients */

for (node = engine->clients; node; node = jack_slist_next (node)) {
jack_client_internal_t *clintl =
(jack_client_internal_t *) node->data;
if (clintl->control->sync_cb) {
clintl->control->sync_ready = 0;
sync_count++;
}
engine->timebase_client = NULL;
ectl->transport_state = JackTransportStopped;
ectl->transport_cmd = TransportCommandNone;
memset (&ectl->current_time, 0, sizeof(ectl->current_time));
memset (&ectl->pending_time, 0, sizeof(ectl->pending_time));
memset (&ectl->request_time, 0, sizeof(ectl->request_time));
ectl->new_pos = 0;
ectl->sync_remain = 0;
ectl->sync_clients = 0;
ectl->sync_timeout = 2000000000; /* 2 second default */
ectl->sync_time_left = 0;
}

/* when any client exits the graph
*
* precondition: caller holds the graph lock */
void
jack_transport_client_exit (jack_engine_t *engine,
jack_client_internal_t *client)
{
if (client == engine->timebase_client) {
engine->timebase_client->control->is_timebase = 0;
engine->timebase_client = NULL;
engine->control->current_time.valid = 0;
engine->control->pending_time.valid = 0;
}

ectl->sync_remain = ectl->sync_clients = sync_count;
ectl->sync_cycle = 0;
if (client->control->is_slowsync)
jack_sync_poll_exit(engine, client);
}

/* when timebase master exits the graph */
void
jack_timebase_exit (jack_engine_t *engine)
/* when a new client is being created */
void
jack_transport_client_new (jack_client_internal_t *client)
{
jack_control_t *ectl = engine->control;
client->control->is_timebase = 0;
client->control->is_slowsync = 0;
client->control->sync_poll = 0;
client->control->sync_new = 0;
client->control->sync_cb = NULL;
client->control->sync_arg = NULL;
client->control->timebase_cb = NULL;
client->control->timebase_arg = NULL;
}

engine->timebase_client->control->is_timebase = 0;
engine->timebase_client = NULL;
ectl->current_time.valid = 0;
ectl->pending_time.valid = 0;
/* on ResetSyncClient request */
int
jack_transport_client_reset_sync (jack_engine_t *engine,
jack_client_id_t client_id)
{
int ret;
jack_client_internal_t *client;

jack_lock_graph (engine);

client = jack_client_internal_by_id (engine, client_id);

if (client && (client->control->is_slowsync)) {
jack_sync_poll_exit(engine, client);
ret = 0;
} else
ret = EINVAL;

jack_unlock_graph (engine);

return ret;
}

/* engine initialization */
void
jack_timebase_init (jack_engine_t *engine)
/* on SetSyncClient request */
int
jack_transport_client_set_sync (jack_engine_t *engine,
jack_client_id_t client_id)
{
jack_control_t *ectl = engine->control;
int ret;
jack_client_internal_t *client;

engine->timebase_client = NULL;
ectl->transport_state = JackTransportStopped;
ectl->transport_cmd = TransportCommandNone;
memset (&ectl->current_time, 0, sizeof(ectl->current_time));
memset (&ectl->pending_time, 0, sizeof(ectl->pending_time));
memset (&ectl->request_time, 0, sizeof(ectl->request_time));
ectl->new_pos = 0;
ectl->sync_remain = 0;
ectl->sync_cycle = 0;
ectl->sync_clients = 0;
// JOQ: I am assuming the process cycle is serialized with
// respect to this lock...
jack_lock_graph (engine);

client = jack_client_internal_by_id (engine, client_id);

if (client) {
if (!client->control->is_slowsync) {

/* force poll of the new slow-sync client */
client->control->is_slowsync = 1;
engine->control->sync_clients++;

// JOQ: I don't like doing this here...
client->control->sync_poll = 1;
engine->control->sync_remain++;
engine->control->sync_time_left =
engine->control->sync_timeout;
if (engine->control->transport_state ==
JackTransportRolling)
engine->control->transport_state =
JackTransportStarting;
}
client->control->sync_new = 1;
ret = 0;
} else
ret = EINVAL;

jack_unlock_graph (engine);

return ret;
}

/* This runs at the end of every process cycle. It determines the
* transport parameters for the next cycle.
/* at the end of every process cycle
*
* Determines the transport parameters for the following cycle.
* precondition: caller holds the graph lock.
*/
void
jack_transport_cycle_end (jack_engine_t *engine)
{
/* precondition: caller holds the graph lock. */
jack_control_t *ectl = engine->control;
transport_command_t cmd; /* latest transport command */

@@ -211,6 +326,8 @@ jack_transport_cycle_end (jack_engine_t *engine)
* replaced it anyway, we won't bother with <asm/atomic.h>.
*/
cmd = ectl->transport_cmd;
// JOQ: may be able to close the window by eliminating this
// store, but watch out below...
ectl->transport_cmd = TransportCommandNone;

if (ectl->request_time.usecs) {
@@ -229,25 +346,27 @@ jack_transport_cycle_end (jack_engine_t *engine)
ectl->pending_time.frame_rate = ectl->current_time.frame_rate;
ectl->current_time = ectl->pending_time;

/* accumulate sync results from previous cycle */
if (ectl->sync_remain) {
ectl->sync_remain -= ectl->sync_cycle;
if ((ectl->sync_remain == 0) &&
(ectl->transport_state == JackTransportStarting))
/* check sync results from previous cycle */
if (ectl->transport_state == JackTransportStarting) {
if ((ectl->sync_remain == 0) ||
(jack_sync_timeout(engine)))
ectl->transport_state = JackTransportRolling;
ectl->sync_cycle = 0;



}

/* state transition switch */
switch (ectl->transport_state) {

case JackTransportStopped:
if (cmd == TransportCommandPlay) {
if (cmd == TransportCommandStart) {
if (ectl->sync_clients) {
ectl->transport_state = JackTransportStarting;
jack_start_sync_poll(engine);
} else
jack_sync_poll_start(engine);
} else {
ectl->transport_state = JackTransportRolling;
}
}
break;

@@ -255,14 +374,14 @@ jack_transport_cycle_end (jack_engine_t *engine)
case JackTransportRolling:
if (cmd == TransportCommandStop) {
ectl->transport_state = JackTransportStopped;
ectl->sync_remain = 0; /* halt polling */
jack_sync_poll_stop(engine);
} else if (ectl->new_pos) {
if (ectl->sync_clients) {
ectl->transport_state = JackTransportStarting;
jack_start_sync_poll(engine);
}
else
jack_sync_poll_start(engine);
} else {
ectl->transport_state = JackTransportRolling;
}
}
break;

@@ -272,3 +391,20 @@ jack_transport_cycle_end (jack_engine_t *engine)
}
return;
}

/* driver callback at start of cycle */
void
jack_transport_cycle_start (jack_engine_t *engine, jack_time_t time)
{
engine->control->current_time.guard_usecs =
engine->control->current_time.usecs = time;
}

/* on SetSyncTimeout request */
int
jack_transport_set_sync_timeout (jack_engine_t *engine,
jack_time_t usecs)
{
engine->control->sync_timeout = usecs;
return 0;
}

+ 14
- 6
jackd/transengine.h View File

@@ -19,11 +19,19 @@
*/

int jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes);
int jack_set_sync_client (jack_engine_t *engine, jack_client_id_t client);
void jack_timebase_exit (jack_engine_t *engine);
void jack_timebase_init (jack_engine_t *engine);
int jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client);
int jack_timebase_reset (jack_engine_t *engine,
jack_client_id_t client_id);
int jack_timebase_set (jack_engine_t *engine,
jack_client_id_t client, int conditional);
void jack_transport_cycle_start(jack_engine_t *engine, jack_time_t time);
jack_client_id_t client_id, int conditional);
void jack_transport_init (jack_engine_t *engine);
void jack_transport_client_exit (jack_engine_t *engine,
jack_client_internal_t *client);
void jack_transport_client_new (jack_client_internal_t *client);
int jack_transport_client_reset_sync (jack_engine_t *engine,
jack_client_id_t client_id);
int jack_transport_client_set_sync (jack_engine_t *engine,
jack_client_id_t client_id);
void jack_transport_cycle_end (jack_engine_t *engine);
void jack_transport_cycle_start(jack_engine_t *engine, jack_time_t time);
int jack_transport_set_sync_timeout (jack_engine_t *engine,
jack_time_t usecs);

+ 40
- 16
libjack/transclient.c View File

@@ -82,7 +82,11 @@ jack_transport_request_new_pos (jack_client_t *client, jack_position_t *pos)
{
jack_control_t *eng = client->engine;

//JOQ: check validity of input
// JOQ: I don't think using guard_usecs is good enough. On
// faster machines we could get another request in the same
// microsecond. Better to use something like get_cycles().
// SMP further complicates the issue. It may require a CPU id
// in addition to the cycle counter for uniqueness.

/* carefully copy requested postion into shared memory */
pos->guard_usecs = pos->usecs = jack_get_microseconds();
@@ -100,15 +104,21 @@ jack_call_sync_client (jack_client_t *client)
jack_client_control_t *control = client->control;
jack_control_t *eng = client->engine;

if (eng->new_pos || !control->sync_ready) {
/* Make sure we are still slow-sync; is_slowsync is set in a
* critical section; sync_cb is not. */
if ((eng->new_pos || control->sync_poll || control->sync_new) &&
control->is_slowsync) {

if (control->sync_cb (eng->transport_state,
&eng->current_time,
control->sync_arg)) {

control->sync_ready = 1;
eng->sync_cycle++;
if (control->sync_poll) {
control->sync_poll = 0;
eng->sync_remain--;
}
}
control->sync_new = 0;
}
}

@@ -119,7 +129,8 @@ jack_call_timebase_master (jack_client_t *client)
jack_control_t *eng = client->engine;
int new_pos = eng->new_pos;

/* make sure we're still the master */
/* Make sure we're still the master. Test is_timebase, which
* is set in a critical section; timebase_cb is not. */
if (control->is_timebase) {

if (client->new_timebase) { /* first callback? */
@@ -229,7 +240,10 @@ jack_set_sync_callback (jack_client_t *client,
jack_request_t req;
int rc;

req.type = SetSyncClient;
if (sync_callback)
req.type = SetSyncClient;
else
req.type = ResetSyncClient;
req.x.client_id = ctl->id;

rc = jack_client_deliver_request (client, &req);
@@ -241,9 +255,14 @@ jack_set_sync_callback (jack_client_t *client,
}

int
jack_set_sync_timeout (jack_client_t *client, jack_nframes_t timeout)
jack_set_sync_timeout (jack_client_t *client, jack_time_t usecs)
{
return ENOSYS; /* this is a stub */
jack_request_t req;

req.type = SetSyncTimeout;
req.x.timeout = usecs;

return jack_client_deliver_request (client, &req);
}

int
@@ -290,16 +309,20 @@ jack_transport_query (jack_client_t *client, jack_position_t *pos)
int
jack_transport_reposition (jack_client_t *client, jack_position_t *pos)
{
/* copy the input, so we don't modify the input argument */
/* copy the input, to avoid modifying its contents */
jack_position_t tmp = *pos;

/* validate input */
if (tmp.valid & ~JACK_POSITION_MASK) /* unknown field present? */
return EINVAL;

return jack_transport_request_new_pos (client, &tmp);
}

void
jack_transport_start (jack_client_t *client)
{
client->engine->transport_cmd = TransportCommandPlay;
client->engine->transport_cmd = TransportCommandStart;
}

void
@@ -344,7 +367,7 @@ jack_get_transport_info (jack_client_t *client,
info->valid = (eng->current_time.valid |
JackTransportState | JackTransportPosition);

if (info->valid & JackPositionBBT) {
if (info->valid & JackTransportBBT) {
info->bar = eng->current_time.bar;
info->beat = eng->current_time.beat;
info->tick = eng->current_time.tick;
@@ -366,11 +389,12 @@ jack_set_transport_info (jack_client_t *client,

if (!client->control->is_timebase) { /* not timebase master? */
if (first_error)
jack_error ("Called jack_set_transport_info(), but not timebase master.");
jack_error ("Called jack_set_transport_info(), "
"but not timebase master.");
first_error = 0;

/* JOQ: I would prefer to ignore this request, but if
* I do, it breaks ardour 0.9-beta2. So, let's allow
/* JOQ: I would prefer to ignore this request, but
* that would break ardour 0.9-beta2. So, let's allow
* it for now. */
// return;
}
@@ -387,7 +411,7 @@ jack_set_transport_info (jack_client_t *client,
if (info->transport_state == JackTransportStopped)
eng->transport_cmd = TransportCommandStop;
else if (info->transport_state == JackTransportRolling)
eng->transport_cmd = TransportCommandPlay;
eng->transport_cmd = TransportCommandStart;
/* silently ignore anything else */
}

@@ -396,7 +420,7 @@ jack_set_transport_info (jack_client_t *client,
else
eng->pending_time.frame = eng->current_time.frame;

eng->pending_time.valid = (info->valid & JackTransportBBT);
eng->pending_time.valid = (info->valid & JACK_POSITION_MASK);

if (info->valid & JackTransportBBT) {
eng->pending_time.bar = info->bar;


Loading…
Cancel
Save