|
- /*
- * This file documents the JACK transport design. It is part of the
- * JACK reference manual, built using doxygen.
- */
-
- /**
-
- @page transport-design JACK Transport Design
-
- The @ref index provides simple transport interfaces for starting,
- stopping and repositioning a set of clients. This document describes
- the overall design of these interfaces, their detailed specifications
- are in <jack/transport.h>
-
- - @ref requirements
- - @ref overview
- - @ref timebase
- - @ref transportcontrol
- - @ref transportclients
- - @ref compatibility
- - @ref issues
-
-
- @section requirements Requirements
-
- - We need sample-level accuracy for transport control. This implies
- that the transport client logic has to be part of the realtime
- process chain.
-
- - We don't want to add another context switch. So, the transport
- client logic has to run in the context of the client's process
- thread. To avoid making an extra pass through the process graph, no
- transport changes take effect until the following process cycle.
- That way, the transport info is stable throughout each cycle.
-
- - We want to allow multiple clients to change the transport state.
- This is mostly a usability issue. Any client can start or stop
- playback, or seek to a new location. The user need not switch
- windows to accomplish these tasks.
-
- - We want a way for clients with heavyweight state to sync up when
- the user presses "play", before the transport starts rolling.
-
- - We want to provide for ongoing binary compatibility as the
- transport design evolves.
-
-
- @section overview Overview
-
- The former transport master role has been divided into two layers:
-
- - @ref timebase - counting beats, frames, etc. on every cycle.
- - @ref transportcontrol - start, stop and reposition the playback.
-
- Existing transport clients continue to work in compatibility mode.
- But, old-style timebase masters will no longer control the transport.
-
-
- @section timebase Timebase Master
-
- The timebase master continuously updates extended position
- information, counting beats, timecode, etc. Without this extended
- information, there is no need for this function. There is at most one
- master active at a time. If no client is registered as timebase
- master, frame numbers will be the only position information available.
-
- 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.
-
- @code
- typedef int (*JackTimebaseCallback)(jack_transport_state_t state,
- jack_nframes_t nframes,
- jack_position_t *pos,
- int new_pos,
- void *arg);
- @endcode
-
- 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.
-
- @code
- int jack_set_timebase_callback (jack_client_t *client,
- int conditional,
- JackTimebaseCallback timebase_callback,
- void *arg);
-
- int jack_release_timebase(jack_client_t *client);
- @endcode
-
- 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.
-
-
- @section transportcontrol Transport Control
-
- The JACK engine itself manages stopping and starting of the transport.
- Any client can make transport control requests at any time. These
- requests take effect no sooner than the next process cycle, sometimes
- later. The transport state is always valid, initially it is
- ::JackTransportStopped.
-
- @code
- void jack_transport_start (jack_client_t *client);
- void jack_transport_stop (jack_client_t *client);
- @endcode
-
- @subsection slowsyncclients Slow-sync clients
-
- 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 @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.
-
- @code
- typedef int (*JackSyncCallback)(jack_transport_state_t state,
- jack_position_t *pos, void *arg);
- @endcode
-
- This callback is a realtime function that runs in the JACK process
- thread.
-
- @code
- int jack_set_sync_callback (jack_client_t *client,
- JackSyncCallback sync_callback, void *arg);
- @endcode
-
- Clients that don't declare a @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 @a sync_callback
- to NULL.
-
- @code
- int jack_set_sync_timeout (jack_client_t *client,
- jack_time_t usecs);
- @endcode
-
- There must be a @a timeout to prevent unresponsive slow-sync clients
- from completely halting the transport mechanism. Two seconds is the
- default. When this @a timeout expires, the transport will start
- rolling, even if some slow-sync clients are still unready. The @a
- sync_callback for these clients continues being invoked, giving them
- an opportunity to catch up.
-
- @subsection repositioning Repositioning
-
- @code
- int jack_transport_reposition (jack_client_t *client,
- jack_position_t *pos);
- int jack_transport_locate (jack_client_t *client,
- jack_nframes_t frame);
- @endcode
-
- 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 @a
- sync_callbacks until ready.
-
- @subsection transportstatetransitiondiagram Transport State Transition Diagram
-
- @image html fsm.png "Transport State Transition Diagram"
- @image latex fsm.eps "Transport State Transition Diagram"
-
-
- @section transportclients Transport Clients
-
- Transport clients were formerly known as "transport slaves". We want
- to make it easy for almost every JACK client to be a transport client.
-
- @code
- jack_transport_state_t jack_transport_query (jack_client_t *client,
- jack_position_t *pos);
- @endcode
-
- This function can be called from any thread. If called from the
- process thread, @a pos corresponds to the first frame of the current
- cycle and the state returned is valid for the entire cycle.
-
-
- @section compatibility Compatibility
-
- During the transition period we will support the old-style interfaces
- in compatibility mode as deprecated interfaces. This compatibility is
- not 100%, there are limitations.
-
- The main reasons for doing this are:
-
- - facilitate testing with clients that already have transport
- support
- - provide a clean migration path, so application developers are
- not discouraged from supporting the transport interface
-
- These deprecated interfaces continue to work:
-
- @code
- typedef struct jack_transport_info_t;
-
- void jack_get_transport_info (jack_client_t *client,
- jack_transport_info_t *tinfo);
- @endcode
-
- 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:
-
- @code
- void jack_set_transport_info (jack_client_t *client,
- jack_transport_info_t *tinfo);
- int jack_engine_takeover_timebase (jack_client_t *);
- @endcode
-
- 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.
-
-
- @section issues Issues Not Addressed
-
- This design currently does not address several issues. This means they
- will probably not be included in JACK release 1.0.
-
- - variable speed
- - reverse play
- - looping
- */
|