Jack2 1.9.10
|
00001 /* 00002 Copyright (C) 2004-2008 Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 00018 */ 00019 00020 #include <iostream> 00021 #include <fstream> 00022 #include <set> 00023 #include <assert.h> 00024 #include <ctype.h> 00025 00026 #include "JackSystemDeps.h" 00027 #include "JackLockedEngine.h" 00028 #include "JackExternalClient.h" 00029 #include "JackInternalClient.h" 00030 #include "JackEngineControl.h" 00031 #include "JackClientControl.h" 00032 #include "JackServerGlobals.h" 00033 #include "JackGlobals.h" 00034 #include "JackChannel.h" 00035 #include "JackError.h" 00036 00037 namespace Jack 00038 { 00039 00040 JackEngine::JackEngine(JackGraphManager* manager, 00041 JackSynchro* table, 00042 JackEngineControl* control, 00043 char self_connect_mode) 00044 : JackLockAble(control->fServerName), 00045 fSignal(control->fServerName) 00046 { 00047 fGraphManager = manager; 00048 fSynchroTable = table; 00049 fEngineControl = control; 00050 fSelfConnectMode = self_connect_mode; 00051 for (int i = 0; i < CLIENT_NUM; i++) { 00052 fClientTable[i] = NULL; 00053 } 00054 fLastSwitchUsecs = 0; 00055 fMaxUUID = 0; 00056 fSessionPendingReplies = 0; 00057 fSessionTransaction = NULL; 00058 fSessionResult = NULL; 00059 } 00060 00061 JackEngine::~JackEngine() 00062 {} 00063 00064 int JackEngine::Open() 00065 { 00066 jack_log("JackEngine::Open"); 00067 00068 // Open audio thread => request thread communication channel 00069 if (fChannel.Open(fEngineControl->fServerName) < 0) { 00070 jack_error("Cannot connect to server"); 00071 return -1; 00072 } else { 00073 return 0; 00074 } 00075 } 00076 00077 int JackEngine::Close() 00078 { 00079 jack_log("JackEngine::Close"); 00080 fChannel.Close(); 00081 00082 // Close remaining clients (RT is stopped) 00083 for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { 00084 if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) { 00085 jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName); 00086 loadable_client->Close(); 00087 fClientTable[i] = NULL; 00088 delete loadable_client; 00089 } else if (JackExternalClient* external_client = dynamic_cast<JackExternalClient*>(fClientTable[i])) { 00090 jack_log("JackEngine::Close external client = %s", external_client->GetClientControl()->fName); 00091 external_client->Close(); 00092 fClientTable[i] = NULL; 00093 delete external_client; 00094 } 00095 } 00096 00097 return 0; 00098 } 00099 00100 void JackEngine::NotifyQuit() 00101 { 00102 fChannel.NotifyQuit(); 00103 } 00104 00105 //----------------------------- 00106 // Client ressource management 00107 //----------------------------- 00108 00109 int JackEngine::AllocateRefnum() 00110 { 00111 for (int i = 0; i < CLIENT_NUM; i++) { 00112 if (!fClientTable[i]) { 00113 jack_log("JackEngine::AllocateRefNum ref = %ld", i); 00114 return i; 00115 } 00116 } 00117 return -1; 00118 } 00119 00120 void JackEngine::ReleaseRefnum(int refnum) 00121 { 00122 fClientTable[refnum] = NULL; 00123 00124 if (fEngineControl->fTemporary) { 00125 int i; 00126 for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { 00127 if (fClientTable[i]) { 00128 break; 00129 } 00130 } 00131 if (i == CLIENT_NUM) { 00132 // Last client and temporay case: quit the server 00133 jack_log("JackEngine::ReleaseRefnum server quit"); 00134 fEngineControl->fTemporary = false; 00135 throw JackTemporaryException(); 00136 } 00137 } 00138 } 00139 00140 //------------------ 00141 // Graph management 00142 //------------------ 00143 00144 void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) 00145 { 00146 fLastSwitchUsecs = cur_cycle_begin; 00147 if (fGraphManager->RunNextGraph()) { // True if the graph actually switched to a new state 00148 fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0); 00149 } 00150 fSignal.Signal(); // Signal for threads waiting for next cycle 00151 } 00152 00153 void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin) 00154 { 00155 if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) { // Signal XRun only for the first failing cycle 00156 CheckXRun(cur_cycle_begin); 00157 } 00158 fGraphManager->RunCurrentGraph(); 00159 } 00160 00161 bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) 00162 { 00163 bool res = true; 00164 00165 // Cycle begin 00166 fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end); 00167 00168 // Graph 00169 if (fGraphManager->IsFinishedGraph()) { 00170 ProcessNext(cur_cycle_begin); 00171 res = true; 00172 } else { 00173 jack_log("Process: graph not finished!"); 00174 if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) { 00175 jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs)); 00176 ProcessNext(cur_cycle_begin); 00177 res = true; 00178 } else { 00179 jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs)); 00180 ProcessCurrent(cur_cycle_begin); 00181 res = false; 00182 } 00183 } 00184 00185 // Cycle end 00186 fEngineControl->CycleEnd(fClientTable); 00187 return res; 00188 } 00189 00190 /* 00191 Client that finish *after* the callback date are considered late even if their output buffers may have been 00192 correctly mixed in the time window: callbackUsecs <==> Read <==> Write. 00193 */ 00194 00195 static const char* State2String(jack_client_state_t state) 00196 { 00197 switch (state) { 00198 case NotTriggered: 00199 return "NotTriggered"; 00200 case Triggered: 00201 return "Triggered"; 00202 case Running: 00203 return "Running"; 00204 case Finished: 00205 return "Finished"; 00206 default: 00207 return ""; 00208 } 00209 } 00210 00211 void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions de fin 00212 { 00213 for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { 00214 JackClientInterface* client = fClientTable[i]; 00215 if (client && client->GetClientControl()->fActive) { 00216 JackClientTiming* timing = fGraphManager->GetClientTiming(i); 00217 jack_client_state_t status = timing->fStatus; 00218 jack_time_t finished_date = timing->fFinishedAt; 00219 00220 if (status != NotTriggered && status != Finished) { 00221 jack_error("JackEngine::XRun: client = %s was not finished, state = %s", client->GetClientControl()->fName, State2String(status)); 00222 fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients 00223 } 00224 00225 if (status == Finished && (long)(finished_date - callback_usecs) > 0) { 00226 jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName); 00227 fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); // Notify all clients 00228 } 00229 } 00230 } 00231 } 00232 00233 int JackEngine::ComputeTotalLatencies() 00234 { 00235 std::vector<jack_int_t> sorted; 00236 std::vector<jack_int_t>::iterator it; 00237 std::vector<jack_int_t>::reverse_iterator rit; 00238 00239 fGraphManager->TopologicalSort(sorted); 00240 00241 /* iterate over all clients in graph order, and emit 00242 * capture latency callback. 00243 */ 00244 00245 for (it = sorted.begin(); it != sorted.end(); it++) { 00246 NotifyClient(*it, kLatencyCallback, true, "", 0, 0); 00247 } 00248 00249 /* now issue playback latency callbacks in reverse graph order. 00250 */ 00251 for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) { 00252 NotifyClient(*rit, kLatencyCallback, true, "", 1, 0); 00253 } 00254 00255 return 0; 00256 } 00257 00258 //--------------- 00259 // Notifications 00260 //--------------- 00261 00262 int JackEngine::ClientNotify(JackClientInterface* client, int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) 00263 { 00264 // Check if notification is needed 00265 if (!client->GetClientControl()->fCallback[notify]) { 00266 jack_log("JackEngine::ClientNotify: no callback for notification = %ld", notify); 00267 return 0; 00268 } 00269 00270 int res1; 00271 00272 // External client 00273 if (dynamic_cast<JackExternalClient*>(client)) { 00274 res1 = client->ClientNotify(refnum, name, notify, sync, message, value1, value2); 00275 // Important for internal client : unlock before calling the notification callbacks 00276 } else { 00277 bool res2 = Unlock(); 00278 res1 = client->ClientNotify(refnum, name, notify, sync, message, value1, value2); 00279 if (res2) { 00280 Lock(); 00281 } 00282 } 00283 00284 if (res1 < 0) { 00285 jack_error("ClientNotify fails name = %s notification = %ld val1 = %ld val2 = %ld", name, notify, value1, value2); 00286 } 00287 return res1; 00288 } 00289 00290 void JackEngine::NotifyClient(int refnum, int event, int sync, const char* message, int value1, int value2) 00291 { 00292 JackClientInterface* client = fClientTable[refnum]; 00293 if (client) { 00294 ClientNotify(client, refnum, client->GetClientControl()->fName, event, sync, message, value1, value2); 00295 } 00296 } 00297 00298 void JackEngine::NotifyClients(int event, int sync, const char* message, int value1, int value2) 00299 { 00300 for (int i = 0; i < CLIENT_NUM; i++) { 00301 NotifyClient(i, event, sync, message, value1, value2); 00302 } 00303 } 00304 00305 int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* new_name, int refnum) 00306 { 00307 jack_log("JackEngine::NotifyAddClient: name = %s", new_name); 00308 00309 // Notify existing clients of the new client and new client of existing clients. 00310 for (int i = 0; i < CLIENT_NUM; i++) { 00311 JackClientInterface* old_client = fClientTable[i]; 00312 if (old_client && old_client != new_client) { 00313 char* old_name = old_client->GetClientControl()->fName; 00314 if (ClientNotify(old_client, refnum, new_name, kAddClient, false, "", 0, 0) < 0) { 00315 jack_error("NotifyAddClient old_client fails name = %s", old_name); 00316 // Not considered as a failure... 00317 } 00318 if (ClientNotify(new_client, i, old_name, kAddClient, true, "", 0, 0) < 0) { 00319 jack_error("NotifyAddClient new_client fails name = %s", new_name); 00320 return -1; 00321 } 00322 } 00323 } 00324 00325 return 0; 00326 } 00327 00328 void JackEngine::NotifyRemoveClient(const char* name, int refnum) 00329 { 00330 // Notify existing clients (including the one beeing suppressed) of the removed client 00331 for (int i = 0; i < CLIENT_NUM; i++) { 00332 JackClientInterface* client = fClientTable[i]; 00333 if (client) { 00334 ClientNotify(client, refnum, name, kRemoveClient, false, "", 0, 0); 00335 } 00336 } 00337 } 00338 00339 // Coming from the driver 00340 void JackEngine::NotifyDriverXRun() 00341 { 00342 // Use the audio thread => request thread communication channel 00343 fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0); 00344 } 00345 00346 void JackEngine::NotifyClientXRun(int refnum) 00347 { 00348 if (refnum == ALL_CLIENTS) { 00349 NotifyClients(kXRunCallback, false, "", 0, 0); 00350 } else { 00351 NotifyClient(refnum, kXRunCallback, false, "", 0, 0); 00352 } 00353 } 00354 00355 void JackEngine::NotifyGraphReorder() 00356 { 00357 ComputeTotalLatencies(); 00358 NotifyClients(kGraphOrderCallback, false, "", 0, 0); 00359 } 00360 00361 void JackEngine::NotifyBufferSize(jack_nframes_t buffer_size) 00362 { 00363 NotifyClients(kBufferSizeCallback, true, "", buffer_size, 0); 00364 } 00365 00366 void JackEngine::NotifySampleRate(jack_nframes_t sample_rate) 00367 { 00368 NotifyClients(kSampleRateCallback, true, "", sample_rate, 0); 00369 } 00370 00371 void JackEngine::NotifyFailure(int code, const char* reason) 00372 { 00373 NotifyClients(kShutDownCallback, false, reason, code, 0); 00374 } 00375 00376 void JackEngine::NotifyFreewheel(bool onoff) 00377 { 00378 if (onoff) { 00379 // Save RT state 00380 fEngineControl->fSavedRealTime = fEngineControl->fRealTime; 00381 fEngineControl->fRealTime = false; 00382 } else { 00383 // Restore RT state 00384 fEngineControl->fRealTime = fEngineControl->fSavedRealTime; 00385 fEngineControl->fSavedRealTime = false; 00386 } 00387 NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, "", 0, 0); 00388 } 00389 00390 void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff) 00391 { 00392 NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, "", port_index, 0); 00393 } 00394 00395 void JackEngine::NotifyPortRename(jack_port_id_t port, const char* old_name) 00396 { 00397 NotifyClients(kPortRenameCallback, false, old_name, port, 0); 00398 } 00399 00400 void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff) 00401 { 00402 NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, "", src, dst); 00403 } 00404 00405 void JackEngine::NotifyActivate(int refnum) 00406 { 00407 NotifyClient(refnum, kActivateClient, true, "", 0, 0); 00408 } 00409 00410 //---------------------------- 00411 // Loadable client management 00412 //---------------------------- 00413 00414 int JackEngine::GetInternalClientName(int refnum, char* name_res) 00415 { 00416 JackClientInterface* client = fClientTable[refnum]; 00417 assert(client); 00418 strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE); 00419 return 0; 00420 } 00421 00422 int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref) 00423 { 00424 // Clear status 00425 *status = 0; 00426 00427 for (int i = 0; i < CLIENT_NUM; i++) { 00428 JackClientInterface* client = fClientTable[i]; 00429 if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) { 00430 jack_log("InternalClientHandle found client name = %s ref = %ld", client_name, i); 00431 *int_ref = i; 00432 return 0; 00433 } 00434 } 00435 00436 *status |= (JackNoSuchClient | JackFailure); 00437 return -1; 00438 } 00439 00440 int JackEngine::InternalClientUnload(int refnum, int* status) 00441 { 00442 JackClientInterface* client = fClientTable[refnum]; 00443 if (client) { 00444 int res = client->Close(); 00445 delete client; 00446 *status = 0; 00447 return res; 00448 } else { 00449 *status = (JackNoSuchClient | JackFailure); 00450 return -1; 00451 } 00452 } 00453 00454 //------------------- 00455 // Client management 00456 //------------------- 00457 00458 int JackEngine::ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status) 00459 { 00460 // Clear status 00461 *status = 0; 00462 strcpy(name_res, name); 00463 00464 jack_log("Check protocol client = %ld server = %ld", protocol, JACK_PROTOCOL_VERSION); 00465 00466 if (protocol != JACK_PROTOCOL_VERSION) { 00467 *status |= (JackFailure | JackVersionError); 00468 jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION); 00469 return -1; 00470 } 00471 00472 std::map<int,std::string>::iterator res = fReservationMap.find(uuid); 00473 00474 if (res != fReservationMap.end()) { 00475 strncpy(name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE); 00476 } else if (ClientCheckName(name)) { 00477 00478 *status |= JackNameNotUnique; 00479 00480 if (options & JackUseExactName) { 00481 jack_error("cannot create new client; %s already exists", name); 00482 *status |= JackFailure; 00483 return -1; 00484 } 00485 00486 if (GenerateUniqueName(name_res)) { 00487 *status |= JackFailure; 00488 return -1; 00489 } 00490 } 00491 00492 return 0; 00493 } 00494 00495 bool JackEngine::GenerateUniqueName(char* name) 00496 { 00497 int tens, ones; 00498 int length = strlen(name); 00499 00500 if (length > JACK_CLIENT_NAME_SIZE - 4) { 00501 jack_error("%s exists and is too long to make unique", name); 00502 return true; /* failure */ 00503 } 00504 00505 /* generate a unique name by appending "-01".."-99" */ 00506 name[length++] = '-'; 00507 tens = length++; 00508 ones = length++; 00509 name[tens] = '0'; 00510 name[ones] = '1'; 00511 name[length] = '\0'; 00512 00513 while (ClientCheckName(name)) { 00514 if (name[ones] == '9') { 00515 if (name[tens] == '9') { 00516 jack_error("client %s has 99 extra instances already", name); 00517 return true; /* give up */ 00518 } 00519 name[tens]++; 00520 name[ones] = '0'; 00521 } else { 00522 name[ones]++; 00523 } 00524 } 00525 return false; 00526 } 00527 00528 bool JackEngine::ClientCheckName(const char* name) 00529 { 00530 for (int i = 0; i < CLIENT_NUM; i++) { 00531 JackClientInterface* client = fClientTable[i]; 00532 if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { 00533 return true; 00534 } 00535 } 00536 00537 for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) { 00538 if (i->second == name) { 00539 return true; 00540 } 00541 } 00542 00543 return false; 00544 } 00545 00546 int JackEngine::GetNewUUID() 00547 { 00548 return fMaxUUID++; 00549 } 00550 00551 void JackEngine::EnsureUUID(int uuid) 00552 { 00553 if (uuid > fMaxUUID) { 00554 fMaxUUID = uuid + 1; 00555 } 00556 00557 for (int i = 0; i < CLIENT_NUM; i++) { 00558 JackClientInterface* client = fClientTable[i]; 00559 if (client && (client->GetClientControl()->fSessionID == uuid)) { 00560 client->GetClientControl()->fSessionID = GetNewUUID(); 00561 } 00562 } 00563 } 00564 00565 int JackEngine::GetClientPID(const char* name) 00566 { 00567 for (int i = 0; i < CLIENT_NUM; i++) { 00568 JackClientInterface* client = fClientTable[i]; 00569 if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { 00570 return client->GetClientControl()->fPID; 00571 } 00572 } 00573 00574 return 0; 00575 } 00576 00577 int JackEngine::GetClientRefNum(const char* name) 00578 { 00579 for (int i = 0; i < CLIENT_NUM; i++) { 00580 JackClientInterface* client = fClientTable[i]; 00581 if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { 00582 return client->GetClientControl()->fRefNum; 00583 } 00584 } 00585 00586 return -1; 00587 } 00588 00589 // Used for external clients 00590 int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager) 00591 { 00592 char real_name[JACK_CLIENT_NAME_SIZE + 1]; 00593 00594 if (uuid < 0) { 00595 uuid = GetNewUUID(); 00596 strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); 00597 } else { 00598 std::map<int, std::string>::iterator res = fReservationMap.find(uuid); 00599 if (res != fReservationMap.end()) { 00600 strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE); 00601 fReservationMap.erase(uuid); 00602 } else { 00603 strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); 00604 } 00605 EnsureUUID(uuid); 00606 } 00607 00608 jack_log("JackEngine::ClientExternalOpen: uuid = %d, name = %s", uuid, real_name); 00609 00610 int refnum = AllocateRefnum(); 00611 if (refnum < 0) { 00612 jack_error("No more refnum available"); 00613 return -1; 00614 } 00615 00616 JackExternalClient* client = new JackExternalClient(); 00617 00618 if (!fSynchroTable[refnum].Allocate(real_name, fEngineControl->fServerName, 0)) { 00619 jack_error("Cannot allocate synchro"); 00620 goto error; 00621 } 00622 00623 if (client->Open(real_name, pid, refnum, uuid, shared_client) < 0) { 00624 jack_error("Cannot open client"); 00625 goto error; 00626 } 00627 00628 if (!fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) { 00629 // Failure if RT thread is not running (problem with the driver...) 00630 jack_error("Driver is not running"); 00631 goto error; 00632 } 00633 00634 fClientTable[refnum] = client; 00635 00636 if (NotifyAddClient(client, real_name, refnum) < 0) { 00637 jack_error("Cannot notify add client"); 00638 goto error; 00639 } 00640 00641 fGraphManager->InitRefNum(refnum); 00642 fEngineControl->ResetRollingUsecs(); 00643 *shared_engine = fEngineControl->GetShmIndex(); 00644 *shared_graph_manager = fGraphManager->GetShmIndex(); 00645 *ref = refnum; 00646 return 0; 00647 00648 error: 00649 // Cleanup... 00650 fSynchroTable[refnum].Destroy(); 00651 fClientTable[refnum] = 0; 00652 client->Close(); 00653 delete client; 00654 return -1; 00655 } 00656 00657 // Used for server driver clients 00658 int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait) 00659 { 00660 jack_log("JackEngine::ClientInternalOpen: name = %s", name); 00661 00662 int refnum = AllocateRefnum(); 00663 if (refnum < 0) { 00664 jack_error("No more refnum available"); 00665 goto error; 00666 } 00667 00668 if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) { 00669 jack_error("Cannot allocate synchro"); 00670 goto error; 00671 } 00672 00673 if (wait && !fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) { 00674 // Failure if RT thread is not running (problem with the driver...) 00675 jack_error("Driver is not running"); 00676 goto error; 00677 } 00678 00679 fClientTable[refnum] = client; 00680 00681 if (NotifyAddClient(client, name, refnum) < 0) { 00682 jack_error("Cannot notify add client"); 00683 goto error; 00684 } 00685 00686 fGraphManager->InitRefNum(refnum); 00687 fEngineControl->ResetRollingUsecs(); 00688 *shared_engine = fEngineControl; 00689 *shared_manager = fGraphManager; 00690 *ref = refnum; 00691 return 0; 00692 00693 error: 00694 // Cleanup... 00695 fSynchroTable[refnum].Destroy(); 00696 fClientTable[refnum] = 0; 00697 return -1; 00698 } 00699 00700 // Used for external clients 00701 int JackEngine::ClientExternalClose(int refnum) 00702 { 00703 jack_log("JackEngine::ClientExternalClose ref = %ld", refnum); 00704 JackClientInterface* client = fClientTable[refnum]; 00705 assert(client); 00706 int res = ClientCloseAux(refnum, true); 00707 client->Close(); 00708 delete client; 00709 return res; 00710 } 00711 00712 // Used for server internal clients or drivers when the RT thread is stopped 00713 int JackEngine::ClientInternalClose(int refnum, bool wait) 00714 { 00715 jack_log("JackEngine::ClientInternalClose ref = %ld", refnum); 00716 return ClientCloseAux(refnum, wait); 00717 } 00718 00719 int JackEngine::ClientCloseAux(int refnum, bool wait) 00720 { 00721 jack_log("JackEngine::ClientCloseAux ref = %ld", refnum); 00722 00723 JackClientInterface* client = fClientTable[refnum]; 00724 fEngineControl->fTransport.ResetTimebase(refnum); 00725 00726 // Unregister all ports ==> notifications are sent 00727 jack_int_t ports[PORT_NUM_FOR_CLIENT]; 00728 int i; 00729 00730 fGraphManager->GetInputPorts(refnum, ports); 00731 for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY); i++) { 00732 PortUnRegister(refnum, ports[i]); 00733 } 00734 00735 fGraphManager->GetOutputPorts(refnum, ports); 00736 for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY); i++) { 00737 PortUnRegister(refnum, ports[i]); 00738 } 00739 00740 // Remove the client from the table 00741 ReleaseRefnum(refnum); 00742 00743 // Remove all ports 00744 fGraphManager->RemoveAllPorts(refnum); 00745 00746 // Wait until next cycle to be sure client is not used anymore 00747 if (wait) { 00748 if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure 00749 jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum); 00750 } 00751 } 00752 00753 // Notify running clients 00754 NotifyRemoveClient(client->GetClientControl()->fName, refnum); 00755 00756 // Cleanup... 00757 fSynchroTable[refnum].Destroy(); 00758 fEngineControl->ResetRollingUsecs(); 00759 return 0; 00760 } 00761 00762 int JackEngine::ClientActivate(int refnum, bool is_real_time) 00763 { 00764 JackClientInterface* client = fClientTable[refnum]; 00765 jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); 00766 00767 if (is_real_time) { 00768 fGraphManager->Activate(refnum); 00769 } 00770 00771 // Wait for graph state change to be effective 00772 if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) { 00773 jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName); 00774 return -1; 00775 } else { 00776 jack_int_t input_ports[PORT_NUM_FOR_CLIENT]; 00777 jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; 00778 fGraphManager->GetInputPorts(refnum, input_ports); 00779 fGraphManager->GetOutputPorts(refnum, output_ports); 00780 00781 // Notify client 00782 NotifyActivate(refnum); 00783 00784 // Then issue port registration notification 00785 for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { 00786 NotifyPortRegistation(input_ports[i], true); 00787 } 00788 for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { 00789 NotifyPortRegistation(output_ports[i], true); 00790 } 00791 00792 return 0; 00793 } 00794 } 00795 00796 // May be called without client 00797 int JackEngine::ClientDeactivate(int refnum) 00798 { 00799 JackClientInterface* client = fClientTable[refnum]; 00800 jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); 00801 00802 jack_int_t input_ports[PORT_NUM_FOR_CLIENT]; 00803 jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; 00804 fGraphManager->GetInputPorts(refnum, input_ports); 00805 fGraphManager->GetOutputPorts(refnum, output_ports); 00806 00807 // First disconnect all ports 00808 for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { 00809 PortDisconnect(-1, input_ports[i], ALL_PORTS); 00810 } 00811 for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { 00812 PortDisconnect(-1, output_ports[i], ALL_PORTS); 00813 } 00814 00815 // Then issue port registration notification 00816 for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { 00817 NotifyPortRegistation(input_ports[i], false); 00818 } 00819 for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { 00820 NotifyPortRegistation(output_ports[i], false); 00821 } 00822 00823 fGraphManager->Deactivate(refnum); 00824 fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients 00825 00826 // Wait for graph state change to be effective 00827 if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) { 00828 jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName); 00829 return -1; 00830 } else { 00831 return 0; 00832 } 00833 } 00834 00835 void JackEngine::ClientKill(int refnum) 00836 { 00837 jack_log("JackEngine::ClientKill ref = %ld", refnum); 00838 if (ClientDeactivate(refnum) < 0) { 00839 jack_error("JackEngine::ClientKill ref = %ld cannot be removed from the graph !!", refnum); 00840 } 00841 if (ClientExternalClose(refnum) < 0) { 00842 jack_error("JackEngine::ClientKill ref = %ld cannot be closed", refnum); 00843 } 00844 } 00845 00846 //----------------- 00847 // Port management 00848 //----------------- 00849 00850 int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index) 00851 { 00852 jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size); 00853 JackClientInterface* client = fClientTable[refnum]; 00854 00855 // Check if port name already exists 00856 if (fGraphManager->GetPort(name) != NO_PORT) { 00857 jack_error("port_name \"%s\" already exists", name); 00858 return -1; 00859 } 00860 00861 // buffer_size is actually ignored... 00862 *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize); 00863 if (*port_index != NO_PORT) { 00864 if (client->GetClientControl()->fActive) { 00865 NotifyPortRegistation(*port_index, true); 00866 } 00867 return 0; 00868 } else { 00869 return -1; 00870 } 00871 } 00872 00873 int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index) 00874 { 00875 jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index); 00876 JackClientInterface* client = fClientTable[refnum]; 00877 assert(client); 00878 00879 // Disconnect port ==> notification is sent 00880 PortDisconnect(-1, port_index, ALL_PORTS); 00881 00882 if (fGraphManager->ReleasePort(refnum, port_index) == 0) { 00883 if (client->GetClientControl()->fActive) { 00884 NotifyPortRegistation(port_index, false); 00885 } 00886 return 0; 00887 } else { 00888 return -1; 00889 } 00890 } 00891 00892 // this check is to prevent apps to self connect to other apps 00893 // TODO: make this work with multiple clients per app 00894 int JackEngine::CheckPortsConnect(int refnum, jack_port_id_t src, jack_port_id_t dst) 00895 { 00896 if (fSelfConnectMode == ' ') return 1; 00897 00898 JackPort* src_port = fGraphManager->GetPort(src); 00899 JackPort* dst_port = fGraphManager->GetPort(dst); 00900 00901 jack_log("JackEngine::CheckPortsConnect(ref = %d, src = %d, dst = %d)", refnum, src_port->GetRefNum(), dst_port->GetRefNum()); 00902 00903 //jack_log("%s -> %s", src_port->GetName(), dst_port->GetName()); 00904 //jack_log("mode = '%c'", fSelfConnectMode); 00905 00906 int src_self = src_port->GetRefNum() == refnum ? 1 : 0; 00907 int dst_self = dst_port->GetRefNum() == refnum ? 1 : 0; 00908 00909 //jack_log("src_self is %s", src_self ? "true" : "false"); 00910 //jack_log("dst_self is %s", dst_self ? "true" : "false"); 00911 00912 // 0 means client is connecting other client ports (control app patchbay functionality) 00913 // 1 means client is connecting its own port to port of other client (e.g. self connecting into "system" client) 00914 // 2 means client is connecting its own ports (for app internal functionality) 00915 int sum = src_self + dst_self; 00916 //jack_log("sum = %d", sum); 00917 if (sum == 0) return 1; 00918 char lmode = tolower(fSelfConnectMode); 00919 //jack_log("lmode = '%c'", lmode); 00920 if (sum == 2 && lmode == 'e') return 1; 00921 bool fail = lmode != fSelfConnectMode; // fail modes are upper case 00922 //jack_log("fail = %d", (int)fail); 00923 00924 jack_info( 00925 "%s port self connect request%s (%s -> %s)", 00926 fail ? "rejecting" : "ignoring", 00927 sum == 1 ? " to external port" : "", 00928 src_port->GetName(), 00929 dst_port->GetName()); 00930 00931 return fail ? -1 : 0; 00932 } 00933 00934 int JackEngine::PortConnect(int refnum, const char* src, const char* dst) 00935 { 00936 jack_log("JackEngine::PortConnect ref = %d src = %s dst = %s", refnum, src, dst); 00937 jack_port_id_t port_src, port_dst; 00938 00939 return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0) 00940 ? -1 00941 : PortConnect(refnum, port_src, port_dst); 00942 } 00943 00944 int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst) 00945 { 00946 jack_log("JackEngine::PortConnect ref = %d src = %d dst = %d", refnum, src, dst); 00947 JackClientInterface* client; 00948 int ref; 00949 00950 if (fGraphManager->CheckPorts(src, dst) < 0) { 00951 return -1; 00952 } 00953 00954 ref = fGraphManager->GetOutputRefNum(src); 00955 assert(ref >= 0); 00956 client = fClientTable[ref]; 00957 assert(client); 00958 if (!client->GetClientControl()->fActive) { 00959 jack_error("Cannot connect ports owned by inactive clients:" 00960 " \"%s\" is not active", client->GetClientControl()->fName); 00961 return -1; 00962 } 00963 00964 ref = fGraphManager->GetInputRefNum(dst); 00965 assert(ref >= 0); 00966 client = fClientTable[ref]; 00967 assert(client); 00968 if (!client->GetClientControl()->fActive) { 00969 jack_error("Cannot connect ports owned by inactive clients:" 00970 " \"%s\" is not active", client->GetClientControl()->fName); 00971 return -1; 00972 } 00973 00974 int res = CheckPortsConnect(refnum, src, dst); 00975 if (res != 1) { 00976 return res; 00977 } 00978 00979 res = fGraphManager->Connect(src, dst); 00980 if (res == 0) { 00981 NotifyPortConnect(src, dst, true); 00982 } 00983 return res; 00984 } 00985 00986 int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst) 00987 { 00988 jack_log("JackEngine::PortDisconnect ref = %d src = %s dst = %s", refnum, src, dst); 00989 jack_port_id_t port_src, port_dst; 00990 00991 return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0) 00992 ? -1 00993 : PortDisconnect(refnum, port_src, port_dst); 00994 } 00995 00996 int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst) 00997 { 00998 jack_log("JackEngine::PortDisconnect ref = %d src = %d dst = %d", refnum, src, dst); 00999 01000 if (dst == ALL_PORTS) { 01001 01002 jack_int_t connections[CONNECTION_NUM_FOR_PORT]; 01003 fGraphManager->GetConnections(src, connections); 01004 01005 JackPort* port = fGraphManager->GetPort(src); 01006 int res = 0; 01007 if (port->GetFlags() & JackPortIsOutput) { 01008 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) { 01009 if (PortDisconnect(refnum, src, connections[i]) != 0) { 01010 res = -1; 01011 } 01012 } 01013 } else { 01014 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) { 01015 if (PortDisconnect(refnum, connections[i], src) != 0) { 01016 res = -1; 01017 } 01018 } 01019 } 01020 01021 return res; 01022 } 01023 01024 if (fGraphManager->CheckPorts(src, dst) < 0) { 01025 return -1; 01026 } 01027 01028 int res = CheckPortsConnect(refnum, src, dst); 01029 if (res != 1) { 01030 return res; 01031 } 01032 01033 res = fGraphManager->Disconnect(src, dst); 01034 if (res == 0) 01035 NotifyPortConnect(src, dst, false); 01036 return res; 01037 } 01038 01039 int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name) 01040 { 01041 char old_name[REAL_JACK_PORT_NAME_SIZE]; 01042 strcpy(old_name, fGraphManager->GetPort(port)->GetName()); 01043 fGraphManager->GetPort(port)->SetName(name); 01044 NotifyPortRename(port, old_name); 01045 return 0; 01046 } 01047 01048 //-------------------- 01049 // Session management 01050 //-------------------- 01051 01052 void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, detail::JackChannelTransactionInterface *socket, JackSessionNotifyResult** result) 01053 { 01054 if (fSessionPendingReplies != 0) { 01055 JackSessionNotifyResult res(-1); 01056 res.Write(socket); 01057 jack_log("JackEngine::SessionNotify ... busy"); 01058 if (result != NULL) *result = NULL; 01059 return; 01060 } 01061 01062 for (int i = 0; i < CLIENT_NUM; i++) { 01063 JackClientInterface* client = fClientTable[i]; 01064 if (client && (client->GetClientControl()->fSessionID < 0)) { 01065 client->GetClientControl()->fSessionID = GetNewUUID(); 01066 } 01067 } 01068 fSessionResult = new JackSessionNotifyResult(); 01069 01070 for (int i = 0; i < CLIENT_NUM; i++) { 01071 JackClientInterface* client = fClientTable[i]; 01072 if (client && client->GetClientControl()->fCallback[kSessionCallback]) { 01073 01074 // check if this is a notification to a specific client. 01075 if (target != NULL && strlen(target) != 0) { 01076 if (strcmp(target, client->GetClientControl()->fName)) { 01077 continue; 01078 } 01079 } 01080 01081 char path_buf[JACK_PORT_NAME_SIZE]; 01082 if (path[strlen(path) - 1] == DIR_SEPARATOR) { 01083 snprintf(path_buf, sizeof path_buf, "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR); 01084 } else { 01085 snprintf(path_buf, sizeof path_buf, "%s%c%s%c", path, DIR_SEPARATOR, client->GetClientControl()->fName, DIR_SEPARATOR); 01086 } 01087 01088 int res = JackTools::MkDir(path_buf); 01089 if (res) jack_error("JackEngine::SessionNotify: can not create session directory '%s'", path_buf); 01090 01091 int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int)type, 0); 01092 01093 if (result == kPendingSessionReply) { 01094 fSessionPendingReplies += 1; 01095 } else if (result == kImmediateSessionReply) { 01096 char uuid_buf[JACK_UUID_SIZE]; 01097 snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID); 01098 fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf, 01099 client->GetClientControl()->fName, 01100 client->GetClientControl()->fSessionCommand, 01101 client->GetClientControl()->fSessionFlags)); 01102 } 01103 } 01104 } 01105 01106 if (result != NULL) *result = fSessionResult; 01107 01108 if (fSessionPendingReplies == 0) { 01109 fSessionResult->Write(socket); 01110 if (result == NULL) delete fSessionResult; 01111 fSessionResult = NULL; 01112 } else { 01113 fSessionTransaction = socket; 01114 } 01115 } 01116 01117 int JackEngine::SessionReply(int refnum) 01118 { 01119 JackClientInterface* client = fClientTable[refnum]; 01120 assert(client); 01121 char uuid_buf[JACK_UUID_SIZE]; 01122 snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID); 01123 fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf, 01124 client->GetClientControl()->fName, 01125 client->GetClientControl()->fSessionCommand, 01126 client->GetClientControl()->fSessionFlags)); 01127 fSessionPendingReplies -= 1; 01128 01129 if (fSessionPendingReplies == 0) { 01130 fSessionResult->Write(fSessionTransaction); 01131 if (fSessionTransaction != NULL) { 01132 delete fSessionResult; 01133 } 01134 fSessionResult = NULL; 01135 } 01136 01137 return 0; 01138 } 01139 01140 int JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res) 01141 { 01142 for (int i = 0; i < CLIENT_NUM; i++) { 01143 JackClientInterface* client = fClientTable[i]; 01144 01145 if (client && (strcmp(client_name, client->GetClientControl()->fName) == 0)) { 01146 snprintf(uuid_res, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID); 01147 return 0; 01148 } 01149 } 01150 // Did not find name. 01151 return -1; 01152 } 01153 01154 int JackEngine::GetClientNameForUUID(const char *uuid, char *name_res) 01155 { 01156 for (int i = 0; i < CLIENT_NUM; i++) { 01157 JackClientInterface* client = fClientTable[i]; 01158 01159 if (!client) { 01160 continue; 01161 } 01162 01163 char uuid_buf[JACK_UUID_SIZE]; 01164 snprintf(uuid_buf, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID); 01165 01166 if (strcmp(uuid,uuid_buf) == 0) { 01167 strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE); 01168 return 0; 01169 } 01170 } 01171 // Did not find uuid. 01172 return -1; 01173 } 01174 01175 int JackEngine::ReserveClientName(const char *name, const char *uuid) 01176 { 01177 jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid); 01178 01179 if (ClientCheckName(name)) { 01180 jack_log("name already taken"); 01181 return -1; 01182 } 01183 01184 EnsureUUID(atoi(uuid)); 01185 fReservationMap[atoi(uuid)] = name; 01186 return 0; 01187 } 01188 01189 int JackEngine::ClientHasSessionCallback(const char *name) 01190 { 01191 JackClientInterface* client = NULL; 01192 for (int i = 0; i < CLIENT_NUM; i++) { 01193 client = fClientTable[i]; 01194 if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { 01195 break; 01196 } 01197 } 01198 01199 if (client) { 01200 return client->GetClientControl()->fCallback[kSessionCallback]; 01201 } else { 01202 return -1; 01203 } 01204 } 01205 01206 } // end of namespace 01207