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