git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2061 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.71
| @@ -20,8 +20,11 @@ Fernando Lopez-Lezcano | |||
| Jackdmp changes log | |||
| --------------------------- | |||
| 2008-03-20 Stephane Letz <letz@grame.fr> | |||
| * Transport timebase fix (in progress). | |||
| 2008-03-10 Stephane Letz <letz@grame.fr> | |||
| 2008-03-19 Stephane Letz <letz@grame.fr> | |||
| * Synchronise transport.h with latest jackd version (Video handling). | |||
| @@ -254,19 +254,15 @@ int JackClient::Activate() | |||
| if (StartThread() < 0) | |||
| return -1; | |||
| /* seems just useless | |||
| if (fSync != NULL) // If a SyncCallback is pending... | |||
| SetSyncCallback(fSync, fSyncArg); | |||
| if (fTimebase != NULL) // If a TimebaseCallback is pending... | |||
| SetTimebaseCallback(fConditionnal, fTimebase, fTimebaseArg); | |||
| */ | |||
| /* | |||
| Insertion of client in the graph will cause a kGraphOrderCallback notification | |||
| to be delivered by the server, the client wants to receive it. | |||
| */ | |||
| GetClientControl()->fActive = true; | |||
| // Transport related callback become "active" | |||
| GetClientControl()->fTransportSync = true; | |||
| GetClientControl()->fTransportTimebase = true; | |||
| int result = -1; | |||
| fChannel->ClientActivate(GetClientControl()->fRefNum, &result); | |||
| @@ -283,6 +279,11 @@ int JackClient::Deactivate() | |||
| return 0; | |||
| GetClientControl()->fActive = false; | |||
| // Transport related callback become "unactive" | |||
| GetClientControl()->fTransportSync = false; | |||
| GetClientControl()->fTransportTimebase = false; | |||
| int result = -1; | |||
| fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | |||
| @@ -606,6 +607,7 @@ int JackClient::ReleaseTimebase() | |||
| int result = -1; | |||
| fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result); | |||
| if (result == 0) { | |||
| GetClientControl()->fTransportTimebase = false; | |||
| fTimebase = NULL; | |||
| fTimebaseArg = NULL; | |||
| } | |||
| @@ -615,10 +617,9 @@ int JackClient::ReleaseTimebase() | |||
| /* Call the server if the client is active, otherwise keeps the arguments */ | |||
| int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) | |||
| { | |||
| if (IsActive()) | |||
| GetClientControl()->fTransportState = (sync_callback == NULL) ? JackTransportStopped : JackTransportSynching; | |||
| fSync = sync_callback; | |||
| GetClientControl()->fTransportSync = (fSync != NULL); | |||
| fSyncArg = arg; | |||
| fSync = sync_callback; | |||
| return 0; | |||
| } | |||
| @@ -628,38 +629,13 @@ int JackClient::SetSyncTimeout(jack_time_t timeout) | |||
| return 0; | |||
| } | |||
| /* Call the server if the client is active, otherwise keeps the arguments */ | |||
| /* | |||
| int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) | |||
| { | |||
| if (IsActive()) { | |||
| int result = -1; | |||
| fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | |||
| jack_log("SetTimebaseCallback result = %ld", result); | |||
| if (result == 0) { | |||
| fTimebase = timebase_callback; | |||
| fTimebaseArg = arg; | |||
| } else { | |||
| fTimebase = NULL; | |||
| fTimebaseArg = NULL; | |||
| } | |||
| jack_log("SetTimebaseCallback OK result = %ld", result); | |||
| return result; | |||
| } else { | |||
| fTimebase = timebase_callback; | |||
| fTimebaseArg = arg; | |||
| fConditionnal = conditional; | |||
| return 0; | |||
| } | |||
| } | |||
| */ | |||
| int JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) | |||
| { | |||
| int result = -1; | |||
| fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | |||
| jack_log("SetTimebaseCallback result = %ld", result); | |||
| if (result == 0) { | |||
| GetClientControl()->fTransportTimebase = true; | |||
| fTimebase = timebase_callback; | |||
| fTimebaseArg = arg; | |||
| } else { | |||
| @@ -731,68 +707,45 @@ void JackClient::TransportStop() | |||
| } | |||
| // Never called concurently with the server | |||
| // TODO check concurency with SetSyncCallback | |||
| // TODO check concurrency with SetSyncCallback | |||
| void JackClient::CallSyncCallback() | |||
| { | |||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
| jack_position_t* cur_pos = transport.ReadCurrentState(); | |||
| jack_transport_state_t transport_state = transport.GetState(); | |||
| switch (transport_state) { | |||
| case JackTransportStarting: // Starting... | |||
| if (fSync == NULL) { | |||
| if (GetClientControl()->fTransportSync) { | |||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
| jack_position_t* cur_pos = transport.ReadCurrentState(); | |||
| jack_transport_state_t transport_state = transport.GetState(); | |||
| if (fSync != NULL) { | |||
| if (fSync(transport_state, cur_pos, fSyncArg)) { | |||
| GetClientControl()->fTransportState = JackTransportRolling; | |||
| } else if (GetClientControl()->fTransportState == JackTransportStarting) { | |||
| if (fSync(transport_state, cur_pos, fSyncArg)) | |||
| GetClientControl()->fTransportState = JackTransportRolling; | |||
| GetClientControl()->fTransportSync = false; | |||
| } | |||
| break; | |||
| case JackTransportRolling: | |||
| if (fSync != NULL && GetClientControl()->fTransportState == JackTransportStarting) { // Client still not ready | |||
| if (fSync(transport_state, cur_pos, fSyncArg)) | |||
| GetClientControl()->fTransportState = JackTransportRolling; | |||
| } | |||
| break; | |||
| case JackTransportSynching: | |||
| // New pos when transport engine is stopped... | |||
| if (fSync != NULL) { | |||
| fSync(JackTransportStopped, cur_pos, fSyncArg); | |||
| GetClientControl()->fTransportState = JackTransportStopped; | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } else { | |||
| GetClientControl()->fTransportState = JackTransportRolling; | |||
| GetClientControl()->fTransportSync = false; | |||
| } | |||
| } | |||
| } | |||
| void JackClient::CallTimebaseCallback() | |||
| { | |||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | |||
| if (fTimebase != NULL && GetClientControl()->fRefNum == transport.GetTimebaseMaster()) { | |||
| if (GetClientControl()->fRefNum == transport.GetTimebaseMaster()) { // Client *is* timebase... | |||
| jack_transport_state_t transport_state = transport.GetState(); | |||
| jack_position_t* cur_pos = transport.WriteNextStateStart(1); | |||
| switch (transport_state) { | |||
| case JackTransportRolling: | |||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); | |||
| break; | |||
| case JackTransportSynching: | |||
| fTimebase(JackTransportStopped, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); | |||
| break; | |||
| default: | |||
| break; | |||
| if (transport_state == JackTransportRolling) { | |||
| assert(fTimebase); | |||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, false, fTimebaseArg); | |||
| } else if (GetClientControl()->fTransportTimebase) { | |||
| assert(fTimebase); | |||
| fTimebase(transport_state, GetEngineControl()->fBufferSize, cur_pos, true, fTimebaseArg); | |||
| GetClientControl()->fTransportTimebase = true; // Callback is called only once with "new_pos" = true | |||
| } | |||
| transport.WriteNextStateStop(1); | |||
| } | |||
| } | |||
| @@ -39,6 +39,8 @@ struct JackClientControl : public JackShmMem | |||
| char fName[JACK_CLIENT_NAME_SIZE + 1]; | |||
| bool fCallback[kMaxNotification]; | |||
| volatile jack_transport_state_t fTransportState; | |||
| volatile bool fTransportSync; /* Will be true when slow-sync cb has to be called */ | |||
| volatile bool fTransportTimebase; /* Will be true when timebase cb is called with new_pos on */ | |||
| int fRefNum; | |||
| bool fActive; | |||
| @@ -71,6 +73,8 @@ struct JackClientControl : public JackShmMem | |||
| fCallback[kStopFreewheelCallback] = true; | |||
| fRefNum = refnum; | |||
| fTransportState = JackTransportStopped; | |||
| fTransportSync = false; | |||
| fTransportTimebase = false; | |||
| fActive = false; | |||
| } | |||
| @@ -374,7 +374,7 @@ int JackEngine::ClientCheck(const char* name, char* name_res, int protocol, int | |||
| *status = 0; | |||
| strcpy(name_res, name); | |||
| jack_log("Check protocol client %ld server = %ld", protocol, JACK_PROTOCOL_VERSION); | |||
| jack_log("Check protocol client %ld server = %ld", protocol, JACK_PROTOCOL_VERSION); | |||
| if (protocol != JACK_PROTOCOL_VERSION) { | |||
| *status |= (JackFailure | JackVersionError); | |||
| @@ -561,7 +561,7 @@ int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wai | |||
| // Remove the client from the table | |||
| ReleaseRefnum(refnum); | |||
| // Notiy unregister | |||
| // Notify unregister | |||
| jack_int_t ports[PORT_NUM_FOR_CLIENT]; | |||
| int i; | |||
| @@ -44,11 +44,12 @@ JackTransportEngine::JackTransportEngine(): JackAtomicArrayState<jack_position_t | |||
| // compute the number of cycle for timeout | |||
| void JackTransportEngine::SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size) | |||
| { | |||
| long buf_usecs = (long)((buffer_size * (jack_time_t) 1000000) / frame_rate); | |||
| long buf_usecs = (long)((buffer_size * (jack_time_t)1000000) / frame_rate); | |||
| fSyncTimeLeft = fSyncTimeout / buf_usecs; | |||
| jack_log("SyncTimeout fSyncTimeout = %ld fSyncTimeLeft = %ld", (long)fSyncTimeout, (long)fSyncTimeLeft); | |||
| } | |||
| // Server | |||
| int JackTransportEngine::ResetTimebase(int refnum) | |||
| { | |||
| if (fTimeBaseMaster == refnum) { | |||
| @@ -62,6 +63,7 @@ int JackTransportEngine::ResetTimebase(int refnum) | |||
| } | |||
| } | |||
| // Server | |||
| int JackTransportEngine::SetTimebase(int refnum, bool conditionnal) | |||
| { | |||
| if (conditionnal && fTimeBaseMaster > 0) { | |||
| @@ -79,44 +81,50 @@ int JackTransportEngine::SetTimebase(int refnum, bool conditionnal) | |||
| } | |||
| } | |||
| bool JackTransportEngine::CheckOneSynching(JackClientInterface** table) | |||
| // RT | |||
| bool JackTransportEngine::CheckAllRolling(JackClientInterface** table) | |||
| { | |||
| for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||
| JackClientInterface* client = table[i]; | |||
| if (client && client->GetClientControl()->fTransportState == JackTransportSynching) { | |||
| jack_log("CheckOneSynching"); | |||
| return true; | |||
| if (client && client->GetClientControl()->fTransportState != JackTransportRolling) { | |||
| jack_log("CheckAllRolling ref = %ld is not rolling", i); | |||
| return false; | |||
| } | |||
| } | |||
| return false; | |||
| jack_log("CheckAllRolling"); | |||
| return true; | |||
| } | |||
| bool JackTransportEngine::CheckAllRolling(JackClientInterface** table) | |||
| // RT | |||
| void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table) | |||
| { | |||
| for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||
| JackClientInterface* client = table[i]; | |||
| if (client && client->GetClientControl()->fTransportState != JackTransportRolling) { | |||
| jack_log("CheckAllRolling refnum = %ld is not rolling", i); | |||
| return false; | |||
| if (client) { | |||
| // Inactive clients don't have their process function called at all, so they appear as already "rolling" for the transport.... | |||
| client->GetClientControl()->fTransportState = (client->GetClientControl()->fActive) ? JackTransportStarting : JackTransportRolling; | |||
| client->GetClientControl()->fTransportSync = true; | |||
| client->GetClientControl()->fTransportTimebase = true; | |||
| jack_log("MakeAllStartingLocating ref = %ld", i); | |||
| } | |||
| } | |||
| jack_log("CheckAllRolling"); | |||
| return true; | |||
| } | |||
| void JackTransportEngine::MakeAllStarting(JackClientInterface** table) | |||
| // RT | |||
| void JackTransportEngine::MakeAllStopping(JackClientInterface** table) | |||
| { | |||
| for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||
| JackClientInterface* client = table[i]; | |||
| if (client) { | |||
| // Unactive clients don't have their process function called at all, they appear as already "rolling" for the transport.... | |||
| client->GetClientControl()->fTransportState = (client->GetClientControl()->fActive) ? JackTransportStarting : JackTransportRolling; | |||
| jack_log("MakeAllStarting refnum = %ld", i); | |||
| client->GetClientControl()->fTransportSync = false; | |||
| client->GetClientControl()->fTransportTimebase = false; | |||
| client->GetClientControl()->fTransportState = JackTransportStopped; | |||
| jack_log("MakeAllStopping ref = %ld", i); | |||
| } | |||
| } | |||
| jack_log("MakeAllStarting"); | |||
| } | |||
| // RT | |||
| void JackTransportEngine::CycleBegin(jack_nframes_t frame_rate, jack_time_t time) // really needed?? (would be done in CycleEnd...) | |||
| { | |||
| jack_position_t* pending = WriteNextStateStart(1); // Update "pending" state | |||
| @@ -125,6 +133,7 @@ void JackTransportEngine::CycleBegin(jack_nframes_t frame_rate, jack_time_t time | |||
| WriteNextStateStop(1); | |||
| } | |||
| // RT | |||
| void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size) | |||
| { | |||
| TrySwitchState(1); // Switch from "pending" to "current", it always works since there is always a pending state | |||
| @@ -141,59 +150,42 @@ void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t f | |||
| /* state transition switch */ | |||
| switch (fTransportState) { | |||
| case JackTransportSynching: | |||
| if (cmd == TransportCommandStart) { | |||
| fTransportState = JackTransportStarting; | |||
| MakeAllStarting(table); | |||
| SyncTimeout(frame_rate, buffer_size); | |||
| jack_log("transport locate ==> starting...."); | |||
| } else if (fPendingPos) { | |||
| fTransportState = JackTransportSynching; | |||
| jack_log("transport locate ==> locate...."); | |||
| } else { | |||
| fTransportState = JackTransportStopped; | |||
| jack_log("transport locate ==> stopped...."); | |||
| } | |||
| break; | |||
| case JackTransportStopped: | |||
| // Set a JackTransportStarting for the current cycle, if all clients are ready (now slow_sync) ==> JackTransportRolling next state | |||
| // Set a JackTransportStarting for the current cycle, if all clients are ready (no slow_sync) ==> JackTransportRolling next state | |||
| if (cmd == TransportCommandStart) { | |||
| jack_log("transport stopped ==> starting"); | |||
| fTransportState = JackTransportStarting; | |||
| MakeAllStarting(table); | |||
| MakeAllStartingLocating(table); | |||
| SyncTimeout(frame_rate, buffer_size); | |||
| jack_log("transport stopped ==> starting...."); | |||
| } else if (fPendingPos || CheckOneSynching(table)) { | |||
| fTransportState = JackTransportSynching; | |||
| jack_log("transport stopped ==> locate...."); | |||
| } | |||
| } | |||
| break; | |||
| case JackTransportStarting: | |||
| jack_log("transport starting fSyncTimeLeft %ld", fSyncTimeLeft); | |||
| if (cmd == TransportCommandStop) { | |||
| fTransportState = JackTransportStopped; | |||
| jack_log("transport starting ==> stopped"); | |||
| fTransportState = JackTransportStopped; | |||
| MakeAllStopping(table); | |||
| } else if (fPendingPos) { | |||
| jack_log("transport starting ==> starting"); | |||
| fTransportState = JackTransportStarting; | |||
| MakeAllStarting(table); | |||
| MakeAllStartingLocating(table); | |||
| SyncTimeout(frame_rate, buffer_size); | |||
| } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) { | |||
| } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) { // Slow clients may still catch up | |||
| jack_log("transport starting ==> rolling fSyncTimeLeft = %ld", fSyncTimeLeft); | |||
| fTransportState = JackTransportRolling; | |||
| jack_log("transport starting ==> rolling.... fSyncTimeLeft %ld", fSyncTimeLeft); | |||
| } | |||
| break; | |||
| case JackTransportRolling: | |||
| if (cmd == TransportCommandStop) { | |||
| fTransportState = JackTransportStopped; | |||
| jack_log("transport rolling ==> stopped"); | |||
| } else if (fPendingPos || CheckOneSynching(table)) { | |||
| fTransportState = JackTransportStopped; | |||
| MakeAllStopping(table); | |||
| } else if (fPendingPos) { | |||
| jack_log("transport rolling ==> starting"); | |||
| fTransportState = JackTransportStarting; | |||
| MakeAllStarting(table); | |||
| MakeAllStartingLocating(table); | |||
| SyncTimeout(frame_rate, buffer_size); | |||
| jack_log("transport rolling ==> starting...."); | |||
| } | |||
| break; | |||
| @@ -218,6 +210,7 @@ void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t f | |||
| } | |||
| } | |||
| // Client | |||
| void JackTransportEngine::ReadCurrentPos(jack_position_t* pos) | |||
| { | |||
| UInt16 next_index = GetCurrentIndex(); | |||
| @@ -229,6 +222,7 @@ void JackTransportEngine::ReadCurrentPos(jack_position_t* pos) | |||
| } while (cur_index != next_index); // Until a coherent state has been read | |||
| } | |||
| // RT, client | |||
| void JackTransportEngine::TransportCopyPosition(jack_position_t* from, jack_position_t* to) | |||
| { | |||
| int tries = 0; | |||
| @@ -49,6 +49,43 @@ We have: | |||
| The current position can be read by clients. | |||
| We use a JackAtomicArrayState pattern that allows to manage several "next" states independantly. | |||
| In jack1 implementation, transport code (jack_transport_cycle_end) was not called if the graph could not be locked (see jack_run_one_cycle). | |||
| Here transport cycle (CycleBegin, CycleEnd) has to run in the RT thread concurrently with code executed from the "command" thread. | |||
| Each client maintains a state in it's shared memory area defined by: | |||
| - it's current transport state | |||
| - a boolean that is "true" when slow-sync cb has to be called | |||
| - a boolean that is "true" when timebase cb is called with new_pos on | |||
| Several operations set the "slow-sync cb" flag to true: | |||
| - setting a new cb (client) | |||
| - activate (client) | |||
| - transport start (server) | |||
| - new pos (server) | |||
| Slow-sync cb calls stops when: | |||
| - the cb return true (client) | |||
| - desactivate (client) | |||
| - transport stop (server) | |||
| Several operations set the "timebase cb" flag to true: | |||
| - setting a new cb (client) | |||
| - activate (client) | |||
| - transport start (server) ?? | |||
| - new pos (server) | |||
| Timebase cb "new_pos" argument calls stops when: | |||
| - after one cb call with "new_pos" argument true (client) | |||
| - desactivate (client) | |||
| - release (client) | |||
| - transport stop (server) | |||
| */ | |||
| class JackTransportEngine : public JackAtomicArrayState<jack_position_t> | |||
| @@ -65,9 +102,11 @@ class JackTransportEngine : public JackAtomicArrayState<jack_position_t> | |||
| bool fPendingPos; | |||
| SInt32 fWriteCounter; | |||
| bool CheckOneSynching(JackClientInterface** table); | |||
| bool CheckAllRolling(JackClientInterface** table); | |||
| void MakeAllStarting(JackClientInterface** table); | |||
| void MakeAllStartingLocating(JackClientInterface** table); | |||
| void MakeAllStopping(JackClientInterface** table); | |||
| void SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size); | |||
| public: | |||
| @@ -923,20 +923,20 @@ extern "C" | |||
| */ | |||
| void jack_set_error_function (void (*func)(const char *)); | |||
| /** | |||
| * Display JACK info message. | |||
| * | |||
| * Set via jack_set_info_function(), otherwise a JACK-provided | |||
| * default will print @a msg (plus a newline) to stdout. | |||
| * | |||
| * @param msg info message text (no newline at end). | |||
| */ | |||
| extern void (*jack_info_callback)(const char *msg); | |||
| /** | |||
| * Set the @ref jack_info_callback for info message display. | |||
| */ | |||
| void jack_set_info_function (void (*func)(const char *)); | |||
| /** | |||
| * Display JACK info message. | |||
| * | |||
| * Set via jack_set_info_function(), otherwise a JACK-provided | |||
| * default will print @a msg (plus a newline) to stdout. | |||
| * | |||
| * @param msg info message text (no newline at end). | |||
| */ | |||
| extern void (*jack_info_callback)(const char *msg); | |||
| /** | |||
| * Set the @ref jack_info_callback for info message display. | |||
| */ | |||
| void jack_set_info_function (void (*func)(const char *)); | |||
| #ifdef __cplusplus | |||
| } | |||
| @@ -37,7 +37,6 @@ typedef enum { | |||
| JackTransportRolling = 1, /**< Transport playing */ | |||
| JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */ | |||
| JackTransportStarting = 3, /**< Waiting for sync ready */ | |||
| JackTransportSynching = 4 /**< internal use*/ | |||
| } jack_transport_state_t; | |||
| @@ -39,7 +39,7 @@ extern "C" | |||
| JackTransportRolling = 1, /**< Transport playing */ | |||
| JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */ | |||
| JackTransportStarting = 3, /**< Waiting for sync ready */ | |||
| JackTransportSynching = 4 /**< temporary*/ | |||
| //JackTransportSynching = 4 /**< temporary*/ | |||
| } jack_transport_state_t; | |||
| @@ -51,53 +51,84 @@ extern "C" | |||
| typedef enum { | |||
| JackPositionBBT = 0x10, /**< Bar, Beat, Tick */ | |||
| JackPositionTimecode = 0x20 /**< External timecode */ | |||
| JackPositionTimecode = 0x20, /**< External timecode */ | |||
| JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */ | |||
| JackAudioVideoRatio = 0x80, /**< audio frames per video frame */ | |||
| JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */ | |||
| } jack_position_bits_t; | |||
| /** all valid position bits */ | |||
| #define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode) | |||
| #define EXTENDED_TIME_INFO | |||
| /** | |||
| * Struct for transport position information. | |||
| */ | |||
| typedef struct { | |||
| /* these four cannot be set from clients: the server sets them */ | |||
| jack_unique_t unique_1; /**< unique ID */ | |||
| jack_time_t usecs; /**< monotonic, free-rolling */ | |||
| jack_time_t usecs; /**< monotonic, free-rolling */ | |||
| jack_nframes_t frame_rate; /**< current frame rate (per second) */ | |||
| jack_nframes_t frame; /**< frame number, always present */ | |||
| jack_position_bits_t valid; /**< which other fields are valid */ | |||
| /* JackPositionBBT fields: */ | |||
| int32_t bar; /**< current bar */ | |||
| int32_t beat; /**< current beat-within-bar */ | |||
| int32_t tick; /**< current tick-within-beat */ | |||
| double bar_start_tick; | |||
| int32_t bar; /**< current bar */ | |||
| int32_t beat; /**< current beat-within-bar */ | |||
| int32_t tick; /**< current tick-within-beat */ | |||
| double bar_start_tick; | |||
| float beats_per_bar; /**< time signature "numerator" */ | |||
| float beat_type; /**< time signature "denominator" */ | |||
| double ticks_per_beat; | |||
| double beats_per_minute; | |||
| float beats_per_bar; /**< time signature "numerator" */ | |||
| float beat_type; /**< time signature "denominator" */ | |||
| double ticks_per_beat; | |||
| double beats_per_minute; | |||
| /* JackPositionTimecode fields: (EXPERIMENTAL: could change) */ | |||
| double frame_time; /**< current time in seconds */ | |||
| double next_time; /**< next sequential frame_time | |||
| (unless repositioned) */ | |||
| double frame_time; /**< current time in seconds */ | |||
| double next_time; /**< next sequential frame_time | |||
| (unless repositioned) */ | |||
| /* JackBBTFrameOffset fields: */ | |||
| jack_nframes_t bbt_offset; /**< frame offset for the BBT fields | |||
| (the given bar, beat, and tick | |||
| values actually refer to a time | |||
| frame_offset frames before the | |||
| start of the cycle), should | |||
| be assumed to be 0 if | |||
| JackBBTFrameOffset is not | |||
| set. If JackBBTFrameOffset is | |||
| set and this value is zero, the BBT | |||
| time refers to the first frame of this | |||
| cycle. If the value is positive, | |||
| the BBT time refers to a frame that | |||
| many frames before the start of the | |||
| cycle. */ | |||
| /* JACK video positional data (experimental) */ | |||
| float audio_frames_per_video_frame; /**< number of audio frames | |||
| per video frame. Should be assumed | |||
| zero if JackAudioVideoRatio is not | |||
| set. If JackAudioVideoRatio is set | |||
| and the value is zero, no video | |||
| data exists within the JACK graph */ | |||
| jack_nframes_t video_offset; /**< audio frame at which the first video | |||
| frame in this cycle occurs. Should | |||
| be assumed to be 0 if JackVideoFrameOffset | |||
| is not set. If JackVideoFrameOffset is | |||
| set, but the value is zero, there is | |||
| no video frame within this cycle. */ | |||
| /* For binary compatibility, new fields should be allocated from | |||
| * this padding area with new valid bits controlling access, so | |||
| * the existing structure size and offsets are preserved. */ | |||
| int32_t padding[10]; | |||
| int32_t padding[7]; | |||
| /* When (unique_1 == unique_2) the contents are consistent. */ | |||
| jack_unique_t unique_2; /**< unique ID */ | |||
| } | |||
| jack_position_t; | |||
| } jack_position_t; | |||
| /** | |||
| * Prototype for the @a sync_callback defined by slow-sync clients. | |||