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

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 <assert.h>
23
24
#include <cassert>
#include <csignal>
sletz's avatar
sletz committed
25
26
#include <sys/types.h>
#include <getopt.h>
27
28
#include <cstring>
#include <cstdio>
29
#include <list>
30

31
#include "types.h"
sletz's avatar
sletz committed
32
#include "jack.h"
33
34
#include "control.h"

sletz's avatar
sletz committed
35
#include "JackConstants.h"
36
#include "JackPlatformPlug.h"
sletz's avatar
sletz committed
37

38
#if defined(JACK_DBUS) && defined(__linux__)
39
#include <dbus/dbus.h>
40
41
42
#include "audio_reserve.h"
#endif

sletz's avatar
sletz committed
43
/*
sletz's avatar
sletz committed
44
This is a simple port of the old jackdmp.cpp file to use the new Jack 2.0 control API. Available options for the server
sletz's avatar
sletz committed
45
46
47
48
are "hard-coded" in the source. A much better approach would be to use the control API to:
- dynamically retrieve available server parameters and then prepare to parse them
- get available drivers and their possible parameters, then prepare to parse them.
*/
sletz's avatar
sletz committed
49

50
#ifdef __APPLE__
51
#include <CoreFoundation/CFNotificationCenter.h>
52
#include <CoreFoundation/CoreFoundation.h>
53

sletz's avatar
sletz committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
static void notify_server_start(const char* server_name)
{
    // Send notification to be used in the JackRouter plugin
    CFStringRef ref = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
    CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
            CFSTR("com.grame.jackserver.start"),
            ref,
            NULL,
            kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
    CFRelease(ref);
}

static void notify_server_stop(const char* server_name)
{
    // Send notification to be used in the JackRouter plugin
sletz's avatar
sletz committed
69
    CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
sletz's avatar
sletz committed
70
71
72
73
74
75
76
    CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
            CFSTR("com.grame.jackserver.stop"),
            ref1,
            NULL,
            kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
    CFRelease(ref1);
}
sletz's avatar
sletz committed
77

sletz's avatar
sletz committed
78
79
80
81
82
83
84
85
#else

static void notify_server_start(const char* server_name)
{}
static void notify_server_stop(const char* server_name)
{}

#endif
sletz's avatar
sletz committed
86
87
88

static void copyright(FILE* file)
{
sletz's avatar
sletz committed
89
    fprintf(file, "jackdmp " VERSION "\n"
sletz's avatar
sletz committed
90
            "Copyright 2001-2005 Paul Davis and others.\n"
91
            "Copyright 2004-2013 Grame.\n"
sletz's avatar
sletz committed
92
93
94
            "jackdmp comes with ABSOLUTELY NO WARRANTY\n"
            "This is free software, and you are welcome to redistribute it\n"
            "under certain conditions; see the file COPYING for details\n");
sletz's avatar
sletz committed
95
96
}

97
static jackctl_driver_t * jackctl_server_get_driver(jackctl_server_t *server, const char *driver_name)
sletz's avatar
sletz committed
98
{
99
    const JSList * node_ptr = jackctl_server_get_drivers_list(server);
sletz's avatar
sletz committed
100

101
102
    while (node_ptr) {
        if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) {
sletz's avatar
sletz committed
103
104
105
106
107
108
            return (jackctl_driver_t *)node_ptr->data;
        }
        node_ptr = jack_slist_next(node_ptr);
    }

    return NULL;
sletz's avatar
sletz committed
109
110
}

111
112
113
114
115
116
117
118
119
120
121
122
123
124
static void print_server_drivers(jackctl_server_t *server, FILE* file)
{
    const JSList * node_ptr = jackctl_server_get_drivers_list(server);

    fprintf(file, "Available backends:\n");
    
    while (node_ptr) {
        jackctl_driver_t* driver = (jackctl_driver_t *)node_ptr->data;
        fprintf(file, "      %s (%s)\n", jackctl_driver_get_name(driver), (jackctl_driver_get_type(driver) == JackMaster) ? "master" : "slave");
        node_ptr = jack_slist_next(node_ptr);
    }
    fprintf(file, "\n");
}

125
126
127
128
129
130
131
132
133
134
135
136
137
138
static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name)
{
    const JSList * node_ptr = jackctl_server_get_internals_list(server);

    while (node_ptr) {
        if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) {
            return (jackctl_internal_t *)node_ptr->data;
        }
        node_ptr = jack_slist_next(node_ptr);
    }

    return NULL;
}

139
140
141
142
143
144
145
146
147
148
149
150
151
152
static void print_server_internals(jackctl_server_t *server, FILE* file)
{
    const JSList * node_ptr = jackctl_server_get_internals_list(server);

    fprintf(file, "Available internals:\n");
    
    while (node_ptr) {
        jackctl_internal_t* internal = (jackctl_internal_t *)node_ptr->data;
        fprintf(file, "      %s\n", jackctl_internal_get_name(internal));
        node_ptr = jack_slist_next(node_ptr);
    }
    fprintf(file, "\n");
}

153
static jackctl_parameter_t * jackctl_get_parameter(const JSList * parameters_list, const char * parameter_name)
sletz's avatar
sletz committed
154
{
155
156
    while (parameters_list) {
        if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) {
sletz's avatar
sletz committed
157
158
159
160
161
162
            return (jackctl_parameter_t *)parameters_list->data;
        }
        parameters_list = jack_slist_next(parameters_list);
    }

    return NULL;
sletz's avatar
sletz committed
163
164
}

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

static void usage(FILE* file, jackctl_server_t *server)
{
    fprintf(file, "\n"
            "usage: jackdmp [ --no-realtime OR -r ]\n"
            "               [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n"
            "      (the two previous arguments are mutually exclusive. The default is --realtime)\n"
            "               [ --name OR -n server-name ]\n"
            "               [ --timeout OR -t client-timeout-in-msecs ]\n"
            "               [ --loopback OR -L loopback-port-number ]\n"
            "               [ --port-max OR -p maximum-number-of-ports]\n"
            "               [ --slave-backend OR -X slave-backend-name ]\n"
            "               [ --internal-client OR -I internal-client-name ]\n"
            "               [ --verbose OR -v ]\n"
#ifdef __linux__
            "               [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n"
#endif
            "               [ --replace-registry ]\n"
            "               [ --silent OR -s ]\n"
            "               [ --sync OR -S ]\n"
            "               [ --temporary OR -T ]\n"
            "               [ --version OR -V ]\n"
            "         -d master-backend-name [ ... master-backend args ... ]\n"
            "       jackdmp -d master-backend-name --help\n"
            "             to display options for each master backend\n\n");
    
    if (server) {
        print_server_drivers(server, file);
        print_server_internals(server, file);
    }
}

sletz's avatar
sletz committed
197
198
199
// Prototype to be found in libjackserver
extern "C" void silent_jack_error_callback(const char *desc);

200
int main(int argc, char** argv)
sletz's avatar
sletz committed
201
{
sletz's avatar
sletz committed
202
203
204
    jackctl_server_t * server_ctl;
    const JSList * server_parameters;
    const char* server_name = "default";
205
    jackctl_driver_t * master_driver_ctl;
sletz's avatar
sletz committed
206
    jackctl_driver_t * loopback_driver_ctl = NULL;
207
    int replace_registry = 0;
208

209
    const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:"
210
#ifdef __linux__
211
        "c:"
212
#endif
213
        ;
214

sletz's avatar
sletz committed
215
    struct option long_options[] = {
216
217
218
#ifdef __linux__
                                       { "clock-source", 1, 0, 'c' },
#endif
219
                                       { "loopback-driver", 1, 0, 'L' },
220
221
                                       { "audio-driver", 1, 0, 'd' },
                                       { "midi-driver", 1, 0, 'X' },
222
                                       { "internal-client", 1, 0, 'I' },
sletz's avatar
sletz committed
223
224
225
226
                                       { "verbose", 0, 0, 'v' },
                                       { "help", 0, 0, 'h' },
                                       { "port-max", 1, 0, 'p' },
                                       { "no-mlock", 0, 0, 'm' },
sletz's avatar
sletz committed
227
                                       { "name", 1, 0, 'n' },
sletz's avatar
sletz committed
228
229
                                       { "unlock", 0, 0, 'u' },
                                       { "realtime", 0, 0, 'R' },
230
                                       { "no-realtime", 0, 0, 'r' },
231
                                       { "replace-registry", 0, &replace_registry, 0 },
sletz's avatar
sletz committed
232
233
234
235
236
237
238
239
240
                                       { "loopback", 0, 0, 'L' },
                                       { "realtime-priority", 1, 0, 'P' },
                                       { "timeout", 1, 0, 't' },
                                       { "temporary", 0, 0, 'T' },
                                       { "version", 0, 0, 'V' },
                                       { "silent", 0, 0, 's' },
                                       { "sync", 0, 0, 'S' },
                                       { 0, 0, 0, 0 }
                                   };
241

sletz's avatar
sletz committed
242
    int i,opt = 0;
sletz's avatar
sletz committed
243
    int option_index = 0;
244
245
    char* master_driver_name = NULL;
    char** master_driver_args = NULL;
246
    int master_driver_nargs = 1;
247
    int loopback = 0;
sletz's avatar
sletz committed
248
    bool show_version = false;
249
    jackctl_sigmask_t * sigmask;
sletz's avatar
sletz committed
250
251
    jackctl_parameter_t* param;
    union jackctl_parameter_value value;
sletz's avatar
sletz committed
252

253
254
255
256
    std::list<char*> internals_list;
    std::list<char*> slaves_list;
    std::list<char*>::iterator it;

257
258
259
260
    // Assume that we fail.
    int return_value = -1;
    bool notify_sent = false;

nedko's avatar
nedko committed
261
    copyright(stdout);
262
263
264
#if defined(JACK_DBUS) && defined(__linux__)
    server_ctl = jackctl_server_create(audio_acquire, audio_release);
#else
265
    server_ctl = jackctl_server_create(NULL, NULL);
266
#endif
sletz's avatar
sletz committed
267
    if (server_ctl == NULL) {
sletz's avatar
Cleanup    
sletz committed
268
        fprintf(stderr, "Failed to create server object\n");
sletz's avatar
sletz committed
269
270
        return -1;
    }
271

sletz's avatar
sletz committed
272
    server_parameters = jackctl_server_get_parameters(server_ctl);
273

sletz's avatar
sletz committed
274
    opterr = 0;
275
    while (!master_driver_name &&
sletz's avatar
sletz committed
276
277
278
279
            (opt = getopt_long(argc, argv, options,
                               long_options, &option_index)) != EOF) {
        switch (opt) {

280
        #ifdef __linux__
281
282
283
284
285
286
287
288
289
290
291
292
293
            case 'c':
                param = jackctl_get_parameter(server_parameters, "clock-source");
                if (param != NULL) {
                    if (tolower (optarg[0]) == 'h') {
                        value.ui = JACK_TIMER_HPET;
                        jackctl_parameter_set_value(param, &value);
                    } else if (tolower (optarg[0]) == 'c') {
                        value.ui = JACK_TIMER_CYCLE_COUNTER;
                        jackctl_parameter_set_value(param, &value);
                    } else if (tolower (optarg[0]) == 's') {
                        value.ui = JACK_TIMER_SYSTEM_CLOCK;
                        jackctl_parameter_set_value(param, &value);
                    } else {
294
                        usage(stdout, NULL);
295
                        goto destroy_server;
296
297
298
299
300
                    }
                }
                break;
        #endif

sletz's avatar
sletz committed
301
            case 'd':
302
                master_driver_name = optarg;
303
                break;
304

305
306
307
            case 'L':
                loopback = atoi(optarg);
                break;
sletz's avatar
sletz committed
308

309
            case 'X':
310
311
312
313
314
                slaves_list.push_back(optarg);
                break;

            case 'I':
                internals_list.push_back(optarg);
sletz's avatar
sletz committed
315
                break;
sletz's avatar
sletz committed
316

317
            case 'p':
sletz's avatar
sletz committed
318
319
320
321
322
                param = jackctl_get_parameter(server_parameters, "port-max");
                if (param != NULL) {
                    value.ui = atoi(optarg);
                    jackctl_parameter_set_value(param, &value);
                }
323
                break;
sletz's avatar
sletz committed
324

sletz's avatar
sletz committed
325
            case 'v':
sletz's avatar
sletz committed
326
327
328
329
330
                param = jackctl_get_parameter(server_parameters, "verbose");
                if (param != NULL) {
                    value.b = true;
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
331
332
333
334
335
336
337
                break;

            case 's':
                jack_set_error_function(silent_jack_error_callback);
                break;

            case 'S':
sletz's avatar
sletz committed
338
339
340
341
342
                param = jackctl_get_parameter(server_parameters, "sync");
                if (param != NULL) {
                    value.b = true;
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
343
344
345
346
                break;

            case 'n':
                server_name = optarg;
sletz's avatar
sletz committed
347
348
349
350
351
                param = jackctl_get_parameter(server_parameters, "name");
                if (param != NULL) {
                    strncpy(value.str, optarg, JACK_PARAM_STRING_MAX);
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
352
353
354
                break;

            case 'P':
sletz's avatar
sletz committed
355
356
357
358
359
                param = jackctl_get_parameter(server_parameters, "realtime-priority");
                if (param != NULL) {
                    value.i = atoi(optarg);
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
360
                break;
361

sletz's avatar
sletz committed
362
            case 'r':
363
                param = jackctl_get_parameter(server_parameters, "realtime");
sletz's avatar
sletz committed
364
                if (param != NULL) {
365
                    value.b = false;
sletz's avatar
sletz committed
366
367
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
368
369
                break;

sletz's avatar
sletz committed
370
            case 'R':
sletz's avatar
sletz committed
371
372
373
374
375
                param = jackctl_get_parameter(server_parameters, "realtime");
                if (param != NULL) {
                    value.b = true;
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
376
377
378
                break;

            case 'T':
sletz's avatar
sletz committed
379
380
381
382
383
                param = jackctl_get_parameter(server_parameters, "temporary");
                if (param != NULL) {
                    value.b = true;
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
384
385
386
                break;

            case 't':
sletz's avatar
sletz committed
387
388
389
390
391
                param = jackctl_get_parameter(server_parameters, "client-timeout");
                if (param != NULL) {
                    value.i = atoi(optarg);
                    jackctl_parameter_set_value(param, &value);
                }
sletz's avatar
sletz committed
392
393
394
                break;

            case 'V':
sletz's avatar
sletz committed
395
                show_version = true;
sletz's avatar
sletz committed
396
397
398
                break;

            default:
sletz's avatar
sletz committed
399
                fprintf(stderr, "unknown option character %c\n", optopt);
sletz's avatar
sletz committed
400
                /*fallthru*/
sletz's avatar
sletz committed
401

sletz's avatar
sletz committed
402
            case 'h':
403
                usage(stdout, server_ctl);
404
                goto destroy_server;
sletz's avatar
sletz committed
405
406
        }
    }
407

408
409
410
411
412
413
    // Long option with no letter so treated separately
    param = jackctl_get_parameter(server_parameters, "replace-registry");
    if (param != NULL) {
        value.b = replace_registry;
        jackctl_parameter_set_value(param, &value);
    }
414

sletz's avatar
sletz committed
415
    if (show_version) {
sletz's avatar
sletz committed
416
        printf( "jackdmp version " VERSION
nedko's avatar
nedko committed
417
418
419
420
                " tmpdir " jack_server_dir
                " protocol %d"
                "\n", JACK_PROTOCOL_VERSION);
        return -1;
sletz's avatar
sletz committed
421
    }
sletz's avatar
sletz committed
422

423
    if (!master_driver_name) {
424
        usage(stderr, NULL);
425
        goto destroy_server;
sletz's avatar
sletz committed
426
    }
sletz's avatar
sletz committed
427

428
    // Master driver
429
430
431
    master_driver_ctl = jackctl_server_get_driver(server_ctl, master_driver_name);
    if (master_driver_ctl == NULL) {
        fprintf(stderr, "Unknown driver \"%s\"\n", master_driver_name);
432
        goto destroy_server;
sletz's avatar
sletz committed
433
434
    }

sletz's avatar
sletz committed
435
436
437
438
439
    if (jackctl_driver_get_type(master_driver_ctl) != JackMaster) {
        fprintf(stderr, "Driver \"%s\" is not a master \n", master_driver_name);
        goto destroy_server;
    }

sletz's avatar
sletz committed
440
    if (optind < argc) {
441
        master_driver_nargs = 1 + argc - optind;
sletz's avatar
sletz committed
442
    } else {
443
        master_driver_nargs = 1;
sletz's avatar
sletz committed
444
445
    }

446
    if (master_driver_nargs == 0) {
sletz's avatar
sletz committed
447
        fprintf(stderr, "No driver specified ... hmm. JACK won't do"
sletz's avatar
sletz committed
448
                " anything when run like this.\n");
449
        goto destroy_server;
sletz's avatar
sletz committed
450
451
    }

452
453
    master_driver_args = (char **) malloc(sizeof(char *) * master_driver_nargs);
    master_driver_args[0] = master_driver_name;
sletz's avatar
sletz committed
454

455
456
    for (i = 1; i < master_driver_nargs; i++) {
        master_driver_args[i] = argv[optind++];
sletz's avatar
sletz committed
457
458
    }

459
    if (jackctl_driver_params_parse(master_driver_ctl, master_driver_nargs, master_driver_args)) {
460
        goto destroy_server;
sletz's avatar
sletz committed
461
    }
sletz's avatar
sletz committed
462

463
    // Setup signals
464
    sigmask = jackctl_setup_signals(0);
465

466
467
468
469
    // Open server
    if (! jackctl_server_open(server_ctl, master_driver_ctl)) {
        fprintf(stderr, "Failed to open server\n");
        goto destroy_server;
sletz's avatar
sletz committed
470
    }
sletz's avatar
sletz committed
471

472
    // Slave drivers
473
474
475
476
    for (it = slaves_list.begin(); it != slaves_list.end(); it++) {
        jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it);
        if (slave_driver_ctl == NULL) {
            fprintf(stderr, "Unknown driver \"%s\"\n", *it);
477
            goto close_server;
478
        }
sletz's avatar
sletz committed
479
480
481
482
        if (jackctl_driver_get_type(slave_driver_ctl) != JackSlave) {
            fprintf(stderr, "Driver \"%s\" is not a slave \n", *it);
            goto close_server;
        }
Stephane Letz's avatar
Stephane Letz committed
483
484
        if (!jackctl_server_add_slave(server_ctl, slave_driver_ctl)) {
            fprintf(stderr, "Driver \"%s\" cannot be loaded\n", *it);
485
            goto close_server;
Stephane Letz's avatar
Stephane Letz committed
486
        }
487
    }
488

489
490
491
    // Loopback driver
    if (loopback > 0) {
        loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback");
492

493
494
495
496
497
498
499
        if (loopback_driver_ctl != NULL) {
            const JSList * loopback_parameters = jackctl_driver_get_parameters(loopback_driver_ctl);
            param = jackctl_get_parameter(loopback_parameters, "channels");
            if (param != NULL) {
                value.ui = loopback;
                jackctl_parameter_set_value(param, &value);
            }
Stephane Letz's avatar
Stephane Letz committed
500
501
            if (!jackctl_server_add_slave(server_ctl, loopback_driver_ctl)) {
                fprintf(stderr, "Driver \"loopback\" cannot be loaded\n");
502
                goto close_server;
Stephane Letz's avatar
Stephane Letz committed
503
            }
sletz's avatar
sletz committed
504
505
506
        } else {
            fprintf(stderr, "Driver \"loopback\" not found\n");
            goto close_server;
507
        }
508
509
510
511
512
513
    }

    // Start the server
    if (!jackctl_server_start(server_ctl)) {
        fprintf(stderr, "Failed to start server\n");
        goto close_server;
514
    }
515

516
    // Internal clients
517
518
519
520
    for (it = internals_list.begin(); it != internals_list.end(); it++) {
        jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it);
        if (internal_driver_ctl == NULL) {
            fprintf(stderr, "Unknown internal \"%s\"\n", *it);
521
            goto stop_server;
522
        }
Stephane Letz's avatar
Stephane Letz committed
523
524
        if (!jackctl_server_load_internal(server_ctl, internal_driver_ctl)) {
            fprintf(stderr, "Internal client \"%s\" cannot be loaded\n", *it);
525
            goto stop_server;
Stephane Letz's avatar
Stephane Letz committed
526
        }
527
528
    }

sletz's avatar
sletz committed
529
    notify_server_start(server_name);
530
531
    notify_sent = true;
    return_value = 0;
sletz's avatar
sletz committed
532
533

    // Waits for signal
534
    jackctl_wait_signals(sigmask);
sletz's avatar
sletz committed
535

536
 stop_server:
sletz's avatar
sletz committed
537
    if (!jackctl_server_stop(server_ctl)) {
sletz's avatar
Cleanup    
sletz committed
538
        fprintf(stderr, "Cannot stop server...\n");
539
    }
sletz's avatar
sletz committed
540

541
 close_server:
sletz's avatar
sletz committed
542
    if (loopback > 0 && loopback_driver_ctl) {
sletz's avatar
sletz committed
543
544
545
546
547
        jackctl_server_remove_slave(server_ctl, loopback_driver_ctl);
    }
    // Slave drivers
    for (it = slaves_list.begin(); it != slaves_list.end(); it++) {
        jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it);
548
        if (slave_driver_ctl) {
sletz's avatar
sletz committed
549
            jackctl_server_remove_slave(server_ctl, slave_driver_ctl);
550
        }
sletz's avatar
sletz committed
551
    }
sletz's avatar
sletz committed
552

sletz's avatar
sletz committed
553
554
555
    // Internal clients
    for (it = internals_list.begin(); it != internals_list.end(); it++) {
        jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it);
556
        if (internal_driver_ctl) {
sletz's avatar
sletz committed
557
            jackctl_server_unload_internal(server_ctl, internal_driver_ctl);
558
        }
sletz's avatar
sletz committed
559
    }
560
    jackctl_server_close(server_ctl);
sletz's avatar
sletz committed
561

562
 destroy_server:
sletz's avatar
sletz committed
563
    jackctl_server_destroy(server_ctl);
564
565
566
    if (notify_sent) {
        notify_server_stop(server_name);
    }
567
    return return_value;
sletz's avatar
sletz committed
568
}