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. | ||||