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 void JackTransportEngine::GetTimebaseMaster(int& refnum, bool& conditionnal)
00090 {
00091 refnum = fTimeBaseMaster;
00092 conditionnal = fConditionnal;
00093 }
00094
00095
00096 bool JackTransportEngine::CheckAllRolling(JackClientInterface** table)
00097 {
00098 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00099 JackClientInterface* client = table[i];
00100 if (client && client->GetClientControl()->fTransportState != JackTransportRolling) {
00101 jack_log("CheckAllRolling ref = %ld is not rolling", i);
00102 return false;
00103 }
00104 }
00105 jack_log("CheckAllRolling");
00106 return true;
00107 }
00108
00109
00110 void JackTransportEngine::MakeAllStartingLocating(JackClientInterface** table)
00111 {
00112 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00113 JackClientInterface* client = table[i];
00114 if (client) {
00115 JackClientControl* control = client->GetClientControl();
00116
00117 control->fTransportState = (control->fActive && control->fCallback[kRealTimeCallback]) ? JackTransportStarting : JackTransportRolling;
00118 control->fTransportSync = true;
00119 control->fTransportTimebase = true;
00120 jack_log("MakeAllStartingLocating ref = %ld", i);
00121 }
00122 }
00123 }
00124
00125
00126 void JackTransportEngine::MakeAllStopping(JackClientInterface** table)
00127 {
00128 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00129 JackClientInterface* client = table[i];
00130 if (client) {
00131 JackClientControl* control = client->GetClientControl();
00132 control->fTransportState = JackTransportStopped;
00133 control->fTransportSync = false;
00134 control->fTransportTimebase = false;
00135 jack_log("MakeAllStopping ref = %ld", i);
00136 }
00137 }
00138 }
00139
00140
00141 void JackTransportEngine::MakeAllLocating(JackClientInterface** table)
00142 {
00143 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00144 JackClientInterface* client = table[i];
00145 if (client) {
00146 JackClientControl* control = client->GetClientControl();
00147 control->fTransportState = JackTransportStopped;
00148 control->fTransportTimebase = true;
00149 jack_log("MakeAllLocating ref = %ld", i);
00150 }
00151 }
00152 }
00153
00154
00155 void JackTransportEngine::CycleBegin(jack_nframes_t frame_rate, jack_time_t time)
00156 {
00157 jack_position_t* pending = WriteNextStateStart(1);
00158 pending->usecs = time;
00159 pending->frame_rate = frame_rate;
00160 WriteNextStateStop(1);
00161 }
00162
00163
00164 void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size)
00165 {
00166 TrySwitchState(1);
00167
00168
00169 transport_command_t cmd = fTransportCmd;
00170 if (cmd != fPreviousCmd) {
00171 fPreviousCmd = cmd;
00172 jack_log("transport command: %s", (cmd == TransportCommandStart ? "Transport start" : "Transport stop"));
00173 } else {
00174 cmd = TransportCommandNone;
00175 }
00176
00177
00178 switch (fTransportState) {
00179
00180 case JackTransportStopped:
00181
00182 if (cmd == TransportCommandStart) {
00183 jack_log("transport stopped ==> starting");
00184 fTransportState = JackTransportStarting;
00185 MakeAllStartingLocating(table);
00186 SyncTimeout(frame_rate, buffer_size);
00187 } else if (fPendingPos) {
00188 jack_log("transport stopped ==> stopped (locating)");
00189 MakeAllLocating(table);
00190 }
00191 break;
00192
00193 case JackTransportStarting:
00194 if (cmd == TransportCommandStop) {
00195 jack_log("transport starting ==> stopped");
00196 fTransportState = JackTransportStopped;
00197 MakeAllStopping(table);
00198 } else if (fPendingPos) {
00199 jack_log("transport starting ==> starting");
00200 fTransportState = JackTransportStarting;
00201 MakeAllStartingLocating(table);
00202 SyncTimeout(frame_rate, buffer_size);
00203 } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) {
00204 if (fNetworkSync) {
00205 jack_log("transport starting ==> netstarting");
00206 fTransportState = JackTransportNetStarting;
00207 } else {
00208 jack_log("transport starting ==> rolling fSyncTimeLeft = %ld", fSyncTimeLeft);
00209 fTransportState = JackTransportRolling;
00210 }
00211 }
00212 break;
00213
00214 case JackTransportRolling:
00215 if (cmd == TransportCommandStop) {
00216 jack_log("transport rolling ==> stopped");
00217 fTransportState = JackTransportStopped;
00218 MakeAllStopping(table);
00219 } else if (fPendingPos) {
00220 jack_log("transport rolling ==> starting");
00221 fTransportState = JackTransportStarting;
00222 MakeAllStartingLocating(table);
00223 SyncTimeout(frame_rate, buffer_size);
00224 }
00225 break;
00226
00227 case JackTransportNetStarting:
00228 break;
00229
00230 default:
00231 jack_error("Invalid JACK transport state: %d", fTransportState);
00232 }
00233
00234
00235 if (fTransportState == JackTransportRolling) {
00236 jack_position_t* pending = WriteNextStateStart(1);
00237 pending->frame += buffer_size;
00238 WriteNextStateStop(1);
00239 }
00240
00241
00242 jack_position_t* request = WriteNextStateStart(2, &fPendingPos);
00243 if (fPendingPos) {
00244 jack_log("New pos = %ld", request->frame);
00245 jack_position_t* pending = WriteNextStateStart(1);
00246 CopyPosition(request, pending);
00247 WriteNextStateStop(1);
00248 }
00249 }
00250
00251
00252 void JackTransportEngine::ReadCurrentPos(jack_position_t* pos)
00253 {
00254 UInt16 next_index = GetCurrentIndex();
00255 UInt16 cur_index;
00256 do {
00257 cur_index = next_index;
00258 memcpy(pos, ReadCurrentState(), sizeof(jack_position_t));
00259 next_index = GetCurrentIndex();
00260 } while (cur_index != next_index);
00261 }
00262
00263 void JackTransportEngine::RequestNewPos(jack_position_t* pos)
00264 {
00265 jack_position_t* request = WriteNextStateStart(2);
00266 pos->unique_1 = pos->unique_2 = GenerateUniqueID();
00267 CopyPosition(pos, request);
00268 jack_log("RequestNewPos pos = %ld", pos->frame);
00269 WriteNextStateStop(2);
00270 }
00271
00272 jack_transport_state_t JackTransportEngine::Query(jack_position_t* pos)
00273 {
00274 if (pos)
00275 ReadCurrentPos(pos);
00276 return GetState();
00277 }
00278
00279 jack_nframes_t JackTransportEngine::GetCurrentFrame()
00280 {
00281 jack_position_t pos;
00282 ReadCurrentPos(&pos);
00283
00284 if (fTransportState == JackTransportRolling) {
00285 float usecs = GetMicroSeconds() - pos.usecs;
00286 jack_nframes_t elapsed = (jack_nframes_t)floor((((float) pos.frame_rate) / 1000000.0f) * usecs);
00287 return pos.frame + elapsed;
00288 } else {
00289 return pos.frame;
00290 }
00291 }
00292
00293
00294 void JackTransportEngine::CopyPosition(jack_position_t* from, jack_position_t* to)
00295 {
00296 int tries = 0;
00297 long timeout = 1000;
00298
00299 do {
00300
00301
00302
00303
00304 if (tries > 10) {
00305 JackSleep(20);
00306 tries = 0;
00307
00308
00309 if (--timeout == 0) {
00310 jack_error("hung in loop copying position B");
00311 abort();
00312 }
00313 }
00314 *to = *from;
00315 tries++;
00316
00317 } while (to->unique_1 != to->unique_2);
00318 }
00319
00320
00321 }