diff --git a/ChangeLog b/ChangeLog index f53671a4..f430e9e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,10 @@ Tom Szilagyi Jackdmp changes log --------------------------- +2007-10-04 Stephane Letz + + * Fix a resource leak issue in JackCoreAudioDriver::Close(). Better implement "jack_client_open" when linking a client with the server library. + 2007-10-03 Stephane Letz * Rename server_name from "default" to "jackdmp_default" to avoid conflict with regular jackd server. diff --git a/common/JackDriver.cpp b/common/JackDriver.cpp index 152e26bb..c9f5b783 100644 --- a/common/JackDriver.cpp +++ b/common/JackDriver.cpp @@ -70,7 +70,7 @@ int JackDriver::Open() { int refnum = -1; - if (fEngine->ClientInternalOpen(fClientControl->fName, &refnum, &fEngineControl, &fGraphManager, this) != 0) { + if (fEngine->ClientInternalOpen(fClientControl->fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { jack_error("Cannot allocate internal client for audio driver"); return -1; } @@ -107,7 +107,7 @@ int JackDriver::Open(jack_nframes_t nframes, JackLog("JackDriver::Open playback_driver_name = %s\n", playback_driver_name); int refnum = -1; - if (fEngine->ClientInternalOpen(fClientControl->fName, &refnum, &fEngineControl, &fGraphManager, this) != 0) { + if (fEngine->ClientInternalOpen(fClientControl->fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { jack_error("Cannot allocate internal client for audio driver"); return -1; } diff --git a/common/JackEngine.cpp b/common/JackEngine.cpp index 4ffbfe74..ea7b20d3 100644 --- a/common/JackEngine.cpp +++ b/common/JackEngine.cpp @@ -502,7 +502,7 @@ error: } // Used for server driver clients -int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client) +int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait) { JackLog("JackEngine::ClientInternalNew: name = %s\n", name); @@ -516,6 +516,12 @@ int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl jack_error("Cannot allocate synchro"); return -1; } + + if (wait && !fSignal->TimedWait(5 * 1000000)) { + // Failure if RT thread is not running (problem with the driver...) + jack_error("Driver is not running"); + return -1; + } if (NotifyAddClient(client, name, refnum) < 0) { jack_error("Cannot notify add client"); diff --git a/common/JackEngine.h b/common/JackEngine.h index 2ce6f3ae..2ab1846d 100644 --- a/common/JackEngine.h +++ b/common/JackEngine.h @@ -83,7 +83,7 @@ class JackEngine // Client management int ClientCheck(const char* name, char* name_res, int protocol, int options, int* status); int ClientExternalOpen(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager); - int ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client); + int ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait); int ClientExternalClose(int refnum); int ClientInternalClose(int refnum); diff --git a/common/JackInternalClientChannel.h b/common/JackInternalClientChannel.h index 8c72e2a7..bebe4946 100644 --- a/common/JackInternalClientChannel.h +++ b/common/JackInternalClientChannel.h @@ -56,7 +56,7 @@ class JackInternalClientChannel : public JackClientChannelInterface } void ClientOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, int* result) { - *result = fEngine->ClientInternalOpen(name, ref, shared_engine, shared_manager, client); + *result = fEngine->ClientInternalOpen(name, ref, shared_engine, shared_manager, client, true); } void ClientClose(int refnum, int* result) { diff --git a/common/JackServerAPI.cpp b/common/JackServerAPI.cpp index 4ec49773..8eddf3c4 100644 --- a/common/JackServerAPI.cpp +++ b/common/JackServerAPI.cpp @@ -139,16 +139,12 @@ EXPORT jack_client_t* jack_client_open(const char* client_name, jack_options_t o return NULL; } - JackServerGlobals::Init(); // jack server initialisation - -#ifndef WIN32 - if (try_start_server(&va, options, status)) { - jack_error("jack server is not running or cannot be started"); - JackServerGlobals::Destroy(); // jack library destruction - return 0; + if (!JackServerGlobals::Init()) { // jack server initialisation + int my_status1 = (JackFailure | JackServerError); + *status = (jack_status_t)my_status1; + return NULL; } -#endif - + #ifdef __CLIENTDEBUG__ JackClient* client = new JackDebugClient(new JackInternalClient(JackServer::fInstance, GetSynchroTable())); // Debug mode #else @@ -159,7 +155,7 @@ EXPORT jack_client_t* jack_client_open(const char* client_name, jack_options_t o if (res < 0) { delete client; JackServerGlobals::Destroy(); // jack server destruction - int my_status1 = (JackFailure|JackServerError); + int my_status1 = (JackFailure | JackServerError); *status = (jack_status_t)my_status1; return NULL; } else { @@ -178,7 +174,7 @@ EXPORT int jack_client_close(jack_client_t* ext_client) int res = client->Close(); delete client; JackLog("jack_client_close OK\n"); - JackServerGlobals::Destroy(); // jack library destruction + JackServerGlobals::Destroy(); // jack server destruction return res; } } diff --git a/common/JackServerGlobals.cpp b/common/JackServerGlobals.cpp index 2cf8de18..dad62a82 100644 --- a/common/JackServerGlobals.cpp +++ b/common/JackServerGlobals.cpp @@ -31,22 +31,12 @@ This program is free software; you can redistribute it and/or modify #endif #define DEFAULT_TMP_DIR "/tmp" -char* jack_tmpdir = DEFAULT_TMP_DIR; -static char* server_name = "default"; -static int realtime = 0; -static int client_timeout = 0; /* msecs; if zero, use period size. */ -static int realtime_priority = 10; -static int verbose_aux = 0; -static int do_mlock = 1; -static unsigned int port_max = 128; -static int loopback = 0; -static int do_unlock = 0; -static int temporary = 0; +static char* jack_tmpdir = DEFAULT_TMP_DIR; +static char* server_name = "jackdmp_default"; namespace Jack { -JackServerGlobals* JackServerGlobals::fGlobals = NULL; long JackServerGlobals::fClientCount = 0; JackServer* JackServerGlobals::fServer = NULL; @@ -67,7 +57,7 @@ static char* jack_user_dir(void) /* format the path name on the first call */ if (user_dir[0] == '\0') { - snprintf (user_dir, sizeof (user_dir), "%s/jack-%d", + snprintf(user_dir, sizeof (user_dir), "%s/jack-%d", jack_tmpdir, getuid ()); } @@ -82,19 +72,18 @@ static char* get_jack_server_dir(const char* toto) // format the path name on the first call if (server_dir[0] == '\0') { - snprintf (server_dir, sizeof (server_dir), "%s/%s", - jack_user_dir (), server_name); + snprintf(server_dir, sizeof (server_dir), "%s/%s", jack_user_dir(), server_name); } return server_dir; } static void -jack_cleanup_files (const char *server_name) +jack_cleanup_files(const char *server_name) { DIR *dir; struct dirent *dirent; - char *dir_name = get_jack_server_dir (server_name); + char *dir_name = get_jack_server_dir(server_name); /* On termination, we remove all files that jackd creates so * subsequent attempts to start jackd will not believe that an @@ -113,42 +102,40 @@ jack_cleanup_files (const char *server_name) */ /* nothing to do if the server directory does not exist */ - if ((dir = opendir (dir_name)) == NULL) { + if ((dir = opendir(dir_name)) == NULL) { return ; } /* unlink all the files in this directory, they are mine */ - while ((dirent = readdir (dir)) != NULL) { + while ((dirent = readdir(dir)) != NULL) { char fullpath[PATH_MAX]; - if ((strcmp (dirent->d_name, ".") == 0) - || (strcmp (dirent->d_name, "..") == 0)) { + if ((strcmp(dirent->d_name, ".") == 0) + || (strcmp(dirent->d_name, "..") == 0)) { continue; } - snprintf (fullpath, sizeof (fullpath), "%s/%s", - dir_name, dirent->d_name); + snprintf(fullpath, sizeof (fullpath), "%s/%s", dir_name, dirent->d_name); - if (unlink (fullpath)) { - jack_error ("cannot unlink `%s' (%s)", fullpath, - strerror (errno)); + if (unlink(fullpath)) { + jack_error("cannot unlink `%s' (%s)", fullpath, strerror(errno)); } } - closedir (dir); + closedir(dir); /* now, delete the per-server subdirectory, itself */ - if (rmdir (dir_name)) { - jack_error ("cannot remove `%s' (%s)", dir_name, - strerror (errno)); + if (rmdir(dir_name)) { + jack_error("cannot remove `%s' (%s)", dir_name, + strerror(errno)); } /* finally, delete the per-user subdirectory, if empty */ - if (rmdir (jack_user_dir ())) { + if (rmdir (jack_user_dir())) { if (errno != ENOTEMPTY) { - jack_error ("cannot remove `%s' (%s)", - jack_user_dir (), strerror (errno)); + jack_error("cannot remove `%s' (%s)", + jack_user_dir(), strerror(errno)); } } } @@ -158,7 +145,7 @@ jack_cleanup_files (const char *server_name) int JackServerGlobals::JackStart(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) { JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose); - fServer = new JackServer(sync, temporary, time_out_ms, rt, priority, loopback, verbose); + fServer = new JackServer(sync, temporary, time_out_ms, rt, priority, loopback, verbose); int res = fServer->Open(driver_desc, driver_params); return (res < 0) ? res : fServer->Start(); } @@ -180,210 +167,241 @@ int JackServerGlobals::JackDelete() return 0; } -// Temporary : to test -JackServerGlobals::JackServerGlobals() +bool JackServerGlobals::Init() { - jack_driver_desc_t* driver_desc; - const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:"; - struct option long_options[] = { - { "driver", 1, 0, 'd' - }, - { "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' }, - { "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; - JSList* drivers = NULL; - char* server_name = NULL; - int show_version = 0; - int sync = 0; - int rc, i; - - int argc = 8; - //char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512"}; - char* argv[] = {"jackdmp", "-R", "-S", "-v", "-d", "portaudio", "-p", "512"}; - - for (i = 0; i < argc; i++) { - printf("arg %i %s\n", i, argv[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': - verbose_aux = 1; - 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; - - 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 ; - } - } - - drivers = jack_drivers_load (drivers); - if (!drivers) { - fprintf (stderr, "jackdmp: no drivers found; exiting\n"); - exit (1); - } - - driver_desc = jack_find_driver_descriptor (drivers, driver_name); - if (!driver_desc) { - fprintf (stderr, "jackdmp: 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 ; - } - - 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(driver_desc, driver_nargs, - driver_args, &driver_params)) { - return ; - } - -#ifndef WIN32 - if (server_name == NULL) - server_name = jack_default_server_name(); -#endif - - rc = jack_register_server(server_name); - - /* clean up shared memory and files from any previous - * instance of this server name */ - jack_cleanup_shm(); -#ifndef WIN32 - jack_cleanup_files(server_name); -#endif - - if (!realtime && client_timeout == 0) - client_timeout = 500; /* 0.5 sec; usable when non realtime. */ - - int res = JackStart(driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, loopback, verbose_aux); - if (res < 0) { - jack_error("Cannot start server... exit"); - JackDelete(); - return ; - } -} - -JackServerGlobals::~JackServerGlobals() -{ - JackLog("~JackServerGlobals\n"); - JackStop(); - jack_cleanup_shm(); -#ifndef WIN32 - jack_cleanup_files(server_name); -#endif - jack_unregister_server(server_name); -} - -void JackServerGlobals::Init() -{ - if (fClientCount++ == 0 && !fGlobals) { - JackLog("JackServerGlobals Init %x\n", fGlobals); - fGlobals = new JackServerGlobals(); - } + if (fClientCount++ == 0) { + + JackLog("JackServerGlobals Init\n"); + 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 loopback = 0; + int do_unlock = 0; + int temporary = 0; + + jack_driver_desc_t* driver_desc; + const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:"; + static struct option long_options[] = { + { "driver", 1, 0, 'd'}, + { "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' }, + { "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; + JSList* drivers = NULL; + char* server_name = NULL; + int show_version = 0; + int sync = 0; + int rc, i; + int ret; + + FILE* fp = 0; + char filename[255]; + char buffer[255]; + int argc = 0; + char* argv[32]; + + snprintf(filename, 255, "%s/.jackdmprc", getenv("HOME")); + fp = fopen(filename, "r"); + + if (!fp) { + fp = fopen("/etc/jackdmprc", "r"); + } + // if still not found, check old config name for backwards compatability + if (!fp) { + fp = fopen("/etc/jackdmp.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); + } + + /* + 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 (!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': + verbose_aux = 1; + 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; + + 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); + break; + } + } + + drivers = jack_drivers_load(drivers); + if (!drivers) { + fprintf(stderr, "jackdmp: no drivers found; exiting\n"); + goto error; + } + + driver_desc = jack_find_driver_descriptor(drivers, driver_name); + if (!driver_desc) { + fprintf(stderr, "jackdmp: unknown driver '%s'\n", driver_name); + goto error; + } + + 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"); + goto error; + } + + 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(driver_desc, driver_nargs, driver_args, &driver_params)) { + goto error; + } + + #ifndef WIN32 + if (server_name == NULL) + server_name = jack_default_server_name(); + #endif + + rc = jack_register_server(server_name); + + /* clean up shared memory and files from any previous instance of this server name */ + jack_cleanup_shm(); + #ifndef WIN32 + jack_cleanup_files(server_name); + #endif + + 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 = JackStart(driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, loopback, verbose_aux); + if (res < 0) { + jack_error("Cannot start server... exit"); + JackDelete(); + jack_cleanup_shm(); + #ifndef WIN32 + jack_cleanup_files(server_name); + #endif + jack_unregister_server(server_name); + goto error; + } + } + + return true; + +error: + fClientCount--; + return false; } void JackServerGlobals::Destroy() { - if (--fClientCount == 0 && fGlobals) { - JackLog("JackServerGlobals Destroy %x\n", fGlobals); - delete fGlobals; - fGlobals = NULL; + if (--fClientCount == 0) { + JackLog("JackServerGlobals Destroy\n"); + JackStop(); + jack_cleanup_shm(); + #ifndef WIN32 + jack_cleanup_files(server_name); + #endif + jack_unregister_server(server_name); } } diff --git a/common/JackServerGlobals.h b/common/JackServerGlobals.h index 0fdf8ad3..afd3f65b 100644 --- a/common/JackServerGlobals.h +++ b/common/JackServerGlobals.h @@ -39,13 +39,12 @@ class JackClient; struct JackServerGlobals { static long fClientCount; - static JackServerGlobals* fGlobals; static JackServer* fServer; JackServerGlobals(); virtual ~JackServerGlobals(); - static void Init(); + static bool Init(); static void Destroy(); static int JackStart(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); static int JackStop(); diff --git a/common/JackServerLaunch.cpp b/common/JackServerLaunch.cpp index 5e85f1c9..cabda903 100644 --- a/common/JackServerLaunch.cpp +++ b/common/JackServerLaunch.cpp @@ -63,6 +63,7 @@ static void start_server_aux(const char* server_name) if (strlen(arguments) > 0) { good = 1; } + fclose(fp); } if (!good) { @@ -70,7 +71,7 @@ static void start_server_aux(const char* server_name) strncpy(arguments, JACK_LOCATION "/jackdmp -T -d "JACK_DEFAULT_DRIVER, 255); } else { result = strcspn(arguments, " "); - command = (char*)malloc(result+1); + command = (char*)malloc(result + 1); strncpy(command, arguments, result); command[result] = '\0'; } @@ -86,7 +87,7 @@ static void start_server_aux(const char* server_name) size_t optlen = strlen("-n"); char* buf = (char*)malloc(optlen + strlen(server_name) + 1); strcpy(buf, "-n"); - strcpy(buf+optlen, server_name); + strcpy(buf + optlen, server_name); argv[i++] = buf; } } diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp index 06e09412..17d1a2cd 100644 --- a/common/Jackdmp.cpp +++ b/common/Jackdmp.cpp @@ -249,8 +249,7 @@ int main(int argc, char* argv[]) jack_driver_desc_t* driver_desc; const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:"; struct option long_options[] = { - { "driver", 1, 0, 'd' - }, + { "driver", 1, 0, 'd' }, { "verbose", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { "port-max", 1, 0, 'p' }, diff --git a/macosx/JackCoreAudioDriver.cpp b/macosx/JackCoreAudioDriver.cpp index fbdd1616..f4dd575e 100644 --- a/macosx/JackCoreAudioDriver.cpp +++ b/macosx/JackCoreAudioDriver.cpp @@ -781,11 +781,13 @@ error: int JackCoreAudioDriver::Close() { + JackLog("JackCoreAudioDriver::Close\n"); JackAudioDriver::Close(); // Possibly (if MeasureCallback has not been called) AudioDeviceStop(fDeviceID, MeasureCallback); AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback); AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback); + AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback); free(fJackInputData); AudioUnitUninitialize(fAUHAL); CloseComponent(fAUHAL);