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 | 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). | * Synchronise transport.h with latest jackd version (Video handling). | ||||
| @@ -254,19 +254,15 @@ int JackClient::Activate() | |||||
| if (StartThread() < 0) | if (StartThread() < 0) | ||||
| return -1; | 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 | Insertion of client in the graph will cause a kGraphOrderCallback notification | ||||
| to be delivered by the server, the client wants to receive it. | to be delivered by the server, the client wants to receive it. | ||||
| */ | */ | ||||
| GetClientControl()->fActive = true; | GetClientControl()->fActive = true; | ||||
| // Transport related callback become "active" | |||||
| GetClientControl()->fTransportSync = true; | |||||
| GetClientControl()->fTransportTimebase = true; | |||||
| int result = -1; | int result = -1; | ||||
| fChannel->ClientActivate(GetClientControl()->fRefNum, &result); | fChannel->ClientActivate(GetClientControl()->fRefNum, &result); | ||||
| @@ -283,6 +279,11 @@ int JackClient::Deactivate() | |||||
| return 0; | return 0; | ||||
| GetClientControl()->fActive = false; | GetClientControl()->fActive = false; | ||||
| // Transport related callback become "unactive" | |||||
| GetClientControl()->fTransportSync = false; | |||||
| GetClientControl()->fTransportTimebase = false; | |||||
| int result = -1; | int result = -1; | ||||
| fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result); | ||||
| @@ -606,6 +607,7 @@ int JackClient::ReleaseTimebase() | |||||
| int result = -1; | int result = -1; | ||||
| fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result); | fChannel->ReleaseTimebase(GetClientControl()->fRefNum, &result); | ||||
| if (result == 0) { | if (result == 0) { | ||||
| GetClientControl()->fTransportTimebase = false; | |||||
| fTimebase = NULL; | fTimebase = NULL; | ||||
| fTimebaseArg = NULL; | fTimebaseArg = NULL; | ||||
| } | } | ||||
| @@ -615,10 +617,9 @@ int JackClient::ReleaseTimebase() | |||||
| /* Call the server if the client is active, otherwise keeps the arguments */ | /* Call the server if the client is active, otherwise keeps the arguments */ | ||||
| int JackClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) | 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; | fSyncArg = arg; | ||||
| fSync = sync_callback; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -628,38 +629,13 @@ int JackClient::SetSyncTimeout(jack_time_t timeout) | |||||
| return 0; | 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 JackClient::SetTimebaseCallback(int conditional, JackTimebaseCallback timebase_callback, void* arg) | ||||
| { | { | ||||
| int result = -1; | int result = -1; | ||||
| fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | fChannel->SetTimebaseCallback(GetClientControl()->fRefNum, conditional, &result); | ||||
| jack_log("SetTimebaseCallback result = %ld", result); | jack_log("SetTimebaseCallback result = %ld", result); | ||||
| if (result == 0) { | if (result == 0) { | ||||
| GetClientControl()->fTransportTimebase = true; | |||||
| fTimebase = timebase_callback; | fTimebase = timebase_callback; | ||||
| fTimebaseArg = arg; | fTimebaseArg = arg; | ||||
| } else { | } else { | ||||
| @@ -731,68 +707,45 @@ void JackClient::TransportStop() | |||||
| } | } | ||||
| // Never called concurently with the server | // Never called concurently with the server | ||||
| // TODO check concurency with SetSyncCallback | |||||
| // TODO check concurrency with SetSyncCallback | |||||
| void JackClient::CallSyncCallback() | 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; | 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() | void JackClient::CallTimebaseCallback() | ||||
| { | { | ||||
| JackTransportEngine& transport = GetEngineControl()->fTransport; | 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_transport_state_t transport_state = transport.GetState(); | ||||
| jack_position_t* cur_pos = transport.WriteNextStateStart(1); | 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); | transport.WriteNextStateStop(1); | ||||
| } | } | ||||
| } | } | ||||
| @@ -39,6 +39,8 @@ struct JackClientControl : public JackShmMem | |||||
| char fName[JACK_CLIENT_NAME_SIZE + 1]; | char fName[JACK_CLIENT_NAME_SIZE + 1]; | ||||
| bool fCallback[kMaxNotification]; | bool fCallback[kMaxNotification]; | ||||
| volatile jack_transport_state_t fTransportState; | 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; | int fRefNum; | ||||
| bool fActive; | bool fActive; | ||||
| @@ -71,6 +73,8 @@ struct JackClientControl : public JackShmMem | |||||
| fCallback[kStopFreewheelCallback] = true; | fCallback[kStopFreewheelCallback] = true; | ||||
| fRefNum = refnum; | fRefNum = refnum; | ||||
| fTransportState = JackTransportStopped; | fTransportState = JackTransportStopped; | ||||
| fTransportSync = false; | |||||
| fTransportTimebase = false; | |||||
| fActive = false; | fActive = false; | ||||
| } | } | ||||
| @@ -374,7 +374,7 @@ int JackEngine::ClientCheck(const char* name, char* name_res, int protocol, int | |||||
| *status = 0; | *status = 0; | ||||
| strcpy(name_res, name); | 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) { | if (protocol != JACK_PROTOCOL_VERSION) { | ||||
| *status |= (JackFailure | JackVersionError); | *status |= (JackFailure | JackVersionError); | ||||
| @@ -561,7 +561,7 @@ int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wai | |||||
| // Remove the client from the table | // Remove the client from the table | ||||
| ReleaseRefnum(refnum); | ReleaseRefnum(refnum); | ||||
| // Notiy unregister | |||||
| // Notify unregister | |||||
| jack_int_t ports[PORT_NUM_FOR_CLIENT]; | jack_int_t ports[PORT_NUM_FOR_CLIENT]; | ||||
| int i; | int i; | ||||
| @@ -44,11 +44,12 @@ JackTransportEngine::JackTransportEngine(): JackAtomicArrayState<jack_position_t | |||||
| // compute the number of cycle for timeout | // compute the number of cycle for timeout | ||||
| void JackTransportEngine::SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size) | 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; | fSyncTimeLeft = fSyncTimeout / buf_usecs; | ||||
| jack_log("SyncTimeout fSyncTimeout = %ld fSyncTimeLeft = %ld", (long)fSyncTimeout, (long)fSyncTimeLeft); | jack_log("SyncTimeout fSyncTimeout = %ld fSyncTimeLeft = %ld", (long)fSyncTimeout, (long)fSyncTimeLeft); | ||||
| } | } | ||||
| // Server | |||||
| int JackTransportEngine::ResetTimebase(int refnum) | int JackTransportEngine::ResetTimebase(int refnum) | ||||
| { | { | ||||
| if (fTimeBaseMaster == refnum) { | if (fTimeBaseMaster == refnum) { | ||||
| @@ -62,6 +63,7 @@ int JackTransportEngine::ResetTimebase(int refnum) | |||||
| } | } | ||||
| } | } | ||||
| // Server | |||||
| int JackTransportEngine::SetTimebase(int refnum, bool conditionnal) | int JackTransportEngine::SetTimebase(int refnum, bool conditionnal) | ||||
| { | { | ||||
| if (conditionnal && fTimeBaseMaster > 0) { | 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++) { | for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | ||||
| JackClientInterface* client = table[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++) { | for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | ||||
| JackClientInterface* client = table[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++) { | for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | ||||
| JackClientInterface* client = table[i]; | JackClientInterface* client = table[i]; | ||||
| if (client) { | 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...) | 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 | 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); | WriteNextStateStop(1); | ||||
| } | } | ||||
| // RT | |||||
| void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size) | 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 | 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 */ | /* state transition switch */ | ||||
| switch (fTransportState) { | 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: | 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) { | if (cmd == TransportCommandStart) { | ||||
| jack_log("transport stopped ==> starting"); | |||||
| fTransportState = JackTransportStarting; | fTransportState = JackTransportStarting; | ||||
| MakeAllStarting(table); | |||||
| MakeAllStartingLocating(table); | |||||
| SyncTimeout(frame_rate, buffer_size); | SyncTimeout(frame_rate, buffer_size); | ||||
| jack_log("transport stopped ==> starting...."); | |||||
| } else if (fPendingPos || CheckOneSynching(table)) { | |||||
| fTransportState = JackTransportSynching; | |||||
| jack_log("transport stopped ==> locate...."); | |||||
| } | |||||
| } | |||||
| break; | break; | ||||
| case JackTransportStarting: | case JackTransportStarting: | ||||
| jack_log("transport starting fSyncTimeLeft %ld", fSyncTimeLeft); | |||||
| if (cmd == TransportCommandStop) { | if (cmd == TransportCommandStop) { | ||||
| fTransportState = JackTransportStopped; | |||||
| jack_log("transport starting ==> stopped"); | jack_log("transport starting ==> stopped"); | ||||
| fTransportState = JackTransportStopped; | |||||
| MakeAllStopping(table); | |||||
| } else if (fPendingPos) { | } else if (fPendingPos) { | ||||
| jack_log("transport starting ==> starting"); | |||||
| fTransportState = JackTransportStarting; | fTransportState = JackTransportStarting; | ||||
| MakeAllStarting(table); | |||||
| MakeAllStartingLocating(table); | |||||
| SyncTimeout(frame_rate, buffer_size); | 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; | fTransportState = JackTransportRolling; | ||||
| jack_log("transport starting ==> rolling.... fSyncTimeLeft %ld", fSyncTimeLeft); | |||||
| } | } | ||||
| break; | break; | ||||
| case JackTransportRolling: | case JackTransportRolling: | ||||
| if (cmd == TransportCommandStop) { | if (cmd == TransportCommandStop) { | ||||
| fTransportState = JackTransportStopped; | |||||
| jack_log("transport rolling ==> stopped"); | jack_log("transport rolling ==> stopped"); | ||||
| } else if (fPendingPos || CheckOneSynching(table)) { | |||||
| fTransportState = JackTransportStopped; | |||||
| MakeAllStopping(table); | |||||
| } else if (fPendingPos) { | |||||
| jack_log("transport rolling ==> starting"); | |||||
| fTransportState = JackTransportStarting; | fTransportState = JackTransportStarting; | ||||
| MakeAllStarting(table); | |||||
| MakeAllStartingLocating(table); | |||||
| SyncTimeout(frame_rate, buffer_size); | SyncTimeout(frame_rate, buffer_size); | ||||
| jack_log("transport rolling ==> starting...."); | |||||
| } | } | ||||
| break; | break; | ||||
| @@ -218,6 +210,7 @@ void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t f | |||||
| } | } | ||||
| } | } | ||||
| // Client | |||||
| void JackTransportEngine::ReadCurrentPos(jack_position_t* pos) | void JackTransportEngine::ReadCurrentPos(jack_position_t* pos) | ||||
| { | { | ||||
| UInt16 next_index = GetCurrentIndex(); | 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 | } 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) | void JackTransportEngine::TransportCopyPosition(jack_position_t* from, jack_position_t* to) | ||||
| { | { | ||||
| int tries = 0; | int tries = 0; | ||||
| @@ -49,6 +49,43 @@ We have: | |||||
| The current position can be read by clients. | The current position can be read by clients. | ||||
| We use a JackAtomicArrayState pattern that allows to manage several "next" states independantly. | 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> | class JackTransportEngine : public JackAtomicArrayState<jack_position_t> | ||||
| @@ -65,9 +102,11 @@ class JackTransportEngine : public JackAtomicArrayState<jack_position_t> | |||||
| bool fPendingPos; | bool fPendingPos; | ||||
| SInt32 fWriteCounter; | SInt32 fWriteCounter; | ||||
| bool CheckOneSynching(JackClientInterface** table); | |||||
| bool CheckAllRolling(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); | void SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size); | ||||
| public: | public: | ||||
| @@ -923,20 +923,20 @@ extern "C" | |||||
| */ | */ | ||||
| void jack_set_error_function (void (*func)(const char *)); | 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 | #ifdef __cplusplus | ||||
| } | } | ||||
| @@ -37,7 +37,6 @@ typedef enum { | |||||
| JackTransportRolling = 1, /**< Transport playing */ | JackTransportRolling = 1, /**< Transport playing */ | ||||
| JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */ | JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */ | ||||
| JackTransportStarting = 3, /**< Waiting for sync ready */ | JackTransportStarting = 3, /**< Waiting for sync ready */ | ||||
| JackTransportSynching = 4 /**< internal use*/ | |||||
| } jack_transport_state_t; | } jack_transport_state_t; | ||||
| @@ -39,7 +39,7 @@ extern "C" | |||||
| JackTransportRolling = 1, /**< Transport playing */ | JackTransportRolling = 1, /**< Transport playing */ | ||||
| JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */ | JackTransportLooping = 2, /**< For OLD_TRANSPORT, now ignored */ | ||||
| JackTransportStarting = 3, /**< Waiting for sync ready */ | JackTransportStarting = 3, /**< Waiting for sync ready */ | ||||
| JackTransportSynching = 4 /**< temporary*/ | |||||
| //JackTransportSynching = 4 /**< temporary*/ | |||||
| } jack_transport_state_t; | } jack_transport_state_t; | ||||
| @@ -51,53 +51,84 @@ extern "C" | |||||
| typedef enum { | typedef enum { | ||||
| JackPositionBBT = 0x10, /**< Bar, Beat, Tick */ | 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; | } jack_position_bits_t; | ||||
| /** all valid position bits */ | /** all valid position bits */ | ||||
| #define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode) | #define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode) | ||||
| #define EXTENDED_TIME_INFO | #define EXTENDED_TIME_INFO | ||||
| /** | |||||
| * Struct for transport position information. | |||||
| */ | |||||
| typedef struct { | typedef struct { | ||||
| /* these four cannot be set from clients: the server sets them */ | /* these four cannot be set from clients: the server sets them */ | ||||
| jack_unique_t unique_1; /**< unique ID */ | 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_rate; /**< current frame rate (per second) */ | ||||
| jack_nframes_t frame; /**< frame number, always present */ | jack_nframes_t frame; /**< frame number, always present */ | ||||
| jack_position_bits_t valid; /**< which other fields are valid */ | jack_position_bits_t valid; /**< which other fields are valid */ | ||||
| /* JackPositionBBT fields: */ | /* 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) */ | /* 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 | /* For binary compatibility, new fields should be allocated from | ||||
| * this padding area with new valid bits controlling access, so | * this padding area with new valid bits controlling access, so | ||||
| * the existing structure size and offsets are preserved. */ | * 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. */ | /* When (unique_1 == unique_2) the contents are consistent. */ | ||||
| jack_unique_t unique_2; /**< unique ID */ | jack_unique_t unique_2; /**< unique ID */ | ||||
| } | |||||
| jack_position_t; | |||||
| } jack_position_t; | |||||
| /** | /** | ||||
| * Prototype for the @a sync_callback defined by slow-sync clients. | * Prototype for the @a sync_callback defined by slow-sync clients. | ||||