JackGraphManager.cpp 25.4 KB
Newer Older
sletz's avatar
sletz committed
1
2
/*
Copyright (C) 2001 Paul Davis
sletz's avatar
sletz committed
3
Copyright (C) 2004-2008 Grame
sletz's avatar
sletz committed
4
5

This program is free software; you can redistribute it and/or modify
sletz's avatar
sletz committed
6
7
8
9
10
11
12
13
14
15
16
17
18
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software 
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

sletz's avatar
sletz committed
19
20
21
22
*/

#include "JackGraphManager.h"
#include "JackConstants.h"
sletz's avatar
sletz committed
23
#include "JackError.h"
sletz's avatar
sletz committed
24
25
26
27
28
29
30
31
32
33
34
#include <assert.h>
#include <stdlib.h>
#include <algorithm>
#include <regex.h>

namespace Jack
{

static void AssertPort(jack_port_id_t port_index)
{
    if (port_index >= PORT_NUM) {
sletz's avatar
sletz committed
35
        jack_log("JackGraphManager::AssertPort port_index = %ld", port_index);
sletz's avatar
sletz committed
36
37
38
39
        assert(port_index < PORT_NUM);
    }
}

40
static void AssertBufferSize(jack_nframes_t buffer_size)
sletz's avatar
sletz committed
41
{
42
    if (buffer_size > BUFFER_SIZE_MAX) {
sletz's avatar
sletz committed
43
        jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size);
44
        assert(buffer_size <= BUFFER_SIZE_MAX);
sletz's avatar
sletz committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    }
}

JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
{
    AssertPort(port_index);
    return &fPortArray[port_index];
}

float* JackGraphManager::GetBuffer(jack_port_id_t port_index)
{
    return fPortArray[port_index].GetBuffer();
}

// Server
60
61
62
63
64
65
void JackGraphManager::InitRefNum(int refnum)
{
    JackConnectionManager* manager = WriteNextStateStart();
    manager->InitRefNum(refnum);
    WriteNextStateStop();
}
sletz's avatar
sletz committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

// RT
void JackGraphManager::RunCurrentGraph()
{
    JackConnectionManager* manager = ReadCurrentState();
    manager->ResetGraph(fClientTiming);
}

// RT
bool JackGraphManager::RunNextGraph()
{
    bool res;
    JackConnectionManager* manager = TrySwitchState(&res);
    manager->ResetGraph(fClientTiming);
    return res;
}

// RT
bool JackGraphManager::IsFinishedGraph()
{
    JackConnectionManager* manager = ReadCurrentState();
    return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
}

// RT
91
int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro* table)
sletz's avatar
sletz committed
92
93
94
95
96
97
{
    JackConnectionManager* manager = ReadCurrentState();
    return manager->ResumeRefNum(control, table, fClientTiming);
}

// RT
98
int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, long usec)
sletz's avatar
sletz committed
99
100
101
102
103
104
105
{
    JackConnectionManager* manager = ReadCurrentState();
    return manager->SuspendRefNum(control, table, fClientTiming, usec);
}

JackClientTiming* JackGraphManager::GetClientTiming(int ref)
{
sletz's avatar
sletz committed
106
    return &fClientTiming[ref];
sletz's avatar
sletz committed
107
108
109
110
111
112
113
}

// Server
void JackGraphManager::DirectConnect(int ref1, int ref2)
{
    JackConnectionManager* manager = WriteNextStateStart();
    manager->DirectConnect(ref1, ref2);
sletz's avatar
sletz committed
114
    jack_log("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2);
sletz's avatar
sletz committed
115
116
117
118
119
120
121
122
    WriteNextStateStop();
}

// Server
void JackGraphManager::DirectDisconnect(int ref1, int ref2)
{
    JackConnectionManager* manager = WriteNextStateStart();
    manager->DirectDisconnect(ref1, ref2);
sletz's avatar
sletz committed
123
    jack_log("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2);
sletz's avatar
sletz committed
124
125
126
127
128
129
130
131
132
133
134
    WriteNextStateStop();
}

// Server
bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
{
    JackConnectionManager* manager = ReadCurrentState();
    return manager->IsDirectConnection(ref1, ref2);
}

// RT
135
void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buffer_size)
sletz's avatar
sletz committed
136
137
{
    AssertPort(port_index);
138
    AssertBufferSize(buffer_size);
sletz's avatar
sletz committed
139
140
141
142
143
144

    JackConnectionManager* manager = ReadCurrentState();
    JackPort* port = GetPort(port_index);

    if (!port->IsUsed()) {
        // This happens when a port has just been unregistered and is still used by the RT code.
sletz's avatar
sletz committed
145
        jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index);
sletz's avatar
sletz committed
146
147
148
149
150
        return GetBuffer(0); // port_index 0 is not used
    }

    // Output port
    if (port->fFlags & JackPortIsOutput) {
151
        return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, buffer_size) : GetBuffer(port_index);
sletz's avatar
sletz committed
152
153
154
155
156
157
    }

    // Input port
    jack_int_t len = manager->Connections(port_index);

    if (len == 0) {  // No connections: return a zero-filled buffer
sletz's avatar
sletz committed
158
159
        port->ClearBuffer(buffer_size);
        return port->GetBuffer();
sletz's avatar
sletz committed
160
161
    } else if (len == 1) {	 // One connection: use zero-copy mode - just pass the buffer of the connected (output) port.
        assert(manager->GetPort(port_index, 0) != port_index); // Check recursion
162
        return GetBuffer(manager->GetPort(port_index, 0), buffer_size);
sletz's avatar
sletz committed
163
    } else {  // Multiple connections
sletz's avatar
sletz committed
164

sletz's avatar
sletz committed
165
        const jack_int_t* connections = manager->GetConnections(port_index);
166
        void* buffers[CONNECTION_NUM_FOR_PORT];
sletz's avatar
sletz committed
167
168
169
        jack_port_id_t src_index;
        int i;

170
        for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) {
sletz's avatar
sletz committed
171
            AssertPort(src_index);
sletz's avatar
sletz committed
172
            buffers[i] = GetBuffer(src_index, buffer_size);
sletz's avatar
sletz committed
173
        }
sletz's avatar
sletz committed
174
175
176

        JackPort* port = GetPort(port_index);
        port->MixBuffers(buffers, i, buffer_size);
sletz's avatar
sletz committed
177
        return port->GetBuffer();
sletz's avatar
sletz committed
178
179
180
    }
}

181
// Server
sletz's avatar
sletz committed
182
183
184
185
186
187
188
189
int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
{
    AssertPort(port_index);
    JackPort* port = GetPort(port_index);

    /**
    jackd.h 
        * If @ref JackPortCanMonitor is set for this @a port, turn input
sletz's avatar
sletz committed
190
        * monitoring on or off. Otherwise, do nothing.
sletz's avatar
sletz committed
191
192
193
194
195
196
197
198
199
200
     
     if (!(fFlags & JackPortCanMonitor))
    	return -1;
    */

    port->RequestMonitor(onoff);

    const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
    if ((port->fFlags & JackPortIsOutput) == 0) { // ?? Taken from jack, why not (port->fFlags  & JackPortIsInput) ?
        jack_port_id_t src_index;
201
        for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) {
sletz's avatar
sletz committed
202
203
204
205
206
207
208
209
            // XXX much worse things will happen if there is a feedback loop !!!
            RequestMonitor(src_index, onoff);
        }
    }

    return 0;
}

210
211
// Client
jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
sletz's avatar
sletz committed
212
213
214
215
216
217
{
    const jack_int_t* connections = manager->GetConnections(port_index);
    jack_nframes_t max_latency = 0;
    jack_port_id_t dst_index;

    if (hop_count > 8)
sletz's avatar
sletz committed
218
        return GetPort(port_index)->GetLatency();
sletz's avatar
sletz committed
219

220
    for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
sletz's avatar
sletz committed
221
        if (src_port_index != dst_index) {
sletz's avatar
sletz committed
222
            AssertPort(dst_index);
sletz's avatar
sletz committed
223
224
225
            JackPort* dst_port = GetPort(dst_index);
            jack_nframes_t this_latency = (dst_port->fFlags & JackPortIsTerminal)
                                          ? dst_port->GetLatency()
226
                                          : ComputeTotalLatencyAux(dst_index, port_index, manager, hop_count + 1);
227
            max_latency = ((max_latency > this_latency) ? max_latency : this_latency);
sletz's avatar
sletz committed
228
229
        }
    }
sletz's avatar
sletz committed
230

sletz's avatar
sletz committed
231
    return max_latency + GetPort(port_index)->GetLatency();
sletz's avatar
sletz committed
232
233
}

234
235
// Client
int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index)
sletz's avatar
sletz committed
236
237
238
{
    UInt16 cur_index;
    UInt16 next_index;
sletz's avatar
sletz committed
239
    JackPort* port = GetPort(port_index);
sletz's avatar
sletz committed
240
    AssertPort(port_index);
sletz's avatar
sletz committed
241

sletz's avatar
sletz committed
242
243
    do {
        cur_index = GetCurrentIndex();
244
        port->fTotalLatency = ComputeTotalLatencyAux(port_index, port_index, ReadCurrentState(), 0);
sletz's avatar
sletz committed
245
246
        next_index = GetCurrentIndex();
    } while (cur_index != next_index); // Until a coherent state has been read
sletz's avatar
sletz committed
247

sletz's avatar
sletz committed
248
    jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index, port->fTotalLatency);
sletz's avatar
sletz committed
249
    return 0;
250
}
sletz's avatar
sletz committed
251

252
253
254
// Client
int JackGraphManager::ComputeTotalLatencies()
{
sletz's avatar
sletz committed
255
256
    jack_port_id_t port_index;
    for (port_index = FIRST_AVAILABLE_PORT; port_index < PORT_NUM; port_index++) {
257
        JackPort* port = GetPort(port_index);
sletz's avatar
sletz committed
258
259
260
261
        if (port->IsUsed())
            ComputeTotalLatency(port_index);
    }
    return 0;
sletz's avatar
sletz committed
262
263
}

sletz's avatar
Cleanup    
sletz committed
264
265
266
// Server
void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
{
267
    jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size);
sletz's avatar
sletz committed
268
269

    jack_port_id_t port_index;
sletz's avatar
Cleanup    
sletz committed
270
271
272
    for (port_index = FIRST_AVAILABLE_PORT; port_index < PORT_NUM; port_index++) {
        JackPort* port = GetPort(port_index);
        if (port->IsUsed())
273
            port->ClearBuffer(buffer_size);
sletz's avatar
Cleanup    
sletz committed
274
275
276
    }
}

sletz's avatar
sletz committed
277
// Server
sletz's avatar
sletz committed
278
jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags)
sletz's avatar
sletz committed
279
280
281
{
    jack_port_id_t port_index;

sletz's avatar
Cleanup    
sletz committed
282
283
    // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API...
    for (port_index = FIRST_AVAILABLE_PORT; port_index < PORT_NUM; port_index++) {
sletz's avatar
sletz committed
284
285
        JackPort* port = GetPort(port_index);
        if (!port->IsUsed()) {
sletz's avatar
sletz committed
286
            jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index, port_name, port_type);
sletz's avatar
sletz committed
287
            if (!port->Allocate(refnum, port_name, port_type, flags))
sletz's avatar
sletz committed
288
                return NO_PORT;
sletz's avatar
sletz committed
289
290
291
292
293
294
295
296
            break;
        }
    }

    return (port_index < PORT_NUM) ? port_index : NO_PORT;
}

// Server
297
jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size)
sletz's avatar
sletz committed
298
299
{
    JackConnectionManager* manager = WriteNextStateStart();
sletz's avatar
sletz committed
300
301
    jack_port_id_t port_index = AllocatePortAux(refnum, port_name, port_type, flags);

sletz's avatar
sletz committed
302
    if (port_index != NO_PORT) {
sletz's avatar
sletz committed
303
304
        JackPort* port = GetPort(port_index);
        assert(port);
305
        port->ClearBuffer(buffer_size);
sletz's avatar
sletz committed
306

sletz's avatar
sletz committed
307
308
309
310
311
312
        int res;
        if (flags & JackPortIsOutput) {
            res = manager->AddOutputPort(refnum, port_index);
        } else {
            res = manager->AddInputPort(refnum, port_index);
        }
sletz's avatar
sletz committed
313
        // Insertion failure
sletz's avatar
sletz committed
314
315
316
317
318
319
320
321
322
323
324
        if (res < 0) {
            port->Release();
            port_index = NO_PORT;
        }
    }

    WriteNextStateStop();
    return port_index;
}

// Server
325
int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
sletz's avatar
sletz committed
326
327
328
329
330
331
332
333
334
335
336
337
338
{
    JackConnectionManager* manager = WriteNextStateStart();
    JackPort* port = GetPort(port_index);
    int res;

    if (port->fFlags & JackPortIsOutput) {
        DisconnectAllOutput(port_index);
        res = manager->RemoveOutputPort(refnum, port_index);
    } else {
        DisconnectAllInput(port_index);
        res = manager->RemoveInputPort(refnum, port_index);
    }

sletz's avatar
sletz committed
339
    port->Release();
sletz's avatar
sletz committed
340
341
342
343
    WriteNextStateStop();
    return res;
}

344
345
void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res)
{
sletz's avatar
sletz committed
346
347
348
349
    JackConnectionManager* manager = WriteNextStateStart();
    const jack_int_t* input = manager->GetInputPorts(refnum);
    memcpy(res, input, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
    WriteNextStateStop();
350
351
352
353
}

void JackGraphManager::GetOutputPorts(int refnum, jack_int_t* res)
{
sletz's avatar
sletz committed
354
355
356
357
    JackConnectionManager* manager = WriteNextStateStart();
    const jack_int_t* output = manager->GetOutputPorts(refnum);
    memcpy(res, output, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
    WriteNextStateStop();
358
359
}

sletz's avatar
sletz committed
360
361
362
// Server
void JackGraphManager::RemoveAllPorts(int refnum)
{
sletz's avatar
sletz committed
363
    jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum);
sletz's avatar
sletz committed
364
365
366
    JackConnectionManager* manager = WriteNextStateStart();
    jack_port_id_t port_index;

367
    // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty
sletz's avatar
sletz committed
368
369
    const jack_int_t* input = manager->GetInputPorts(refnum);
    while ((port_index = input[0]) != EMPTY) {
370
371
372
373
        int res = ReleasePort(refnum, port_index);
        if (res < 0) {
            jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
            assert(true);
sletz's avatar
sletz committed
374
            break;
375
        }
sletz's avatar
sletz committed
376
377
    }

378
    // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty
sletz's avatar
sletz committed
379
380
    const jack_int_t* output = manager->GetOutputPorts(refnum);
    while ((port_index = output[0]) != EMPTY) {
381
382
383
384
        int res = ReleasePort(refnum, port_index);
        if (res < 0) {
            jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
            assert(true);
sletz's avatar
sletz committed
385
            break;
386
        } 
sletz's avatar
sletz committed
387
388
389
390
391
392
393
394
395
    }

    WriteNextStateStop();
}

// Server
void JackGraphManager::DisconnectAllPorts(int refnum)
{
    int i;
sletz's avatar
sletz committed
396
    jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum);
sletz's avatar
sletz committed
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
    JackConnectionManager* manager = WriteNextStateStart();

    const jack_int_t* input = manager->GetInputPorts(refnum);
    for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) {
        DisconnectAllInput(input[i]);
    }

    const jack_int_t* output = manager->GetOutputPorts(refnum);
    for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) {
        DisconnectAllOutput(output[i]);
    }

    WriteNextStateStop();
}

// Server
void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
{
415
    jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index);
sletz's avatar
sletz committed
416
417
418
419
    JackConnectionManager* manager = WriteNextStateStart();

    for (int i = 0; i < PORT_NUM; i++) {
        if (manager->IsConnected(i, port_index)) {
sletz's avatar
sletz committed
420
            jack_log("JackGraphManager::Disconnect i = %ld  port_index = %ld", i, port_index);
sletz's avatar
sletz committed
421
422
423
424
425
426
427
428
429
            Disconnect(i, port_index);
        }
    }
    WriteNextStateStop();
}

// Server
void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
{
sletz's avatar
sletz committed
430
    jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index);
sletz's avatar
sletz committed
431
432
433
    JackConnectionManager* manager = WriteNextStateStart();

    const jack_int_t* connections = manager->GetConnections(port_index);
sletz's avatar
sletz committed
434
435
    while (connections[0] != EMPTY) {
        Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left
sletz's avatar
sletz committed
436
437
438
439
440
441
442
443
444
445
446
    }
    WriteNextStateStop();
}

// Server
int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
{
    AssertPort(port_index);

    JackPort* port = GetPort(port_index);
    if (port->fFlags & JackPortIsOutput) {
sletz's avatar
sletz committed
447
        DisconnectAllOutput(port_index);
sletz's avatar
sletz committed
448
    } else {
sletz's avatar
sletz committed
449
        DisconnectAllInput(port_index);
sletz's avatar
sletz committed
450
451
452
453
    }
    return 0;
}

sletz's avatar
sletz committed
454
455
456
// Server
void JackGraphManager::GetConnections(jack_port_id_t port_index, jack_int_t* res)
{
sletz's avatar
sletz committed
457
458
    JackConnectionManager* manager = WriteNextStateStart();
    const jack_int_t* connections = manager->GetConnections(port_index);
459
    memcpy(res, connections, sizeof(jack_int_t) * CONNECTION_NUM_FOR_PORT);
sletz's avatar
sletz committed
460
    WriteNextStateStop();
sletz's avatar
sletz committed
461
462
}

463
464
465
// Server
void JackGraphManager::Activate(int refnum)
{
sletz's avatar
sletz committed
466
    DirectConnect(FREEWHEEL_DRIVER_REFNUM, refnum);
467
468
469
470
471
472
473
474
475
476
477
    DirectConnect(refnum, FREEWHEEL_DRIVER_REFNUM);
}

/*
	Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
	(thus unactivated) state may happen where the client is still checked for its end.
*/

// Server
void JackGraphManager::Deactivate(int refnum)
{
sletz's avatar
sletz committed
478
    // Disconnect only when needed
479
480
481
    if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) {
        DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM);
    } else {
482
        jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
483
484
    }

sletz's avatar
sletz committed
485
    // Disconnect only when needed
486
487
488
    if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM, refnum)) {
        DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, refnum);
    } else {
489
        jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
490
491
492
    }
}

sletz's avatar
sletz committed
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
// Server
int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
{
    AssertPort(port_index);
    JackConnectionManager* manager = WriteNextStateStart();
    int res = manager->GetInputRefNum(port_index);
    WriteNextStateStop();
    return res;
}

// Server
int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
{
    AssertPort(port_index);
    JackConnectionManager* manager = WriteNextStateStart();
    int res = manager->GetOutputRefNum(port_index);
    WriteNextStateStop();
    return res;
}

int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
{
    JackConnectionManager* manager = WriteNextStateStart();
sletz's avatar
sletz committed
516
    jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst);
sletz's avatar
sletz committed
517
518
    JackPort* src = GetPort(port_src);
    JackPort* dst = GetPort(port_dst);
sletz's avatar
sletz committed
519
520
    int res = 0;

sletz's avatar
sletz committed
521
522
    if (!src->fInUse || !dst->fInUse) {
        if (!src->fInUse)
523
            jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
sletz's avatar
sletz committed
524
        if (!dst->fInUse)
525
            jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
sletz's avatar
sletz committed
526
527
528
        res = -1;
        goto end;
    }
sletz's avatar
sletz committed
529
    if (src->fTypeId != dst->fTypeId) {
530
        jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst);
sletz's avatar
sletz committed
531
532
        res = -1;
        goto end;
sletz's avatar
sletz committed
533
    }
sletz's avatar
sletz committed
534
535
536
537
538
539
540
541
542
543
544
    if (manager->IsConnected(port_src, port_dst)) {
        jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst);
        res = EEXIST;
        goto end;
    }

    res = manager->Connect(port_src, port_dst);
    if (res < 0) {
        jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
        goto end;
    }
sletz's avatar
sletz committed
545
    res = manager->Connect(port_dst, port_src);
sletz's avatar
sletz committed
546
    if (res < 0) {
547
        jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
sletz's avatar
sletz committed
548
549
550
551
        goto end;
    }

    if (manager->IsLoopPath(port_src, port_dst)) {
sletz's avatar
sletz committed
552
        jack_log("JackGraphManager::Connect: LOOP detected");
sletz's avatar
sletz committed
553
554
555
556
557
558
559
560
561
562
563
564
565
566
        manager->IncFeedbackConnection(port_src, port_dst);
    } else {
        manager->IncDirectConnection(port_src, port_dst);
    }

end:
    WriteNextStateStop();
    return res;
}

// Server
int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
{
    JackConnectionManager* manager = WriteNextStateStart();
sletz's avatar
sletz committed
567
    jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst);
sletz's avatar
sletz committed
568
    bool in_use_src = GetPort(port_src)->fInUse;
569
    bool in_use_dst = GetPort(port_dst)->fInUse;
sletz's avatar
sletz committed
570
571
572
573
    int res = 0;

    if (!in_use_src || !in_use_dst) {
        if (!in_use_src)
574
            jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
sletz's avatar
sletz committed
575
        if (!in_use_dst)
576
            jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
sletz's avatar
sletz committed
577
578
579
580
581
582
583
584
585
        res = -1;
        goto end;
    }
    if (!manager->IsConnected(port_src, port_dst)) {
        jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst);
        res = -1;
        goto end;
    }

sletz's avatar
sletz committed
586
    res = manager->Disconnect(port_src, port_dst);
sletz's avatar
sletz committed
587
588
589
590
    if (res < 0) {
        jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
        goto end;
    }
sletz's avatar
sletz committed
591
    res = manager->Disconnect(port_dst, port_src);
sletz's avatar
sletz committed
592
    if (res < 0) {
593
        jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
sletz's avatar
sletz committed
594
595
596
597
        goto end;
    }

    if (manager->IsFeedbackConnection(port_src, port_dst)) {
sletz's avatar
sletz committed
598
        jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
sletz's avatar
sletz committed
599
600
601
602
603
604
605
606
607
608
609
        manager->DecFeedbackConnection(port_src, port_dst);
    } else {
        manager->DecDirectConnection(port_src, port_dst);
    }

end:
    WriteNextStateStop();
    return res;
}

// Client
610
int JackGraphManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst)
sletz's avatar
sletz committed
611
612
{
    JackConnectionManager* manager = ReadCurrentState();
sletz's avatar
sletz committed
613
    return manager->IsConnected(port_src, port_dst);
sletz's avatar
sletz committed
614
615
616
617
618
619
620
621
}

// Server
int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
{
    JackPort* src = GetPort(port_src);
    JackPort* dst = GetPort(port_dst);

622
    if ((dst->fFlags & JackPortIsInput) == 0) {
sletz's avatar
sletz committed
623
624
625
626
        jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName);
        return -1;
    }

627
    if ((src->fFlags & JackPortIsOutput) == 0) {
sletz's avatar
sletz committed
628
629
630
631
632
633
634
635
636
        jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName);
        return -1;
    }

    return 0;
}

int JackGraphManager::CheckPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
{
sletz's avatar
sletz committed
637
    jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name, dst_name);
sletz's avatar
sletz committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656

    if ((*port_src = GetPort(src_name)) == NO_PORT) {
        jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
        return -1;
    }

    if ((*port_dst = GetPort(dst_name)) == NO_PORT) {
        jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
        return -1;
    }

    return CheckPorts(*port_src, *port_dst);
}

// Client : port array
jack_port_id_t JackGraphManager::GetPort(const char* name)
{
    for (int i = 0; i < PORT_NUM; i++) {
        JackPort* port = GetPort(i);
657
        if (port->IsUsed() && port->NameEquals(name))
sletz's avatar
sletz committed
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
            return i;
    }
    return NO_PORT;
}

/*!
\brief Get the connection port name array.
*/

// Client
void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
{
    const jack_int_t* connections = manager->GetConnections(port_index);
    jack_int_t index;
    int i;
673
674
    
    // Cleanup connection array
675
    memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT);
sletz's avatar
sletz committed
676

sletz's avatar
sletz committed
677
    for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((index = connections[i]) != EMPTY); i++) {
sletz's avatar
sletz committed
678
679
680
681
682
683
684
685
686
687
688
689
        JackPort* port = GetPort(index);
        res[i] = port->fName;
    }

    res[i] = NULL;
}

/*
	Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
	The operation is lock-free since there is no intermediate state in the write operation that could cause the
	read to loop forever.
*/
690
691

// Client
sletz's avatar
sletz committed
692
693
const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
{
694
    const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
695
    UInt16 cur_index, next_index;
sletz's avatar
sletz committed
696
697
698
699
700
701
702

    do {
        cur_index = GetCurrentIndex();
        GetConnectionsAux(ReadCurrentState(), res, port_index);
        next_index = GetCurrentIndex();
    } while (cur_index != next_index); // Until a coherent state has been read

703
704
705
706
707
708
    if (res[0]) {	// at least one connection
        return res;
    } else {		// empty array, should return NULL
        free(res);
        return NULL;
    }
sletz's avatar
sletz committed
709
710
711
}

// Client
712
void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
sletz's avatar
sletz committed
713
{
714
715
716
    int match_cnt = 0;
    regex_t port_regex, type_regex;
  
sletz's avatar
sletz committed
717
718
719
720
721
722
723
    if (port_name_pattern && port_name_pattern[0]) {
        regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
    }
    if (type_name_pattern && type_name_pattern[0]) {
        regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
    }

724
725
    // Cleanup port array
    memset(matching_ports, 0, sizeof(char*) * PORT_NUM);
sletz's avatar
sletz committed
726
727

    for (int i = 0; i < PORT_NUM; i++) {
728
        bool matching = true;
sletz's avatar
sletz committed
729
        JackPort* port = GetPort(i);
sletz's avatar
sletz committed
730
731
732
733
734
735
736
737
738
739

        if (port->IsUsed()) {

            if (flags) {
                if ((port->fFlags & flags) != flags) {
                    matching = false;
                }
            }

            if (matching && port_name_pattern && port_name_pattern[0]) {
740
                if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) {
sletz's avatar
sletz committed
741
742
743
                    matching = false;
                }
            }
sletz's avatar
sletz committed
744
            if (matching && type_name_pattern && type_name_pattern[0]) {
745
                if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) {
sletz's avatar
sletz committed
746
747
748
749
750
751
752
753
754
755
756
757
                    matching = false;
                }
            }

            if (matching) {
                matching_ports[match_cnt++] = port->fName;
            }
        }
    }

    matching_ports[match_cnt] = 0;

758
759
760
761
762
763
    if (port_name_pattern && port_name_pattern[0]) {
        regfree(&port_regex);
    }
    if (type_name_pattern && type_name_pattern[0]) {
        regfree(&type_regex);
    }
sletz's avatar
sletz committed
764
765
766
767
768
769
770
771
772
773
}

// Client
/*
	Check that the state was not changed during the read operation.
	The operation is lock-free since there is no intermediate state in the write operation that could cause the
	read to loop forever.
*/
const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
{
774
775
776
    const char** res = (const char**)malloc(sizeof(char*) * PORT_NUM);
    UInt16 cur_index, next_index;
 
sletz's avatar
sletz committed
777
778
    do {
        cur_index = GetCurrentIndex();
779
        GetPortsAux(res, port_name_pattern, type_name_pattern, flags);
sletz's avatar
sletz committed
780
        next_index = GetCurrentIndex();
781
    } while (cur_index != next_index);  // Until a coherent state has been read 
sletz's avatar
sletz committed
782

783
784
785
786
787
788
    if (res[0]) {    // at least one port
        return res;
    } else {
        free(res);   // empty array, should return NULL
        return NULL;
    }
sletz's avatar
sletz committed
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
}

// Server
void JackGraphManager::Save(JackConnectionManager* dst)
{
    JackConnectionManager* manager = WriteNextStateStart();
    memcpy(dst, manager, sizeof(JackConnectionManager));
    WriteNextStateStop();
}

// Server
void JackGraphManager::Restore(JackConnectionManager* src)
{
    JackConnectionManager* manager = WriteNextStateStart();
    memcpy(manager, src, sizeof(JackConnectionManager));
    WriteNextStateStop();
}

} // end of namespace