Esempio n. 1
0
int	       
main (int argc, char *argv[])

{
	jack_driver_desc_t * desc;
	int replace_registry = 0;
	int do_sanity_checks = 1;
	int show_version = 0;

#ifdef HAVE_ZITA_BRIDGE_DEPS
	const char *options = "A:d:P:uvshVrRZTFlI:t:mM:n:Np:c:X:C:";
#else
	const char *options = "A:d:P:uvshVrRZTFlI:t:mM:n:Np:c:X:C:";
#endif
	struct option long_options[] = 
	{ 
		/* keep ordered by single-letter option code */

#ifdef HAVE_ZITA_BRIDGE_DEPS
                { "alsa-add", 1, 0, 'A' },
#endif
		{ "clock-source", 1, 0, 'c' },
		{ "driver", 1, 0, 'd' },
		{ "help", 0, 0, 'h' },
		{ "tmpdir-location", 0, 0, 'l' },
		{ "internal-client", 0, 0, 'I' },
		{ "no-mlock", 0, 0, 'm' },
		{ "midi-bufsize", 1, 0, 'M' },
		{ "name", 1, 0, 'n' },
                { "no-sanity-checks", 0, 0, 'N' },
		{ "port-max", 1, 0, 'p' },
		{ "realtime-priority", 1, 0, 'P' },
		{ "no-realtime", 0, 0, 'r' },
		{ "realtime", 0, 0, 'R' },
		{ "replace-registry", 0, &replace_registry, 0 },
		{ "silent", 0, 0, 's' },
		{ "sync", 0, 0, 'S' },
		{ "timeout", 1, 0, 't' },
		{ "temporary", 0, 0, 'T' },
		{ "unlock", 0, 0, 'u' },
		{ "version", 0, 0, 'V' },
		{ "verbose", 0, 0, 'v' },
		{ "slave-driver", 1, 0, 'X' },
		{ "nozombies", 0, 0, 'Z' },
		{ "timeout-thres", 2, 0, 'C' },
		{ 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;
	JSList * slave_drivers = NULL;
        JSList * load_list = NULL;
	size_t midi_buffer_size = 0;
	int driver_nargs = 1;
	int i;
	int rc;
#ifdef HAVE_ZITA_BRIDGE_DEPS
        const char* alsa_add_client_name_playback = "zalsa_out";
        const char* alsa_add_client_name_capture = "zalsa_in";
        char alsa_add_args[64];
        char* dirstr;
#endif
	setvbuf (stdout, NULL, _IOLBF, 0);

	maybe_use_capabilities ();

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

#ifdef HAVE_ZITA_BRIDGE_DEPS
                case 'A':
                        /* add a new internal client named after the ALSA device name
                           given as optarg, using the last character 'p' or 'c' to
                           indicate playback or capture. If there isn't one,
                           assume capture (common case: USB mics etc.)
                        */
                        if ((dirstr = strstr (optarg, "%p")) != NULL && dirstr == (optarg + strlen(optarg) - 2)) {
                                snprintf (alsa_add_args, sizeof (alsa_add_args), "%.*s_play:%s/-dhw:%.*s", 
                                          (int) strlen (optarg) - 2, optarg,
                                          alsa_add_client_name_playback,
                                          (int) strlen (optarg) - 2, optarg);
                                load_list = jack_slist_append(load_list, strdup (alsa_add_args));
                        } else if ((dirstr = strstr (optarg, "%c")) != NULL && dirstr == (optarg + strlen(optarg) - 2)) {
                                snprintf (alsa_add_args, sizeof (alsa_add_args), "%.*s_rec:%s/-dhw:%.*s", 
                                          (int) strlen (optarg) - 2, optarg,
                                          alsa_add_client_name_capture,
                                          (int) strlen (optarg) - 2, optarg);
                                load_list = jack_slist_append(load_list, strdup (alsa_add_args));
                        } else {
                                snprintf (alsa_add_args, sizeof (alsa_add_args), "%s_play:%s/-dhw:%s", 
                                          optarg,
                                          alsa_add_client_name_playback,
                                          optarg);
                                load_list = jack_slist_append(load_list, strdup (alsa_add_args));
                                snprintf (alsa_add_args, sizeof (alsa_add_args), "%s_rec:%s/-dhw:%s", 
                                          optarg,
                                          alsa_add_client_name_capture,
                                          optarg);
                                load_list = jack_slist_append(load_list, strdup (alsa_add_args));
                        }
                        break;
#endif

		case 'c':
			if (tolower (optarg[0]) == 'h') {
				clock_source = JACK_TIMER_HPET;
			} else if (tolower (optarg[0]) == 'c') {
				/* For backwards compatibility with scripts,
				 * allow the user to request the cycle clock
				 * on the command line, but use the system
				 * clock instead
				 */
				clock_source = JACK_TIMER_SYSTEM_CLOCK;
			} else if (tolower (optarg[0]) == 's') {
				clock_source = JACK_TIMER_SYSTEM_CLOCK;
			} else {
				usage (stderr);
				return -1;
			}
			break;

		case 'C':
			if (optarg)
				timeout_count_threshold = atoi (optarg);
			else
				timeout_count_threshold = 250;
			break;

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

		case 'D':
			frame_time_offset = JACK_MAX_FRAMES - atoi(optarg); 
			break;

		case 'l':
			/* special flag to allow libjack to determine jackd's idea of where tmpdir is */
			printf ("%s\n", jack_tmpdir);
			exit (0);

                case 'I':
			load_list = jack_slist_append(load_list, optarg);
                        break;

		case 'm':
			do_mlock = 0;
			break;

		case 'M':
			midi_buffer_size = (unsigned int) atol (optarg);
			break;

		case 'n':
			server_name = optarg;
			break;

		case 'N':
			do_sanity_checks = 0;
			break;

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

		case 'P':
			realtime_priority = atoi (optarg);
			break;

		case 'r':
			realtime = 0;
			break;

		case 'R':
			/* this is now the default */
			realtime = 1;
			break;

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

                case 'S':
                        /* this option is for jack2 only (synchronous mode) */
                        break;

		case 'T':
			temporary = 1;
			break;

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

		case 'u':
			do_unlock = 1;
			break;

		case 'v':
			verbose = 1;
			break;

		case 'V':
			show_version = 1;
			break;

		case 'X':
			slave_drivers = jack_slist_append(slave_drivers, optarg);
			break;
		case 'Z':
			nozombies = 1;
			break;

		default:
			jack_error ("Unknown option character %c",
				    optopt);
			/*fallthru*/
		case 'h':
			usage (stdout);
			return -1;
		}
	}

	if (show_version) {
		printf ( "jackd version " VERSION 
				" tmpdir " DEFAULT_TMP_DIR 
				" protocol " PROTOCOL_VERSION
				"\n");
		return 0;
	}

	copyright (stdout);

	if (do_sanity_checks && (0 < sanitycheck (realtime, FALSE))) {
		return -1;
	}

	if (!seen_driver) {
		usage (stderr);
		exit (1);
	}

        /* DIRTY HACK needed to pick up -X supplied as part of ALSA driver args. This is legacy
           hack to make control apps like qjackctl based on the < 0.124 command line interface
           continue to work correctly.

           If -X seq was given as part of the driver args, load the ALSA MIDI slave driver.
        */
        
        for (i = seen_driver; i < argc; ++i) {
                if (strcmp (argv[i], "-X") == 0) {
                        if (argc >= i + 2) {
                                if (strcmp (argv[i+1], "seq") == 0) {
                                        slave_drivers = jack_slist_append (slave_drivers,"alsa_midi");
                                }
                        }
                        break;
                } else if (strcmp (argv[i], "-Xseq") == 0) {
                        slave_drivers = jack_slist_append (slave_drivers,"alsa_midi");
                        break;
                }
        }

	drivers = jack_drivers_load ();

	if (!drivers) {
		fprintf (stderr, "jackd: no drivers found; exiting\n");
		exit (1);
	}
	
	if (midi_buffer_size != 0) {
		jack_port_type_info_t* port_type = &jack_builtin_port_types[JACK_MIDI_PORT_TYPE];
		port_type->buffer_size = midi_buffer_size * jack_midi_internal_event_size ();
		port_type->buffer_scale_factor = -1;
		if (verbose) {
			fprintf (stderr, "Set MIDI buffer size to %u bytes\n", port_type->buffer_size);
		}
	}

	desc = jack_find_driver_descriptor (driver_name);
	if (!desc) {
		fprintf (stderr, "jackd: unknown driver '%s'\n", driver_name);
		exit (1);
	}

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

	if (driver_nargs == 0) {
		fprintf (stderr, "No driver specified ... hmm. JACK won't do"
			 " anything when run like this.\n");
		return -1;
	}

	driver_args = (char **) malloc (sizeof (char *) * driver_nargs);
	driver_args[0] = driver_name;
	
	for (i = 1; i < driver_nargs; i++) {
		driver_args[i] = argv[optind++];
	}

	if (jack_parse_driver_params (desc, driver_nargs,
				      driver_args, &driver_params)) {
		exit (0);
	}

	if (server_name == NULL)
		server_name = jack_default_server_name ();

	rc = jack_register_server (server_name, replace_registry);
	switch (rc) {
	case EEXIST:
		fprintf (stderr, "`%s' server already active\n", server_name);
		exit (1);
	case ENOSPC:
		fprintf (stderr, "too many servers already active\n");
		exit (2);
	case ENOMEM:
		fprintf (stderr, "no access to shm registry\n");
		exit (3);
	default:
		if (verbose)
			fprintf (stderr, "server `%s' registered\n",
				 server_name);
	}

	/* clean up shared memory and files from any previous
	 * instance of this server name */
	jack_cleanup_shm ();
	jack_cleanup_files (server_name);

	/* run the server engine until it terminates */
	jack_main (desc, driver_params, slave_drivers, load_list);

	/* clean up shared memory and files from this server instance */
	if (verbose)
		fprintf (stderr, "cleaning up shared memory\n");
	jack_cleanup_shm ();
	if (verbose)
		fprintf (stderr, "cleaning up files\n");
	jack_cleanup_files (server_name);
	if (verbose)
		fprintf (stderr, "unregistering server `%s'\n", server_name);
	jack_unregister_server (server_name);

	exit (0);
}
bool JackServerGlobals::Init()
{
    int realtime = 0;
    int client_timeout = 0; /* msecs; if zero, use period size. */
    int realtime_priority = 10;
    int verbose_aux = 0;
    int do_mlock = 1;
    unsigned int port_max = 128;
    int do_unlock = 0;
    int temporary = 0;

    int opt = 0;
    int option_index = 0;
    char *master_driver_name = NULL;
    char **master_driver_args = NULL;
    JSList* master_driver_params = NULL;
    jack_driver_desc_t* driver_desc;
    jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK;
    int driver_nargs = 1;
    JSList* drivers = NULL;
    int loopback = 0;
    int sync = 0;
    int rc, i;
    int ret;
    int replace_registry = 0;

    FILE* fp = 0;
    char filename[255];
    char buffer[255];
    int argc = 0;
    char* argv[32];

    // First user starts the server
    if (fUserCount++ == 0) {

        jack_log("JackServerGlobals Init");

        const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:"
    #ifdef __linux__
            "c:"
    #endif
        ;

    struct option long_options[] = {
    #ifdef __linux__
                                       { "clock-source", 1, 0, 'c' },
    #endif
                                       { "loopback-driver", 1, 0, 'L' },
                                       { "audio-driver", 1, 0, 'd' },
                                       { "midi-driver", 1, 0, 'X' },
                                       { "internal-client", 1, 0, 'I' },
                                       { "verbose", 0, 0, 'v' },
                                       { "help", 0, 0, 'h' },
                                       { "port-max", 1, 0, 'p' },
                                       { "no-mlock", 0, 0, 'm' },
                                       { "name", 1, 0, 'n' },
                                       { "unlock", 0, 0, 'u' },
                                       { "realtime", 0, 0, 'R' },
                                       { "no-realtime", 0, 0, 'r' },
                                       { "replace-registry", 0, &replace_registry, 0 },
                                       { "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 }
                                   };

        snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
        fp = fopen(filename, "r");

        if (!fp) {
            fp = fopen("/etc/jackdrc", "r");
        }
        // if still not found, check old config name for backwards compatability
        if (!fp) {
            fp = fopen("/etc/jackd.conf", "r");
        }

        argc = 0;
        if (fp) {
            ret = fscanf(fp, "%s", buffer);
            while (ret != 0 && ret != EOF) {
                argv[argc] = (char*)malloc(64);
                strcpy(argv[argc], buffer);
                ret = fscanf(fp, "%s", buffer);
                argc++;
            }
            fclose(fp);
        }

        /*
        For testing
        int argc = 15;
        char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512", "-d", "~:Aggregate:0", "-r", "48000", "-i", "2", "-o", "2" };
        */

        opterr = 0;
        optind = 1; // Important : to reset argv parsing

        while (!master_driver_name &&
                (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) {

            switch (opt) {

                case 'c':
                    if (tolower (optarg[0]) == 'h') {
                        clock_source = JACK_TIMER_HPET;
                    } else if (tolower (optarg[0]) == 'c') {
                        clock_source = JACK_TIMER_CYCLE_COUNTER;
                    } else if (tolower (optarg[0]) == 's') {
                        clock_source = JACK_TIMER_SYSTEM_CLOCK;
                    } else {
                        jack_error("unknown option character %c", optopt);
                    }
                    break;

                case 'd':
                    master_driver_name = optarg;
                    break;

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

                 case 'X':
                    fSlavesList[optarg] = NULL;
                    break;

                case 'I':
                    fInternalsList[optarg] = -1;
                    break;

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

                case 'm':
                    do_mlock = 0;
                    break;

                case 'u':
                    do_unlock = 1;
                    break;

                case 'v':
                    verbose_aux = 1;
                    break;

                case 'S':
                    sync = 1;
                    break;

                case 'n':
                    server_name = optarg;
                    break;

                case 'P':
                    realtime_priority = atoi(optarg);
                    break;

                case 'r':
                    realtime = 0;
                    break;

                case 'R':
                    realtime = 1;
                    break;

                case 'T':
                    temporary = 1;
                    break;

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

                default:
                    jack_error("unknown option character %c", optopt);
                    break;
            }
        }

        drivers = jack_drivers_load(drivers);
        if (!drivers) {
            jack_error("jackdmp: no drivers found; exiting");
            goto error;
        }

        driver_desc = jack_find_driver_descriptor(drivers, master_driver_name);
        if (!driver_desc) {
            jack_error("jackdmp: unknown master driver '%s'", master_driver_name);
            goto error;
        }

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

        if (driver_nargs == 0) {
            jack_error("No driver specified ... hmm. JACK won't do"
                       " anything when run like this.");
            goto error;
        }

        master_driver_args = (char**)malloc(sizeof(char*) * driver_nargs);
        master_driver_args[0] = master_driver_name;

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

        if (jack_parse_driver_params(driver_desc, driver_nargs, master_driver_args, &master_driver_params)) {
            goto error;
        }

#ifndef WIN32
        if (server_name == NULL)
            server_name = (char*)JackTools::DefaultServerName();
#endif

        rc = jack_register_server(server_name, false);
        switch (rc) {
            case EEXIST:
                jack_error("`%s' server already active", server_name);
                goto error;
            case ENOSPC:
                jack_error("too many servers already active");
                goto error;
            case ENOMEM:
                jack_error("no access to shm registry");
                goto error;
            default:
                jack_info("server `%s' registered", server_name);
        }

        /* clean up shared memory and files from any previous instance of this server name */
        jack_cleanup_shm();
        JackTools::CleanupFiles(server_name);

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

        for (i = 0; i < argc; i++) {
            free(argv[i]);
        }

        int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source);
        if (res < 0) {
            jack_error("Cannot start server... exit");
            Delete();
            jack_cleanup_shm();
            JackTools::CleanupFiles(server_name);
            jack_unregister_server(server_name);
            goto error;
        }

        // Slave drivers
        std::map<std::string, JackDriverInfo*>::iterator it1;
        for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) {
            const char* name = ((*it1).first).c_str();
            driver_desc = jack_find_driver_descriptor(drivers, name);
            if (!driver_desc) {
                jack_error("jackdmp: unknown slave driver '%s'", name);
            } else {
                (*it1).second = fInstance->AddSlave(driver_desc, NULL);
            }
        }

        // Loopback driver
        if (loopback > 0) {
            driver_desc = jack_find_driver_descriptor(drivers, "loopback");
            if (!driver_desc) {
                jack_error("jackdmp: unknown driver '%s'", "loopback");
            } else {
                fSlavesList["loopback"] = fInstance->AddSlave(driver_desc, NULL);
            }
        }

        // Internal clients
        std::map<std::string, int>::iterator it2;
        for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) {
            int status, refnum;
            const char* name = ((*it2).first).c_str();
            fInstance->InternalClientLoad2(name, name, NULL, JackNullOption, &refnum, -1, &status);
            (*it2).second = refnum;
        }
    }

    if (master_driver_params)
        jack_free_driver_params(master_driver_params);
    return true;

error:
    jack_log("JackServerGlobals Init error");
    if (master_driver_params)
        jack_free_driver_params(master_driver_params);
    Destroy();
    return false;
}
Esempio n. 3
0
static int
jack_main (jack_driver_desc_t * driver_desc, JSList * driver_params, JSList * slave_names, JSList * load_list)
{
	int sig;
	int i;
	sigset_t allsignals;
	struct sigaction action;
	int waiting;
	JSList * node;

	/* ensure that we are in our own process group so that
	   kill (SIG, -pgrp) does the right thing.
	*/

	setsid ();

	pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

	/* what's this for?

	   POSIX says that signals are delivered like this:

	   * if a thread has blocked that signal, it is not
	       a candidate to receive the signal.
           * of all threads not blocking the signal, pick
	       one at random, and deliver the signal.

           this means that a simple-minded multi-threaded program can
           expect to get POSIX signals delivered randomly to any one
           of its threads,

	   here, we block all signals that we think we might receive
	   and want to catch. all "child" threads will inherit this
	   setting. if we create a thread that calls sigwait() on the
	   same set of signals, implicitly unblocking all those
	   signals. any of those signals that are delivered to the
	   process will be delivered to that thread, and that thread
	   alone. this makes cleanup for a signal-driven exit much
	   easier, since we know which thread is doing it and more
	   importantly, we are free to call async-unsafe functions,
	   because the code is executing in normal thread context
	   after a return from sigwait().
	*/

	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 
	 */

	pthread_sigmask (SIG_BLOCK, &signals, 0);

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

	/* get the engine/driver started */

	if ((engine = jack_engine_new (realtime, realtime_priority, 
				       do_mlock, do_unlock, server_name,
				       temporary, verbose, client_timeout,
				       port_max, getpid(), frame_time_offset, 
				       nozombies, timeout_count_threshold, drivers)) == 0) {
		jack_error ("cannot create engine");
		return -1;
	}

	jack_info ("loading driver ..");
	
	if (jack_engine_load_driver (engine, driver_desc, driver_params)) {
		jack_error ("cannot load driver module %s",
			 driver_desc->name);
		goto error;
	}

	for (node=slave_names; node; node=jack_slist_next(node)) {
		char *sl_name = node->data;
		jack_driver_desc_t *sl_desc = jack_find_driver_descriptor(sl_name);
		if (sl_desc) {
			jack_engine_load_slave_driver(engine, sl_desc, NULL);
		}
	}


	if (jack_drivers_start (engine) != 0) {
		jack_error ("cannot start driver");
		goto error;
	}

        jack_load_internal_clients (load_list);

	/* install a do-nothing handler because otherwise pthreads
	   behaviour is undefined when we enter sigwait.
	*/

	sigfillset (&allsignals);
	action.sa_handler = do_nothing_handler;
	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);
		} 
	}
	
	if (verbose) {
		jack_info ("%d waiting for signals", getpid());
	}

	waiting = TRUE;

	while (waiting) {
		sigwait (&signals, &sig);

		jack_info ("jack main caught signal %d", 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);
	}
	
	jack_engine_delete (engine);
	return 1;
	
error:
	jack_engine_delete (engine);
	return -1;
}