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