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