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