From 955b4a7e41db5e094ef3baea56071e7d846cb593 Mon Sep 17 00:00:00 2001 From: sletz Date: Wed, 24 Jan 2007 12:00:28 +0000 Subject: [PATCH] Automatic jack server launch (in progress) git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@1362 0c269be4-1314-0410-8aa9-9f06e86f4224 --- common/JackAPI.cpp | 155 +++++++++++++++++++++++++++++++++++++++ common/JackAPI.h | 23 ++++++ common/JackGlobals.h | 24 +++--- common/JackServerAPI.cpp | 14 ++-- 4 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 common/JackAPI.h diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index f1cdac4c..3fb923ba 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackGlobals.h" #include "JackTime.h" #include "JackExports.h" +#include "JackAPI.h" + #ifdef __APPLE__ #include "JackMachThread.h" #elif WIN32 @@ -1346,3 +1348,156 @@ EXPORT jack_status_t jack_internal_client_unload(jack_client_t* ext_client, jack JackLog("jack_internal_client_unload: not yet implemented\n"); return JackFailure; } + +// Automatic jack server launch + +#define JACK_LOCATION +#define JACK_DEFAULT_DRIVER + +/* Exec the JACK server in this process. Does not return. */ +static void start_server_aux(const char *server_name) +{ + FILE* fp = 0; + char filename[255]; + char arguments[255]; + char buffer[255]; + char* command = 0; + size_t pos = 0; + size_t result = 0; + char** argv = 0; + int i = 0; + int good = 0; + int ret; + + 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"); + } + + if (fp) { + arguments[0] = '\0'; + ret = fscanf(fp, "%s", buffer); + while(ret != 0 && ret != EOF) { + strcat(arguments, buffer); + strcat(arguments, " "); + ret = fscanf(fp, "%s", buffer); + } + if (strlen(arguments) > 0) { + good = 1; + } + } + + if (!good) { + command = JACK_LOCATION "/jackdmp"; + strncpy(arguments, JACK_LOCATION "/jackdmp -T -d "JACK_DEFAULT_DRIVER, 255); + } else { + result = strcspn(arguments, " "); + command = (char *) malloc(result+1); + strncpy(command, arguments, result); + command[result] = '\0'; + } + + argv = (char **) malloc (255); + + while (1) { + /* insert -T and -nserver_name in front of arguments */ + if (i == 1) { + argv[i] = (char *) malloc(strlen ("-T") + 1); + strcpy (argv[i++], "-T"); + if (server_name) { + size_t optlen = strlen ("-n"); + char* buf = (char*)malloc(optlen + strlen (server_name) + 1); + strcpy (buf, "-n"); + strcpy (buf+optlen, server_name); + argv[i++] = buf; + } + } + + result = strcspn(arguments + pos, " "); + if (result == 0) { + break; + } + argv[i] = (char*)malloc(result + 1); + strncpy(argv[i], arguments+pos, result); + argv[i][result] = '\0'; + pos += result + 1; + ++i; + } + argv[i] = 0; + execv(command, argv); + + /* If execv() succeeds, it does not return. There's no point + * in calling jack_error() here in the child process. */ + perror("exec of JACK server failed"); +} + +static int start_server(const char *server_name, jack_options_t options) +{ + if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) { + return 1; + } + + /* The double fork() forces the server to become a child of + * init, which will always clean up zombie process state on + * termination. This even works in cases where the server + * terminates but this client does not. + * + * Since fork() is usually implemented using copy-on-write + * virtual memory tricks, the overhead of the second fork() is + * probably relatively small. + */ + switch (fork()) { + case 0: /* child process */ + switch (fork()) { + case 0: /* grandchild process */ + start_server_aux(server_name); + _exit(99); /* exec failed */ + case -1: + _exit(98); + default: + _exit(0); + } + case -1: /* fork() error */ + return 1; /* failed to start server */ + } + + /* only the original parent process goes here */ + return 0; /* (probably) successful */ +} + +int server_connect(char* name) +{ + return -1; +} + +int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status) +{ + if (server_connect(va->server_name) < 0) { + int trys; + if (start_server(va->server_name, options)) { + int my_status1 = *status | JackFailure | JackServerFailed; + *status = (jack_status_t)my_status1; + return -1; + } + trys = 5; + do { + sleep(1); + if (--trys < 0) { + int my_status1 = *status | JackFailure | JackServerFailed; + *status = (jack_status_t)my_status1; + return -1; + } + } while (server_connect(va->server_name) < 0); + int my_status1 = *status | JackServerStarted; + *status = (jack_status_t)my_status1; + } + + return 0; +} + diff --git a/common/JackAPI.h b/common/JackAPI.h new file mode 100644 index 00000000..79cdf8b1 --- /dev/null +++ b/common/JackAPI.h @@ -0,0 +1,23 @@ +/* +Copyright (C) 2007 Grame + +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 "types.h" +#include "varargs.h" + +int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status); diff --git a/common/JackGlobals.h b/common/JackGlobals.h index af4a8809..44fb171c 100644 --- a/common/JackGlobals.h +++ b/common/JackGlobals.h @@ -231,17 +231,17 @@ class JackGlobals JackLog("JackGlobals InitServer\n"); if (!fInstance) { -#ifdef __APPLE__ + #ifdef __APPLE__ fInstance = new JackFactoryOSXServer(); -#endif + #endif -#ifdef WIN32 + #ifdef WIN32 fInstance = new JackFactoryWindowsServer(); -#endif + #endif -#ifdef __linux__ + #ifdef __linux__ fInstance = new JackFactoryLinuxServer(); -#endif + #endif } } @@ -251,17 +251,17 @@ class JackGlobals JackLog("JackGlobals InitClient\n"); if (!fInstance) { -#ifdef __APPLE__ + #ifdef __APPLE__ fInstance = new JackFactoryOSXClient(); -#endif + #endif -#ifdef WIN32 + #ifdef WIN32 fInstance = new JackFactoryWindowsClient(); -#endif + #endif -#ifdef __linux__ + #ifdef __linux__ fInstance = new JackFactoryLinuxClient(); -#endif + #endif } } diff --git a/common/JackServerAPI.cpp b/common/JackServerAPI.cpp index e8931b0c..6db119ad 100644 --- a/common/JackServerAPI.cpp +++ b/common/JackServerAPI.cpp @@ -156,7 +156,6 @@ EXPORT jack_client_t* jack_client_open(const char* client_name, jack_options_t o *status = (jack_status_t)0; return (jack_client_t*)client; } - return NULL; } EXPORT int jack_client_close(jack_client_t* ext_client) @@ -166,11 +165,12 @@ EXPORT int jack_client_close(jack_client_t* ext_client) if (client == NULL) { jack_error("jack_client_close called with a NULL client"); return -1; - } - int res = client->Close(); - delete client; - JackLog("jack_client_close OK\n"); - JackServerGlobals::Destroy(); // jack library destruction - return res; + } else { + int res = client->Close(); + delete client; + JackLog("jack_client_close OK\n"); + JackServerGlobals::Destroy(); // jack library destruction + return res; + } }