Browse Source

[0.95.10] handle internal client jack_initialize() failure

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@666 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
joq 22 years ago
parent
commit
dfe479bda9
10 changed files with 138 additions and 58 deletions
  1. +1
    -1
      configure.in
  2. +5
    -3
      doc/Makefile.am
  3. +6
    -4
      doc/mainpage.dox
  4. +2
    -1
      doc/reference.doxygen.in
  5. +76
    -20
      example-clients/inprocess.c
  6. +3
    -3
      example-clients/intime.c
  7. +2
    -2
      example-clients/simple_client.c
  8. +8
    -2
      jack/jack.h
  9. +32
    -22
      jackd/engine.c
  10. +3
    -0
      libjack/client.c

+ 1
- 1
configure.in View File

@@ -15,7 +15,7 @@ dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=95
JACK_MICRO_VERSION=9
JACK_MICRO_VERSION=10

dnl ---
dnl HOWTO: updating the jack protocol version


+ 5
- 3
doc/Makefile.am View File

@@ -4,6 +4,10 @@ MAINTAINERCLEANFILES=Makefile.in
CLEANFILES=doxygen-build.stamp

DOX=reference.doxygen
DOXSOURCES=mainpage.dox transport.dox fsm.png \
../jack/jack.h ../jack/types.h ../jack/transport.h \
../jack/ringbuffer.h ../jack/port.h \
../example-clients/simple_client.c ../example-clients/inprocess.c

EXTRA_DIST=mainpage.dox transport.dox fsm.png

@@ -15,9 +19,7 @@ DOC_DIR=$(HTML_DIR)

all-local: doxygen-build.stamp

doxygen-build.stamp: $(DOX) mainpage.dox transport.dox fsm.png \
../jack/jack.h ../jack/types.h ../jack/transport.h ../jack/ringbuffer.h ../jack/port.h \
../example-clients/simple_client.c
doxygen-build.stamp: $(DOX) $(DOXSOURCES)
@echo '*** Running doxygen ***'
doxygen $(DOX)
touch doxygen-build.stamp


+ 6
- 4
doc/mainpage.dox View File

@@ -72,9 +72,11 @@ of just:
data.

There is a lot more that you can do with JACK's interfaces, but for
many applications, this is all that is needed. This <simple_client.c>
demonstrates a complete (simple!) JACK application that just copies
the signal arriving at its input port to its output port.
many applications, this is all that is needed. The @ref
simple_client.c example demonstrates a complete (simple!) JACK
application that just copies the signal arriving at its input port to
its output port. Similarly, @ref inprocess.c shows how to write an
internal client "plugin" that runs within the JACK server process.

@section reference Reference

@@ -90,7 +92,7 @@ The JACK programming interfaces are described in several header files:
media software. It is critical for use in applications that do disk
I/O such as audio file players and recording software.

In addition, the example_clients directory provides numerous examples
In addition, the example-clients directory provides numerous examples
of simple JACK clients that nevertheless use the API to do something
useful. It includes



+ 2
- 1
doc/reference.doxygen.in View File

@@ -368,7 +368,8 @@ INPUT = @top_srcdir@/doc/mainpage.dox \
@top_srcdir@/jack/types.h \
@top_srcdir@/jack/transport.h \
@top_srcdir@/jack/ringbuffer.h \
@top_srcdir@/example-clients/simple_client.c
@top_srcdir@/example-clients/simple_client.c \
@top_srcdir@/example-clients/inprocess.c

# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp


+ 76
- 20
example-clients/inprocess.c View File

@@ -1,52 +1,108 @@
/** @file inprocess.c
*
* @brief This demonstrates the basic concepts for writing a client
* that runs within the JACK server process.
*
* For the sake of example, a port_pair_t is allocated in
* jack_initialize(), passed to process() as an argument, then freed
* in jack_finish().
*/

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <jack/jack.h>

jack_port_t *input_port;
jack_port_t *output_port;
/**
* For the sake of example, an instance of this struct is allocated in
* jack_initialize(), passed to process() as an argument, then freed
* in jack_finish().
*/
typedef struct {
jack_port_t *input_port;
jack_port_t *output_port;
} port_pair_t;

static int
/**
* Called in the realtime thread on every process cycle. The entry
* point name was passed to jack_set_process_callback() by
* jack_initialize().
*
* @return 0 if successful; otherwise jack_finish() will be called and
* the client terminated immediately.
*/
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);
port_pair_t *pp = arg;
jack_default_audio_sample_t *out =
jack_port_get_buffer (pp->output_port, nframes);
jack_default_audio_sample_t *in =
jack_port_get_buffer (pp->input_port, nframes);

memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);

return 0;
return 0; /* continue */
}

/**
* This required entry point is called after the client is loaded by
* jack_internal_client_new().
*
* @param client pointer to JACK client structure.
* @param so_data character string passed from jack_internal_client_new().
*
* @return 0 if successful; otherwise jack_finish() will be called and
* the client terminated immediately.
*/
int
jack_initialize (jack_client_t *client, const char *data)
jack_initialize (jack_client_t *client, const char *so_data)
{
jack_set_process_callback (client, process, 0);
port_pair_t *pp = malloc (sizeof (port_pair_t));

/* create two ports */
if (pp == NULL)
return 1; /* heap exhausted */

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);
jack_set_process_callback (client, process, pp);

/* start the client */
/* create a pair of ports */
pp->input_port = jack_port_register (client, "input",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
pp->output_port = jack_port_register (client, "output",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

/* join the process() cycle */
jack_activate (client);

/* connect the ports */

if (jack_connect (client, "alsa_pcm:capture_1", jack_port_name (input_port))) {
if (jack_connect (client, "alsa_pcm:capture_1",
jack_port_name (pp->input_port))) {
fprintf (stderr, "cannot connect input port\n");
return 1; /* terminate client */
}

if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:playback_1")) {
if (jack_connect (client, jack_port_name (pp->output_port),
"alsa_pcm:playback_1")) {
fprintf (stderr, "cannot connect output port\n");
return 1; /* terminate client */
}

/* our client is running. we're happy */
return 0;
return 0; /* success */
}

/**
* This required entry point is called immediately before the client
* is unloaded, which could happen due to a call to
* jack_internal_client_close(), or a nonzero return from either
* jack_initialize() or process().
*
* @param arg the same parameter provided to process().
*/
void
jack_finish (void)
jack_finish (void *arg)
{
/* relax */
if (arg)
free ((port_pair_t *) arg);
}

+ 3
- 3
example-clients/intime.c View File

@@ -142,17 +142,17 @@ jack_initialize (jack_client_t *client, const char *arg)

if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) {
fprintf (stderr, "Unable to take over timebase.\n");
return 1;
return 1; /* terminate */
}

fprintf (stderr, "Internal timebase master defined.\n");
jack_activate (client);
return 0;
return 0; /* success */
}

/* before unloading */
void
jack_finish (void)
jack_finish (void *arg)
{
fprintf (stderr, "Internal timebase client exiting.\n");
}

+ 2
- 2
example-clients/simple_client.c View File

@@ -1,7 +1,7 @@
/** @file simple_client.c
*
* @brief This is very simple client that demonstrates the basic
* features of JACK as they would be used by many applications.
* @brief This simple client demonstrates the basic features of JACK
* as they would be used by many applications.
*/

#include <stdio.h>


+ 8
- 2
jack/jack.h View File

@@ -64,11 +64,17 @@ int jack_client_name_size(void);
/**
* Attempt to load an internal client into the Jack server.
*
* Internal clients run within the JACK server process. They can use
* of the same functions as external clients. Each internal client
* must declare jack_initialize() and jack_finish() entry points,
* called at load and unload times. See inprocess.c for an example of
* how to write an internal client.
*
* @param client_name of at most jack_client_name_size() characters.
* @param so_name A path to a shared object file containing the code
* for the new client
* for the new client.
* @param so_data An arbitary string containing information to be
* passed to the init() routine of the new client
* passed to the jack_initialize() routine of the new client.
*/
int jack_internal_client_new (const char *client_name, const char *so_name,
const char *so_data);


+ 32
- 22
jackd/engine.c View File

@@ -88,8 +88,8 @@ static void jack_remove_client (jack_engine_t *engine,
jack_client_internal_t *client);
static void jack_client_delete (jack_engine_t *, jack_client_internal_t *);
static jack_client_internal_t
*jack_client_internal_new (jack_engine_t *engine, int fd,
jack_client_connect_request_t *);
*jack_setup_client_control (jack_engine_t *engine, int fd,
jack_client_connect_request_t *);
static void jack_sort_graph (jack_engine_t *engine);
static int jack_rechain_graph (jack_engine_t *engine);
static int jack_get_fifo_fd (jack_engine_t *engine, unsigned int which_fifo);
@@ -1006,7 +1006,7 @@ setup_client (jack_engine_t *engine, int client_fd,
}
}

if ((client = jack_client_internal_new (engine, client_fd, req))
if ((client = jack_setup_client_control (engine, client_fd, req))
== NULL) {
jack_error ("cannot create new client object");
return 0;
@@ -1030,16 +1030,15 @@ setup_client (jack_engine_t *engine, int client_fd,
#endif
if (jack_client_is_internal(client)) {
/* set up the pointers necessary for the request system
to work.
*/

/* set up the pointers necessary for the request
* system to work. */

client->control->deliver_request = internal_client_request;
client->control->deliver_arg = engine;
/* the client is in the same address space */
res->client_control = client->control;
res->engine_control = engine->control;

@@ -1047,10 +1046,9 @@ setup_client (jack_engine_t *engine, int client_fd,
strcpy (res->fifo_prefix, engine->fifo_prefix);
}

/* add new client to the clients list */
jack_lock_graph (engine);

engine->clients = jack_slist_prepend (engine->clients, client);

engine->clients = jack_slist_prepend (engine->clients, client);
jack_engine_reset_rolling_usecs (engine);
switch (client->control->type) {
@@ -1072,8 +1070,15 @@ setup_client (jack_engine_t *engine, int client_fd,

if (client->initialize (client->control->private_client,
req->object_data)) {
jack_client_delete (engine, client);
return 0;

/* failed: clean up client data */
VERBOSE (engine,
"%s jack_initialize() failed!\n",
client->control->name);
jack_lock_graph (engine);
jack_remove_client (engine, client);
jack_unlock_graph (engine);
return NULL;
}
}

@@ -2482,9 +2487,11 @@ jack_engine_delete (jack_engine_t *engine)
return 0;
}

/* Set up the engine's client internal and control structures for both
* internal and external clients. */
static jack_client_internal_t *
jack_client_internal_new (jack_engine_t *engine, int fd,
jack_client_connect_request_t *req)
jack_setup_client_control (jack_engine_t *engine, int fd,
jack_client_connect_request_t *req)
{
jack_client_internal_t *client;

@@ -2522,14 +2529,15 @@ jack_client_internal_new (jack_engine_t *engine, int fd,
}

if (jack_attach_shm (&client->control_shm)) {
jack_error ("cannot attach to client control block for %s (%s)",
req->name, strerror (errno));
jack_error ("cannot attach to client control block "
"for %s (%s)", req->name, strerror (errno));
jack_destroy_shm (&client->control_shm);
free (client);
return 0;
}

client->control = (jack_client_control_t *) jack_shm_addr (&client->control_shm);
client->control = (jack_client_control_t *)
jack_shm_addr (&client->control_shm);
}

client->control->type = req->type;
@@ -2567,7 +2575,7 @@ jack_client_internal_new (jack_engine_t *engine, int fd,
jack_error ("cannot dynamically load client from"
" \"%s\"", req->object_path);
jack_client_delete (engine, client);
return 0;
return NULL;
}
}

@@ -2628,6 +2636,7 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
}

/* try to force the server thread to return from poll */
/* JOQ: why do this for internal clients? */
close (client->event_fd);
close (client->request_fd);
@@ -2677,7 +2686,8 @@ jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
if (jack_client_is_internal (client)) {

jack_client_unload (client);
free ((char *) client->control);
free (client->control->private_client);
free ((void *) client->control);

} else {


+ 3
- 0
libjack/client.c View File

@@ -176,6 +176,9 @@ jack_client_alloc ()
return client;
}

/*
* Build the jack_client_t structure for an internal client.
*/
jack_client_t *
jack_client_alloc_internal (jack_client_control_t *cc, jack_engine_t* engine)
{


Loading…
Cancel
Save