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