git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2340 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.90
@@ -0,0 +1,921 @@ | |||
/* -*- Mode: C++ ; c-basic-offset: 4 -*- */ | |||
/* | |||
JACK control API implementation | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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; version 2 of the License. | |||
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. | |||
*/ | |||
#ifndef WIN32 | |||
#include <stdbool.h> | |||
#include <stdint.h> | |||
#include <dirent.h> | |||
#include <pthread.h> | |||
#endif | |||
#include "types.h" | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <assert.h> | |||
#include <signal.h> | |||
#include "jslist.h" | |||
#include "driver_interface.h" | |||
#include "JackError.h" | |||
#include "JackServer.h" | |||
#include "shm.h" | |||
#include "JackTools.h" | |||
#include "control_types.h" | |||
using namespace Jack; | |||
struct jackctl_server | |||
{ | |||
JSList * drivers; | |||
JSList * parameters; | |||
class JackServer * engine; | |||
/* string, server name */ | |||
union jackctl_parameter_value name; | |||
union jackctl_parameter_value default_name; | |||
/* bool, whether to be "realtime" */ | |||
union jackctl_parameter_value realtime; | |||
union jackctl_parameter_value default_realtime; | |||
/* int32_t */ | |||
union jackctl_parameter_value realtime_priority; | |||
union jackctl_parameter_value default_realtime_priority; | |||
/* bool, whether to exit once all clients have closed their connections */ | |||
union jackctl_parameter_value temporary; | |||
union jackctl_parameter_value default_temporary; | |||
/* bool, whether to be verbose */ | |||
union jackctl_parameter_value verbose; | |||
union jackctl_parameter_value default_verbose; | |||
/* int32_t, msecs; if zero, use period size. */ | |||
union jackctl_parameter_value client_timeout; | |||
union jackctl_parameter_value default_client_timeout; | |||
/* uint32_t, ports of the loopback driver */ | |||
union jackctl_parameter_value loopback_ports; | |||
union jackctl_parameter_value default_loopback_ports; | |||
/* bool */ | |||
union jackctl_parameter_value replace_registry; | |||
union jackctl_parameter_value default_replace_registry; | |||
/* bool, synchronous or asynchronous engine mode */ | |||
union jackctl_parameter_value sync; | |||
union jackctl_parameter_value default_sync; | |||
}; | |||
struct jackctl_driver | |||
{ | |||
jack_driver_desc_t * desc_ptr; | |||
JSList * parameters; | |||
JSList * set_parameters; | |||
}; | |||
struct jackctl_parameter | |||
{ | |||
const char * name; | |||
const char * short_description; | |||
const char * long_description; | |||
jackctl_param_type_t type; | |||
bool is_set; | |||
union jackctl_parameter_value * value_ptr; | |||
union jackctl_parameter_value * default_value_ptr; | |||
union jackctl_parameter_value value; | |||
union jackctl_parameter_value default_value; | |||
struct jackctl_driver * driver_ptr; | |||
char id; | |||
jack_driver_param_t * driver_parameter_ptr; | |||
}; | |||
static | |||
struct jackctl_parameter * | |||
jackctl_add_parameter( | |||
JSList ** parameters_list_ptr_ptr, | |||
const char * name, | |||
const char * short_description, | |||
const char * long_description, | |||
jackctl_param_type_t type, | |||
union jackctl_parameter_value * value_ptr, | |||
union jackctl_parameter_value * default_value_ptr, | |||
union jackctl_parameter_value value) | |||
{ | |||
struct jackctl_parameter * parameter_ptr; | |||
parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter)); | |||
if (parameter_ptr == NULL) | |||
{ | |||
jack_error("Cannot allocate memory for jackctl_parameter structure."); | |||
goto fail; | |||
} | |||
parameter_ptr->name = name; | |||
parameter_ptr->short_description = short_description; | |||
parameter_ptr->long_description = long_description; | |||
parameter_ptr->type = type; | |||
parameter_ptr->is_set = false; | |||
if (value_ptr == NULL) | |||
{ | |||
value_ptr = ¶meter_ptr->value; | |||
} | |||
if (default_value_ptr == NULL) | |||
{ | |||
default_value_ptr = ¶meter_ptr->default_value; | |||
} | |||
parameter_ptr->value_ptr = value_ptr; | |||
parameter_ptr->default_value_ptr = default_value_ptr; | |||
*value_ptr = *default_value_ptr = value; | |||
parameter_ptr->driver_ptr = NULL; | |||
parameter_ptr->driver_parameter_ptr = NULL; | |||
parameter_ptr->id = 0; | |||
*parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr); | |||
return parameter_ptr; | |||
fail: | |||
return NULL; | |||
} | |||
static | |||
void | |||
jackctl_free_driver_parameters( | |||
struct jackctl_driver * driver_ptr) | |||
{ | |||
JSList * next_node_ptr; | |||
while (driver_ptr->parameters) | |||
{ | |||
next_node_ptr = driver_ptr->parameters->next; | |||
free(driver_ptr->parameters->data); | |||
free(driver_ptr->parameters); | |||
driver_ptr->parameters = next_node_ptr; | |||
} | |||
while (driver_ptr->set_parameters) | |||
{ | |||
next_node_ptr = driver_ptr->set_parameters->next; | |||
free(driver_ptr->set_parameters->data); | |||
free(driver_ptr->set_parameters); | |||
driver_ptr->set_parameters = next_node_ptr; | |||
} | |||
} | |||
static | |||
bool | |||
jackctl_add_driver_parameters( | |||
struct jackctl_driver * driver_ptr) | |||
{ | |||
uint32_t i; | |||
union jackctl_parameter_value jackctl_value; | |||
jackctl_param_type_t jackctl_type; | |||
struct jackctl_parameter * parameter_ptr; | |||
jack_driver_param_desc_t * descriptor_ptr; | |||
for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++) | |||
{ | |||
descriptor_ptr = driver_ptr->desc_ptr->params + i; | |||
switch (descriptor_ptr->type) | |||
{ | |||
case JackDriverParamInt: | |||
jackctl_type = JackParamInt; | |||
jackctl_value.i = descriptor_ptr->value.i; | |||
break; | |||
case JackDriverParamUInt: | |||
jackctl_type = JackParamUInt; | |||
jackctl_value.ui = descriptor_ptr->value.ui; | |||
break; | |||
case JackDriverParamChar: | |||
jackctl_type = JackParamChar; | |||
jackctl_value.c = descriptor_ptr->value.c; | |||
break; | |||
case JackDriverParamString: | |||
jackctl_type = JackParamString; | |||
strcpy(jackctl_value.str, descriptor_ptr->value.str); | |||
break; | |||
case JackDriverParamBool: | |||
jackctl_type = JackParamBool; | |||
jackctl_value.b = descriptor_ptr->value.i; | |||
break; | |||
default: | |||
jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type); | |||
assert(0); | |||
goto fail; | |||
} | |||
parameter_ptr = jackctl_add_parameter( | |||
&driver_ptr->parameters, | |||
descriptor_ptr->name, | |||
descriptor_ptr->short_desc, | |||
descriptor_ptr->long_desc, | |||
jackctl_type, | |||
NULL, | |||
NULL, | |||
jackctl_value); | |||
if (parameter_ptr == NULL) | |||
{ | |||
goto fail; | |||
} | |||
parameter_ptr->driver_ptr = driver_ptr; | |||
parameter_ptr->id = descriptor_ptr->character; | |||
} | |||
return true; | |||
fail: | |||
jackctl_free_driver_parameters(driver_ptr); | |||
return false; | |||
} | |||
static int | |||
jackctl_drivers_load( | |||
struct jackctl_server * server_ptr) | |||
{ | |||
struct jackctl_driver * driver_ptr; | |||
JSList *node_ptr; | |||
JSList *descriptor_node_ptr; | |||
descriptor_node_ptr = jack_drivers_load(NULL); | |||
if (descriptor_node_ptr == NULL) | |||
{ | |||
jack_error("could not find any drivers in direver directory!"); | |||
return false; | |||
} | |||
while (descriptor_node_ptr != NULL) | |||
{ | |||
driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver)); | |||
if (driver_ptr == NULL) | |||
{ | |||
jack_error("memory allocation of jackctl_driver structure failed."); | |||
goto next; | |||
} | |||
driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; | |||
driver_ptr->parameters = NULL; | |||
driver_ptr->set_parameters = NULL; | |||
if (!jackctl_add_driver_parameters(driver_ptr)) | |||
{ | |||
assert(driver_ptr->parameters == NULL); | |||
free(driver_ptr); | |||
goto next; | |||
} | |||
server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr); | |||
next: | |||
node_ptr = descriptor_node_ptr; | |||
descriptor_node_ptr = descriptor_node_ptr->next; | |||
free(node_ptr); | |||
} | |||
return true; | |||
} | |||
static | |||
void | |||
jackctl_server_free_drivers( | |||
struct jackctl_server * server_ptr) | |||
{ | |||
JSList * next_node_ptr; | |||
struct jackctl_driver * driver_ptr; | |||
while (server_ptr->drivers) | |||
{ | |||
next_node_ptr = server_ptr->drivers->next; | |||
driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data; | |||
jackctl_free_driver_parameters(driver_ptr); | |||
free(driver_ptr->desc_ptr->params); | |||
free(driver_ptr->desc_ptr); | |||
free(driver_ptr); | |||
free(server_ptr->drivers); | |||
server_ptr->drivers = next_node_ptr; | |||
} | |||
} | |||
static | |||
void | |||
jackctl_server_free_parameters( | |||
struct jackctl_server * server_ptr) | |||
{ | |||
JSList * next_node_ptr; | |||
while (server_ptr->parameters) | |||
{ | |||
next_node_ptr = server_ptr->parameters->next; | |||
free(server_ptr->parameters->data); | |||
free(server_ptr->parameters); | |||
server_ptr->parameters = next_node_ptr; | |||
} | |||
} | |||
#ifdef WIN32 | |||
static HANDLE waitEvent; | |||
static void do_nothing_handler(int signum) | |||
{ | |||
printf("jack main caught signal %d\n", signum); | |||
(void) signal(SIGINT, SIG_DFL); | |||
SetEvent(waitEvent); | |||
} | |||
sigset_t | |||
jackctl_setup_signals( | |||
unsigned int flags) | |||
{ | |||
if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { | |||
jack_error("CreateEvent fails err = %ld", GetLastError()); | |||
return 0; | |||
} | |||
(void) signal(SIGINT, do_nothing_handler); | |||
(void) signal(SIGABRT, do_nothing_handler); | |||
(void) signal(SIGTERM, do_nothing_handler); | |||
return waitEvent; | |||
} | |||
void jackctl_wait_signals(sigset_t signals) | |||
{ | |||
if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { | |||
jack_error("WaitForSingleObject fails err = %ld", GetLastError()); | |||
} | |||
} | |||
#else | |||
static | |||
void | |||
do_nothing_handler(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]; | |||
snprintf (buf, sizeof(buf), | |||
"received signal %d during shutdown (ignored)\n", sig); | |||
write (1, buf, strlen (buf)); | |||
} | |||
EXPORT sigset_t | |||
jackctl_setup_signals( | |||
unsigned int flags) | |||
{ | |||
sigset_t signals; | |||
sigset_t allsignals; | |||
struct sigaction action; | |||
int i; | |||
/* 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); | |||
/* 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); | |||
} | |||
} | |||
return signals; | |||
} | |||
EXPORT void | |||
jackctl_wait_signals(sigset_t signals) | |||
{ | |||
int sig; | |||
bool 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); | |||
} | |||
} | |||
#endif | |||
EXPORT jackctl_server_t * jackctl_server_create() | |||
{ | |||
struct jackctl_server * server_ptr; | |||
union jackctl_parameter_value value; | |||
server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server)); | |||
if (server_ptr == NULL) | |||
{ | |||
jack_error("Cannot allocate memory for jackctl_server structure."); | |||
goto fail; | |||
} | |||
server_ptr->drivers = NULL; | |||
server_ptr->parameters = NULL; | |||
server_ptr->engine = NULL; | |||
strcpy(value.str, JACK_DEFAULT_SERVER_NAME); | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"name", | |||
"server name to use", | |||
"", | |||
JackParamString, | |||
&server_ptr->name, | |||
&server_ptr->default_name, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.b = false; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"realtime", | |||
"Whether to use realtime mode", | |||
"Use realtime scheduling. This is needed for reliable low-latency performance. On most systems, it requires JACK to run with special scheduler and memory allocation privileges, which may be obtained in several ways. On Linux you should use PAM.", | |||
JackParamBool, | |||
&server_ptr->realtime, | |||
&server_ptr->default_realtime, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.i = 10; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"realtime-priority", | |||
"Scheduler priority when running in realtime mode.", | |||
"", | |||
JackParamInt, | |||
&server_ptr->realtime_priority, | |||
&server_ptr->default_realtime_priority, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.b = false; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"temporary", | |||
"Exit once all clients have closed their connections.", | |||
"", | |||
JackParamBool, | |||
&server_ptr->temporary, | |||
&server_ptr->default_temporary, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.b = false; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"verbose", | |||
"Verbose mode.", | |||
"", | |||
JackParamBool, | |||
&server_ptr->verbose, | |||
&server_ptr->default_verbose, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.i = 0; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"client-timeout", | |||
"Client timeout limit in milliseconds", | |||
"", | |||
JackParamInt, | |||
&server_ptr->client_timeout, | |||
&server_ptr->default_client_timeout, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.ui = 0; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"loopback-ports", | |||
"Number of loopback ports", | |||
"", | |||
JackParamUInt, | |||
&server_ptr->loopback_ports, | |||
&server_ptr->default_loopback_ports, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.b = false; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"replace-registry", | |||
"Replace registry", | |||
"", | |||
JackParamBool, | |||
&server_ptr->replace_registry, | |||
&server_ptr->default_replace_registry, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
value.b = false; | |||
if (jackctl_add_parameter( | |||
&server_ptr->parameters, | |||
"sync", | |||
"Use synchronous mode", | |||
"", | |||
JackParamBool, | |||
&server_ptr->sync, | |||
&server_ptr->default_sync, | |||
value) == NULL) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
if (!jackctl_drivers_load(server_ptr)) | |||
{ | |||
goto fail_free_parameters; | |||
} | |||
return server_ptr; | |||
fail_free_parameters: | |||
jackctl_server_free_parameters(server_ptr); | |||
free(server_ptr); | |||
fail: | |||
return NULL; | |||
} | |||
EXPORT void jackctl_server_destroy(jackctl_server *server_ptr) | |||
{ | |||
jackctl_server_free_drivers(server_ptr); | |||
jackctl_server_free_parameters(server_ptr); | |||
free(server_ptr); | |||
} | |||
EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr) | |||
{ | |||
return server_ptr->drivers; | |||
} | |||
EXPORT bool jackctl_server_stop(jackctl_server *server_ptr) | |||
{ | |||
server_ptr->engine->Stop(); | |||
server_ptr->engine->Close(); | |||
delete server_ptr->engine; | |||
/* clean up shared memory and files from this server instance */ | |||
jack_log("cleaning up shared memory"); | |||
jack_cleanup_shm(); | |||
jack_log("cleaning up files"); | |||
JackTools::CleanupFiles(server_ptr->name.str); | |||
jack_log("unregistering server `%s'", server_ptr->name.str); | |||
jack_unregister_server(server_ptr->name.str); | |||
server_ptr->engine = NULL; | |||
return true; | |||
} | |||
EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr) | |||
{ | |||
return server_ptr->parameters; | |||
} | |||
EXPORT bool | |||
jackctl_server_start( | |||
jackctl_server *server_ptr, | |||
jackctl_driver *driver_ptr) | |||
{ | |||
int rc; | |||
rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b); | |||
switch (rc) | |||
{ | |||
case EEXIST: | |||
jack_error("`%s' server already active", server_ptr->name.str); | |||
goto fail; | |||
case ENOSPC: | |||
jack_error("too many servers already active"); | |||
goto fail; | |||
case ENOMEM: | |||
jack_error("no access to shm registry"); | |||
goto fail; | |||
} | |||
jack_log("server `%s' registered", server_ptr->name.str); | |||
/* clean up shared memory and files from any previous | |||
* instance of this server name */ | |||
jack_cleanup_shm(); | |||
JackTools::CleanupFiles(server_ptr->name.str); | |||
if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) | |||
server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ | |||
/* get the engine/driver started */ | |||
server_ptr->engine = new JackServer( | |||
server_ptr->sync.b, | |||
server_ptr->temporary.b, | |||
server_ptr->client_timeout.i, | |||
server_ptr->realtime.b, | |||
server_ptr->realtime_priority.i, | |||
server_ptr->loopback_ports.ui, | |||
server_ptr->verbose.b, | |||
server_ptr->name.str); | |||
if (server_ptr->engine == NULL) | |||
{ | |||
jack_error("Failed to create new JackServer object"); | |||
goto fail_unregister; | |||
} | |||
rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters); | |||
if (rc < 0) | |||
{ | |||
jack_error("JackServer::Open() failed with %d", rc); | |||
goto fail_delete; | |||
} | |||
rc = server_ptr->engine->Start(); | |||
if (rc < 0) | |||
{ | |||
jack_error("JackServer::Start() failed with %d", rc); | |||
goto fail_close; | |||
} | |||
return true; | |||
fail_close: | |||
server_ptr->engine->Close(); | |||
fail_delete: | |||
delete server_ptr->engine; | |||
server_ptr->engine = NULL; | |||
fail_unregister: | |||
jack_log("cleaning up shared memory"); | |||
jack_cleanup_shm(); | |||
jack_log("cleaning up files"); | |||
JackTools::CleanupFiles(server_ptr->name.str); | |||
jack_log("unregistering server `%s'", server_ptr->name.str); | |||
jack_unregister_server(server_ptr->name.str); | |||
fail: | |||
return false; | |||
} | |||
EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr) | |||
{ | |||
return driver_ptr->desc_ptr->name; | |||
} | |||
EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr) | |||
{ | |||
return driver_ptr->parameters; | |||
} | |||
EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver_t * driver_ptr) | |||
{ | |||
return driver_ptr->desc_ptr; | |||
} | |||
EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr) | |||
{ | |||
return parameter_ptr->name; | |||
} | |||
EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr) | |||
{ | |||
return parameter_ptr->short_description; | |||
} | |||
EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr) | |||
{ | |||
return parameter_ptr->long_description; | |||
} | |||
EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr) | |||
{ | |||
return parameter_ptr->type; | |||
} | |||
EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr) | |||
{ | |||
return parameter_ptr->id; | |||
} | |||
EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr) | |||
{ | |||
return parameter_ptr->is_set; | |||
} | |||
EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr) | |||
{ | |||
return *parameter_ptr->value_ptr; | |||
} | |||
EXPORT bool jackctl_parameter_reset_value(jackctl_parameter *parameter_ptr) | |||
{ | |||
if (!parameter_ptr->is_set) | |||
{ | |||
return true; | |||
} | |||
parameter_ptr->is_set = true; | |||
*parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr; | |||
return true; | |||
} | |||
EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr) | |||
{ | |||
bool new_driver_parameter; | |||
/* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */ | |||
if (parameter_ptr->driver_ptr != NULL) | |||
{ | |||
/* jack_info("setting driver parameter %p ...", parameter_ptr); */ | |||
new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL; | |||
if (new_driver_parameter) | |||
{ | |||
/* jack_info("new driver parameter..."); */ | |||
parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t)); | |||
if (parameter_ptr->driver_parameter_ptr == NULL) | |||
{ | |||
jack_error ("Allocation of jack_driver_param_t structure failed"); | |||
return false; | |||
} | |||
parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id; | |||
parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); | |||
} | |||
switch (parameter_ptr->type) | |||
{ | |||
case JackParamInt: | |||
parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i; | |||
break; | |||
case JackParamUInt: | |||
parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui; | |||
break; | |||
case JackParamChar: | |||
parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c; | |||
break; | |||
case JackParamString: | |||
strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str); | |||
break; | |||
case JackParamBool: | |||
parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b; | |||
break; | |||
default: | |||
jack_error("unknown parameter type %i", (int)parameter_ptr->type); | |||
assert(0); | |||
if (new_driver_parameter) | |||
{ | |||
parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); | |||
} | |||
return false; | |||
} | |||
} | |||
parameter_ptr->is_set = true; | |||
*parameter_ptr->value_ptr = *value_ptr; | |||
return true; | |||
} | |||
EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr) | |||
{ | |||
return *parameter_ptr->default_value_ptr; | |||
} |
@@ -0,0 +1,134 @@ | |||
/* | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2004-2008 Grame | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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 <stdarg.h> | |||
#include <stdio.h> | |||
#include "JackError.h" | |||
#include "JackGlobals.h" | |||
#include "JackMessageBuffer.h" | |||
int jack_verbose = 0; | |||
void change_thread_log_function(jack_log_function_t log_function) | |||
{ | |||
if (!jack_tls_set(g_key_log_function, (void*)log_function)) | |||
{ | |||
jack_error("failed to set thread log function"); | |||
} | |||
} | |||
EXPORT void set_threaded_log_function() | |||
{ | |||
change_thread_log_function(Jack::JackMessageBufferAdd); | |||
} | |||
void jack_log_function(int level, const char *message) | |||
{ | |||
void (* log_callback)(const char *); | |||
switch (level) | |||
{ | |||
case LOG_LEVEL_INFO: | |||
log_callback = jack_info_callback; | |||
break; | |||
case LOG_LEVEL_ERROR: | |||
log_callback = jack_error_callback; | |||
break; | |||
default: | |||
return; | |||
} | |||
log_callback(message); | |||
} | |||
static | |||
void | |||
jack_format_and_log(int level, const char *prefix, const char *fmt, va_list ap) | |||
{ | |||
char buffer[300]; | |||
size_t len; | |||
jack_log_function_t log_function; | |||
if (prefix != NULL) { | |||
len = strlen(prefix); | |||
memcpy(buffer, prefix, len); | |||
} else { | |||
len = 0; | |||
} | |||
vsnprintf(buffer + len, sizeof(buffer) - len, fmt, ap); | |||
log_function = (jack_log_function_t)jack_tls_get(g_key_log_function); | |||
/* if log function is not overriden for thread, use default one */ | |||
if (log_function == NULL) | |||
{ | |||
log_function = jack_log_function; | |||
//log_function(LOG_LEVEL_INFO, "------ Using default log function"); | |||
} | |||
else | |||
{ | |||
//log_function(LOG_LEVEL_INFO, "++++++ Using thread-specific log function"); | |||
} | |||
log_function(level, buffer); | |||
} | |||
EXPORT void jack_error(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
jack_format_and_log(LOG_LEVEL_ERROR, NULL, fmt, ap); | |||
va_end(ap); | |||
} | |||
EXPORT void jack_info(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
jack_format_and_log(LOG_LEVEL_INFO, NULL, fmt, ap); | |||
va_end(ap); | |||
} | |||
EXPORT void jack_log(const char *fmt,...) | |||
{ | |||
if (jack_verbose) { | |||
va_list ap; | |||
va_start(ap, fmt); | |||
jack_format_and_log(LOG_LEVEL_INFO, "Jack: ", fmt, ap); | |||
va_end(ap); | |||
} | |||
} | |||
static void default_jack_error_callback(const char *desc) | |||
{ | |||
fprintf(stderr, "%s\n", desc); | |||
fflush(stderr); | |||
} | |||
static void default_jack_info_callback (const char *desc) | |||
{ | |||
fprintf(stdout, "%s\n", desc); | |||
fflush(stdout); | |||
} | |||
void (*jack_error_callback)(const char *desc) = &default_jack_error_callback; | |||
void (*jack_info_callback)(const char *desc) = &default_jack_info_callback; |
@@ -0,0 +1,120 @@ | |||
/* | |||
* messagebuffer.h -- realtime-safe message interface for jackd. | |||
* | |||
* This function is included in libjack so backend drivers can use | |||
* it, *not* for external client processes. The VERBOSE() and | |||
* MESSAGE() macros are realtime-safe. | |||
*/ | |||
/* | |||
* Copyright (C) 2004 Rui Nuno Capela, Steve Harris | |||
* Copyright (C) 2008 Nedko Arnaudov | |||
* Copyright (C) 2008 Grame | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
* | |||
*/ | |||
#include "JackMessageBuffer.h" | |||
#include "JackGlobals.h" | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
JackMessageBuffer* JackMessageBuffer::fInstance = NULL; | |||
JackMessageBuffer::JackMessageBuffer():fInBuffer(0),fOutBuffer(0),fOverruns(0) | |||
{ | |||
fThread = JackGlobals::MakeThread(this); | |||
fSignal = JackGlobals::MakeInterProcessSync(); | |||
fMutex = new JackMutex(); | |||
fThread->Start(); | |||
} | |||
JackMessageBuffer::~JackMessageBuffer() | |||
{ | |||
if (fOverruns > 0) { | |||
jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||
} else { | |||
jack_info("no message buffer overruns"); | |||
} | |||
fThread->SetStatus(JackThread::kIdle); | |||
fSignal->SignalAll(); | |||
fThread->Stop(); | |||
Flush(); | |||
delete fThread; | |||
delete fMutex; | |||
delete fSignal; | |||
} | |||
void JackMessageBuffer::Flush() | |||
{ | |||
while (fOutBuffer != fInBuffer) { | |||
jack_log_function(fBuffers[fOutBuffer].level, fBuffers[fOutBuffer].message); | |||
fOutBuffer = MB_NEXT(fOutBuffer); | |||
} | |||
} | |||
void JackMessageBuffer::AddMessage(int level, const char *message) | |||
{ | |||
if (fMutex->Trylock()) { | |||
fBuffers[fInBuffer].level = level; | |||
strncpy(fBuffers[fInBuffer].message, message, MB_BUFFERSIZE); | |||
fInBuffer = MB_NEXT(fInBuffer); | |||
fSignal->SignalAll(); | |||
fMutex->Unlock(); | |||
} else { /* lock collision */ | |||
INC_ATOMIC(&fOverruns); | |||
} | |||
} | |||
bool JackMessageBuffer::Execute() | |||
{ | |||
fSignal->Wait(); | |||
fMutex->Lock(); | |||
Flush(); | |||
fMutex->Unlock(); | |||
return true; | |||
} | |||
void JackMessageBuffer::Create() | |||
{ | |||
if (fInstance == NULL) { | |||
fInstance = new JackMessageBuffer(); | |||
} | |||
} | |||
void JackMessageBuffer::Destroy() | |||
{ | |||
if (fInstance != NULL) { | |||
delete fInstance; | |||
fInstance = NULL; | |||
} | |||
} | |||
void JackMessageBufferAdd(int level, const char *message) | |||
{ | |||
if (Jack::JackMessageBuffer::fInstance == NULL) { | |||
/* Unable to print message with realtime safety. | |||
* Complain and print it anyway. */ | |||
jack_log_function(LOG_LEVEL_ERROR, "messagebuffer not initialized, skip message"); | |||
} else { | |||
Jack::JackMessageBuffer::fInstance->AddMessage(level, message); | |||
} | |||
} | |||
}; | |||
@@ -0,0 +1,192 @@ | |||
/* | |||
* messagebuffer.h -- realtime-safe message interface for jackd. | |||
* | |||
* This function is included in libjack so backend drivers can use | |||
* it, *not* for external client processes. The VERBOSE() and | |||
* MESSAGE() macros are realtime-safe. | |||
*/ | |||
/* | |||
* Copyright (C) 2004 Rui Nuno Capela, Steve Harris | |||
* Copyright (C) 2008 Nedko Arnaudov | |||
* Copyright (C) 2008 Grame | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
* | |||
*/ | |||
#ifndef __JackMessageBuffer__ | |||
#define __JackMessageBuffer__ | |||
#include "JackThread.h" | |||
#include "JackMutex.h" | |||
#include "JackAtomic.h" | |||
#include "JackSyncInterface.h" | |||
namespace Jack | |||
{ | |||
/* MB_NEXT() relies on the fact that MB_BUFFERS is a power of two */ | |||
#define MB_BUFFERS 128 | |||
#define MB_NEXT(index) ((index+1) & (MB_BUFFERS-1)) | |||
#define MB_BUFFERSIZE 256 /* message length limit */ | |||
struct JackMessage | |||
{ | |||
int level; | |||
char message[MB_BUFFERSIZE]; | |||
}; | |||
class JackMessageBuffer : public JackRunnableInterface | |||
{ | |||
private: | |||
JackMessage fBuffers[MB_BUFFERS]; | |||
JackMutex* fMutex; | |||
JackThread* fThread; | |||
JackSyncInterface* fSignal; | |||
volatile unsigned int fInBuffer; | |||
volatile unsigned int fOutBuffer; | |||
SInt32 fOverruns; | |||
void Flush(); | |||
public: | |||
JackMessageBuffer(); | |||
~JackMessageBuffer(); | |||
// JackRunnableInterface interface | |||
bool Execute(); | |||
void static Create(); | |||
void static Destroy(); | |||
void AddMessage(int level, const char *message); | |||
static JackMessageBuffer* fInstance; | |||
}; | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
void JackMessageBufferAdd(int level, const char *message); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
}; | |||
#endif | |||
/* | |||
* messagebuffer.h -- realtime-safe message interface for jackd. | |||
* | |||
* This function is included in libjack so backend drivers can use | |||
* it, *not* for external client processes. The VERBOSE() and | |||
* MESSAGE() macros are realtime-safe. | |||
*/ | |||
/* | |||
* Copyright (C) 2004 Rui Nuno Capela, Steve Harris | |||
* Copyright (C) 2008 Nedko Arnaudov | |||
* Copyright (C) 2008 Grame | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
* | |||
*/ | |||
#ifndef __JackMessageBuffer__ | |||
#define __JackMessageBuffer__ | |||
#include "JackThread.h" | |||
#include "JackMutex.h" | |||
#include "JackAtomic.h" | |||
#include "JackSyncInterface.h" | |||
namespace Jack | |||
{ | |||
/* MB_NEXT() relies on the fact that MB_BUFFERS is a power of two */ | |||
#define MB_BUFFERS 128 | |||
#define MB_NEXT(index) ((index+1) & (MB_BUFFERS-1)) | |||
#define MB_BUFFERSIZE 256 /* message length limit */ | |||
struct JackMessage | |||
{ | |||
int level; | |||
char message[MB_BUFFERSIZE]; | |||
}; | |||
class JackMessageBuffer : public JackRunnableInterface | |||
{ | |||
private: | |||
JackMessage fBuffers[MB_BUFFERS]; | |||
JackMutex* fMutex; | |||
JackThread* fThread; | |||
JackSyncInterface* fSignal; | |||
volatile unsigned int fInBuffer; | |||
volatile unsigned int fOutBuffer; | |||
SInt32 fOverruns; | |||
void Flush(); | |||
public: | |||
JackMessageBuffer(); | |||
~JackMessageBuffer(); | |||
// JackRunnableInterface interface | |||
bool Execute(); | |||
void static Create(); | |||
void static Destroy(); | |||
void AddMessage(int level, const char *message); | |||
static JackMessageBuffer* fInstance; | |||
}; | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
void JackMessageBufferAdd(int level, const char *message); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
}; | |||
#endif |
@@ -0,0 +1,75 @@ | |||
/* | |||
Copyright (C) 2004-2006 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 "JackProcessSync.h" | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
bool JackProcessSync::TimedWait(long usec) | |||
{ | |||
struct timeval T0, T1; | |||
timespec time; | |||
struct timeval now; | |||
int res; | |||
pthread_mutex_lock(&fLock); | |||
jack_log("JackProcessSync::TimedWait time out = %ld", usec); | |||
gettimeofday(&T0, 0); | |||
gettimeofday(&now, 0); | |||
unsigned int next_date_usec = now.tv_usec + usec; | |||
time.tv_sec = now.tv_sec + (next_date_usec / 1000000); | |||
time.tv_nsec = (next_date_usec % 1000000) * 1000; | |||
res = pthread_cond_timedwait(&fCond, &fLock, &time); | |||
if (res != 0) | |||
jack_error("pthread_cond_timedwait error usec = %ld err = %s", usec, strerror(res)); | |||
gettimeofday(&T1, 0); | |||
pthread_mutex_unlock(&fLock); | |||
jack_log("JackProcessSync::TimedWait finished delta = %5.1lf", | |||
(1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec)); | |||
return (res == 0); | |||
} | |||
void JackProcessSync::Wait() | |||
{ | |||
int res; | |||
pthread_mutex_lock(&fLock); | |||
//jack_log("JackProcessSync::Wait..."); | |||
if ((res = pthread_cond_wait(&fCond, &fLock)) != 0) | |||
jack_error("pthread_cond_wait error err = %s", strerror(errno)); | |||
pthread_mutex_unlock(&fLock); | |||
//jack_log("JackProcessSync::Wait finished"); | |||
} | |||
bool JackInterProcessSync::TimedWait(long usec) | |||
{ | |||
struct timeval T0, T1; | |||
//jack_log("JackInterProcessSync::TimedWait..."); | |||
gettimeofday(&T0, 0); | |||
bool res = fSynchro->TimedWait(usec); | |||
gettimeofday(&T1, 0); | |||
//jack_log("JackInterProcessSync::TimedWait finished delta = %5.1lf", (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec)); | |||
return res; | |||
} | |||
} // end of namespace | |||
@@ -0,0 +1,648 @@ | |||
/* | |||
JACK control API | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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; version 2 of the License. | |||
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. | |||
*/ | |||
#ifndef __control_types__ | |||
#define __control_types__ | |||
#include "jslist.h" | |||
#include "JackExports.h" | |||
#ifdef WIN32 | |||
typedef HANDLE sigset_t; | |||
#endif | |||
/** Parameter types, intentionally similar to jack_driver_param_type_t */ | |||
typedef enum | |||
{ | |||
JackParamInt = 1, /**< @brief value type is a signed integer */ | |||
JackParamUInt, /**< @brief value type is an unsigned integer */ | |||
JackParamChar, /**< @brief value type is a char */ | |||
JackParamString, /**< @brief value type is a string with max size of ::JACK_PARAM_STRING_MAX+1 chars */ | |||
JackParamBool, /**< @brief value type is a boolean */ | |||
} jackctl_param_type_t; | |||
/** @brief Max value that jackctl_param_type_t type can have */ | |||
#define JACK_PARAM_MAX (JackParamBool + 1) | |||
/** @brief Max length of string parameter value, excluding terminating nul char */ | |||
#define JACK_PARAM_STRING_MAX 63 | |||
/** @brief Type for parameter value */ | |||
/* intentionally similar to jack_driver_param_value_t */ | |||
union jackctl_parameter_value | |||
{ | |||
uint32_t ui; /**< @brief member used for ::JackParamUInt */ | |||
int32_t i; /**< @brief member used for ::JackParamInt */ | |||
char c; /**< @brief member used for ::JackParamChar */ | |||
char str[JACK_PARAM_STRING_MAX + 1]; /**< @brief member used for ::JackParamString */ | |||
bool b; /**< @brief member used for ::JackParamBool */ | |||
}; | |||
/** opaque type for server object */ | |||
typedef struct jackctl_server jackctl_server_t; | |||
/** opaque type for driver object */ | |||
typedef struct jackctl_driver jackctl_driver_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#if 0 | |||
} /* Adjust editor indent */ | |||
#endif | |||
EXPORT sigset_t | |||
jackctl_setup_signals( | |||
unsigned int flags); | |||
EXPORT void | |||
jackctl_wait_signals( | |||
sigset_t signals); | |||
EXPORT jackctl_server_t * | |||
jackctl_server_create(); | |||
EXPORT void | |||
jackctl_server_destroy( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_drivers_list( | |||
jackctl_server_t * server); | |||
EXPORT bool | |||
jackctl_server_start( | |||
jackctl_server_t * server, | |||
jackctl_driver_t * driver); | |||
EXPORT bool | |||
jackctl_server_stop( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_parameters( | |||
jackctl_server_t * server); | |||
EXPORT const char * | |||
jackctl_driver_get_name( | |||
jackctl_driver_t * driver); | |||
EXPORT const JSList * | |||
jackctl_driver_get_parameters( | |||
jackctl_driver_t * driver); | |||
EXPORT const char * | |||
jackctl_parameter_get_name( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_short_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_long_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT jackctl_param_type_t | |||
jackctl_parameter_get_type( | |||
jackctl_parameter_t * parameter); | |||
EXPORT char | |||
jackctl_parameter_get_id( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_is_set( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_reset( | |||
jackctl_parameter_t * parameter); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_value( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_set_value( | |||
jackctl_parameter_t * parameter, | |||
const union jackctl_parameter_value * value_ptr); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_default_value( | |||
jackctl_parameter_t * parameter); | |||
#if 0 | |||
{ /* Adjust editor indent */ | |||
#endif | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif | |||
/* | |||
JACK control API | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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; version 2 of the License. | |||
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. | |||
*/ | |||
#ifndef __control_types__ | |||
#define __control_types__ | |||
#include "jslist.h" | |||
#include "JackExports.h" | |||
#ifdef WIN32 | |||
typedef HANDLE sigset_t; | |||
#endif | |||
/** Parameter types, intentionally similar to jack_driver_param_type_t */ | |||
typedef enum | |||
{ | |||
JackParamInt = 1, /**< @brief value type is a signed integer */ | |||
JackParamUInt, /**< @brief value type is an unsigned integer */ | |||
JackParamChar, /**< @brief value type is a char */ | |||
JackParamString, /**< @brief value type is a string with max size of ::JACK_PARAM_STRING_MAX+1 chars */ | |||
JackParamBool, /**< @brief value type is a boolean */ | |||
} jackctl_param_type_t; | |||
/** @brief Max value that jackctl_param_type_t type can have */ | |||
#define JACK_PARAM_MAX (JackParamBool + 1) | |||
/** @brief Max length of string parameter value, excluding terminating nul char */ | |||
#define JACK_PARAM_STRING_MAX 63 | |||
/** @brief Type for parameter value */ | |||
/* intentionally similar to jack_driver_param_value_t */ | |||
union jackctl_parameter_value | |||
{ | |||
uint32_t ui; /**< @brief member used for ::JackParamUInt */ | |||
int32_t i; /**< @brief member used for ::JackParamInt */ | |||
char c; /**< @brief member used for ::JackParamChar */ | |||
char str[JACK_PARAM_STRING_MAX + 1]; /**< @brief member used for ::JackParamString */ | |||
bool b; /**< @brief member used for ::JackParamBool */ | |||
}; | |||
/** opaque type for server object */ | |||
typedef struct jackctl_server jackctl_server_t; | |||
/** opaque type for driver object */ | |||
typedef struct jackctl_driver jackctl_driver_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#if 0 | |||
} /* Adjust editor indent */ | |||
#endif | |||
EXPORT sigset_t | |||
jackctl_setup_signals( | |||
unsigned int flags); | |||
EXPORT void | |||
jackctl_wait_signals( | |||
sigset_t signals); | |||
EXPORT jackctl_server_t * | |||
jackctl_server_create(); | |||
EXPORT void | |||
jackctl_server_destroy( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_drivers_list( | |||
jackctl_server_t * server); | |||
EXPORT bool | |||
jackctl_server_start( | |||
jackctl_server_t * server, | |||
jackctl_driver_t * driver); | |||
EXPORT bool | |||
jackctl_server_stop( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_parameters( | |||
jackctl_server_t * server); | |||
EXPORT const char * | |||
jackctl_driver_get_name( | |||
jackctl_driver_t * driver); | |||
EXPORT const JSList * | |||
jackctl_driver_get_parameters( | |||
jackctl_driver_t * driver); | |||
EXPORT const char * | |||
jackctl_parameter_get_name( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_short_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_long_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT jackctl_param_type_t | |||
jackctl_parameter_get_type( | |||
jackctl_parameter_t * parameter); | |||
EXPORT char | |||
jackctl_parameter_get_id( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_is_set( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_reset( | |||
jackctl_parameter_t * parameter); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_value( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_set_value( | |||
jackctl_parameter_t * parameter, | |||
const union jackctl_parameter_value * value_ptr); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_default_value( | |||
jackctl_parameter_t * parameter); | |||
#if 0 | |||
{ /* Adjust editor indent */ | |||
#endif | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif | |||
/* | |||
JACK control API | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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; version 2 of the License. | |||
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. | |||
*/ | |||
#ifndef __control_types__ | |||
#define __control_types__ | |||
#include "jslist.h" | |||
#include "JackExports.h" | |||
#ifdef WIN32 | |||
typedef HANDLE sigset_t; | |||
#endif | |||
/** Parameter types, intentionally similar to jack_driver_param_type_t */ | |||
typedef enum | |||
{ | |||
JackParamInt = 1, /**< @brief value type is a signed integer */ | |||
JackParamUInt, /**< @brief value type is an unsigned integer */ | |||
JackParamChar, /**< @brief value type is a char */ | |||
JackParamString, /**< @brief value type is a string with max size of ::JACK_PARAM_STRING_MAX+1 chars */ | |||
JackParamBool, /**< @brief value type is a boolean */ | |||
} jackctl_param_type_t; | |||
/** @brief Max value that jackctl_param_type_t type can have */ | |||
#define JACK_PARAM_MAX (JackParamBool + 1) | |||
/** @brief Max length of string parameter value, excluding terminating nul char */ | |||
#define JACK_PARAM_STRING_MAX 63 | |||
/** @brief Type for parameter value */ | |||
/* intentionally similar to jack_driver_param_value_t */ | |||
union jackctl_parameter_value | |||
{ | |||
uint32_t ui; /**< @brief member used for ::JackParamUInt */ | |||
int32_t i; /**< @brief member used for ::JackParamInt */ | |||
char c; /**< @brief member used for ::JackParamChar */ | |||
char str[JACK_PARAM_STRING_MAX + 1]; /**< @brief member used for ::JackParamString */ | |||
bool b; /**< @brief member used for ::JackParamBool */ | |||
}; | |||
/** opaque type for server object */ | |||
typedef struct jackctl_server jackctl_server_t; | |||
/** opaque type for driver object */ | |||
typedef struct jackctl_driver jackctl_driver_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#if 0 | |||
} /* Adjust editor indent */ | |||
#endif | |||
EXPORT sigset_t | |||
jackctl_setup_signals( | |||
unsigned int flags); | |||
EXPORT void | |||
jackctl_wait_signals( | |||
sigset_t signals); | |||
EXPORT jackctl_server_t * | |||
jackctl_server_create(); | |||
EXPORT void | |||
jackctl_server_destroy( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_drivers_list( | |||
jackctl_server_t * server); | |||
EXPORT bool | |||
jackctl_server_start( | |||
jackctl_server_t * server, | |||
jackctl_driver_t * driver); | |||
EXPORT bool | |||
jackctl_server_stop( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_parameters( | |||
jackctl_server_t * server); | |||
EXPORT const char * | |||
jackctl_driver_get_name( | |||
jackctl_driver_t * driver); | |||
EXPORT const JSList * | |||
jackctl_driver_get_parameters( | |||
jackctl_driver_t * driver); | |||
EXPORT const char * | |||
jackctl_parameter_get_name( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_short_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_long_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT jackctl_param_type_t | |||
jackctl_parameter_get_type( | |||
jackctl_parameter_t * parameter); | |||
EXPORT char | |||
jackctl_parameter_get_id( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_is_set( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_reset( | |||
jackctl_parameter_t * parameter); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_value( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_set_value( | |||
jackctl_parameter_t * parameter, | |||
const union jackctl_parameter_value * value_ptr); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_default_value( | |||
jackctl_parameter_t * parameter); | |||
#if 0 | |||
{ /* Adjust editor indent */ | |||
#endif | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif | |||
/* | |||
JACK control API | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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; version 2 of the License. | |||
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. | |||
*/ | |||
#ifndef __control_types__ | |||
#define __control_types__ | |||
#include "jslist.h" | |||
#include "JackExports.h" | |||
#ifdef WIN32 | |||
typedef HANDLE sigset_t; | |||
#endif | |||
/** Parameter types, intentionally similar to jack_driver_param_type_t */ | |||
typedef enum | |||
{ | |||
JackParamInt = 1, /**< @brief value type is a signed integer */ | |||
JackParamUInt, /**< @brief value type is an unsigned integer */ | |||
JackParamChar, /**< @brief value type is a char */ | |||
JackParamString, /**< @brief value type is a string with max size of ::JACK_PARAM_STRING_MAX+1 chars */ | |||
JackParamBool, /**< @brief value type is a boolean */ | |||
} jackctl_param_type_t; | |||
/** @brief Max value that jackctl_param_type_t type can have */ | |||
#define JACK_PARAM_MAX (JackParamBool + 1) | |||
/** @brief Max length of string parameter value, excluding terminating nul char */ | |||
#define JACK_PARAM_STRING_MAX 63 | |||
/** @brief Type for parameter value */ | |||
/* intentionally similar to jack_driver_param_value_t */ | |||
union jackctl_parameter_value | |||
{ | |||
uint32_t ui; /**< @brief member used for ::JackParamUInt */ | |||
int32_t i; /**< @brief member used for ::JackParamInt */ | |||
char c; /**< @brief member used for ::JackParamChar */ | |||
char str[JACK_PARAM_STRING_MAX + 1]; /**< @brief member used for ::JackParamString */ | |||
bool b; /**< @brief member used for ::JackParamBool */ | |||
}; | |||
/** opaque type for server object */ | |||
typedef struct jackctl_server jackctl_server_t; | |||
/** opaque type for driver object */ | |||
typedef struct jackctl_driver jackctl_driver_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#if 0 | |||
} /* Adjust editor indent */ | |||
#endif | |||
EXPORT sigset_t | |||
jackctl_setup_signals( | |||
unsigned int flags); | |||
EXPORT void | |||
jackctl_wait_signals( | |||
sigset_t signals); | |||
EXPORT jackctl_server_t * | |||
jackctl_server_create(); | |||
EXPORT void | |||
jackctl_server_destroy( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_drivers_list( | |||
jackctl_server_t * server); | |||
EXPORT bool | |||
jackctl_server_start( | |||
jackctl_server_t * server, | |||
jackctl_driver_t * driver); | |||
EXPORT bool | |||
jackctl_server_stop( | |||
jackctl_server_t * server); | |||
EXPORT const JSList * | |||
jackctl_server_get_parameters( | |||
jackctl_server_t * server); | |||
EXPORT const char * | |||
jackctl_driver_get_name( | |||
jackctl_driver_t * driver); | |||
EXPORT const JSList * | |||
jackctl_driver_get_parameters( | |||
jackctl_driver_t * driver); | |||
EXPORT const char * | |||
jackctl_parameter_get_name( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_short_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT const char * | |||
jackctl_parameter_get_long_description( | |||
jackctl_parameter_t * parameter); | |||
EXPORT jackctl_param_type_t | |||
jackctl_parameter_get_type( | |||
jackctl_parameter_t * parameter); | |||
EXPORT char | |||
jackctl_parameter_get_id( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_is_set( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_reset( | |||
jackctl_parameter_t * parameter); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_value( | |||
jackctl_parameter_t * parameter); | |||
EXPORT bool | |||
jackctl_parameter_set_value( | |||
jackctl_parameter_t * parameter, | |||
const union jackctl_parameter_value * value_ptr); | |||
EXPORT union jackctl_parameter_value | |||
jackctl_parameter_get_default_value( | |||
jackctl_parameter_t * parameter); | |||
#if 0 | |||
{ /* Adjust editor indent */ | |||
#endif | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif |
@@ -0,0 +1,702 @@ | |||
/* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
/* | |||
JACK control API | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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; version 2 of the License. | |||
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. | |||
*/ | |||
/** | |||
* @file jack/control.h | |||
* @ingroup publicheader | |||
* @brief JACK control API | |||
* | |||
*/ | |||
#ifndef JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED | |||
#define JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED | |||
#include <jack/jslist.h> | |||
#ifdef WIN32 | |||
typedef unsigned long sigset_t; | |||
#endif | |||
/** Parameter types, intentionally similar to jack_driver_param_type_t */ | |||
typedef enum | |||
{ | |||
JackParamInt = 1, /**< @brief value type is a signed integer */ | |||
JackParamUInt, /**< @brief value type is an unsigned integer */ | |||
JackParamChar, /**< @brief value type is a char */ | |||
JackParamString, /**< @brief value type is a string with max size of ::JACK_PARAM_STRING_MAX+1 chars */ | |||
JackParamBool, /**< @brief value type is a boolean */ | |||
} jackctl_param_type_t; | |||
/** @brief Max value that jackctl_param_type_t type can have */ | |||
#define JACK_PARAM_MAX (JackParamBool + 1) | |||
/** @brief Max length of string parameter value, excluding terminating nul char */ | |||
#define JACK_PARAM_STRING_MAX 63 | |||
/** @brief Type for parameter value */ | |||
/* intentionally similar to jack_driver_param_value_t */ | |||
union jackctl_parameter_value | |||
{ | |||
uint32_t ui; /**< @brief member used for ::JackParamUInt */ | |||
int32_t i; /**< @brief member used for ::JackParamInt */ | |||
char c; /**< @brief member used for ::JackParamChar */ | |||
char str[JACK_PARAM_STRING_MAX + 1]; /**< @brief member used for ::JackParamString */ | |||
bool b; /**< @brief member used for ::JackParamBool */ | |||
}; | |||
/** opaque type for server object */ | |||
typedef struct jackctl_server jackctl_server_t; | |||
/** opaque type for driver object */ | |||
typedef struct jackctl_driver jackctl_driver_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#if 0 | |||
} /* Adjust editor indent */ | |||
#endif | |||