Jackdmp.cpp 12.7 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
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

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>
#include <signal.h>
#include <pwd.h>
#include <sys/types.h>
#include <dirent.h>
#include <getopt.h>

#include "JackServer.h"
#include "JackConstants.h"
#include "driver_interface.h"
#include "driver_parse.h"
#include "JackDriverLoader.h"
#include "jslist.h"
#include "JackError.h"
36
#include "JackTools.h"
sletz's avatar
sletz committed
37
38
39
#include "shm.h"
#include "jack.h"

40
41
42
43
#ifdef __APPLE_
#include <CoreFoundation/CFNotificationCenter.h>
#endif

sletz's avatar
sletz committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using namespace Jack;

static JackServer* fServer;
static char* server_name = NULL;
static int realtime_priority = 10;
static int do_mlock = 1;
static unsigned int port_max = 128;
static int realtime = 0;
static int loopback = 0;
static int temporary = 0;
static int client_timeout = 0; /* msecs; if zero, use period size. */
static int do_unlock = 0;
static JSList* drivers = NULL;
static sigset_t signals;

sletz's avatar
sletz committed
59
static void silent_jack_error_callback(const char *desc)
sletz's avatar
sletz committed
60
61
62
63
{}

static void copyright(FILE* file)
{
sletz's avatar
sletz committed
64
    fprintf(file, "jackdmp " VERSION "\n"
sletz's avatar
sletz committed
65
             "Copyright 2001-2005 Paul Davis and others.\n"
sletz's avatar
sletz committed
66
             "Copyright 2004-2008 Grame.\n"
sletz's avatar
sletz committed
67
68
69
70
71
             "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
72
static void usage(FILE* file)
sletz's avatar
sletz committed
73
{
sletz's avatar
sletz committed
74
75
    copyright(file);
    fprintf(file, "\n"
sletz's avatar
sletz committed
76
             "usage: jackdmp [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n"
77
			 "               [ --name OR -n server-name ]\n"
sletz's avatar
sletz committed
78
79
80
81
82
83
             // "               [ --no-mlock OR -m ]\n"
             // "               [ --unlock OR -u ]\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"
             "               [ --verbose OR -v ]\n"
84
			 "               [ --replace-registry OR -r ]\n"
sletz's avatar
sletz committed
85
86
             "               [ --silent OR -s ]\n"
             "               [ --sync OR -S ]\n"
sletz's avatar
Typo    
sletz committed
87
			 "               [ --temporary OR -T ]\n"
sletz's avatar
sletz committed
88
89
             "               [ --version OR -V ]\n"
             "         -d driver [ ... driver args ... ]\n"
sletz's avatar
sletz committed
90
             "             where driver can be `alsa', `coreaudio', 'portaudio' or `dummy'\n"
sletz's avatar
sletz committed
91
92
93
94
95
96
97
98
99
100
101
102
             "       jackdmp -d driver --help\n"
             "             to display options for each driver\n\n");
}


static void DoNothingHandler(int sig)
{
    /* this is used by the child (active) process, but it never
       gets called unless we are already shutting down after
       another signal.
    */
    char buf[64];
sletz's avatar
sletz committed
103
    snprintf(buf, sizeof(buf), "received signal %d during shutdown(ignored)\n", sig);
sletz's avatar
sletz committed
104
105
106
    write(1, buf, strlen(buf));
}

107
static int JackStart(const char* server_name, jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int temporary, int time_out_ms, int rt, int priority, int loopback, int verbose)
sletz's avatar
sletz committed
108
109
{
    JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose);
110
    fServer = new JackServer(sync, temporary, time_out_ms, rt, priority, loopback, verbose, server_name);
sletz's avatar
sletz committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    int res = fServer->Open(driver_desc, driver_params);
    return (res < 0) ? res : fServer->Start();
}

static int JackStop()
{
    fServer->Stop();
    fServer->Close();
    JackLog("Jackdmp: server close\n");
    delete fServer;
    JackLog("Jackdmp: delete server\n");
    return 0;
}

static int JackDelete()
{
    delete fServer;
    JackLog("Jackdmp: delete server\n");
    return 0;
}

static void FilterSIGPIPE()
{
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGPIPE);
    //sigprocmask(SIG_BLOCK, &set, 0);
    pthread_sigmask(SIG_BLOCK, &set, 0);
}

int main(int argc, char* argv[])
{
    int sig;
    sigset_t allsignals;
    struct sigaction action;
    int waiting;

    jack_driver_desc_t* driver_desc;
149
    const char *options = "-ad:P:uvrshVRL:STFl:t:mn:p:";
sletz's avatar
sletz committed
150
    struct option long_options[] = {
151
                                       { "driver", 1, 0, 'd' },
sletz's avatar
sletz committed
152
153
154
155
156
157
158
                                       { "verbose", 0, 0, 'v' },
                                       { "help", 0, 0, 'h' },
                                       { "port-max", 1, 0, 'p' },
                                       { "no-mlock", 0, 0, 'm' },
                                       { "name", 0, 0, 'n' },
                                       { "unlock", 0, 0, 'u' },
                                       { "realtime", 0, 0, 'R' },
159
									   { "replace-registry", 0, 0, 'r' },
sletz's avatar
sletz committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
                                       { "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 }
                                   };
    int opt = 0;
    int option_index = 0;
    int seen_driver = 0;
    char *driver_name = NULL;
    char **driver_args = NULL;
    JSList* driver_params;
    int driver_nargs = 1;
    int show_version = 0;
177
	int replace_registry = 0;
sletz's avatar
sletz committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
    int sync = 0;
    int rc, i;

    opterr = 0;
    while (!seen_driver &&
            (opt = getopt_long(argc, argv, options,
                               long_options, &option_index)) != EOF) {
        switch (opt) {

            case 'd':
                seen_driver = 1;
                driver_name = optarg;
                break;

            case 'v':
sletz's avatar
sletz committed
193
                jack_verbose = 1;
sletz's avatar
sletz committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
                break;

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

            case 'S':
                sync = 1;
                break;

            case 'n':
                server_name = optarg;
                break;

            case 'm':
                do_mlock = 0;
                break;

            case 'p':
                port_max = (unsigned int)atol(optarg);
                break;

            case 'P':
                realtime_priority = atoi(optarg);
                break;
219
220
221
222
223
			
			case 'r':
				replace_registry = 1;
				break;
				
sletz's avatar
sletz committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
            case 'R':
                realtime = 1;
                break;

            case 'L':
                loopback = atoi(optarg);
                break;

            case 'T':
                temporary = 1;
                break;

            case 't':
                client_timeout = atoi(optarg);
                break;

            case 'u':
                do_unlock = 1;
                break;

            case 'V':
                show_version = 1;
                break;

            default:
                fprintf(stderr, "unknown option character %c\n",
                        optopt);
                /*fallthru*/
            case 'h':
                usage(stdout);
                return -1;
        }
    }

    /*
    if (show_version) {
    	printf ( "jackd version " VERSION 
    			" tmpdir " DEFAULT_TMP_DIR 
    			" protocol " PROTOCOL_VERSION
    			"\n");
    	return -1;
    }
    */

    if (!seen_driver) {
sletz's avatar
sletz committed
269
270
        usage(stderr);
        exit(1);
sletz's avatar
sletz committed
271
272
    }

sletz's avatar
sletz committed
273
    drivers = jack_drivers_load(drivers);
sletz's avatar
sletz committed
274
    if (!drivers) {
sletz's avatar
sletz committed
275
276
        fprintf(stderr, "jackdmp: no drivers found; exiting\n");
        exit(1);
sletz's avatar
sletz committed
277
278
    }

sletz's avatar
sletz committed
279
    driver_desc = jack_find_driver_descriptor(drivers, driver_name);
sletz's avatar
sletz committed
280
    if (!driver_desc) {
sletz's avatar
sletz committed
281
282
        fprintf(stderr, "jackdmp: unknown driver '%s'\n", driver_name);
        exit(1);
sletz's avatar
sletz committed
283
284
285
286
287
288
289
290
291
    }

    if (optind < argc) {
        driver_nargs = 1 + argc - optind;
    } else {
        driver_nargs = 1;
    }

    if (driver_nargs == 0) {
sletz's avatar
sletz committed
292
        fprintf(stderr, "No driver specified ... hmm. JACK won't do"
sletz's avatar
sletz committed
293
294
295
296
                 " anything when run like this.\n");
        return -1;
    }

sletz's avatar
sletz committed
297
    driver_args = (char **) malloc(sizeof(char *) * driver_nargs);
sletz's avatar
sletz committed
298
299
300
301
302
303
    driver_args[0] = driver_name;

    for (i = 1; i < driver_nargs; i++) {
        driver_args[i] = argv[optind++];
    }

sletz's avatar
sletz committed
304
    if (jack_parse_driver_params(driver_desc, driver_nargs,
sletz's avatar
sletz committed
305
                                  driver_args, &driver_params)) {
sletz's avatar
sletz committed
306
        exit(0);
sletz's avatar
sletz committed
307
308
309
    }

    if (server_name == NULL)
sletz's avatar
sletz committed
310
        server_name = (char*)JackTools::DefaultServerName();
sletz's avatar
sletz committed
311

sletz's avatar
sletz committed
312
    copyright(stdout);
sletz's avatar
sletz committed
313

314
    rc = jack_register_server(server_name, replace_registry);
sletz's avatar
sletz committed
315
316
    switch (rc) {
        case EEXIST:
sletz's avatar
sletz committed
317
318
            fprintf(stderr, "`%s' server already active\n", server_name);
            exit(1);
sletz's avatar
sletz committed
319
        case ENOSPC:
sletz's avatar
sletz committed
320
321
            fprintf(stderr, "too many servers already active\n");
            exit(2);
sletz's avatar
sletz committed
322
        case ENOMEM:
sletz's avatar
sletz committed
323
324
            fprintf(stderr, "no access to shm registry\n");
            exit(3);
sletz's avatar
sletz committed
325
        default:
sletz's avatar
sletz committed
326
            if (jack_verbose)
sletz's avatar
Cleanup    
sletz committed
327
                fprintf(stderr, "server `%s' registered\n", server_name);
sletz's avatar
sletz committed
328
329
330
331
332
    }

    /* clean up shared memory and files from any previous
     * instance of this server name */
    jack_cleanup_shm();
333
    JackTools::CleanupFiles(server_name);
sletz's avatar
sletz committed
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

    sigemptyset(&signals);
    sigaddset(&signals, SIGHUP);
    sigaddset(&signals, SIGINT);
    sigaddset(&signals, SIGQUIT);
    sigaddset(&signals, SIGPIPE);
    sigaddset(&signals, SIGTERM);
    sigaddset(&signals, SIGUSR1);
    sigaddset(&signals, SIGUSR2);

    // all child threads will inherit this mask unless they
    // explicitly reset it

    FilterSIGPIPE();
    pthread_sigmask(SIG_BLOCK, &signals, 0);

    if (!realtime && client_timeout == 0)
        client_timeout = 500; /* 0.5 sec; usable when non realtime. */

355
    int res = JackStart(server_name, driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, loopback, jack_verbose);
sletz's avatar
sletz committed
356
357
358
359
360
    if (res < 0) {
        jack_error("Cannot start server... exit");
        JackDelete();
        return 0;
    }
361
362

#ifdef __APPLE__
363
364
	CFStringRef ref = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
    // Send notification to be used in the JackRouter plugin
365
366
    CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
													CFSTR("com.grame.jackserver.start"),
367
													ref,
368
369
													NULL,
													kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
370
	CFRelease(ref);
371
#endif
372
	
sletz's avatar
sletz committed
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
    // install a do-nothing handler because otherwise pthreads
    // behaviour is undefined when we enter sigwait.

    sigfillset(&allsignals);
    action.sa_handler = DoNothingHandler;
    action.sa_mask = allsignals;
    action.sa_flags = SA_RESTART | SA_RESETHAND;

    for (i = 1; i < NSIG; i++) {
        if (sigismember(&signals, i)) {
            sigaction(i, &action, 0);
        }
    }

    waiting = TRUE;

    while (waiting) {
        sigwait(&signals, &sig);
        fprintf(stderr, "jack main caught signal %d\n", sig);

        switch (sig) {
            case SIGUSR1:
                //jack_dump_configuration(engine, 1);
                break;
            case SIGUSR2:
                // driver exit
                waiting = FALSE;
                break;
            default:
                waiting = FALSE;
                break;
        }
    }

    if (sig != SIGSEGV) {
        // unblock signals so we can see them during shutdown.
        // this will help prod developers not to lose sight of
        // bugs that cause segfaults etc. during shutdown.
        sigprocmask(SIG_UNBLOCK, &signals, 0);
    }
413
	
414
	JackStop();
sletz's avatar
sletz committed
415
416

    jack_cleanup_shm();
417
    JackTools::CleanupFiles(server_name);
sletz's avatar
sletz committed
418
419
    jack_unregister_server(server_name);

420
#ifdef __APPLE__
421
422
	CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
    // Send notification to be used in the JackRouter plugin
423
424
    CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
													CFSTR("com.grame.jackserver.stop"),
425
													ref1,
426
427
													NULL,
													kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
428
	CFRelease(ref1);
429
430
#endif

sletz's avatar
sletz committed
431
432
    return 1;
}