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