00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "JackTransportEngine.h"
00022 #include "JackClientInterface.h"
00023 #include "JackClientControl.h"
00024 #include "JackError.h"
00025 #include "JackTime.h"
00026 #include <assert.h>
00027 #include <math.h>
00028 #include <stdlib.h>
00029
00030 using namespace std;
00031
00032 namespace Jack
00033 {
00034
00035 JackTransportEngine::JackTransportEngine(): JackAtomicArrayState<jack_position_t>()
00036 {
00037 fTransportState = JackTransportStopped;
00038 fTransportCmd = fPreviousCmd = TransportCommandStop;
00039 fSyncTimeout = 2000000;
00040 fSyncTimeLeft = 0;
00041 fTimeBaseMaster = -1;
00042 fWriteCounter = 0;
00043 fConditionnal = false;
00044 fPendingPos = false;
00045 fNetworkSync = false;
00046 }
00047
00048
00049 void JackTransportEngine::SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size)
00050 {
00051 long buf_usecs = (long)((buffer_size * (jack_time_t)1000000) / frame_rate);
00052 fSyncTimeLeft = fSyncTimeout / buf_usecs;
00053 jack_log("SyncTimeout fSyncTimeout = %ld fSyncTimeLeft = %ld", (long)fSyncTimeout, (long)fSyncTimeLeft);
00054 }
00055
00056
00057 int JackTransportEngine::ResetTimebase(int refnum)
00058 {
00059 if (fTimeBaseMaster == refnum) {
00060 jack_position_t* request = WriteNextStateStart(2);
00061 request->valid = (jack_position_bits_t)0;
00062 WriteNextStateStop(2);
00063 fTimeBaseMaster = -1;
00064 return 0;
00065 } else {
00066 return EINVAL;
00067 }
00068 }
00069
00070
00071 int JackTransportEngine::SetTimebaseMaster(int refnum, bool conditionnal)
00072 {
00073 if (conditionnal && fTimeBaseMaster > 0) {
00074 if (refnum != fTimeBaseMaster) {
00075 jack_log("conditional timebase for ref = %ld failed: %ld is already the master", refnum, fTimeBaseMaster);
00076 return EBUSY;
00077 } else {
00078 jack_log("ref = %ld was already timebase master", refnum);
00079 return 0;
00080 }
00081 } else {
00082 fTimeBaseMaster = refnum;
00083 fConditionnal = conditionnal;
00084 jack_log("new timebase master: ref = %ld", refnum);
00085 return 0;
00086 }
00087 }
00088
00089
00090 bool JackTransportEngine::CheckAllRolling(JackClientInterface** table)
00091 {
00092 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00093 JackClientInterface* client = table[i];
00094 if (client && client->GetClientControl()->fTransportState != JackTransportRolling) {
00095 jack_log("CheckAllRolling ref = %ld is not rolling", i);
00096 return false;
00097 }
00098 }
00099 jack_log("CheckAllRolling");
00100 return true;
00101 }
00102
00103
00104 void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table)
00105 {
00106 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00107 JackClientInterface* client = table[i];
00108 if (client) {
00109 JackClientControl* control = client->GetClientControl();
00110
00111 control->fTransportState = (control->fActive && control->fCallback[kRealTimeCallback]) ? JackTransportStarting : JackTransportRolling;
00112 control->fTransportSync = true;
00113 control->fTransportTimebase = true;
00114 jack_log("MakeAllStartingLocating ref = %ld", i);
00115 }
00116 }
00117 }
00118
00119
00120 void JackTransportEngine::MakeAllStopping(JackClientInterface** table)
00121 {
00122 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00123 JackClientInterface* client = table[i];
00124 if (client) {
00125 JackClientControl* control = client->GetClientControl();
00126 control->fTransportState = JackTransportStopped;
00127 control->fTransportSync = false;
00128 control->fTransportTimebase = false;
00129 jack_log("MakeAllStopping ref = %ld", i);
00130 }
00131 }
00132 }
00133
00134
00135 void JackTransportEngine::MakeAllLocating(JackClientInterface** table)
00136 {
00137 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00138 JackClientInterface* client = table[i];
00139 if (client) {
00140 JackClientControl* control = client->GetClientControl();
00141 control->fTransportState = JackTransportStopped;
00142 control->fTransportTimebase = true;
00143 jack_log("MakeAllLocating ref = %ld", i);
00144 }
00145 }
00146 }
00147
00148
00149 void JackTransportEngine::CycleBegin(jack_nframes_t frame_rate, jack_time_t time)
00150 {
00151 jack_position_t* pending = WriteNextStateStart(1);
00152 pending->usecs = time;
00153 pending->frame_rate = frame_rate;
00154 WriteNextStateStop(1);
00155 }
00156
00157
00158 void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size)
00159 {
00160 TrySwitchState(1);
00161
00162
00163 transport_command_t cmd = fTransportCmd;
00164 if (cmd != fPreviousCmd) {
00165 fPreviousCmd = cmd;
00166 jack_log("transport command: %s", (cmd == TransportCommandStart ? "Transport start" : "Transport stop"));
00167 } else {
00168 cmd = TransportCommandNone;
00169 }
00170
00171
00172 switch (fTransportState) {
00173
00174 case JackTransportStopped:
00175
00176 if (cmd == TransportCommandStart) {
00177 jack_log("transport stopped ==> starting");
00178 fTransportState = JackTransportStarting;
00179 MakeAllStartingLocating(table);
00180 SyncTimeout(frame_rate, buffer_size);
00181 } else if (fPendingPos) {
00182 jack_log("transport stopped ==> stopped (locating)");
00183 MakeAllLocating(table);
00184 }
00185 break;
00186
00187 case JackTransportStarting:
00188 if (cmd == TransportCommandStop) {
00189 jack_log("transport starting ==> stopped");
00190 fTransportState = JackTransportStopped;
00191 MakeAllStopping(table);
00192 } else if (fPendingPos) {
00193 jack_log("transport starting ==> starting");
00194 fTransportState = JackTransportStarting;
00195 MakeAllStartingLocating(table);
00196 SyncTimeout(frame_rate, buffer_size);
00197 } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) {
00198 if (fNetworkSync) {
00199 jack_log("transport starting ==> netstarting");
00200 fTransportState = JackTransportNetStarting;
00201 } else {
00202 jack_log("transport starting ==> rolling fSyncTimeLeft = %ld", fSyncTimeLeft);
00203 fTransportState = JackTransportRolling;
00204 }
00205 }
00206 break;
00207
00208 case JackTransportRolling:
00209 if (cmd == TransportCommandStop) {
00210 jack_log("transport rolling ==> stopped");
00211 fTransportState = JackTransportStopped;
00212 MakeAllStopping(table);
00213 } else if (fPendingPos) {
00214 jack_log("transport rolling ==> starting");
00215 fTransportState = JackTransportStarting;
00216 MakeAllStartingLocating(table);
00217 SyncTimeout(frame_rate, buffer_size);
00218 }
00219 break;
00220
00221 case JackTransportNetStarting:
00222 break;
00223
00224 default:
00225 jack_error("Invalid JACK transport state: %d", fTransportState);
00226 }
00227
00228
00229 if (fTransportState == JackTransportRolling) {
00230 jack_position_t* pending = WriteNextStateStart(1);
00231 pending->frame += buffer_size;
00232 WriteNextStateStop(1);
00233 }
00234
00235
00236 jack_position_t* request = WriteNextStateStart(2, &fPendingPos);
00237 if (fPendingPos) {
00238 jack_log("New pos = %ld", request->frame);
00239 jack_position_t* pending = WriteNextStateStart(1);
00240 CopyPosition(request, pending);
00241 WriteNextStateStop(1);
00242 }
00243 }
00244
00245
00246 void JackTransportEngine::ReadCurrentPos(jack_position_t* pos)
00247 {
00248 UInt16 next_index = GetCurrentIndex();
00249 UInt16 cur_index;
00250 do {
00251 cur_index = next_index;
00252 memcpy(pos, ReadCurrentState(), sizeof(jack_position_t));
00253 next_index = GetCurrentIndex();
00254 } while (cur_index != next_index);
00255 }
00256
00257 void JackTransportEngine::RequestNewPos(jack_position_t* pos)
00258 {
00259 jack_position_t* request = WriteNextStateStart(2);
00260 pos->unique_1 = pos->unique_2 = GenerateUniqueID();
00261 CopyPosition(pos, request);
00262 jack_log("RequestNewPos pos = %ld", pos->frame);
00263 WriteNextStateStop(2);
00264 }
00265
00266 jack_transport_state_t JackTransportEngine::Query(jack_position_t* pos)
00267 {
00268 if (pos)
00269 ReadCurrentPos(pos);
00270 return GetState();
00271 }
00272
00273 jack_nframes_t JackTransportEngine::GetCurrentFrame()
00274 {
00275 jack_position_t pos;
00276 ReadCurrentPos(&pos);
00277
00278 if (fTransportState == JackTransportRolling) {
00279 float usecs = GetMicroSeconds() - pos.usecs;
00280 jack_nframes_t elapsed = (jack_nframes_t)floor((((float) pos.frame_rate) / 1000000.0f) * usecs);
00281 return pos.frame + elapsed;
00282 } else {
00283 return pos.frame;
00284 }
00285 }
00286
00287
00288 void JackTransportEngine::CopyPosition(jack_position_t* from, jack_position_t* to)
00289 {
00290 int tries = 0;
00291 long timeout = 1000;
00292
00293 do {
00294
00295
00296
00297
00298 if (tries > 10) {
00299 JackSleep(20);
00300 tries = 0;
00301
00302
00303 if (--timeout == 0) {
00304 jack_error("hung in loop copying position B");
00305 abort();
00306 }
00307 }
00308 *to = *from;
00309 tries++;
00310
00311 } while (to->unique_1 != to->unique_2);
00312 }
00313
00314
00315 }