Browse Source

[0.99.5] jack_client_open() first step

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@768 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
joq 21 years ago
parent
commit
8fe87b2f75
9 changed files with 253 additions and 83 deletions
  1. +2
    -2
      configure.in
  2. +82
    -33
      example-clients/simple_client.c
  3. +8
    -5
      jack/internal.h
  4. +5
    -5
      jack/jack.h
  5. +82
    -12
      jackd/engine.c
  6. +1
    -0
      libjack/.cvsignore
  7. +4
    -0
      libjack/ChangeLog
  8. +67
    -25
      libjack/client.c
  9. +2
    -1
      libjack/local.h

+ 2
- 2
configure.in View File

@@ -15,7 +15,7 @@ dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=99
JACK_MICRO_VERSION=4
JACK_MICRO_VERSION=5

dnl ---
dnl HOWTO: updating the jack protocol version
@@ -25,7 +25,7 @@ dnl made to the way libjack communicates with jackd
dnl that would break applications linked with an older
dnl version of libjack.
dnl ---
JACK_PROTOCOL_VERSION=13
JACK_PROTOCOL_VERSION=14

dnl ---
dnl HOWTO: updating the libjack interface version


+ 82
- 33
example-clients/simple_client.c View File

@@ -16,30 +16,52 @@ jack_port_t *input_port;
jack_port_t *output_port;
jack_client_t *client;

/* a simple state machine for this client */
volatile enum {
Init,
Run,
Exit
} client_state = Init;

/**
* The process callback for this JACK application.
* It is called by JACK at the appropriate times.
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client follows a simple rule: when the JACK transport is
* running, copy the input port to the output. When it stops, exit.
*/
int
process (jack_nframes_t nframes, void *arg)
{
jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes);
jack_default_audio_sample_t *in, *out;
jack_transport_state_t ts = jack_transport_query(client, NULL);

if (ts == JackTransportRolling) {

if (client_state == Init)
client_state = Run;

memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);
in = jack_port_get_buffer (input_port, nframes);
out = jack_port_get_buffer (output_port, nframes);
memcpy (out, in,
sizeof (jack_default_audio_sample_t) * nframes);

} else if (ts == JackTransportStopped) {

if (client_state == Run)
client_state = Exit;
}

return 0;
}

/**
* This is the shutdown callback for this JACK application.
* It is called by JACK if the server ever shuts down or
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
void
jack_shutdown (void *arg)
{

exit (1);
}

@@ -47,17 +69,34 @@ int
main (int argc, char *argv[])
{
const char **ports;

if (argc < 2) {
fprintf (stderr, "usage: jack_simple_client <name>\n");
return 1;
const char *client_name;
jack_status_t status;

if (argc >= 2) { /* session name specified? */
client_name = argv[1];
} else { /* use basename of argv[0] */
client_name = strrchr(argv[0], '/');
if (client_name == 0) {
client_name = argv[0];
} else {
client_name++;
}
}

/* try to become a client of the JACK server */
/* open a client connection to the JACK server */

if ((client = jack_client_new (argv[1])) == 0) {
fprintf (stderr, "jack server not running?\n");
return 1;
client = jack_client_open (client_name, 0, &status, NULL, NULL);
if (client == NULL) {
fprintf (stderr, "jack_client_open() failed, status = %d\n",
status);
exit (1);
}
if (status & JackServerStarted) {
fprintf (stderr, "JACK server started\n");
}
if (status & JackNameNotUnique) {
client_name = jack_get_client_name(client);
fprintf (stderr, "unique name `%s' assigned\n", client_name);
}

/* tell the JACK server to call `process()' whenever
@@ -81,25 +120,31 @@ main (int argc, char *argv[])

/* create two ports */

input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
input_port = jack_port_register (client, "input",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
output_port = jack_port_register (client, "output",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

/* tell the JACK server that we are ready to roll */
/* Tell the JACK server that we are ready to roll. Our
* process() callback will start running now. */

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
return 1;
exit (1);
}

/* connect the ports. Note: you can't do this before
the client is activated, because we can't allow
connections to be made to clients that aren't
running.
/* connect the ports. Note: you can't do this before the
client is activated, because we can't allow connections to
be made to clients that aren't running.
*/

if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
fprintf(stderr, "Cannot find any physical capture ports\n");
exit(1);
ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsOutput);
if (ports == NULL) {
fprintf(stderr, "no physical capture ports\n");
exit (1);
}

if (jack_connect (client, ports[0], jack_port_name (input_port))) {
@@ -108,9 +153,11 @@ main (int argc, char *argv[])

free (ports);
if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
fprintf(stderr, "Cannot find any physical playback ports\n");
exit(1);
ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical playback ports\n");
exit (1);
}

if (jack_connect (client, jack_port_name (output_port), ports[0])) {
@@ -119,10 +166,12 @@ main (int argc, char *argv[])

free (ports);

/* Since this is just a toy, run for a few seconds, then finish */
/* keep running until the transport stops */

while (client_state != Exit) {
sleep (1);
}

sleep (10);
jack_client_close (client);
exit (0);
}


+ 8
- 5
jack/internal.h View File

@@ -170,7 +170,7 @@ typedef volatile struct {
volatile jack_client_id_t id; /* w: engine r: engine and client */
volatile jack_nframes_t nframes; /* w: engine r: client */
volatile jack_client_state_t state; /* w: engine and client r: engine */
volatile int8_t name[JACK_CLIENT_NAME_SIZE];
volatile char name[JACK_CLIENT_NAME_SIZE];
volatile ClientType type; /* w: engine r: engine and client */
volatile int8_t active; /* w: engine r: engine and client */
volatile int8_t dead; /* r/w: engine */
@@ -228,6 +228,7 @@ typedef struct {
int32_t load;
ClientType type;
jack_options_t options;

char name[JACK_CLIENT_NAME_SIZE];
char object_path[PATH_MAX+1];
@@ -237,10 +238,10 @@ typedef struct {

typedef struct {

int32_t status;

int32_t status; /* messy name overloading */
uint32_t protocol_v;

jack_status_t open_status; /* used for open() */
jack_shm_info_t client_shm;
jack_shm_info_t engine_shm;

@@ -249,6 +250,8 @@ typedef struct {
int32_t realtime;
int32_t realtime_priority;

char name[JACK_CLIENT_NAME_SIZE]; /* unique name, if assigned */

/* these two are valid only if the connect request
was for type == ClientDriver.
*/
@@ -323,8 +326,8 @@ struct _jack_request {
int32_t status;
};

/* per-client structure allocated in the server's address space
* its here because its not part of the engine structure.
/* Per-client structure allocated in the server's address space.
* It's here because its not part of the engine structure.
*/

typedef struct _jack_client_internal {


+ 5
- 5
jack/jack.h View File

@@ -58,10 +58,10 @@ extern "C" {
* possible concurrent server instances. If unspecified, "default" is
* assumed. Server names are unique to each user.
*
* @param start_command (if non-NULL) is a command line to use if the
* server was not running and must be started. Defining
* $JACK_NO_START_SERVER in the environment disables automatic server
* creation.
* @param server_command (if non-NULL) is a command line to start the
* server if it was not running. The @ref JackNoStartServer option
* disables automatic server creation, as does defining
* $JACK_NO_START_SERVER in the environment.
*
* @return Opaque client handle if successful. If this is NULL, the
* open operation failed, and the caller is not a JACK client.
@@ -70,7 +70,7 @@ jack_client_t *jack_client_open (const char *client_name,
jack_options_t options,
jack_status_t *status,
const char *server_name,
const char *start_command);
const char *server_command);

/**
* Attempt to become an external client of the Jack server.


+ 82
- 12
jackd/engine.c View File

@@ -1001,29 +1001,96 @@ jack_client_unload (jack_client_internal_t *client)
}
}

static jack_client_internal_t *
jack_client_lookup_name (jack_engine_t *engine, char *name)
{
JSList *node;

jack_lock_graph (engine);
for (node = engine->clients; node; node = jack_slist_next (node)) {
jack_client_internal_t *client = node->data;

if (strncmp(name, (char *) client->control->name,
JACK_CLIENT_NAME_SIZE) == 0) {
jack_unlock_graph (engine);
return client; /* name exists */
}
}
jack_unlock_graph (engine);
return NULL; /* not found */
}

/* generate a unique client name
*
* returns 0 if successful, updates name in place
*/
static inline int
jack_generate_unique_name (jack_engine_t *engine, char *name)
{
int tens, ones;
int length = strlen (name);

if (length > JACK_CLIENT_NAME_SIZE - 4) {
jack_error ("%s exists and is too long to make unique", name);
return 1; /* failure */
}

/* generate a unique name by appending "-01".."-99" */
name[length++] = '-';
tens = length++;
ones = length++;
name[tens] = '0';
name[ones] = '1';
name[length] = '\0';
while (jack_client_lookup_name (engine, name)) {
if (name[ones] == '9') {
if (name[tens] == '9') {
jack_error ("client %s has 99 extra"
" instances already", name);
return 1; /* give up */
}
name[tens]++;
name[ones] = '0';
} else {
name[ones]++;
}
}
return 0;
}

static jack_client_internal_t *
setup_client (jack_engine_t *engine, int client_fd,
jack_client_connect_request_t *req,
jack_client_connect_result_t *res)
{
JSList *node;
jack_client_internal_t *client = NULL;
jack_client_internal_t *client;

for (node = engine->clients; node; node = jack_slist_next (node)) {
client = (jack_client_internal_t *) node->data;
/* Since this thread already holds the request_lock, no other
* new client will be created at the same time. So, testing a
* name for uniqueness is valid here. */

//JOQ: watch out for internal clients, they come here too

if (jack_client_lookup_name (engine, req->name)) {

if (strncmp(req->name, (char*)client->control->name,
sizeof(req->name)) == 0) {
jack_error ("cannot create new client; %s already"
" exists", client->control->name);
res->open_status |= JackNameNotUnique;

if (req->options & JackUseExactName) {
jack_error ("cannot create new client; %s already"
" exists", req->name);
return NULL;
}

if (jack_generate_unique_name(engine, req->name)) {
return NULL; /* failure */
}
}

if ((client = jack_setup_client_control (engine, client_fd, req))
== NULL) {
/* create a client struct for this client name */
client = jack_setup_client_control (engine, client_fd, req);
if (client == NULL) {
jack_error ("cannot create new client object");
return 0;
return NULL;
}
VERBOSE (engine, "new client: %s, id = %" PRIu32
@@ -1036,6 +1103,7 @@ setup_client (jack_engine_t *engine, int client_fd,
res->engine_shm = engine->control_shm;
res->realtime = engine->control->real_time;
res->realtime_priority = engine->rtpriority - 1;
strncpy (res->name, req->name, sizeof(res->name));

#ifdef JACK_USE_MACH_THREADS
/* specific resources for server/client real-time thread
@@ -1271,8 +1339,10 @@ handle_new_client (jack_engine_t *engine, int client_fd)
jack_client_internal_t *client;
jack_client_connect_request_t req;
jack_client_connect_result_t res;

//JOQ: fix messy overloading of `status'
res.status = 0;
res.open_status = 0;

if (read (client_fd, &req, sizeof (req)) != sizeof (req)) {
jack_error ("cannot read connection request from client");


+ 1
- 0
libjack/.cvsignore View File

@@ -3,4 +3,5 @@
Makefile
Makefile.in
*.lo
*.loT
*.la

+ 4
- 0
libjack/ChangeLog View File

@@ -1,3 +1,7 @@
2004-10-08 Jack O'Quin <joq@io.com>

* new API functions: jack_client_open(), jack_get_client_name()

2004-09-15 Jack O'Quin <joq@io.com>

* new API functions from <jack/thread.h>


+ 67
- 25
libjack/client.c View File

@@ -330,10 +330,11 @@ jack_handle_reorder (jack_client_t *client, jack_event_t *event)
}
static int
server_connect (int which)
server_connect (const char *server_name)
{
int fd;
struct sockaddr_un addr;
int which = 0;

if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
jack_error ("cannot create client socket (%s)",
@@ -341,6 +342,7 @@ server_connect (int which)
return -1;
}

//JOQ: use server_name as part of socket path
addr.sun_family = AF_UNIX;
snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_%d_%d",
jack_server_dir, getuid (), which);
@@ -406,7 +408,7 @@ server_event_connect (jack_client_t *client)

/* Exec the JACK server in this process. Does not return. */
static void
_start_server (void)
_start_server (const char *server_command)
{
FILE* fp = 0;
char filename[255];
@@ -420,6 +422,10 @@ _start_server (void)
int good = 0;
int ret;

//JOQ:
// if (start_command) {
// parse user-supplied command
// } else {

snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
fp = fopen(filename, "r");
@@ -453,12 +459,12 @@ _start_server (void)
#endif /* USE_CAPABILITIES */
} else {
result = strcspn(arguments, " ");
command = (char*)malloc(result+1);
command = (char *) malloc(result+1);
strncpy(command, arguments, result);
command[result] = '\0';
}

argv = (char**)malloc(255);
argv = (char **) malloc (255);
while(1) {
/* insert -T into arguments */
@@ -491,12 +497,10 @@ _start_server (void)
}

int
start_server (void)
start_server (jack_options_t options, const char *server_command)
{
/* Only fork() a server when $JACK_START_SERVER is defined and
* $JACK_NO_START_SERVER is not. */
if (getenv("JACK_START_SERVER") == NULL ||
getenv("JACK_NO_START_SERVER") != NULL) {
if ((options & JackNoStartServer)
|| (getenv("JACK_NO_START_SERVER") != NULL)) {
return 1;
}

@@ -513,7 +517,7 @@ start_server (void)
case 0: /* child process */
switch (fork()) {
case 0: /* grandchild process */
_start_server();
_start_server(server_command);
_exit (99); /* exec failed */
case -1:
_exit (98);
@@ -531,7 +535,9 @@ start_server (void)
static int
jack_request_client (ClientType type, const char* client_name,
const char* so_name, const char* so_data,
jack_client_connect_result_t *res, int *req_fd)
jack_client_connect_result_t *res, int *req_fd,
jack_options_t options, jack_status_t *status,
const char *server_name, const char *server_command)
{
jack_client_connect_request_t req;

@@ -539,6 +545,8 @@ jack_request_client (ClientType type, const char* client_name,

memset (&req, 0, sizeof (req));

req.options = options;

if (strlen (client_name) >= sizeof (req.name)) {
jack_error ("\"%s\" is too long to be used as a JACK client"
" name.\n"
@@ -563,9 +571,9 @@ jack_request_client (ClientType type, const char* client_name,
return -1;
}

if ((*req_fd = server_connect (0)) < 0) {
if ((*req_fd = server_connect (server_name)) < 0) {
int trys;
if (start_server()) {
if (start_server(options, server_command)) {
goto fail;
}
trys = 5;
@@ -574,7 +582,8 @@ jack_request_client (ClientType type, const char* client_name,
if (--trys < 0) {
goto fail;
}
} while ((*req_fd = server_connect (0)) < 0);
} while ((*req_fd = server_connect (server_name)) < 0);
*status |= JackServerStarted;
}

req.load = TRUE;
@@ -603,6 +612,9 @@ jack_request_client (ClientType type, const char* client_name,
goto fail;
}

*status |= res->open_status; /* return server status bits */

//JOQ: fixme overloading confusion
if (res->status) {
jack_error ("could not attach as client "
"(duplicate client name?)");
@@ -707,17 +719,27 @@ jack_attach_port_segment (jack_client_t *client, jack_port_type_id_t ptid)
}

jack_client_t *
jack_client_new (const char *client_name)
jack_client_open (const char *client_name,
jack_options_t options,
jack_status_t *status,
const char *server_name,
const char *server_command)
{
int req_fd = -1;
int ev_fd = -1;
jack_client_connect_result_t res;
jack_client_t *client;
jack_port_type_id_t ptid;
jack_status_t my_status;

/* external clients need this initialized; internal clients
will use the setup in the server's address space.
*/
if (status == NULL) /* no status from caller? */
status = &my_status; /* use local status word */

*status = 0;

/* External clients need this initialized. It is already set
* up in the server's address space for internal clients.
*/
jack_init_time ();

if (jack_initialize_shm ()) {
@@ -726,17 +748,19 @@ jack_client_new (const char *client_name)
}

if (jack_request_client (ClientExternal, client_name, "", "",
&res, &req_fd)) {
&res, &req_fd, options, status,
server_name, server_command)) {
return NULL;
}

client = jack_client_alloc ();
strcpy (client->name, res.name);
strcpy (client->fifo_prefix, res.fifo_prefix);
client->request_fd = req_fd;

client->pollfd[EVENT_POLL_INDEX].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
client->pollfd[WAIT_POLL_INDEX].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
client->pollfd[EVENT_POLL_INDEX].events =
POLLIN|POLLERR|POLLHUP|POLLNVAL;
client->pollfd[WAIT_POLL_INDEX].events =
POLLIN|POLLERR|POLLHUP|POLLNVAL;

/* attach the engine control/info block */
client->engine_shm = res.engine_shm;
@@ -824,13 +848,31 @@ jack_client_new (const char *client_name)
return 0;
}

jack_client_t *
jack_client_new (const char *client_name)
{
jack_options_t options = JackUseExactName;
if (getenv("JACK_START_SERVER") == NULL)
options |= JackNoStartServer;

return jack_client_open (client_name, options, NULL, NULL, NULL);
}

char *
jack_get_client_name (jack_client_t *client)
{
return client->name;
}

int
jack_internal_client_new (const char *client_name, const char *so_name, const char *so_data)
{
jack_client_connect_result_t res;
int req_fd;
return jack_request_client (ClientInternal, client_name, so_name, so_data, &res, &req_fd);
return jack_request_client (ClientInternal, client_name, so_name,
so_data, &res, &req_fd,
0, NULL, NULL, NULL);
}

void
@@ -842,7 +884,7 @@ jack_internal_client_close (const char *client_name)
req.load = FALSE;
snprintf (req.name, sizeof (req.name), "%s", client_name);
if ((fd = server_connect (0)) < 0) {
if ((fd = server_connect (NULL)) < 0) {
return;
}



+ 2
- 1
libjack/local.h View File

@@ -31,7 +31,8 @@ struct _jack_client {
char thread_ok : 1;
char first_active : 1;
pthread_t thread_id;
char name[JACK_CLIENT_NAME_SIZE];

#ifdef JACK_USE_MACH_THREADS
/* specific ressources for server/client real-time thread communication */
mach_port_t clienttask, bp, serverport, replyport;


Loading…
Cancel
Save