Jack2 1.9.7
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 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