Jack2 1.9.6

JackGraphManager.cpp

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