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