Jack2 1.9.6
|
00001 /* 00002 Copyright (C) 2001-2003 Paul Davis 00003 Copyright (C) 2004-2008 Grame 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU Lesser General Public License as published by 00007 the Free Software Foundation; either version 2.1 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 00019 */ 00020 00021 #include "JackConstants.h" 00022 #include "JackChannel.h" 00023 #include "JackLibGlobals.h" 00024 #include "JackServerLaunch.h" 00025 #include "JackPlatformPlug.h" 00026 00027 using namespace Jack; 00028 00029 #if defined(USE_LIBDBUS_AUTOLAUNCH) 00030 00031 #include <dbus/dbus.h> 00032 00033 static int start_server_dbus(const char* server_name) 00034 { 00035 DBusError err; 00036 DBusConnection *conn; 00037 DBusMessage *msg; 00038 00039 // initialise the errors 00040 dbus_error_init(&err); 00041 00042 // connect to the bus 00043 conn = dbus_bus_get(DBUS_BUS_SESSION, &err); 00044 if (dbus_error_is_set(&err)) { 00045 fprintf(stderr, "Connection Error (%s)\n", err.message); 00046 dbus_error_free(&err); 00047 } 00048 if (NULL == conn) { 00049 return 1; 00050 } 00051 00052 msg = dbus_message_new_method_call( 00053 "org.jackaudio.service", // target for the method call 00054 "/org/jackaudio/Controller", // object to call on 00055 "org.jackaudio.JackControl", // interface to call on 00056 "StartServer"); // method name 00057 if (NULL == msg) { 00058 fprintf(stderr, "Message Null\n"); 00059 return 1; 00060 } 00061 00062 // send message and get a handle for a reply 00063 if (!dbus_connection_send(conn, msg, NULL)) 00064 { 00065 fprintf(stderr, "Out Of Memory!\n"); 00066 return 1; 00067 } 00068 00069 dbus_message_unref(msg); 00070 dbus_connection_flush(conn); 00071 dbus_error_free(&err); 00072 00073 return 0; 00074 } 00075 00076 #else 00077 00078 /* Exec the JACK server in this process. Does not return. */ 00079 static void start_server_classic_aux(const char* server_name) 00080 { 00081 FILE* fp = 0; 00082 char filename[255]; 00083 char arguments[255]; 00084 char buffer[255]; 00085 char* command = 0; 00086 size_t pos = 0; 00087 size_t result = 0; 00088 char** argv = 0; 00089 int i = 0; 00090 int good = 0; 00091 int ret; 00092 00093 snprintf(filename, 255, "%s/.jackdrc", getenv("HOME")); 00094 fp = fopen(filename, "r"); 00095 00096 if (!fp) { 00097 fp = fopen("/etc/jackdrc", "r"); 00098 } 00099 /* if still not found, check old config name for backwards compatability */ 00100 if (!fp) { 00101 fp = fopen("/etc/jackd.conf", "r"); 00102 } 00103 00104 if (fp) { 00105 arguments[0] = '\0'; 00106 ret = fscanf(fp, "%s", buffer); 00107 while (ret != 0 && ret != EOF) { 00108 strcat(arguments, buffer); 00109 strcat(arguments, " "); 00110 ret = fscanf(fp, "%s", buffer); 00111 } 00112 if (strlen(arguments) > 0) { 00113 good = 1; 00114 } 00115 fclose(fp); 00116 } 00117 00118 if (!good) { 00119 command = (char*)(JACK_LOCATION "/jackd"); 00120 strncpy(arguments, JACK_LOCATION "/jackd -T -d "JACK_DEFAULT_DRIVER, 255); 00121 } else { 00122 result = strcspn(arguments, " "); 00123 command = (char*)malloc(result + 1); 00124 strncpy(command, arguments, result); 00125 command[result] = '\0'; 00126 } 00127 00128 argv = (char**)malloc(255); 00129 00130 while (1) { 00131 /* insert -T and -nserver_name in front of arguments */ 00132 if (i == 1) { 00133 argv[i] = (char*)malloc(strlen ("-T") + 1); 00134 strcpy (argv[i++], "-T"); 00135 if (server_name) { 00136 size_t optlen = strlen("-n"); 00137 char* buf = (char*)malloc(optlen + strlen(server_name) + 1); 00138 strcpy(buf, "-n"); 00139 strcpy(buf + optlen, server_name); 00140 argv[i++] = buf; 00141 } 00142 } 00143 00144 result = strcspn(arguments + pos, " "); 00145 if (result == 0) { 00146 break; 00147 } 00148 argv[i] = (char*)malloc(result + 1); 00149 strncpy(argv[i], arguments + pos, result); 00150 argv[i][result] = '\0'; 00151 pos += result + 1; 00152 ++i; 00153 } 00154 argv[i] = 0; 00155 execv(command, argv); 00156 00157 /* If execv() succeeds, it does not return. There's no point 00158 * in calling jack_error() here in the child process. */ 00159 fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno)); 00160 } 00161 00162 static int start_server_classic(const char* server_name) 00163 { 00164 /* The double fork() forces the server to become a child of 00165 * init, which will always clean up zombie process state on 00166 * termination. This even works in cases where the server 00167 * terminates but this client does not. 00168 * 00169 * Since fork() is usually implemented using copy-on-write 00170 * virtual memory tricks, the overhead of the second fork() is 00171 * probably relatively small. 00172 */ 00173 switch (fork()) { 00174 case 0: /* child process */ 00175 switch (fork()) { 00176 case 0: /* grandchild process */ 00177 start_server_classic_aux(server_name); 00178 _exit(99); /* exec failed */ 00179 case - 1: 00180 _exit(98); 00181 default: 00182 _exit(0); 00183 } 00184 case - 1: /* fork() error */ 00185 return 1; /* failed to start server */ 00186 } 00187 00188 /* only the original parent process goes here */ 00189 return 0; /* (probably) successful */ 00190 } 00191 00192 #endif 00193 00194 static int start_server(const char* server_name, jack_options_t options) 00195 { 00196 if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) { 00197 return 1; 00198 } 00199 00200 #if defined(USE_LIBDBUS_AUTOLAUNCH) 00201 return start_server_dbus(server_name); 00202 #else 00203 return start_server_classic(server_name); 00204 #endif 00205 } 00206 00207 static int server_connect(char* server_name) 00208 { 00209 JackClientChannel channel; 00210 int res = channel.ServerCheck(server_name); 00211 channel.Close(); 00212 return res; 00213 } 00214 00215 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status) 00216 { 00217 if (server_connect(va->server_name) < 0) { 00218 int trys; 00219 if (start_server(va->server_name, options)) { 00220 int my_status1 = *status | JackFailure | JackServerFailed; 00221 *status = (jack_status_t)my_status1; 00222 return -1; 00223 } 00224 trys = 5; 00225 do { 00226 sleep(1); 00227 if (--trys < 0) { 00228 int my_status1 = *status | JackFailure | JackServerFailed; 00229 *status = (jack_status_t)my_status1; 00230 return -1; 00231 } 00232 } while (server_connect(va->server_name) < 0); 00233 int my_status1 = *status | JackServerStarted; 00234 *status = (jack_status_t)my_status1; 00235 } 00236 00237 return 0; 00238 }