Existing transport clients continue to work in compatibility mode. But, old-style timebase masters will no longer control the transport.
The timebase master registers a callback that updates position information while the transport is rolling. Its output affects the following process cycle. This function is called immediately after the process callback in the same thread whenever the transport is rolling, or when any client has set a new position in the previous cycle. The first cycle after jack_set_timebase_callback() is also treated as a new position, or the first cycle after jack_activate() if the client had been inactive.
typedef int (*JackTimebaseCallback)(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg);
When a new client takes over, the former timebase callback is no longer called. Taking over the timebase may be done conditionally, in which case the takeover fails when there is a master already. The existing master can release it voluntarily, if desired.
int jack_set_timebase_callback (jack_client_t *client, int conditional, JackTimebaseCallback timebase_callback, void *arg); int jack_release_timebase(jack_client_t *client);
If the timebase master releases the timebase or exits the JACK graph for any reason, the JACK engine takes over at the start of the next process cycle. The transport state does not change. If rolling, it continues to play, with frame numbers as the only available position information.
void jack_transport_start (jack_client_t *client); void jack_transport_stop (jack_client_t *client);
The engine handles polling of slow-sync clients. When someone calls jack_transport_start(), the engine resets the poll bits and changes to a new state, JackTransportStarting. The 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 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.
typedef int (*JackSyncCallback)(jack_transport_state_t state, jack_position_t *pos, void *arg);
This callback is a realtime function that runs in the JACK process thread.
int jack_set_sync_callback (jack_client_t *client, JackSyncCallback sync_callback, void *arg);
Clients that don't declare a sync_callback are assumed to be ready immediately, any time the transport wants to start. If a client no longer requires slow-sync processing, it can set its sync_callback to NULL.
int jack_set_sync_timeout (jack_client_t *client, jack_time_t usecs);
There must be a timeout to prevent unresponsive slow-sync clients from completely halting the transport mechanism. Two seconds is the default. When this timeout expires, the transport will start rolling, even if some slow-sync clients are still unready. The sync_callback for these clients continues being invoked, giving them an opportunity to catch up.
int jack_transport_reposition (jack_client_t *client, jack_position_t *pos); int jack_transport_locate (jack_client_t *client, jack_nframes_t frame);
These request a new transport position. They can be called at any time by any client. Even the timebase master must use them. If the request is valid, it goes into effect in two process cycles. If there are slow-sync clients and the transport is already rolling, it will enter the JackTransportStarting state and begin invoking their sync_callbacks until ready.
Transport State Transition Diagram
This function can be called from any thread. If called from the process thread, pos corresponds to the first frame of the current cycle and the state returned is valid for the entire cycle.
The main reasons for doing this are:
These deprecated interfaces continue to work:
typedef struct jack_transport_info_t; void jack_get_transport_info (jack_client_t *client, jack_transport_info_t *tinfo);
Unfortunately, the old-style timebase master interface cannot coexist cleanly with such new features as jack_transport_locate() and slow-sync clients. So, these interfaces are only present as stubs:
void jack_set_transport_info (jack_client_t *client, jack_transport_info_t *tinfo); int jack_engine_takeover_timebase (jack_client_t *);
For compatibility with future changes, it would be good to avoid structures entirely. Nevertheless, the jack_position_t structure provides a convenient way to collect timebase information in several formats that clearly all refer to a single moment. To minimize future binary compatibility problems, this structure has some padding at the end, making it possible to extend it without necessarily breaking compatibility. New fields can be allocated from the padding area, with access controlled by newly defined valid bits, all of which are currently forced to zero. That allows the structure size and offsets to remain constant.