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 "JackClientControl.h"
00023 #include "JackError.h"
00024 #include "JackTime.h"
00025 #include <assert.h>
00026 #include <stdlib.h>
00027
00028 using namespace std;
00029
00030 namespace Jack
00031 {
00032
00033 JackTransportEngine::JackTransportEngine(): JackAtomicArrayState<jack_position_t>()
00034 {
00035 fTransportState = JackTransportStopped;
00036 fTransportCmd = fPreviousCmd = TransportCommandStop;
00037 fSyncTimeout = 2000000;
00038 fSyncTimeLeft = 0;
00039 fTimeBaseMaster = -1;
00040 fWriteCounter = 0;
00041 fPendingPos = false;
00042 }
00043
00044
00045 void JackTransportEngine::SyncTimeout(jack_nframes_t frame_rate, jack_nframes_t buffer_size)
00046 {
00047 long buf_usecs = (long)((buffer_size * (jack_time_t) 1000000) / frame_rate);
00048 fSyncTimeLeft = fSyncTimeout / buf_usecs;
00049 JackLog("SyncTimeout fSyncTimeout = %ld fSyncTimeLeft = %ld\n", (long)fSyncTimeout, (long)fSyncTimeLeft);
00050 }
00051
00052 int JackTransportEngine::ResetTimebase(int refnum)
00053 {
00054 if (fTimeBaseMaster == refnum) {
00055 jack_position_t* request = WriteNextStateStart(2);
00056 request->valid = (jack_position_bits_t)0;
00057 WriteNextStateStop(2);
00058 fTimeBaseMaster = -1;
00059 return 0;
00060 } else {
00061 return EINVAL;
00062 }
00063 }
00064
00065 int JackTransportEngine::SetTimebase(int refnum, bool conditionnal)
00066 {
00067 if (conditionnal && fTimeBaseMaster > 0) {
00068 if (refnum != fTimeBaseMaster) {
00069 JackLog("conditional timebase for ref = %ld failed: %ld is already the master\n", refnum, fTimeBaseMaster);
00070 return EBUSY;
00071 } else {
00072 JackLog("ref = %ld was already timebase master\n", refnum);
00073 return 0;
00074 }
00075 } else {
00076 fTimeBaseMaster = refnum;
00077 JackLog("new timebase master: ref = %ld\n", refnum);
00078 return 0;
00079 }
00080 }
00081
00082 bool JackTransportEngine::CheckOneSynching(JackClientInterface** table)
00083 {
00084 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00085 JackClientInterface* client = table[i];
00086 if (client && client->GetClientControl()->fTransportState == JackTransportSynching) {
00087 JackLog("CheckOneSynching\n");
00088 return true;
00089 }
00090 }
00091 return false;
00092 }
00093
00094 bool JackTransportEngine::CheckAllRolling(JackClientInterface** table)
00095 {
00096 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00097 JackClientInterface* client = table[i];
00098 if (client && client->GetClientControl()->fTransportState != JackTransportRolling) {
00099 JackLog("CheckAllRolling refnum = %ld is not rolling\n", i);
00100 return false;
00101 }
00102 }
00103 JackLog("CheckAllRolling\n");
00104 return true;
00105 }
00106
00107 void JackTransportEngine::MakeAllStarting(JackClientInterface** table)
00108 {
00109 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00110 JackClientInterface* client = table[i];
00111 if (client) {
00112
00113 client->GetClientControl()->fTransportState = (client->GetClientControl()->fActive) ? JackTransportStarting : JackTransportRolling;
00114 JackLog("MakeAllStarting refnum = %ld \n", i);
00115 }
00116 }
00117 JackLog("MakeAllStarting\n");
00118 }
00119
00120 void JackTransportEngine::CycleBegin(jack_nframes_t frame_rate, jack_time_t time)
00121 {
00122 jack_position_t* pending = WriteNextStateStart(1);
00123 pending->usecs = time;
00124 pending->frame_rate = frame_rate;
00125 WriteNextStateStop(1);
00126 }
00127
00128 void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t frame_rate, jack_nframes_t buffer_size)
00129 {
00130 TrySwitchState(1);
00131
00132
00133 transport_command_t cmd = fTransportCmd;
00134 if (cmd != fPreviousCmd) {
00135 fPreviousCmd = cmd;
00136 JackLog("transport command: %s\n", (cmd == TransportCommandStart ? "START" : "STOP"));
00137 } else {
00138 cmd = TransportCommandNone;
00139 }
00140
00141
00142 switch (fTransportState) {
00143
00144 case JackTransportSynching:
00145 if (cmd == TransportCommandStart) {
00146 fTransportState = JackTransportStarting;
00147 MakeAllStarting(table);
00148 SyncTimeout(frame_rate, buffer_size);
00149 JackLog("transport locate ==> starting....\n");
00150 } else if (fPendingPos) {
00151 fTransportState = JackTransportSynching;
00152 JackLog("transport locate ==> locate....\n");
00153 } else {
00154 fTransportState = JackTransportStopped;
00155 JackLog("transport locate ==> stopped....\n");
00156 }
00157 break;
00158
00159 case JackTransportStopped:
00160
00161 if (cmd == TransportCommandStart) {
00162 fTransportState = JackTransportStarting;
00163 MakeAllStarting(table);
00164 SyncTimeout(frame_rate, buffer_size);
00165 JackLog("transport stopped ==> starting....\n");
00166 } else if (fPendingPos || CheckOneSynching(table)) {
00167 fTransportState = JackTransportSynching;
00168 JackLog("transport stopped ==> locate....\n");
00169 }
00170 break;
00171
00172 case JackTransportStarting:
00173 JackLog("transport starting fSyncTimeLeft %ld\n", fSyncTimeLeft);
00174
00175 if (cmd == TransportCommandStop) {
00176 fTransportState = JackTransportStopped;
00177 JackLog("transport starting ==> stopped\n");
00178 } else if (fPendingPos) {
00179 fTransportState = JackTransportStarting;
00180 MakeAllStarting(table);
00181 SyncTimeout(frame_rate, buffer_size);
00182 } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) {
00183 fTransportState = JackTransportRolling;
00184 JackLog("transport starting ==> rolling.... fSyncTimeLeft %ld\n", fSyncTimeLeft);
00185 }
00186 break;
00187
00188 case JackTransportRolling:
00189 if (cmd == TransportCommandStop) {
00190 fTransportState = JackTransportStopped;
00191 JackLog("transport rolling ==> stopped\n");
00192 } else if (fPendingPos || CheckOneSynching(table)) {
00193 fTransportState = JackTransportStarting;
00194 MakeAllStarting(table);
00195 SyncTimeout(frame_rate, buffer_size);
00196 JackLog("transport rolling ==> starting....\n");
00197 }
00198 break;
00199
00200 default:
00201 jack_error("Invalid JACK transport state: %d", fTransportState);
00202 }
00203
00204
00205 if (fTransportState == JackTransportRolling) {
00206 jack_position_t* pending = WriteNextStateStart(1);
00207 pending->frame += buffer_size;
00208 WriteNextStateStop(1);
00209 }
00210
00211
00212 jack_position_t* request = WriteNextStateStart(2, &fPendingPos);
00213 if (fPendingPos) {
00214 JackLog("New pos = %ld\n", request->frame);
00215 jack_position_t* pending = WriteNextStateStart(1);
00216 TransportCopyPosition(request, pending);
00217 WriteNextStateStop(1);
00218 }
00219 }
00220
00221 void JackTransportEngine::ReadCurrentPos(jack_position_t* pos)
00222 {
00223 UInt16 next_index = GetCurrentIndex();
00224 UInt16 cur_index;
00225 do {
00226 cur_index = next_index;
00227 memcpy(pos, ReadCurrentState(), sizeof(jack_position_t));
00228 next_index = GetCurrentIndex();
00229 } while (cur_index != next_index);
00230 }
00231
00232 void JackTransportEngine::TransportCopyPosition(jack_position_t* from, jack_position_t* to)
00233 {
00234 int tries = 0;
00235 long timeout = 1000;
00236
00237 do {
00238
00239
00240
00241
00242 if (tries > 10) {
00243 JackSleep(20);
00244 tries = 0;
00245
00246
00247 if (--timeout == 0) {
00248 jack_error("hung in loop copying position B");
00249 abort();
00250 }
00251 }
00252 *to = *from;
00253 tries++;
00254
00255 } while (to->unique_1 != to->unique_2);
00256 }
00257
00258
00259 }