Jack2
1.9.7
|
00001 /* 00002 Copyright (C) 2001 Paul Davis 00003 Copyright (C) 2004-2008 Grame 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU Lesser General Public License as published by 00007 the Free Software Foundation; either version 2.1 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 00019 */ 00020 00021 #include "JackGraphManager.h" 00022 #include "JackConstants.h" 00023 #include "JackError.h" 00024 #include <assert.h> 00025 #include <stdlib.h> 00026 #include <algorithm> 00027 #include <regex.h> 00028 00029 namespace Jack 00030 { 00031 00032 00033 static void AssertBufferSize(jack_nframes_t buffer_size) 00034 { 00035 if (buffer_size > BUFFER_SIZE_MAX) { 00036 jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size); 00037 assert(buffer_size <= BUFFER_SIZE_MAX); 00038 } 00039 } 00040 00041 void JackGraphManager::AssertPort(jack_port_id_t port_index) 00042 { 00043 if (port_index >= fPortMax) { 00044 jack_log("JackGraphManager::AssertPort port_index = %ld", port_index); 00045 assert(port_index < fPortMax); 00046 } 00047 } 00048 00049 JackGraphManager* JackGraphManager::Allocate(int port_max) 00050 { 00051 // Using "Placement" new 00052 void* shared_ptr = JackShmMem::operator new(sizeof(JackGraphManager) + port_max * sizeof(JackPort)); 00053 return new(shared_ptr) JackGraphManager(port_max); 00054 } 00055 00056 void JackGraphManager::Destroy(JackGraphManager* manager) 00057 { 00058 // "Placement" new was used 00059 manager->~JackGraphManager(); 00060 JackShmMem::operator delete(manager); 00061 } 00062 00063 JackGraphManager::JackGraphManager(int port_max) 00064 { 00065 assert(port_max <= PORT_NUM_MAX); 00066 00067 for (int i = 0; i < port_max; i++) { 00068 fPortArray[i].Release(); 00069 } 00070 00071 fPortMax = port_max; 00072 } 00073 00074 JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) 00075 { 00076 AssertPort(port_index); 00077 return &fPortArray[port_index]; 00078 } 00079 00080 jack_default_audio_sample_t* JackGraphManager::GetBuffer(jack_port_id_t port_index) 00081 { 00082 return fPortArray[port_index].GetBuffer(); 00083 } 00084 00085 // Server 00086 void JackGraphManager::InitRefNum(int refnum) 00087 { 00088 JackConnectionManager* manager = WriteNextStateStart(); 00089 manager->InitRefNum(refnum); 00090 WriteNextStateStop(); 00091 } 00092 00093 // RT 00094 void JackGraphManager::RunCurrentGraph() 00095 { 00096 JackConnectionManager* manager = ReadCurrentState(); 00097 manager->ResetGraph(fClientTiming); 00098 } 00099 00100 // RT 00101 bool JackGraphManager::RunNextGraph() 00102 { 00103 bool res; 00104 JackConnectionManager* manager = TrySwitchState(&res); 00105 manager->ResetGraph(fClientTiming); 00106 return res; 00107 } 00108 00109 // RT 00110 bool JackGraphManager::IsFinishedGraph() 00111 { 00112 JackConnectionManager* manager = ReadCurrentState(); 00113 return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0); 00114 } 00115 00116 // RT 00117 int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro* table) 00118 { 00119 JackConnectionManager* manager = ReadCurrentState(); 00120 return manager->ResumeRefNum(control, table, fClientTiming); 00121 } 00122 00123 // RT 00124 int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, long usec) 00125 { 00126 JackConnectionManager* manager = ReadCurrentState(); 00127 return manager->SuspendRefNum(control, table, fClientTiming, usec); 00128 } 00129 00130 void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& sorted) 00131 { 00132 UInt16 cur_index; 00133 UInt16 next_index; 00134 00135 do { 00136 cur_index = GetCurrentIndex(); 00137 sorted.clear(); 00138 ReadCurrentState()->TopologicalSort(sorted); 00139 next_index = GetCurrentIndex(); 00140 } while (cur_index != next_index); // Until a coherent state has been read 00141 } 00142 00143 // Server 00144 void JackGraphManager::DirectConnect(int ref1, int ref2) 00145 { 00146 JackConnectionManager* manager = WriteNextStateStart(); 00147 manager->DirectConnect(ref1, ref2); 00148 jack_log("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2); 00149 WriteNextStateStop(); 00150 } 00151 00152 // Server 00153 void JackGraphManager::DirectDisconnect(int ref1, int ref2) 00154 { 00155 JackConnectionManager* manager = WriteNextStateStart(); 00156 manager->DirectDisconnect(ref1, ref2); 00157 jack_log("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2); 00158 WriteNextStateStop(); 00159 } 00160 00161 // Server 00162 bool JackGraphManager::IsDirectConnection(int ref1, int ref2) 00163 { 00164 JackConnectionManager* manager = ReadCurrentState(); 00165 return manager->IsDirectConnection(ref1, ref2); 00166 } 00167 00168 // RT 00169 void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buffer_size) 00170 { 00171 AssertPort(port_index); 00172 AssertBufferSize(buffer_size); 00173 00174 JackConnectionManager* manager = ReadCurrentState(); 00175 JackPort* port = GetPort(port_index); 00176 00177 // This happens when a port has just been unregistered and is still used by the RT code 00178 if (!port->IsUsed()) { 00179 jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index); 00180 return GetBuffer(0); // port_index 0 is not used 00181 } 00182 00183 // Output port 00184 if (port->fFlags & JackPortIsOutput) { 00185 return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, buffer_size) : GetBuffer(port_index); 00186 } 00187 00188 // Input port 00189 jack_int_t len = manager->Connections(port_index); 00190 00191 // No connections : return a zero-filled buffer 00192 if (len == 0) { 00193 port->ClearBuffer(buffer_size); 00194 return port->GetBuffer(); 00195 00196 // One connection 00197 } else if (len == 1) { 00198 jack_port_id_t src_index = manager->GetPort(port_index, 0); 00199 00200 // Ports in same client : copy the buffer 00201 if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) { 00202 void* buffers[1]; 00203 buffers[0] = GetBuffer(src_index, buffer_size); 00204 port->MixBuffers(buffers, 1, buffer_size); 00205 return port->GetBuffer(); 00206 // Otherwise, use zero-copy mode, just pass the buffer of the connected (output) port. 00207 } else { 00208 return GetBuffer(src_index, buffer_size); 00209 } 00210 00211 // Multiple connections : mix all buffers 00212 } else { 00213 00214 const jack_int_t* connections = manager->GetConnections(port_index); 00215 void* buffers[CONNECTION_NUM_FOR_PORT]; 00216 jack_port_id_t src_index; 00217 int i; 00218 00219 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) { 00220 AssertPort(src_index); 00221 buffers[i] = GetBuffer(src_index, buffer_size); 00222 } 00223 00224 port->MixBuffers(buffers, i, buffer_size); 00225 return port->GetBuffer(); 00226 } 00227 } 00228 00229 // Server 00230 int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client 00231 { 00232 AssertPort(port_index); 00233 JackPort* port = GetPort(port_index); 00234 00244 port->RequestMonitor(onoff); 00245 00246 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); 00247 if ((port->fFlags & JackPortIsOutput) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ? 00248 jack_port_id_t src_index; 00249 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) { 00250 // XXX much worse things will happen if there is a feedback loop !!! 00251 RequestMonitor(src_index, onoff); 00252 } 00253 } 00254 00255 return 0; 00256 } 00257 00258 // Client 00259 jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count) 00260 { 00261 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); 00262 jack_nframes_t max_latency = 0; 00263 jack_port_id_t dst_index; 00264 00265 if (hop_count > 8) 00266 return GetPort(port_index)->GetLatency(); 00267 00268 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) { 00269 if (src_port_index != dst_index) { 00270 AssertPort(dst_index); 00271 JackPort* dst_port = GetPort(dst_index); 00272 jack_nframes_t this_latency = (dst_port->fFlags & JackPortIsTerminal) 00273 ? dst_port->GetLatency() 00274 : ComputeTotalLatencyAux(dst_index, port_index, manager, hop_count + 1); 00275 max_latency = ((max_latency > this_latency) ? max_latency : this_latency); 00276 } 00277 } 00278 00279 return max_latency + GetPort(port_index)->GetLatency(); 00280 } 00281 00282 // Client 00283 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index) 00284 { 00285 UInt16 cur_index; 00286 UInt16 next_index; 00287 JackPort* port = GetPort(port_index); 00288 AssertPort(port_index); 00289 00290 do { 00291 cur_index = GetCurrentIndex(); 00292 port->fTotalLatency = ComputeTotalLatencyAux(port_index, port_index, ReadCurrentState(), 0); 00293 next_index = GetCurrentIndex(); 00294 } while (cur_index != next_index); // Until a coherent state has been read 00295 00296 jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index, port->fTotalLatency); 00297 return 0; 00298 } 00299 00300 // Client 00301 int JackGraphManager::ComputeTotalLatencies() 00302 { 00303 jack_port_id_t port_index; 00304 for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) { 00305 JackPort* port = GetPort(port_index); 00306 if (port->IsUsed()) 00307 ComputeTotalLatency(port_index); 00308 } 00309 return 0; 00310 } 00311 00312 void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode) 00313 { 00314 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index); 00315 JackPort* port = GetPort(port_index); 00316 jack_latency_range_t latency = { UINT32_MAX, 0 }; 00317 jack_port_id_t dst_index; 00318 00319 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) { 00320 AssertPort(dst_index); 00321 JackPort* dst_port = GetPort(dst_index); 00322 jack_latency_range_t other_latency; 00323 00324 dst_port->GetLatencyRange(mode, &other_latency); 00325 00326 if (other_latency.max > latency.max) 00327 latency.max = other_latency.max; 00328 if (other_latency.min < latency.min) 00329 latency.min = other_latency.min; 00330 } 00331 00332 if (latency.min == UINT32_MAX) 00333 latency.min = 0; 00334 00335 port->SetLatencyRange(mode, &latency); 00336 } 00337 00338 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode) 00339 { 00340 UInt16 cur_index; 00341 UInt16 next_index; 00342 00343 do { 00344 cur_index = GetCurrentIndex(); 00345 RecalculateLatencyAux(port_index, mode); 00346 next_index = GetCurrentIndex(); 00347 } while (cur_index != next_index); // Until a coherent state has been read 00348 00349 jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index); 00350 } 00351 00352 // Server 00353 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size) 00354 { 00355 jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size); 00356 00357 jack_port_id_t port_index; 00358 for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) { 00359 JackPort* port = GetPort(port_index); 00360 if (port->IsUsed()) 00361 port->ClearBuffer(buffer_size); 00362 } 00363 } 00364 00365 // Server 00366 jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags) 00367 { 00368 jack_port_id_t port_index; 00369 00370 // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API... 00371 for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) { 00372 JackPort* port = GetPort(port_index); 00373 if (!port->IsUsed()) { 00374 jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index, port_name, port_type); 00375 if (!port->Allocate(refnum, port_name, port_type, flags)) 00376 return NO_PORT; 00377 break; 00378 } 00379 } 00380 00381 return (port_index < fPortMax) ? port_index : NO_PORT; 00382 } 00383 00384 // Server 00385 jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size) 00386 { 00387 JackConnectionManager* manager = WriteNextStateStart(); 00388 jack_port_id_t port_index = AllocatePortAux(refnum, port_name, port_type, flags); 00389 00390 if (port_index != NO_PORT) { 00391 JackPort* port = GetPort(port_index); 00392 assert(port); 00393 port->ClearBuffer(buffer_size); 00394 00395 int res; 00396 if (flags & JackPortIsOutput) { 00397 res = manager->AddOutputPort(refnum, port_index); 00398 } else { 00399 res = manager->AddInputPort(refnum, port_index); 00400 } 00401 // Insertion failure 00402 if (res < 0) { 00403 port->Release(); 00404 port_index = NO_PORT; 00405 } 00406 } 00407 00408 WriteNextStateStop(); 00409 return port_index; 00410 } 00411 00412 // Server 00413 int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index) 00414 { 00415 JackConnectionManager* manager = WriteNextStateStart(); 00416 JackPort* port = GetPort(port_index); 00417 int res; 00418 00419 if (port->fFlags & JackPortIsOutput) { 00420 DisconnectAllOutput(port_index); 00421 res = manager->RemoveOutputPort(refnum, port_index); 00422 } else { 00423 DisconnectAllInput(port_index); 00424 res = manager->RemoveInputPort(refnum, port_index); 00425 } 00426 00427 port->Release(); 00428 WriteNextStateStop(); 00429 return res; 00430 } 00431 00432 void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res) 00433 { 00434 JackConnectionManager* manager = WriteNextStateStart(); 00435 const jack_int_t* input = manager->GetInputPorts(refnum); 00436 memcpy(res, input, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT); 00437 WriteNextStateStop(); 00438 } 00439 00440 void JackGraphManager::GetOutputPorts(int refnum, jack_int_t* res) 00441 { 00442 JackConnectionManager* manager = WriteNextStateStart(); 00443 const jack_int_t* output = manager->GetOutputPorts(refnum); 00444 memcpy(res, output, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT); 00445 WriteNextStateStop(); 00446 } 00447 00448 // Server 00449 void JackGraphManager::RemoveAllPorts(int refnum) 00450 { 00451 jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum); 00452 JackConnectionManager* manager = WriteNextStateStart(); 00453 jack_port_id_t port_index; 00454 00455 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty 00456 const jack_int_t* input = manager->GetInputPorts(refnum); 00457 while ((port_index = input[0]) != EMPTY) { 00458 int res = ReleasePort(refnum, port_index); 00459 if (res < 0) { 00460 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index); 00461 assert(true); 00462 break; 00463 } 00464 } 00465 00466 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty 00467 const jack_int_t* output = manager->GetOutputPorts(refnum); 00468 while ((port_index = output[0]) != EMPTY) { 00469 int res = ReleasePort(refnum, port_index); 00470 if (res < 0) { 00471 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index); 00472 assert(true); 00473 break; 00474 } 00475 } 00476 00477 WriteNextStateStop(); 00478 } 00479 00480 // Server 00481 void JackGraphManager::DisconnectAllPorts(int refnum) 00482 { 00483 int i; 00484 jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum); 00485 JackConnectionManager* manager = WriteNextStateStart(); 00486 00487 const jack_int_t* input = manager->GetInputPorts(refnum); 00488 for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) { 00489 DisconnectAllInput(input[i]); 00490 } 00491 00492 const jack_int_t* output = manager->GetOutputPorts(refnum); 00493 for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) { 00494 DisconnectAllOutput(output[i]); 00495 } 00496 00497 WriteNextStateStop(); 00498 } 00499 00500 // Server 00501 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index) 00502 { 00503 jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index); 00504 JackConnectionManager* manager = WriteNextStateStart(); 00505 00506 for (unsigned int i = 0; i < fPortMax; i++) { 00507 if (manager->IsConnected(i, port_index)) { 00508 jack_log("JackGraphManager::Disconnect i = %ld port_index = %ld", i, port_index); 00509 Disconnect(i, port_index); 00510 } 00511 } 00512 WriteNextStateStop(); 00513 } 00514 00515 // Server 00516 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index) 00517 { 00518 jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index); 00519 JackConnectionManager* manager = WriteNextStateStart(); 00520 00521 const jack_int_t* connections = manager->GetConnections(port_index); 00522 while (connections[0] != EMPTY) { 00523 Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left 00524 } 00525 WriteNextStateStop(); 00526 } 00527 00528 // Server 00529 int JackGraphManager::DisconnectAll(jack_port_id_t port_index) 00530 { 00531 AssertPort(port_index); 00532 00533 JackPort* port = GetPort(port_index); 00534 if (port->fFlags & JackPortIsOutput) { 00535 DisconnectAllOutput(port_index); 00536 } else { 00537 DisconnectAllInput(port_index); 00538 } 00539 return 0; 00540 } 00541 00542 // Server 00543 void JackGraphManager::GetConnections(jack_port_id_t port_index, jack_int_t* res) 00544 { 00545 JackConnectionManager* manager = WriteNextStateStart(); 00546 const jack_int_t* connections = manager->GetConnections(port_index); 00547 memcpy(res, connections, sizeof(jack_int_t) * CONNECTION_NUM_FOR_PORT); 00548 WriteNextStateStop(); 00549 } 00550 00551 // Server 00552 void JackGraphManager::Activate(int refnum) 00553 { 00554 DirectConnect(FREEWHEEL_DRIVER_REFNUM, refnum); 00555 DirectConnect(refnum, FREEWHEEL_DRIVER_REFNUM); 00556 } 00557 00558 /* 00559 Disconnection from the FW must be done in last otherwise an intermediate "unconnected" 00560 (thus unactivated) state may happen where the client is still checked for its end. 00561 */ 00562 00563 // Server 00564 void JackGraphManager::Deactivate(int refnum) 00565 { 00566 // Disconnect only when needed 00567 if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) { 00568 DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM); 00569 } else { 00570 jack_log("JackServer::Deactivate client = %ld was not activated", refnum); 00571 } 00572 00573 // Disconnect only when needed 00574 if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM, refnum)) { 00575 DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, refnum); 00576 } else { 00577 jack_log("JackServer::Deactivate client = %ld was not activated", refnum); 00578 } 00579 } 00580 00581 // Server 00582 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index) 00583 { 00584 AssertPort(port_index); 00585 JackConnectionManager* manager = WriteNextStateStart(); 00586 int res = manager->GetInputRefNum(port_index); 00587 WriteNextStateStop(); 00588 return res; 00589 } 00590 00591 // Server 00592 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index) 00593 { 00594 AssertPort(port_index); 00595 JackConnectionManager* manager = WriteNextStateStart(); 00596 int res = manager->GetOutputRefNum(port_index); 00597 WriteNextStateStop(); 00598 return res; 00599 } 00600 00601 int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst) 00602 { 00603 JackConnectionManager* manager = WriteNextStateStart(); 00604 jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst); 00605 JackPort* src = GetPort(port_src); 00606 JackPort* dst = GetPort(port_dst); 00607 int res = 0; 00608 00609 if (!src->fInUse || !dst->fInUse) { 00610 if (!src->fInUse) 00611 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName); 00612 if (!dst->fInUse) 00613 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName); 00614 res = -1; 00615 goto end; 00616 } 00617 if (src->fTypeId != dst->fTypeId) { 00618 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst); 00619 res = -1; 00620 goto end; 00621 } 00622 if (manager->IsConnected(port_src, port_dst)) { 00623 jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst); 00624 res = EEXIST; 00625 goto end; 00626 } 00627 00628 res = manager->Connect(port_src, port_dst); 00629 if (res < 0) { 00630 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst); 00631 goto end; 00632 } 00633 res = manager->Connect(port_dst, port_src); 00634 if (res < 0) { 00635 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src); 00636 goto end; 00637 } 00638 00639 if (manager->IsLoopPath(port_src, port_dst)) { 00640 jack_log("JackGraphManager::Connect: LOOP detected"); 00641 manager->IncFeedbackConnection(port_src, port_dst); 00642 } else { 00643 manager->IncDirectConnection(port_src, port_dst); 00644 } 00645 00646 end: 00647 WriteNextStateStop(); 00648 return res; 00649 } 00650 00651 // Server 00652 int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst) 00653 { 00654 JackConnectionManager* manager = WriteNextStateStart(); 00655 jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst); 00656 bool in_use_src = GetPort(port_src)->fInUse; 00657 bool in_use_dst = GetPort(port_dst)->fInUse; 00658 int res = 0; 00659 00660 if (!in_use_src || !in_use_dst) { 00661 if (!in_use_src) 00662 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName); 00663 if (!in_use_dst) 00664 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName); 00665 res = -1; 00666 goto end; 00667 } 00668 if (!manager->IsConnected(port_src, port_dst)) { 00669 jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst); 00670 res = -1; 00671 goto end; 00672 } 00673 00674 res = manager->Disconnect(port_src, port_dst); 00675 if (res < 0) { 00676 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst); 00677 goto end; 00678 } 00679 res = manager->Disconnect(port_dst, port_src); 00680 if (res < 0) { 00681 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src); 00682 goto end; 00683 } 00684 00685 if (manager->IsFeedbackConnection(port_src, port_dst)) { 00686 jack_log("JackGraphManager::Disconnect: FEEDBACK removed"); 00687 manager->DecFeedbackConnection(port_src, port_dst); 00688 } else { 00689 manager->DecDirectConnection(port_src, port_dst); 00690 } 00691 00692 end: 00693 WriteNextStateStop(); 00694 return res; 00695 } 00696 00697 // Client 00698 int JackGraphManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) 00699 { 00700 JackConnectionManager* manager = ReadCurrentState(); 00701 return manager->IsConnected(port_src, port_dst); 00702 } 00703 00704 // Server 00705 int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst) 00706 { 00707 JackPort* src = GetPort(port_src); 00708 JackPort* dst = GetPort(port_dst); 00709 00710 if ((dst->fFlags & JackPortIsInput) == 0) { 00711 jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName); 00712 return -1; 00713 } 00714 00715 if ((src->fFlags & JackPortIsOutput) == 0) { 00716 jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName); 00717 return -1; 00718 } 00719 00720 return 0; 00721 } 00722 00723 int JackGraphManager::GetTwoPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst) 00724 { 00725 jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name, dst_name); 00726 00727 if ((*port_src = GetPort(src_name)) == NO_PORT) { 00728 jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name); 00729 return -1; 00730 } 00731 00732 if ((*port_dst = GetPort(dst_name)) == NO_PORT) { 00733 jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name); 00734 return -1; 00735 } 00736 00737 return 0; 00738 } 00739 00740 // Client : port array 00741 jack_port_id_t JackGraphManager::GetPort(const char* name) 00742 { 00743 for (unsigned int i = 0; i < fPortMax; i++) { 00744 JackPort* port = GetPort(i); 00745 if (port->IsUsed() && port->NameEquals(name)) 00746 return i; 00747 } 00748 return NO_PORT; 00749 } 00750 00755 // Client 00756 void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index) 00757 { 00758 const jack_int_t* connections = manager->GetConnections(port_index); 00759 jack_int_t index; 00760 int i; 00761 00762 // Cleanup connection array 00763 memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT); 00764 00765 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((index = connections[i]) != EMPTY); i++) { 00766 JackPort* port = GetPort(index); 00767 res[i] = port->fName; 00768 } 00769 00770 res[i] = NULL; 00771 } 00772 00773 /* 00774 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation. 00775 The operation is lock-free since there is no intermediate state in the write operation that could cause the 00776 read to loop forever. 00777 */ 00778 00779 // Client 00780 const char** JackGraphManager::GetConnections(jack_port_id_t port_index) 00781 { 00782 const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT); 00783 UInt16 cur_index, next_index; 00784 00785 if (!res) 00786 return NULL; 00787 00788 do { 00789 cur_index = GetCurrentIndex(); 00790 GetConnectionsAux(ReadCurrentState(), res, port_index); 00791 next_index = GetCurrentIndex(); 00792 } while (cur_index != next_index); // Until a coherent state has been read 00793 00794 if (res[0]) { // at least one connection 00795 return res; 00796 } else { // empty array, should return NULL 00797 free(res); 00798 return NULL; 00799 } 00800 } 00801 00802 // Client 00803 void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags) 00804 { 00805 int match_cnt = 0; 00806 regex_t port_regex, type_regex; 00807 00808 if (port_name_pattern && port_name_pattern[0]) { 00809 regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB); 00810 } 00811 if (type_name_pattern && type_name_pattern[0]) { 00812 regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB); 00813 } 00814 00815 // Cleanup port array 00816 memset(matching_ports, 0, sizeof(char*) * fPortMax); 00817 00818 for (unsigned int i = 0; i < fPortMax; i++) { 00819 bool matching = true; 00820 JackPort* port = GetPort(i); 00821 00822 if (port->IsUsed()) { 00823 00824 if (flags) { 00825 if ((port->fFlags & flags) != flags) { 00826 matching = false; 00827 } 00828 } 00829 00830 if (matching && port_name_pattern && port_name_pattern[0]) { 00831 if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) { 00832 matching = false; 00833 } 00834 } 00835 if (matching && type_name_pattern && type_name_pattern[0]) { 00836 if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) { 00837 matching = false; 00838 } 00839 } 00840 00841 if (matching) { 00842 matching_ports[match_cnt++] = port->fName; 00843 } 00844 } 00845 } 00846 00847 matching_ports[match_cnt] = 0; 00848 00849 if (port_name_pattern && port_name_pattern[0]) { 00850 regfree(&port_regex); 00851 } 00852 if (type_name_pattern && type_name_pattern[0]) { 00853 regfree(&type_regex); 00854 } 00855 } 00856 00857 // Client 00858 /* 00859 Check that the state was not changed during the read operation. 00860 The operation is lock-free since there is no intermediate state in the write operation that could cause the 00861 read to loop forever. 00862 */ 00863 const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags) 00864 { 00865 const char** res = (const char**)malloc(sizeof(char*) * fPortMax); 00866 UInt16 cur_index, next_index; 00867 00868 if (!res) 00869 return NULL; 00870 00871 do { 00872 cur_index = GetCurrentIndex(); 00873 GetPortsAux(res, port_name_pattern, type_name_pattern, flags); 00874 next_index = GetCurrentIndex(); 00875 } while (cur_index != next_index); // Until a coherent state has been read 00876 00877 if (res[0]) { // at least one port 00878 return res; 00879 } else { 00880 free(res); // empty array, should return NULL 00881 return NULL; 00882 } 00883 } 00884 00885 // Server 00886 void JackGraphManager::Save(JackConnectionManager* dst) 00887 { 00888 JackConnectionManager* manager = WriteNextStateStart(); 00889 memcpy(dst, manager, sizeof(JackConnectionManager)); 00890 WriteNextStateStop(); 00891 } 00892 00893 // Server 00894 void JackGraphManager::Restore(JackConnectionManager* src) 00895 { 00896 JackConnectionManager* manager = WriteNextStateStart(); 00897 memcpy(manager, src, sizeof(JackConnectionManager)); 00898 WriteNextStateStop(); 00899 } 00900 00901 } // end of namespace 00902 00903