JackEngine.cpp 25.6 KB
Newer Older
sletz's avatar
sletz committed
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2004-2008 Grame
sletz's avatar
sletz committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <iostream>
#include <fstream>
#include <assert.h>

24
#include "JackSystemDeps.h"
sletz's avatar
sletz committed
25
#include "JackLockedEngine.h"
sletz's avatar
sletz committed
26
#include "JackExternalClient.h"
27
#include "JackInternalClient.h"
sletz's avatar
sletz committed
28
29
#include "JackEngineControl.h"
#include "JackClientControl.h"
sletz's avatar
sletz committed
30
#include "JackServerGlobals.h"
sletz's avatar
sletz committed
31
32
#include "JackGlobals.h"
#include "JackChannel.h"
sletz's avatar
sletz committed
33
#include "JackError.h"
sletz's avatar
sletz committed
34
35
36
37

namespace Jack
{

38
39
#define AssertRefnum(ref) assert(ref >= 0 && ref < CLIENT_NUM);

sletz's avatar
sletz committed
40
JackEngine::JackEngine(JackGraphManager* manager,
41
                       JackSynchro* table,
sletz's avatar
sletz committed
42
                       JackEngineControl* control)
sletz's avatar
sletz committed
43
44
45
46
47
{
    fGraphManager = manager;
    fSynchroTable = table;
    fEngineControl = control;
    for (int i = 0; i < CLIENT_NUM; i++)
48
        fClientTable[i] = NULL;
sletz's avatar
sletz committed
49
50
51
52
}

JackEngine::~JackEngine()
{
sletz's avatar
sletz committed
53
    jack_log("JackEngine::~JackEngine");
sletz's avatar
sletz committed
54
55
56
57
}

int JackEngine::Open()
{
sletz's avatar
sletz committed
58
    jack_log("JackEngine::Open");
sletz's avatar
sletz committed
59
60

    // Open audio thread => request thread communication channel
61
    if (fChannel.Open(fEngineControl->fServerName) < 0) {
sletz's avatar
sletz committed
62
63
64
65
66
67
68
69
70
        jack_error("Cannot connect to server");
        return -1;
    } else {
        return 0;
    }
}

int JackEngine::Close()
{
sletz's avatar
sletz committed
71
    jack_log("JackEngine::Close");
72
    fChannel.Close();
sletz's avatar
sletz committed
73

74
    // Close remaining clients (RT is stopped)
sletz's avatar
sletz committed
75
    for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
sletz's avatar
sletz committed
76
77
78
        if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) {
            jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName);
            loadable_client->Close();
sletz's avatar
sletz committed
79
80
            // Close does not delete the pointer for internal clients
            fClientTable[i] = NULL;
sletz's avatar
sletz committed
81
82
83
84
            delete loadable_client;
        } else if (JackExternalClient* external_client = dynamic_cast<JackExternalClient*>(fClientTable[i])) {
            jack_log("JackEngine::Close external client = %s", external_client->GetClientControl()->fName);
            external_client->Close();
sletz's avatar
sletz committed
85
86
            // Close deletes the pointer for external clients
            fClientTable[i] = NULL;
sletz's avatar
sletz committed
87
88
        }
    }
sletz's avatar
sletz committed
89

sletz's avatar
sletz committed
90
91
    return 0;
}
sletz's avatar
sletz committed
92

sletz's avatar
Cleanup    
sletz committed
93
94
95
96
//-----------------------------
// Client ressource management
//-----------------------------

sletz's avatar
sletz committed
97
int JackEngine::AllocateRefnum()
98
99
100
{
    for (int i = 0; i < CLIENT_NUM; i++) {
        if (!fClientTable[i]) {
sletz's avatar
sletz committed
101
            jack_log("JackEngine::AllocateRefNum ref = %ld", i);
102
103
104
105
106
107
            return i;
        }
    }
    return -1;
}

sletz's avatar
sletz committed
108
109
void JackEngine::ReleaseRefnum(int ref)
{
sletz's avatar
sletz committed
110
111
112
113
    fClientTable[ref] = NULL;

    if (fEngineControl->fTemporary) {
        int i;
sletz's avatar
sletz committed
114
        for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
sletz's avatar
sletz committed
115
116
117
118
119
            if (fClientTable[i])
                break;
        }
        if (i == CLIENT_NUM) {
            // last client and temporay case: quit the server
sletz's avatar
sletz committed
120
            jack_log("JackEngine::ReleaseRefnum server quit");
sletz's avatar
sletz committed
121
122
            fEngineControl->fTemporary = false;
#ifndef WIN32
sletz's avatar
sletz committed
123
 	    exit(0);
sletz's avatar
sletz committed
124
125
126
#endif
        }
    }
sletz's avatar
sletz committed
127
128
}

sletz's avatar
sletz committed
129
130
131
132
//------------------
// Graph management
//------------------

sletz's avatar
sletz committed
133
void JackEngine::ProcessNext(jack_time_t cur_cycle_begin)
sletz's avatar
sletz committed
134
{
sletz's avatar
sletz committed
135
    fLastSwitchUsecs = cur_cycle_begin;
sletz's avatar
sletz committed
136
    if (fGraphManager->RunNextGraph())	// True if the graph actually switched to a new state
137
        fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
138
    fSignal.Signal();                   // Signal for threads waiting for next cycle
sletz's avatar
sletz committed
139
140
}

sletz's avatar
sletz committed
141
void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin)
sletz's avatar
sletz committed
142
{
sletz's avatar
sletz committed
143
144
    if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle
        CheckXRun(cur_cycle_begin);
sletz's avatar
sletz committed
145
    fGraphManager->RunCurrentGraph();
sletz's avatar
sletz committed
146
147
}

sletz's avatar
sletz committed
148
bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
sletz's avatar
sletz committed
149
{
sletz's avatar
sletz committed
150
    bool res = true;
sletz's avatar
sletz committed
151

152
    // Cycle  begin
sletz's avatar
sletz committed
153
    fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end);
sletz's avatar
sletz committed
154

sletz's avatar
sletz committed
155
    // Graph
sletz's avatar
sletz committed
156
    if (fGraphManager->IsFinishedGraph()) {
sletz's avatar
sletz committed
157
        ProcessNext(cur_cycle_begin);
sletz's avatar
sletz committed
158
        res = true;
sletz's avatar
sletz committed
159
    } else {
sletz's avatar
sletz committed
160
        jack_log("Process: graph not finished!");
sletz's avatar
sletz committed
161
162
163
        if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
            jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
            ProcessNext(cur_cycle_begin);
sletz's avatar
sletz committed
164
            res = true;
sletz's avatar
sletz committed
165
        } else {
sletz's avatar
sletz committed
166
167
            jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
            ProcessCurrent(cur_cycle_begin);
sletz's avatar
sletz committed
168
169
            res = false;
        }
sletz's avatar
sletz committed
170
171
    }

172
    // Cycle end
sletz's avatar
sletz committed
173
174
    fEngineControl->CycleEnd(fClientTable);
    return res;
sletz's avatar
sletz committed
175
176
}

sletz's avatar
sletz committed
177
178
179
180
181
182
183
/*
Client that finish *after* the callback date are considered late even if their output buffers may have been
correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
*/

void JackEngine::CheckXRun(jack_time_t callback_usecs)  // REVOIR les conditions de fin
{
sletz's avatar
sletz committed
184
    for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
sletz's avatar
sletz committed
185
186
        JackClientInterface* client = fClientTable[i];
        if (client && client->GetClientControl()->fActive) {
sletz's avatar
sletz committed
187
188
            JackClientTiming* timing = fGraphManager->GetClientTiming(i);
            jack_client_state_t status = timing->fStatus;
sletz's avatar
sletz committed
189
            jack_time_t finished_date = timing->fFinishedAt;
sletz's avatar
sletz committed
190

sletz's avatar
sletz committed
191
            if (status != NotTriggered && status != Finished) {
sletz's avatar
Typo    
sletz committed
192
                jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status);
193
                fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);  // Notify all clients
sletz's avatar
sletz committed
194
            }
sletz's avatar
sletz committed
195

sletz's avatar
sletz committed
196
197
            if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
                jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
198
                fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);  // Notify all clients
sletz's avatar
sletz committed
199
200
201
202
203
204
205
206
207
            }
        }
    }
}

//---------------
// Notifications
//---------------

sletz's avatar
sletz committed
208
void JackEngine::NotifyClient(int refnum, int event, int sync, int value1, int value2)
sletz's avatar
sletz committed
209
210
{
    JackClientInterface* client = fClientTable[refnum];
sletz's avatar
sletz committed
211

sletz's avatar
sletz committed
212
    // The client may be notified by the RT thread while closing
213
    if (!client) {
sletz's avatar
sletz committed
214
        jack_log("JackEngine::NotifyClient: client not available anymore");
sletz's avatar
sletz committed
215
216
    } else if (client->GetClientControl()->fCallback[event]) {
        if (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
sletz's avatar
sletz committed
217
            jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
sletz's avatar
sletz committed
218
    } else {
sletz's avatar
sletz committed
219
        jack_log("JackEngine::NotifyClient: no callback for event = %ld", event);
sletz's avatar
sletz committed
220
221
222
    }
}

sletz's avatar
sletz committed
223
void JackEngine::NotifyClients(int event, int sync, int value1, int value2)
sletz's avatar
sletz committed
224
225
226
{
    for (int i = 0; i < CLIENT_NUM; i++) {
        JackClientInterface* client = fClientTable[i];
sletz's avatar
sletz committed
227
228
229
        if (client) {
            if (client->GetClientControl()->fCallback[event]) {
                if (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
sletz's avatar
sletz committed
230
                    jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
sletz's avatar
sletz committed
231
            } else {
sletz's avatar
sletz committed
232
                jack_log("JackEngine::NotifyClients: no callback for event = %ld", event);
sletz's avatar
sletz committed
233
234
            }
        }
sletz's avatar
sletz committed
235
236
237
238
239
    }
}

int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
{
sletz's avatar
sletz committed
240
    jack_log("JackEngine::NotifyAddClient: name = %s", name);
sletz's avatar
sletz committed
241
242
243
244
    // Notify existing clients of the new client and new client of existing clients.
    for (int i = 0; i < CLIENT_NUM; i++) {
        JackClientInterface* old_client = fClientTable[i];
        if (old_client) {
sletz's avatar
sletz committed
245
            if (old_client->ClientNotify(refnum, name, kAddClient, true, 0, 0) < 0) {
246
                jack_error("NotifyAddClient old_client fails name = %s", old_client->GetClientControl()->fName);
sletz's avatar
sletz committed
247
248
249
                return -1;
            }
            if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, kAddClient, true, 0, 0) < 0) {
250
                jack_error("NotifyAddClient new_client fails name = %s", name);
sletz's avatar
sletz committed
251
252
                return -1;
            }
sletz's avatar
sletz committed
253
254
255
256
257
258
259
260
261
262
263
264
        }
    }

    return 0;
}

void JackEngine::NotifyRemoveClient(const char* name, int refnum)
{
    // Notify existing clients (including the one beeing suppressed) of the removed client
    for (int i = 0; i < CLIENT_NUM; i++) {
        JackClientInterface* client = fClientTable[i];
        if (client) {
sletz's avatar
sletz committed
265
            client->ClientNotify(refnum, name, kRemoveClient, true, 0, 0);
sletz's avatar
sletz committed
266
267
268
269
270
        }
    }
}

// Coming from the driver
271
void JackEngine::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs)
sletz's avatar
sletz committed
272
273
{
    // Use the audio thread => request thread communication channel
sletz's avatar
sletz committed
274
    fEngineControl->ResetFrameTime(callback_usecs);
275
    fEngineControl->NotifyXRun(delayed_usecs);
276
    fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);
sletz's avatar
sletz committed
277
278
279
280
281
}

void JackEngine::NotifyXRun(int refnum)
{
    if (refnum == ALL_CLIENTS) {
sletz's avatar
sletz committed
282
        NotifyClients(kXRunCallback, false, 0, 0);
sletz's avatar
sletz committed
283
    } else {
sletz's avatar
sletz committed
284
        NotifyClient(refnum, kXRunCallback, false, 0, 0);
sletz's avatar
sletz committed
285
286
287
288
289
    }
}

void JackEngine::NotifyGraphReorder()
{
sletz's avatar
sletz committed
290
    NotifyClients(kGraphOrderCallback, false, 0, 0);
sletz's avatar
sletz committed
291
292
}

293
void JackEngine::NotifyBufferSize(jack_nframes_t buffer_size)
sletz's avatar
sletz committed
294
{
295
296
297
298
299
300
    NotifyClients(kBufferSizeCallback, true, buffer_size, 0);
}

void JackEngine::NotifySampleRate(jack_nframes_t sample_rate)
{
    NotifyClients(kSampleRateCallback, true, sample_rate, 0);
sletz's avatar
sletz committed
301
302
303
304
305
}

void JackEngine::NotifyFreewheel(bool onoff)
{
    fEngineControl->fRealTime = !onoff;
sletz's avatar
sletz committed
306
    NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, 0, 0);
sletz's avatar
sletz committed
307
308
309
310
}

void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
{
sletz's avatar
sletz committed
311
312
313
    NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, port_index, 0);
}

314
315
316
317
318
void JackEngine::NotifyPortRename(jack_port_id_t port)
{
    NotifyClients(kPortRenameCallback, false, port, 0);
}

sletz's avatar
sletz committed
319
320
321
void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff)
{
    NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, src, dst);
sletz's avatar
sletz committed
322
323
}

324
325
void JackEngine::NotifyActivate(int refnum)
{
sletz's avatar
sletz committed
326
    NotifyClient(refnum, kActivateClient, true, 0, 0);
327
328
}

329
330
331
332
//----------------------------
// Loadable client management
//----------------------------

333
int JackEngine::GetInternalClientName(int refnum, char* name_res)
334
{
335
    AssertRefnum(refnum);
sletz's avatar
sletz committed
336
337
338
339
340
341
342
    JackClientInterface* client = fClientTable[refnum];
    if (client) {
        strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
        return 0;
    } else {
        return -1;
    }
343
344
345
346
}

int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref)
{
sletz's avatar
sletz committed
347
348
349
350
    // Clear status
    *status = 0;

    for (int i = 0; i < CLIENT_NUM; i++) {
351
352
        JackClientInterface* client = fClientTable[i];
        if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) {
sletz's avatar
sletz committed
353
            jack_log("InternalClientHandle found client name = %s ref = %ld",  client_name, i);
sletz's avatar
sletz committed
354
355
356
            *int_ref = i;
            return 0;
        }
357
    }
sletz's avatar
sletz committed
358
359
360

    *status |= (JackNoSuchClient | JackFailure);
    return -1;
361
362
363
364
}

int JackEngine::InternalClientUnload(int refnum, int* status)
{
365
    AssertRefnum(refnum);
sletz's avatar
sletz committed
366
367
368
369
370
371
372
373
    JackClientInterface* client = fClientTable[refnum];
    if (client) {
        int res = client->Close();
        delete client;
        *status = 0;
        return res;
    } else {
        *status = (JackNoSuchClient | JackFailure);
374
375
376
377
        return -1;
    }
}

sletz's avatar
sletz committed
378
379
380
381
//-------------------
// Client management
//-------------------

382
int JackEngine::ClientCheck(const char* name, char* name_res, int protocol, int options, int* status)
383
{
sletz's avatar
sletz committed
384
385
386
387
    // Clear status
    *status = 0;
    strcpy(name_res, name);

sletz's avatar
sletz committed
388
    jack_log("Check protocol client %ld server = %ld", protocol, JACK_PROTOCOL_VERSION);
sletz's avatar
sletz committed
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

    if (protocol != JACK_PROTOCOL_VERSION) {
        *status |= (JackFailure | JackVersionError);
        jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION);
        return -1;
    }

    if (ClientCheckName(name)) {

        *status |= JackNameNotUnique;

        if (options & JackUseExactName) {
            jack_error("cannot create new client; %s already exists", name);
            *status |= JackFailure;
            return -1;
        }

        if (GenerateUniqueName(name_res)) {
            *status |= JackFailure;
            return -1;
        }
    }

    return 0;
413
414
415
416
}

bool JackEngine::GenerateUniqueName(char* name)
{
sletz's avatar
sletz committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
    int tens, ones;
    int length = strlen(name);

    if (length > JACK_CLIENT_NAME_SIZE - 4) {
        jack_error("%s exists and is too long to make unique", name);
        return true;		/* failure */
    }

    /*  generate a unique name by appending "-01".."-99" */
    name[length++] = '-';
    tens = length++;
    ones = length++;
    name[tens] = '0';
    name[ones] = '1';
    name[length] = '\0';

    while (ClientCheckName(name)) {
        if (name[ones] == '9') {
            if (name[tens] == '9') {
                jack_error("client %s has 99 extra instances already", name);
                return true; /* give up */
            }
            name[tens]++;
            name[ones] = '0';
        } else {
            name[ones]++;
        }
    }
    return false;
446
447
}

sletz's avatar
sletz committed
448
449
450
451
452
453
454
455
456
457
458
bool JackEngine::ClientCheckName(const char* name)
{
    for (int i = 0; i < CLIENT_NUM; i++) {
        JackClientInterface* client = fClientTable[i];
        if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
            return true;
    }

    return false;
}

459
460
461
462
463
464
465
int JackEngine::GetClientPID(const char* name)
{
    for (int i = 0; i < CLIENT_NUM; i++) {
        JackClientInterface* client = fClientTable[i];
        if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
            return client->GetClientControl()->fPID;
    }
sletz's avatar
sletz committed
466

467
468
469
    return 0;
}

sletz's avatar
sletz committed
470
471
472
473
474
475
476
int JackEngine::GetClientRefNum(const char* name)
{
    for (int i = 0; i < CLIENT_NUM; i++) {
        JackClientInterface* client = fClientTable[i];
        if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
            return client->GetClientControl()->fRefNum;
    }
sletz's avatar
sletz committed
477

sletz's avatar
sletz committed
478
479
480
    return -1;
}

sletz's avatar
sletz committed
481
// Used for external clients
482
int JackEngine::ClientExternalOpen(const char* name, int pid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
sletz's avatar
sletz committed
483
{
sletz's avatar
sletz committed
484
    jack_log("JackEngine::ClientOpen: name = %s ", name);
sletz's avatar
sletz committed
485
486

    int refnum = AllocateRefnum();
sletz's avatar
sletz committed
487
488
489
490
    if (refnum < 0) {
        jack_error("No more refnum available");
        return -1;
    }
sletz's avatar
sletz committed
491
492

    JackExternalClient* client = new JackExternalClient();
sletz's avatar
sletz committed
493

494
    if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) {
495
        jack_error("Cannot allocate synchro");
sletz's avatar
sletz committed
496
        goto error;
sletz's avatar
sletz committed
497
498
    }

499
    if (client->Open(name, pid, refnum, shared_client) < 0) {
sletz's avatar
sletz committed
500
        jack_error("Cannot open client");
501
        goto error;
sletz's avatar
sletz committed
502
503
    }

504
    if (!fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
sletz's avatar
sletz committed
505
506
        // Failure if RT thread is not running (problem with the driver...)
        jack_error("Driver is not running");
507
        goto error;
sletz's avatar
sletz committed
508
509
    }

510
511
    fClientTable[refnum] = client;

sletz's avatar
sletz committed
512
513
    if (NotifyAddClient(client, name, refnum) < 0) {
        jack_error("Cannot notify add client");
514
        goto error;
sletz's avatar
sletz committed
515
    }
sletz's avatar
sletz committed
516

sletz's avatar
sletz committed
517
518
    fGraphManager->InitRefNum(refnum);
    fEngineControl->ResetRollingUsecs();
sletz's avatar
sletz committed
519
520
521
    *shared_engine = fEngineControl->GetShmIndex();
    *shared_graph_manager = fGraphManager->GetShmIndex();
    *ref = refnum;
522
523
524
    return 0;

error:
525
    // Cleanup...
526
    fSynchroTable[refnum].Destroy();
527
    fClientTable[refnum] = 0;
sletz's avatar
sletz committed
528
    client->Close();
sletz's avatar
sletz committed
529
    delete client;
sletz's avatar
sletz committed
530
531
532
533
    return -1;
}

// Used for server driver clients
534
int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
sletz's avatar
sletz committed
535
{
sletz's avatar
sletz committed
536
    jack_log("JackEngine::ClientInternalNew: name = %s", name);
sletz's avatar
sletz committed
537
538
539

    int refnum = AllocateRefnum();
    if (refnum < 0) {
sletz's avatar
sletz committed
540
        jack_error("No more refnum available");
541
        goto error;
sletz's avatar
sletz committed
542
543
    }

544
    if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) {
sletz's avatar
sletz committed
545
        jack_error("Cannot allocate synchro");
546
        goto error;
sletz's avatar
sletz committed
547
    }
sletz's avatar
sletz committed
548

549
    if (wait && !fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
550
551
        // Failure if RT thread is not running (problem with the driver...)
        jack_error("Driver is not running");
552
        goto error;
553
    }
sletz's avatar
sletz committed
554

555
556
    fClientTable[refnum] = client;

sletz's avatar
sletz committed
557
558
    if (NotifyAddClient(client, name, refnum) < 0) {
        jack_error("Cannot notify add client");
559
        goto error;
sletz's avatar
sletz committed
560
561
    }

sletz's avatar
sletz committed
562
563
    fGraphManager->InitRefNum(refnum);
    fEngineControl->ResetRollingUsecs();
sletz's avatar
sletz committed
564
565
566
567
    *shared_engine = fEngineControl;
    *shared_manager = fGraphManager;
    *ref = refnum;
    return 0;
568
569
570

error:
    // Cleanup...
571
    fSynchroTable[refnum].Destroy();
572
573
    fClientTable[refnum] = 0;
    return -1;
sletz's avatar
sletz committed
574
575
}

576
// Used for external clients
sletz's avatar
sletz committed
577
int JackEngine::ClientExternalClose(int refnum)
sletz's avatar
sletz committed
578
{
579
    AssertRefnum(refnum);
sletz's avatar
sletz committed
580
    JackClientInterface* client = fClientTable[refnum];
sletz's avatar
sletz committed
581

sletz's avatar
sletz committed
582
583
584
585
586
587
588
589
590
591
592
    if (client)	{
        fEngineControl->fTransport.ResetTimebase(refnum);
        int res = ClientCloseAux(refnum, client, true);
        client->Close();
        delete client;
        return res;
    } else {
        return -1;
    }
}

593
594
// Used for server internal clients or drivers when the RT thread is stopped
int JackEngine::ClientInternalClose(int refnum, bool wait)
sletz's avatar
sletz committed
595
{
596
    AssertRefnum(refnum);
sletz's avatar
sletz committed
597
    JackClientInterface* client = fClientTable[refnum];
598
    return (client)	? ClientCloseAux(refnum, client, wait) : -1;
sletz's avatar
sletz committed
599
600
601
602
}

int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
{
603
    jack_log("JackEngine::ClientCloseAux ref = %ld", refnum);
sletz's avatar
sletz committed
604

605
    // Unregister all ports ==> notifications are sent
sletz's avatar
sletz committed
606
607
608
609
610
    jack_int_t ports[PORT_NUM_FOR_CLIENT];
    int i;

    fGraphManager->GetInputPorts(refnum, ports);
    for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
611
        PortUnRegister(refnum, ports[i]);
sletz's avatar
sletz committed
612
613
614
615
    }

    fGraphManager->GetOutputPorts(refnum, ports);
    for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
616
        PortUnRegister(refnum, ports[i]);
sletz's avatar
sletz committed
617
    }
sletz's avatar
sletz committed
618

619
620
    // Remove the client from the table
    ReleaseRefnum(refnum);
sletz's avatar
sletz committed
621
622

    // Remove all ports
sletz's avatar
Typo    
sletz committed
623
    fGraphManager->RemoveAllPorts(refnum);
sletz's avatar
sletz committed
624
625
626

    // Wait until next cycle to be sure client is not used anymore
    if (wait) {
627
        if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
sletz's avatar
sletz committed
628
            jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum);
sletz's avatar
sletz committed
629
        }
sletz's avatar
Typo    
sletz committed
630
    }
sletz's avatar
sletz committed
631

sletz's avatar
Typo    
sletz committed
632
    // Notify running clients
633
    NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
sletz's avatar
sletz committed
634
635

    // Cleanup...
636
    fSynchroTable[refnum].Destroy();
sletz's avatar
sletz committed
637
    fEngineControl->ResetRollingUsecs();
sletz's avatar
sletz committed
638
639
640
    return 0;
}

641
int JackEngine::ClientActivate(int refnum, bool state)
sletz's avatar
sletz committed
642
{
643
    AssertRefnum(refnum);
sletz's avatar
sletz committed
644
    JackClientInterface* client = fClientTable[refnum];
sletz's avatar
sletz committed
645
    assert(fClientTable[refnum]);
sletz's avatar
sletz committed
646

sletz's avatar
sletz committed
647
    jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
sletz's avatar
sletz committed
648
    if (state)
649
        fGraphManager->Activate(refnum);
sletz's avatar
sletz committed
650

sletz's avatar
sletz committed
651
    // Wait for graph state change to be effective
652
    if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
sletz's avatar
sletz committed
653
654
655
656
657
658
        jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
        return -1;
    } else {
        NotifyActivate(refnum);
        return 0;
    }
sletz's avatar
sletz committed
659
660
661
662
663
}

// May be called without client
int JackEngine::ClientDeactivate(int refnum)
{
664
    AssertRefnum(refnum);
sletz's avatar
sletz committed
665
    JackClientInterface* client = fClientTable[refnum];
sletz's avatar
sletz committed
666
667
668
    if (client == NULL)
        return -1;

sletz's avatar
sletz committed
669
    jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
sletz's avatar
sletz committed
670

671
672
673
    // Disconnect all ports ==> notifications are sent
    jack_int_t ports[PORT_NUM_FOR_CLIENT];
    int i;
sletz's avatar
sletz committed
674

675
676
677
678
679
680
681
682
683
    fGraphManager->GetInputPorts(refnum, ports);
    for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
        PortDisconnect(refnum, ports[i], ALL_PORTS);
    }

    fGraphManager->GetOutputPorts(refnum, ports);
    for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
        PortDisconnect(refnum, ports[i], ALL_PORTS);
    }
sletz's avatar
sletz committed
684

sletz's avatar
sletz committed
685
686
687
688
    fGraphManager->Deactivate(refnum);
    fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients

    // Wait for graph state change to be effective
689
    if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
sletz's avatar
sletz committed
690
691
692
693
694
        jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
        return -1;
    } else {
        return 0;
    }
sletz's avatar
sletz committed
695
696
697
698
699
700
}

//-----------------
// Port management
//-----------------

701
int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
sletz's avatar
sletz committed
702
{
sletz's avatar
sletz committed
703
    jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size);
704
    AssertRefnum(refnum);
sletz's avatar
sletz committed
705
    assert(fClientTable[refnum]);
sletz's avatar
sletz committed
706

707
    // Check if port name already exists
sletz's avatar
sletz committed
708
    if (fGraphManager->GetPort(name) != NO_PORT) {
709
        jack_error("port_name \"%s\" already exists", name);
sletz's avatar
sletz committed
710
        return -1;
711
    }
sletz's avatar
sletz committed
712

713
    *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
sletz's avatar
sletz committed
714
715
716
717
718
719
720
721
722
723
    if (*port_index != NO_PORT) {
        NotifyPortRegistation(*port_index, true);
        return 0;
    } else {
        return -1;
    }
}

int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
{
sletz's avatar
sletz committed
724
    jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index);
725
    AssertRefnum(refnum);
sletz's avatar
sletz committed
726
    assert(fClientTable[refnum]);
sletz's avatar
sletz committed
727

728
729
    // Disconnect port ==> notification is sent
    PortDisconnect(refnum, port_index, ALL_PORTS);
sletz's avatar
sletz committed
730

731
    if (fGraphManager->ReleasePort(refnum, port_index) == 0) {
sletz's avatar
sletz committed
732
733
734
735
736
737
738
739
740
        NotifyPortRegistation(port_index, false);
        return 0;
    } else {
        return -1;
    }
}

int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
{
sletz's avatar
sletz committed
741
    jack_log("JackEngine::PortConnect src = %s dst = %s", src, dst);
sletz's avatar
sletz committed
742
    AssertRefnum(refnum);
sletz's avatar
sletz committed
743
744
    jack_port_id_t port_src, port_dst;

sletz's avatar
sletz committed
745
    return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
sletz's avatar
sletz committed
746
747
748
749
750
751
           ? -1
           : PortConnect(refnum, port_src, port_dst);
}

int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
{
sletz's avatar
sletz committed
752
    jack_log("JackEngine::PortConnect src = %d dst = %d", src, dst);
753
    AssertRefnum(refnum);
sletz's avatar
sletz committed
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
    JackClientInterface* client;
    int ref;

    if (fGraphManager->CheckPorts(src, dst) < 0)
        return -1;

    ref = fGraphManager->GetOutputRefNum(src);
    assert(ref >= 0);
    client = fClientTable[ref];
    assert(client);
    if (!client->GetClientControl()->fActive) {
        jack_error("Cannot connect ports owned by inactive clients:"
                   " \"%s\" is not active", client->GetClientControl()->fName);
        return -1;
    }

    ref = fGraphManager->GetInputRefNum(dst);
    assert(ref >= 0);
    client = fClientTable[ref];
    assert(client);
    if (!client->GetClientControl()->fActive) {
        jack_error("Cannot connect ports owned by inactive clients:"
                   " \"%s\" is not active", client->GetClientControl()->fName);
        return -1;
    }
sletz's avatar
sletz committed
779
780

    int res = fGraphManager->Connect(src, dst);
sletz's avatar
sletz committed
781
    if (res == 0)
sletz's avatar
sletz committed
782
783
        NotifyPortConnect(src, dst, true);
    return res;
sletz's avatar
sletz committed
784
785
}

786
787
int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
{
sletz's avatar
sletz committed
788
    jack_log("JackEngine::PortDisconnect src = %s dst = %s", src, dst);
789
    AssertRefnum(refnum);
790
    jack_port_id_t port_src, port_dst;
sletz's avatar
sletz committed
791

sletz's avatar
sletz committed
792
793
794
    return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
           ? -1
           : PortDisconnect(refnum, port_src, port_dst);
795
796
}

sletz's avatar
sletz committed
797
798
int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
{
sletz's avatar
sletz committed
799
    jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst);
800
    AssertRefnum(refnum);
sletz's avatar
sletz committed
801

sletz's avatar
sletz committed
802
    if (dst == ALL_PORTS) {
sletz's avatar
sletz committed
803

804
        jack_int_t connections[CONNECTION_NUM_FOR_PORT];
sletz's avatar
sletz committed
805
806
807
        fGraphManager->GetConnections(src, connections);

        JackPort* port = fGraphManager->GetPort(src);
sletz's avatar
sletz committed
808
        int ret = 0;
sletz's avatar
sletz committed
809
        if (port->GetFlags() & JackPortIsOutput) {
810
            for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
sletz's avatar
sletz committed
811
812
813
                if (PortDisconnect(refnum, src, connections[i]) != 0) {
                    ret = -1;
                }
sletz's avatar
sletz committed
814
815
            }
        } else {
816
            for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
sletz's avatar
sletz committed
817
818
819
                if (PortDisconnect(refnum, connections[i], src) != 0) {
                    ret = -1;
                }
sletz's avatar
sletz committed
820
821
822
            }
        }

sletz's avatar
sletz committed
823
        return ret;
sletz's avatar
sletz committed
824
825
826
827
828
829
    } else if (fGraphManager->CheckPorts(src, dst) < 0) {
        return -1;
    } else if (fGraphManager->Disconnect(src, dst) == 0) {
        // Notifications
        NotifyPortConnect(src, dst, false);
        return 0;
sletz's avatar
sletz committed
830
    } else {
sletz's avatar
sletz committed
831
832
        return -1;
    }
sletz's avatar
sletz committed
833
834
}

835
836
int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name)
{
sletz's avatar
sletz committed
837
    AssertRefnum(refnum);
sletz's avatar
sletz committed
838
839
840
    fGraphManager->GetPort(port)->SetName(name);
    NotifyPortRename(port);
    return 0;
841
}
sletz's avatar
sletz committed
842
843
844

} // end of namespace