00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <iostream>
00021 #include <fstream>
00022 #include <assert.h>
00023
00024 #include "JackEngine.h"
00025 #include "JackExternalClient.h"
00026 #include "JackEngineControl.h"
00027 #include "JackClientControl.h"
00028 #include "JackEngineTiming.h"
00029 #include "JackGlobals.h"
00030 #include "JackChannel.h"
00031 #include "JackSyncInterface.h"
00032
00033 namespace Jack
00034 {
00035
00036 JackEngine::JackEngine(JackGraphManager* manager, JackSynchro** table, JackEngineControl* control, JackSyncInterface* signal, bool sync, long time_out_ms, bool rt, long priority, bool ve)
00037 {
00038 fGraphManager = manager;
00039 fSynchroTable = table;
00040 fEngineControl = control;
00041 fEngineControl->fSyncMode = sync;
00042 fEngineControl->fTimeOutUsecs = time_out_ms * 1000;
00043 fEngineControl->fRealTime = rt;
00044 fEngineControl->fPriority = priority;
00045 fEngineControl->fVerbose = ve;
00046 fChannel = JackGlobals::MakeServerNotifyChannel();
00047 fEngineTiming = new JackEngineTiming(fClientTable, fGraphManager, fEngineControl);
00048 fSignal = signal;
00049 for (int i = 0; i < CLIENT_NUM; i++)
00050 fClientTable[i] = NULL;
00051 fEngineTiming->ClearTimeMeasures();
00052 fEngineTiming->ResetRollingUsecs();
00053 }
00054
00055 JackEngine::~JackEngine()
00056 {
00057 delete fChannel;
00058 delete fEngineTiming;
00059 }
00060
00061
00062
00063
00064
00065 int JackEngine::Open()
00066 {
00067 JackLog("JackEngine::Open\n");
00068
00069
00070 if (fChannel->Open() < 0) {
00071 jack_error("Cannot connect to server");
00072 return -1;
00073 } else {
00074 return 0;
00075 }
00076 }
00077
00078 int JackEngine::Close()
00079 {
00080 JackLog("JackEngine::Close\n");
00081 fChannel->Close();
00082
00083
00084 for (int i = 0; i < CLIENT_NUM; i++) {
00085 JackClientInterface* client = fClientTable[i];
00086 if (client) {
00087 JackLog("JackEngine::Close remaining client %ld\n", i);
00088 ClientCloseAux(i, client, false);
00089 client->Close();
00090 delete client;
00091 }
00092 }
00093
00094 return 0;
00095 }
00096
00097 int JackEngine::Allocate()
00098 {
00099 for (int i = 0; i < CLIENT_NUM; i++) {
00100 if (!fClientTable[i]) {
00101 JackLog("JackEngine::AllocateRefNum ref = %ld\n", i);
00102 return i;
00103 }
00104 }
00105
00106 return -1;
00107 }
00108
00109
00110
00111
00112
00113 bool JackEngine::Process(jack_time_t callback_usecs)
00114 {
00115 bool res = true;
00116
00117
00118 fEngineControl->CycleBegin(callback_usecs);
00119
00120
00121 fEngineControl->IncFrameTime(callback_usecs);
00122 fEngineTiming->UpdateTiming(callback_usecs);
00123
00124
00125 if (fGraphManager->IsFinishedGraph()) {
00126 fLastSwitchUsecs = callback_usecs;
00127 if (fGraphManager->RunNextGraph())
00128 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kGraphOrderCallback, 0);
00129 fSignal->SignalAll();
00130 res = true;
00131 } else {
00132 JackLog("Process: graph not finished!\n");
00133 if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
00134 JackLog("Process: switch to next state %ld\n", long(callback_usecs - fLastSwitchUsecs));
00135
00136 fLastSwitchUsecs = callback_usecs;
00137 if (fGraphManager->RunNextGraph())
00138 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kGraphOrderCallback, 0);
00139 fSignal->SignalAll();
00140 res = true;
00141 } else {
00142 JackLog("Process: waiting to switch %ld\n", long(callback_usecs - fLastSwitchUsecs));
00143 if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs)
00144 CheckXRun(callback_usecs);
00145 fGraphManager->RunCurrentGraph();
00146 res = false;
00147 }
00148 }
00149
00150
00151 fEngineControl->CycleEnd(fClientTable);
00152 return res;
00153 }
00154
00155
00156
00157
00158
00159
00160 void JackEngine::CheckXRun(jack_time_t callback_usecs)
00161 {
00162 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00163 JackClientInterface* client = fClientTable[i];
00164 if (client && client->GetClientControl()->fActive) {
00165 JackClientTiming* timing = fGraphManager->GetClientTiming(i);
00166 jack_client_state_t status = timing->fStatus;
00167 jack_time_t finished_date = timing->fFinishedAt;
00168
00169 if (status != NotTriggered && status != Finished) {
00170 jack_error("JackEngine::XRun: client = %s was not runned: state = %ld", client->GetClientControl()->fName, status);
00171
00172 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);
00173 }
00174 if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
00175 jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
00176
00177 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);
00178 }
00179 }
00180 }
00181 }
00182
00183
00184
00185
00186
00187 bool JackEngine::IsZombie(JackClientInterface* client, jack_time_t current_time)
00188 {
00189 return ((current_time - fGraphManager->GetClientTiming(client->GetClientControl()->fRefNum)->fFinishedAt) > 2 * fEngineControl->fTimeOutUsecs);
00190 }
00191
00192
00193 void JackEngine::GetZombifiedClients(bool zombi_clients[CLIENT_NUM], jack_time_t current_time)
00194 {
00195 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00196 JackClientInterface* client1 = fClientTable[i];
00197 if (client1 && IsZombie(client1, current_time)) {
00198 JackLog("JackEngine::GetZombifiedClients: %s\n", client1->GetClientControl()->fName);
00199 zombi_clients[i] = true;
00200
00201 for (int j = REAL_REFNUM; j < CLIENT_NUM; j++) {
00202 JackClientInterface* client2 = fClientTable[j];
00203 if (client2 && IsZombie(client2, current_time) && fGraphManager->IsDirectConnection(j, i)) {
00204 zombi_clients[i] = false;
00205 break;
00206 }
00207 }
00208 } else {
00209 zombi_clients[i] = false;
00210 }
00211 }
00212 }
00213
00214 void JackEngine::RemoveZombifiedClients(jack_time_t current_time)
00215 {
00216 bool zombi_clients[CLIENT_NUM];
00217 GetZombifiedClients(zombi_clients, current_time);
00218
00219 for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00220 if (zombi_clients[i] && !fClientTable[i]->GetClientControl()->fZombie) {
00221 fClientTable[i]->GetClientControl()->fZombie = true;
00222 JackLog("RemoveZombifiedCients: name = %s\n", fClientTable[i]->GetClientControl()->fName);
00223 fGraphManager->DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, i);
00224 fGraphManager->DirectDisconnect(i, FREEWHEEL_DRIVER_REFNUM);
00225 fGraphManager->DisconnectAllPorts(i);
00226 fChannel->ClientNotify(i, JackNotifyChannelInterface::kZombifyClient, 0);
00227 }
00228 }
00229 }
00230
00231 void JackEngine::ZombifyClient(int refnum)
00232 {
00233 NotifyClient(refnum, JackNotifyChannelInterface::kZombifyClient, false, 0);
00234 }
00235
00236
00237
00238
00239
00240 void JackEngine::NotifyClient(int refnum, int event, int sync, int value)
00241 {
00242 JackClientInterface* client = fClientTable[refnum];
00243
00244 if (client && (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value) < 0)) {
00245 jack_error("NotifyClient fails name = %s event = %ld = val = %ld", client->GetClientControl()->fName, event, value);
00246 } else {
00247 JackLog("JackEngine::NotifyClient: client not available anymore\n");
00248 }
00249 }
00250
00251 void JackEngine::NotifyClients(int event, int sync, int value)
00252 {
00253 for (int i = 0; i < CLIENT_NUM; i++) {
00254 JackClientInterface* client = fClientTable[i];
00255 if (client && (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value) < 0)) {
00256 jack_error("NotifyClient fails name = %s event = %ld = val = %ld", client->GetClientControl()->fName, event, value);
00257 }
00258 }
00259 }
00260
00261 int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
00262 {
00263
00264 for (int i = 0; i < CLIENT_NUM; i++) {
00265 JackClientInterface* old_client = fClientTable[i];
00266 if (old_client) {
00267 if (old_client->ClientNotify(refnum, name, JackNotifyChannelInterface::kAddClient, true, 0) < 0)
00268 return -1;
00269 if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, JackNotifyChannelInterface::kAddClient, true, 0) < 0)
00270 return -1;
00271 }
00272 }
00273
00274 return 0;
00275 }
00276
00277 void JackEngine::NotifyRemoveClient(const char* name, int refnum)
00278 {
00279
00280 for (int i = 0; i < CLIENT_NUM; i++) {
00281 JackClientInterface* client = fClientTable[i];
00282 if (client) {
00283 client->ClientNotify(refnum, name, JackNotifyChannelInterface::kRemoveClient, true, 0);
00284 }
00285 }
00286 }
00287
00288
00289 void JackEngine::NotifyXRun(jack_time_t callback_usecs)
00290 {
00291
00292 fEngineControl->ResetFrameTime(callback_usecs);
00293 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);
00294 }
00295
00296 void JackEngine::NotifyXRun(int refnum)
00297 {
00298 if (refnum == ALL_CLIENTS) {
00299 NotifyClients(JackNotifyChannelInterface::kXRunCallback, false, 0);
00300 } else {
00301 NotifyClient(refnum, JackNotifyChannelInterface::kXRunCallback, false, 0);
00302 }
00303 }
00304
00305 void JackEngine::NotifyGraphReorder()
00306 {
00307 NotifyClients(JackNotifyChannelInterface::kGraphOrderCallback, false, 0);
00308 }
00309
00310 void JackEngine::NotifyBufferSize(jack_nframes_t nframes)
00311 {
00312 NotifyClients(JackNotifyChannelInterface::kBufferSizeCallback, true, nframes);
00313 }
00314
00315 void JackEngine::NotifyFreewheel(bool onoff)
00316 {
00317 fEngineControl->fRealTime = !onoff;
00318 NotifyClients((onoff ? JackNotifyChannelInterface::kStartFreewheel : JackNotifyChannelInterface::kStopFreewheel), true, 0);
00319 }
00320
00321 void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
00322 {
00323 NotifyClients((onoff ? JackNotifyChannelInterface::kPortRegistrationOn : JackNotifyChannelInterface::kPortRegistrationOff), false, port_index);
00324 }
00325
00326 void JackEngine::NotifyActivate(int refnum)
00327 {
00328 NotifyClient(refnum, JackNotifyChannelInterface::kActivateClient, false, 0);
00329 }
00330
00331
00332
00333
00334
00335 bool JackEngine::ClientCheckName(const char* name)
00336 {
00337 for (int i = 0; i < CLIENT_NUM; i++) {
00338 JackClientInterface* client = fClientTable[i];
00339 if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
00340 return true;
00341 }
00342
00343 return false;
00344 }
00345
00346
00347 int JackEngine::ClientNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
00348 {
00349 if (ClientCheckName(name)) {
00350 jack_error("client %s already registered", name);
00351 return -1;
00352 }
00353
00354 JackExternalClient* client = new JackExternalClient();
00355 if (ClientExternalNew(name, ref, shared_engine, shared_client, shared_graph_manager, client) < 0) {
00356 delete client;
00357 return -1;
00358 }
00359
00360 return 0;
00361 }
00362
00363
00364 int JackEngine::ClientExternalNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager, JackExternalClient* client)
00365 {
00366 JackLog("JackEngine::ClientNew: name = %s \n", name);
00367 int refnum = Allocate();
00368
00369 if (refnum < 0) {
00370 jack_error("No more refnum available");
00371 return -1;
00372 }
00373
00374 if (!fSynchroTable[refnum]->Allocate(name, 0)) {
00375 jack_error("Cannot allocate synchro");
00376 goto error;
00377 }
00378
00379 if (client->Open(name, refnum, shared_client) < 0) {
00380 jack_error("Cannot open client");
00381 goto error;
00382 }
00383
00384 if (!fSignal->TimedWait(5 * 1000000)) {
00385
00386 jack_error("Driver is not running");
00387 goto error;
00388 }
00389
00390 if (NotifyAddClient(client, name, refnum) < 0) {
00391 jack_error("Cannot notify add client");
00392 goto error;
00393 }
00394
00395 fClientTable[refnum] = client;
00396 fGraphManager->InitRefNum(refnum);
00397 fEngineTiming->ResetRollingUsecs();
00398 *shared_engine = fEngineControl->GetShmIndex();
00399 *shared_graph_manager = fGraphManager->GetShmIndex();
00400 *ref = refnum;
00401 return 0;
00402
00403 error:
00404 ClientCloseAux(refnum, client, false);
00405 client->Close();
00406 return -1;
00407 }
00408
00409
00410 int JackEngine::ClientInternalNew(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client)
00411 {
00412 JackLog("JackEngine::ClientInternalNew: name = %s\n", name);
00413 int refnum = Allocate();
00414
00415 if (refnum < 0) {
00416 jack_error("No more refnum available");
00417 return -1;
00418 }
00419
00420 if (!fSynchroTable[refnum]->Allocate(name, 0)) {
00421 jack_error("Cannot allocate synchro");
00422 return -1;
00423 }
00424
00425 if (NotifyAddClient(client, name, refnum) < 0) {
00426 jack_error("Cannot notify add client");
00427 return -1;
00428 }
00429
00430 fClientTable[refnum] = client;
00431 fGraphManager->InitRefNum(refnum);
00432 fEngineTiming->ResetRollingUsecs();
00433 *shared_engine = fEngineControl;
00434 *shared_manager = fGraphManager;
00435 *ref = refnum;
00436 return 0;
00437 }
00438
00439
00440 int JackEngine::ClientClose(int refnum)
00441 {
00442 JackClientInterface* client = fClientTable[refnum];
00443 if (client) {
00444 fEngineControl->fTransport.ResetTimebase(refnum);
00445 int res = ClientCloseAux(refnum, client, true);
00446 client->Close();
00447 delete client;
00448 return res;
00449 } else {
00450 return -1;
00451 }
00452 }
00453
00454
00455 int JackEngine::ClientInternalClose(int refnum)
00456 {
00457 JackClientInterface* client = fClientTable[refnum];
00458 return (client) ? ClientCloseAux(refnum, client, true) : -1;
00459 }
00460
00461
00462 int JackEngine::ClientInternalCloseIm(int refnum)
00463 {
00464 JackClientInterface* client = fClientTable[refnum];
00465 return (client) ? ClientCloseAux(refnum, client, false) : -1;
00466 }
00467
00468 int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
00469 {
00470 JackLog("JackEngine::ClientCloseAux ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00471
00472
00473 fClientTable[refnum] = NULL;
00474
00475
00476 fGraphManager->RemoveAllPorts(refnum);
00477
00478
00479 if (wait) {
00480 if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 2)) {
00481 JackLog("JackEngine::ClientCloseAux wait error ref = %ld \n", refnum);
00482 }
00483 }
00484
00485
00486 NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
00487
00488
00489 fSynchroTable[refnum]->Destroy();
00490 fEngineTiming->ResetRollingUsecs();
00491 return 0;
00492 }
00493
00494 int JackEngine::ClientActivate(int refnum)
00495 {
00496 JackClientInterface* client = fClientTable[refnum];
00497 assert(fClientTable[refnum]);
00498
00499 JackLog("JackEngine::ClientActivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00500
00501 if (!fSignal->TimedWait(fEngineControl->fPeriodUsecs * 10)) {
00502 JackLog("JackEngine::ClientActivate wait error ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00503 return -1;
00504 } else {
00505 NotifyActivate(refnum);
00506 return 0;
00507 }
00508 }
00509
00510
00511 int JackEngine::ClientDeactivate(int refnum)
00512 {
00513 JackClientInterface* client = fClientTable[refnum];
00514 if (client == NULL)
00515 return -1;
00516
00517 JackLog("JackEngine::ClientDeactivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00518 fGraphManager->DisconnectAllPorts(refnum);
00519
00520 if (!fSignal->TimedWait(fEngineControl->fPeriodUsecs * 10)) {
00521 JackLog("JackEngine::ClientDeactivate wait error ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00522 return -1;
00523 } else {
00524 return 0;
00525 }
00526 }
00527
00528
00529
00530
00531
00532 int JackEngine::PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
00533 {
00534 JackLog("JackEngine::PortRegister ref = %ld name = %s flags = %d buffer_size = %d\n", refnum, name, flags, buffer_size);
00535 assert(fClientTable[refnum]);
00536
00537 *port_index = fGraphManager->AllocatePort(refnum, name, (JackPortFlags)flags);
00538 if (*port_index != NO_PORT) {
00539 NotifyPortRegistation(*port_index, true);
00540 return 0;
00541 } else {
00542 return -1;
00543 }
00544 }
00545
00546 int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
00547 {
00548 JackLog("JackEngine::PortUnRegister ref = %ld port_index = %ld\n", refnum, port_index);
00549 assert(fClientTable[refnum]);
00550
00551 if (fGraphManager->RemovePort(refnum, port_index) == 0) {
00552 fGraphManager->ReleasePort(port_index);
00553 NotifyPortRegistation(port_index, false);
00554 return 0;
00555 } else {
00556 return -1;
00557 }
00558 }
00559
00560 int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
00561 {
00562 JackLog("JackEngine::PortConnect src = %s dst = %s\n", src, dst);
00563 jack_port_id_t port_src, port_dst;
00564
00565 return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
00566 ? -1
00567 : PortConnect(refnum, port_src, port_dst);
00568 }
00569
00570 int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
00571 {
00572 JackLog("JackEngine::PortDisconnect src = %s dst = %s\n", src, dst);
00573 jack_port_id_t port_src, port_dst;
00574
00575 return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
00576 ? -1
00577 : fGraphManager->Disconnect(port_src, port_dst);
00578 }
00579
00580 int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00581 {
00582 JackLog("JackEngine::PortConnect src = %d dst = %d\n", src, dst);
00583 JackClientInterface* client;
00584 int ref;
00585
00586 if (fGraphManager->CheckPorts(src, dst) < 0)
00587 return -1;
00588
00589 ref = fGraphManager->GetOutputRefNum(src);
00590 assert(ref >= 0);
00591 client = fClientTable[ref];
00592 assert(client);
00593 if (!client->GetClientControl()->fActive) {
00594 jack_error("Cannot connect ports owned by inactive clients:"
00595 " \"%s\" is not active", client->GetClientControl()->fName);
00596 return -1;
00597 }
00598
00599 ref = fGraphManager->GetInputRefNum(dst);
00600 assert(ref >= 0);
00601 client = fClientTable[ref];
00602 assert(client);
00603 if (!client->GetClientControl()->fActive) {
00604 jack_error("Cannot connect ports owned by inactive clients:"
00605 " \"%s\" is not active", client->GetClientControl()->fName);
00606 return -1;
00607 }
00608
00609 return fGraphManager->Connect(src, dst);
00610 }
00611
00612 int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00613 {
00614 JackLog("JackEngine::PortDisconnect src = %d dst = %d\n", src, dst);
00615
00616 if (dst == ALL_PORTS) {
00617 return (fGraphManager->CheckPort(src) < 0)
00618 ? -1
00619 : fGraphManager->DisconnectAll(src);
00620 } else {
00621 return (fGraphManager->CheckPorts(src, dst) < 0)
00622 ? -1
00623 : fGraphManager->Disconnect(src, dst);
00624 }
00625 }
00626
00627
00628
00629
00630
00631 int JackEngine::ReleaseTimebase(int refnum)
00632 {
00633 return fEngineControl->fTransport.ResetTimebase(refnum);
00634 }
00635
00636 int JackEngine::SetTimebaseCallback(int refnum, int conditional)
00637 {
00638 return fEngineControl->fTransport.SetTimebase(refnum, conditional);
00639 }
00640
00641
00642
00643
00644
00645 void JackEngine::PrintState()
00646 {
00647 std::cout << "Engine State" << std::endl;
00648
00649 for (int i = 0; i < CLIENT_NUM; i++) {
00650 JackClientInterface* client = fClientTable[i];
00651 if (client)
00652 std::cout << "Client : " << client->GetClientControl()->fName << " : " << i << std::endl;
00653 }
00654
00655
00656 fEngineTiming->PrintState();
00657 }
00658
00659 }
00660