Browse Source

remove HUP handling, enable port_get_connections() for internal clients, add metering API, more

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@348 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
pbd 22 years ago
parent
commit
7cb8250ea2
14 changed files with 1063 additions and 936 deletions
  1. +42
    -10
      drivers/alsa/alsa_driver.c
  2. +1
    -1
      example-clients/lsp.c
  3. +4
    -4
      example-clients/simple_client.c
  4. +0
    -1
      jack/engine.h
  5. +3
    -11
      jack/internal.h
  6. +104
    -100
      jack/jack.h
  7. +35
    -20
      jack/port.h
  8. +2
    -2
      jack/types.h
  9. +122
    -159
      jackd/engine.c
  10. +5
    -1
      jackd/jackd.c
  11. +6
    -1
      libjack/Makefile.am
  12. +35
    -626
      libjack/client.c
  13. +32
    -0
      libjack/local.h
  14. +672
    -0
      libjack/port.c

+ 42
- 10
drivers/alsa/alsa_driver.c View File

@@ -1147,7 +1147,8 @@ alsa_driver_process (alsa_driver_t *driver, jack_nframes_t nframes)
/* oh well, the engine can't run, so we'll just throw away this /* oh well, the engine can't run, so we'll just throw away this
cycle's data ... cycle's data ...
*/ */
snd_pcm_mmap_commit (driver->capture_handle, capture_offset, contiguous);
if (driver->capture_handle)
snd_pcm_mmap_commit (driver->capture_handle, capture_offset, contiguous);
} }


/* Now handle input monitoring */ /* Now handle input monitoring */
@@ -1453,19 +1454,50 @@ alsa_driver_new (char *name, char *alsa_device,
driver->clock_sync_listeners = 0; driver->clock_sync_listeners = 0;


if (playing) { if (playing) {
if ((err = snd_pcm_open (&driver->playback_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
jack_error ("ALSA: Cannot open PCM device %s/%s", name, alsa_device);
free (driver);
return 0;
if (snd_pcm_open (&driver->playback_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
driver->playback_handle = NULL;
} }
} }


if (capturing) { if (capturing) {
if ((err = snd_pcm_open (&driver->capture_handle, alsa_device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
snd_pcm_close (driver->playback_handle);
jack_error ("ALSA: Cannot open PCM device %s", name);
free (driver);
return 0;
if (snd_pcm_open (&driver->capture_handle, alsa_device, SND_PCM_STREAM_CAPTURE, 0) < 0) {
driver->capture_handle = NULL;
}
}

if (driver->playback_handle == NULL) {
if (playing) {

/* they asked for playback, but we can't do it */

jack_error ("ALSA: Cannot open PCM device %s for playback. Falling back to capture-only mode",
name);

if (driver->capture_handle == NULL) {
/* can't do anything */
free (driver);
return 0;
}
playing = FALSE;
}
}

if (driver->capture_handle == NULL) {
if (capturing) {

/* they asked for capture, but we can't do it */
jack_error ("ALSA: Cannot open PCM device %s for capture. Falling back to playback-only mode",
name);
if (driver->playback_handle == NULL) {
/* can't do anything */
free (driver);
return 0;
}

capturing = FALSE;
} }
} }




+ 1
- 1
example-clients/lsp.c View File

@@ -56,7 +56,7 @@ main (int argc, char *argv[])
printf (" %s\n", connections[j]); printf (" %s\n", connections[j]);
} }
free (connections); free (connections);
}
}
} }
if (show_latency) { if (show_latency) {
jack_port_t *port = jack_port_by_name (client, ports[i]); jack_port_t *port = jack_port_by_name (client, ports[i]);


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

@@ -17,7 +17,7 @@ process (jack_nframes_t nframes, void *arg)
jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes);


memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);
return 0; return 0;
} }


@@ -32,7 +32,7 @@ srate (jack_nframes_t nframes, void *arg)
void void
error (const char *desc) error (const char *desc)
{ {
printf ("JACK experienced an error: %s\n", desc);
fprintf (stderr, "JACK error: %s\n", desc);
} }


void void
@@ -115,7 +115,7 @@ main (int argc, char *argv[])




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


@@ -126,7 +126,7 @@ main (int argc, char *argv[])
free (ports); free (ports);
if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
fprintf(stderr, "Cannot find any physical playback ports");
fprintf(stderr, "Cannot find any physical playback ports\n");
exit(1); exit(1);
} }




+ 0
- 1
jack/engine.h View File

@@ -66,7 +66,6 @@ struct _jack_engine {


JSList *clients; JSList *clients;
JSList *clients_waiting; JSList *clients_waiting;
JSList *aliases;


struct _jack_port_internal *internal_ports; struct _jack_port_internal *internal_ports;




+ 3
- 11
jack/internal.h View File

@@ -259,8 +259,6 @@ typedef enum {
SetClientCapabilities = 9, SetClientCapabilities = 9,
GetPortConnections = 10, GetPortConnections = 10,
GetPortNConnections = 11, GetPortNConnections = 11,
AddAlias = 12,
RemoveAlias = 13,
} RequestType; } RequestType;


struct _jack_request { struct _jack_request {
@@ -280,21 +278,15 @@ struct _jack_request {
char destination_port[JACK_PORT_NAME_SIZE+1]; char destination_port[JACK_PORT_NAME_SIZE+1];
} connect; } connect;
struct { struct {
char port[JACK_PORT_NAME_SIZE+1];
char alias[JACK_PORT_NAME_SIZE+1];
} alias;
unsigned int nports;
const char **ports;
} port_connections;
jack_client_id_t client_id; jack_client_id_t client_id;
jack_nframes_t nframes; jack_nframes_t nframes;
unsigned int nports;
} x; } x;
int status; int status;
}; };


typedef struct _jack_port_alias {
char port[JACK_PORT_NAME_SIZE+1];
char alias[JACK_PORT_NAME_SIZE+1];
} jack_port_alias_t;

extern void jack_cleanup_shm (); extern void jack_cleanup_shm ();
extern void jack_cleanup_files (); extern void jack_cleanup_files ();




+ 104
- 100
jack/jack.h View File

@@ -79,7 +79,7 @@ void jack_internal_client_close (const char *client_name);
* *
* NOTE: clients do not need to call this. It exists only * NOTE: clients do not need to call this. It exists only
* to help more complex clients understand what is going * to help more complex clients understand what is going
* on. If called, it must be called before jack_client_activate().
* on. If called, it should be called before jack_client_activate().
*/ */
void jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg); void jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg);


@@ -101,7 +101,11 @@ void jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void
int jack_set_process_callback (jack_client_t *, JackProcessCallback process_callback, void *arg); int jack_set_process_callback (jack_client_t *, JackProcessCallback process_callback, void *arg);


/** /**
* <b>Note!</b> This function is deprecated.
* Tell the Jack server to call 'bufsize_callback' whenever the size of the
* the buffer that will be passed to the process callback changes,
* passing 'arg' as the second argument.
*
* @return 0 on success, otherwise a non-zero error code
*/ */
int jack_set_buffer_size_callback (jack_client_t *, JackBufferSizeCallback bufsize_callback, void *arg); int jack_set_buffer_size_callback (jack_client_t *, JackBufferSizeCallback bufsize_callback, void *arg);


@@ -190,6 +194,22 @@ jack_port_t *jack_port_register (jack_client_t *,
*/ */
int jack_port_unregister (jack_client_t *, jack_port_t *); int jack_port_unregister (jack_client_t *, jack_port_t *);


/**
* This returns a pointer to the memory area associated with the
* specified port. For an output port, it will be a memory area
* that can be written to; for an input port, it will be an area
* containing the data from the port's connection(s), or
* zero-filled. if there are multiple inbound connections, the data
* will be mixed appropriately.
*
* You may cache the value returned, but only between calls to
* your "blocksize" callback. For this reason alone, you should
* either never cache the return value or ensure you have
* a "blocksize" callback and be sure to invalidate the cached
* address from there.
*/
void *jack_port_get_buffer (jack_port_t *, jack_nframes_t);

/** /**
* Returns the name of the jack_port_t. * Returns the name of the jack_port_t.
*/ */
@@ -265,82 +285,6 @@ const char ** jack_port_get_connections (const jack_port_t *port);
*/ */
const char ** jack_port_get_all_connections (const jack_client_t *client, const jack_port_t *port); const char ** jack_port_get_all_connections (const jack_client_t *client, const jack_port_t *port);


/**
* This modifies a port's name, and may be called at any time.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_port_set_name (jack_port_t *port, const char *name);

/**
* This returns a pointer to the memory area associated with the
* specified port. For an output port, it will be a memory area
* that can be written to; for an input port, it will be an area
* containing the data from the port's connection(s), or
* zero-filled. if there are multiple inbound connections, the data
* will be mixed appropriately.
*
* You may cache the value returned, but only between calls to
* your "blocksize" callback. For this reason alone, you should
* either never cache the return value or ensure you have
* a "blocksize" callback and be sure to invalidate the cached
* address from there.
*/
void *jack_port_get_buffer (jack_port_t *, jack_nframes_t);

/**
* Establishes a connection between two ports.
*
* When a connection exists, data written to the source port will
* be available to be read at the destination port.
*
* @pre The types of both ports must be identical to establish a connection.
* @pre The flags of the source port must include PortIsOutput.
* @pre The flags of the destination port must include PortIsInput.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_connect (jack_client_t *,
const char *source_port,
const char *destination_port);

/**
* Removes a connection between two ports.
*
* @pre The types of both ports must be identical to establish a connection.
* @pre The flags of the source port must include PortIsOutput.
* @pre The flags of the destination port must include PortIsInput.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_disconnect (jack_client_t *,
const char *source_port,
const char *destination_port);

/**
* Performs the exact same function as jack_connect(), but it uses
* port handles rather than names, which avoids the name lookup inherent
* in the name-based version.
*
* It is envisaged that clients connecting their own ports will use these
* two, whereas generic connection clients (e.g. patchbays) will use the
* name-based versions.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_port_connect (jack_client_t *, jack_port_t *src, jack_port_t *dst);

/**
* Performs the exact same function as jack_disconnect(), but it uses
* port handles rather than names, which avoids the name lookup inherent
* in the name-based version.
*
* It is envisaged that clients disconnecting their own ports will use these
* two, whereas generic connection clients (e.g. patchbays) will use the
* name-based versions.
*/
int jack_port_disconnect (jack_client_t *, jack_port_t *);

/** /**
* A client may call this on a pair of its own ports to * A client may call this on a pair of its own ports to
* semi-permanently wire them together. This means that * semi-permanently wire them together. This means that
@@ -415,6 +359,33 @@ jack_nframes_t jack_port_get_total_latency (jack_client_t *, jack_port_t *port);
*/ */
void jack_port_set_latency (jack_port_t *, jack_nframes_t); void jack_port_set_latency (jack_port_t *, jack_nframes_t);


/**
* This modifies a port's name, and may be called at any time.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_port_set_name (jack_port_t *port, const char *name);

/**
*/

double jack_port_get_peak (jack_port_t*, jack_nframes_t);

/**
*/

double jack_port_get_power (jack_port_t*, jack_nframes_t);

/**
*/

void jack_port_set_peak_function (jack_port_t *, double (*func)(jack_port_t*, jack_nframes_t));

/**
*/

void jack_port_set_power_function (jack_port_t *, double (*func)(jack_port_t*, jack_nframes_t));

/** /**
* If JackPortCanMonitor is set for a port, then these 2 functions will * If JackPortCanMonitor is set for a port, then these 2 functions will
* turn on/off input monitoring for the port. If JackPortCanMonitor * turn on/off input monitoring for the port. If JackPortCanMonitor
@@ -447,6 +418,59 @@ int jack_port_ensure_monitor (jack_port_t *port, int onoff);
*/ */
int jack_port_monitoring_input (jack_port_t *port); int jack_port_monitoring_input (jack_port_t *port);


/**
* Establishes a connection between two ports.
*
* When a connection exists, data written to the source port will
* be available to be read at the destination port.
*
* @pre The types of both ports must be identical to establish a connection.
* @pre The flags of the source port must include PortIsOutput.
* @pre The flags of the destination port must include PortIsInput.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_connect (jack_client_t *,
const char *source_port,
const char *destination_port);

/**
* Removes a connection between two ports.
*
* @pre The types of both ports must be identical to establish a connection.
* @pre The flags of the source port must include PortIsOutput.
* @pre The flags of the destination port must include PortIsInput.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_disconnect (jack_client_t *,
const char *source_port,
const char *destination_port);

/**
* Performs the exact same function as jack_connect(), but it uses
* port handles rather than names, which avoids the name lookup inherent
* in the name-based version.
*
* It is envisaged that clients connecting their own ports will use these
* two, whereas generic connection clients (e.g. patchbays) will use the
* name-based versions.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_port_connect (jack_client_t *, jack_port_t *src, jack_port_t *dst);

/**
* Performs the exact same function as jack_disconnect(), but it uses
* port handles rather than names, which avoids the name lookup inherent
* in the name-based version.
*
* It is envisaged that clients disconnecting their own ports will use these
* two, whereas generic connection clients (e.g. patchbays) will use the
* name-based versions.
*/
int jack_port_disconnect (jack_client_t *, jack_port_t *);

/** /**
* This returns the sample rate of the jack system, as set by the user when * This returns the sample rate of the jack system, as set by the user when
* jackd was started. * jackd was started.
@@ -542,28 +566,6 @@ float jack_cpu_load (jack_client_t *client);
*/ */
void jack_set_server_dir (const char *path); void jack_set_server_dir (const char *path);


/**
* Create an alias for a port. Returns zero if
* successful, non-zero otherwise. After a successful
* return, `alias' may be used to refer to a port
* instead of the port's actual name. the naming
* scheme is "alias:<alias>", so if the port alias
* was "left", and the port name was "foo:out1",
* then "alias:left" will refer to "foo:out1".
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_add_alias (jack_client_t *, const char *portname, const char *alias);

/**
* Remove `alias' from a JACK system.
*
* @return zero if successful, less than zero if the alias
* did not exist, greater than zero if the alias could not
* be removed.
*/
int jack_remove_alias (jack_client_t *, const char *alias);

/** /**
* Return the pthread ID of the thread running the JACK client * Return the pthread ID of the thread running the JACK client
* side code. * side code.
@@ -575,3 +577,5 @@ pthread_t jack_client_thread_id (jack_client_t *);
#endif #endif


#endif /* __jack_h__ */ #endif /* __jack_h__ */



+ 35
- 20
jack/port.h View File

@@ -33,26 +33,38 @@
typedef unsigned long jack_client_id_t; typedef unsigned long jack_client_id_t;


typedef struct _jack_port_type_info { typedef struct _jack_port_type_info {
const char type_name[JACK_PORT_TYPE_SIZE]; /* what do you think ? */

void (*mixdown)(jack_port_t *, jack_nframes_t); /* function to mixdown multiple inputs to a buffer. can be
NULL, indicating that multiple input connections
are not legal for this data type.
*/

long buffer_scale_factor; /* If == 1, then a buffer to handle nframes worth of
data is sizeof(jack_default_audio_sample_t) * nframes bytes large.
If anything other than 1, the buffer allocated
for input mixing will be this value times
sizeof (jack_default_audio_sample_t) * nframes bytes in size.

Obviously, for non-audio data types, it may have
a different value.

if < 0, then the value should be ignored, and
port->shared->buffer_size should be used.
*/
const char type_name[JACK_PORT_TYPE_SIZE];

void (*mixdown)(jack_port_t *, jack_nframes_t); /* function to mixdown multiple inputs to a buffer. can be
NULL, indicating that multiple input connections
are not legal for this data type.
*/
double (*peak)(jack_port_t *, jack_nframes_t); /* function to compute a peak value for a buffer. can be
NULL, indicating that the computation has no meaning.
the return value is normalized to a [0..1] range.
*/

double (*power)(jack_port_t *, jack_nframes_t); /* function to compute a power value for a buffer. can be
NULL, indicating that the computation has no meaning.

the return value is normalized to a [0..1] range.
*/
long buffer_scale_factor; /* If == 1, then a buffer to handle nframes worth of
data is sizeof(jack_default_audio_sample_t) * nframes bytes large.
If anything other than 1, the buffer allocated
for input mixing will be this value times
sizeof (jack_default_audio_sample_t) * nframes bytes in size.
Obviously, for non-audio data types, it may have
a different value.
if < 0, then the value should be ignored, and
port->shared->buffer_size should be used.
*/
} jack_port_type_info_t; } jack_port_type_info_t;


/* This is the data structure allocated in shared memory /* This is the data structure allocated in shared memory
@@ -74,6 +86,9 @@ typedef struct _jack_port_shared {
volatile jack_nframes_t total_latency; volatile jack_nframes_t total_latency;
volatile unsigned char monitor_requests; volatile unsigned char monitor_requests;


double (*peak)(jack_port_t*,jack_nframes_t);
double (*power)(jack_port_t*,jack_nframes_t);

char in_use : 1; char in_use : 1;
char locked : 1; char locked : 1;
struct _jack_port *tied; struct _jack_port *tied;


+ 2
- 2
jack/types.h View File

@@ -44,8 +44,8 @@ typedef struct _jack_port jack_port_t;
typedef struct _jack_client jack_client_t; typedef struct _jack_client jack_client_t;


/** /**
* Ports have unique ids. You will very rarely need to know them, however,
* except in the case of the port registration callback.
* Ports have unique ids. A port registration callback is the only
* place you ever need to know their value.
*/ */
typedef unsigned long jack_port_id_t; typedef unsigned long jack_port_id_t;




+ 122
- 159
jackd/engine.c View File

@@ -60,6 +60,8 @@
*/ */
#define JACKD_SOFT_MODE_TIMEOUT 500 #define JACKD_SOFT_MODE_TIMEOUT 500


#define JACK_ERROR_WITH_SOCKETS 10000000

typedef struct { typedef struct {


jack_port_internal_t *source; jack_port_internal_t *source;
@@ -98,8 +100,9 @@ typedef struct _jack_driver_info {
static int jack_port_assign_buffer (jack_engine_t *, jack_port_internal_t *); static int jack_port_assign_buffer (jack_engine_t *, jack_port_internal_t *);
static jack_port_internal_t *jack_get_port_by_name (jack_engine_t *, const char *name); static jack_port_internal_t *jack_get_port_by_name (jack_engine_t *, const char *name);


static void jack_client_delete (jack_engine_t *, jack_client_internal_t *);
static void jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client);
static void jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client); 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 *); static jack_client_internal_t *jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_request_t *);
static jack_client_internal_t *jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id); static jack_client_internal_t *jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id);
@@ -113,9 +116,6 @@ static int jack_port_do_connect (jack_engine_t *engine, const char *source_port
static int jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, const char *destination_port); static int jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, const char *destination_port);
static int jack_port_do_disconnect_all (jack_engine_t *engine, jack_port_id_t); static int jack_port_do_disconnect_all (jack_engine_t *engine, jack_port_id_t);


static int jack_do_add_alias (jack_engine_t *engine, jack_request_t *);
static int jack_do_remove_alias (jack_engine_t *engine, jack_request_t *);

static int jack_port_do_unregister (jack_engine_t *engine, jack_request_t *); static int jack_port_do_unregister (jack_engine_t *engine, jack_request_t *);
static int jack_port_do_register (jack_engine_t *engine, jack_request_t *); static int jack_port_do_register (jack_engine_t *engine, jack_request_t *);
static int jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int reply_fd); static int jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int reply_fd);
@@ -135,8 +135,6 @@ static int jack_engine_post_process (jack_engine_t *);


static int internal_client_request (void*, jack_request_t *); static int internal_client_request (void*, jack_request_t *);


static const char *jack_lookup_alias (jack_engine_t *engine, const char *alias);

static int jack_use_driver (jack_engine_t *engine, jack_driver_t *driver); static int jack_use_driver (jack_engine_t *engine, jack_driver_t *driver);


static int *jack_shm_registry; static int *jack_shm_registry;
@@ -333,7 +331,7 @@ jack_cleanup_files ()
while ((dirent = readdir (dir)) != NULL) { while ((dirent = readdir (dir)) != NULL) {
if (strncmp (dirent->d_name, "jack-", 5) == 0 || strncmp (dirent->d_name, "jack_", 5) == 0) { if (strncmp (dirent->d_name, "jack-", 5) == 0 || strncmp (dirent->d_name, "jack_", 5) == 0) {
char fullpath[PATH_MAX+1]; char fullpath[PATH_MAX+1];
sprintf (fullpath, "%s/%s", jack_server_dir, dirent->d_name);
snprintf (fullpath, sizeof (fullpath), "%s/%s", jack_server_dir, dirent->d_name);
unlink (fullpath); unlink (fullpath);
} }
} }
@@ -646,7 +644,12 @@ jack_engine_post_process (jack_engine_t *engine)


if (!jack_client_is_internal (client) && ctl->process) { if (!jack_client_is_internal (client) && ctl->process) {
if (ctl->awake_at != 0 && ctl->state > NotTriggered && ctl->state != Finished && ctl->timed_out++) { if (ctl->awake_at != 0 && ctl->state > NotTriggered && ctl->state != Finished && ctl->timed_out++) {
client->error = TRUE;
fprintf (stderr, "client %s error: awake_at = %Lu state = %d timed_out = %d\n",
ctl->name,
ctl->awake_at,
ctl->state,
ctl->timed_out);
client->error++;
} }
} }


@@ -669,14 +672,31 @@ jack_engine_post_process (jack_engine_t *engine)
client = (jack_client_internal_t *) node->data; client = (jack_client_internal_t *) node->data;
if (client->error) { if (client->error) {
if (engine->verbose) {
fprintf (stderr, "removing failed client %s state = %s errors = %d\n",
client->control->name, client_state_names[client->control->state],
client->error);

/* if we have a communication problem with the client,
remove it. otherwise, turn it into a zombie. the client
will/should realize this and will close it sockets.
then we'll end up back here again and will finally
remove the client.
*/

if (client->error >= JACK_ERROR_WITH_SOCKETS) {
if (engine->verbose) {
fprintf (stderr, "removing failed client %s state = %s errors = %d\n",
client->control->name, client_state_names[client->control->state],
client->error);
}
jack_remove_client (engine, (jack_client_internal_t *) node->data);
} else {
if (engine->verbose) {
fprintf (stderr, "zombifying failed client %s state = %s errors = %d\n",
client->control->name, client_state_names[client->control->state],
client->error);
}
jack_zombify_client (engine, (jack_client_internal_t *) node->data);
client->error = 0;
} }
jack_remove_client (engine, (jack_client_internal_t *) node->data);

need_sort = TRUE; need_sort = TRUE;
} }
@@ -1301,7 +1321,7 @@ jack_set_timebase (jack_engine_t *engine, jack_client_id_t client)
} }


static int static int
handle_client_jack_error (jack_engine_t *engine, int fd)
handle_client_socket_error (jack_engine_t *engine, int fd)
{ {
jack_client_internal_t *client = 0; jack_client_internal_t *client = 0;
JSList *node; JSList *node;
@@ -1316,7 +1336,9 @@ handle_client_jack_error (jack_engine_t *engine, int fd)


if (((jack_client_internal_t *) node->data)->request_fd == fd) { if (((jack_client_internal_t *) node->data)->request_fd == fd) {
client = (jack_client_internal_t *) node->data; client = (jack_client_internal_t *) node->data;
client->error++;
if (client->error < JACK_ERROR_WITH_SOCKETS) {
client->error += JACK_ERROR_WITH_SOCKETS;
}
break; break;
} }
} }
@@ -1374,24 +1396,12 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd)
case GetPortConnections: case GetPortConnections:
case GetPortNConnections: case GetPortNConnections:
if (reply_fd) {
req->status = jack_do_get_port_connections (engine, req, *reply_fd);
if (req->status != 0) {
*reply_fd = -1;
}
} else {
req->status = -1;
if ((req->status = jack_do_get_port_connections (engine, req, *reply_fd)) == 0) {
/* we have already replied, don't do it again */
*reply_fd = -1;
} }
break; break;


case AddAlias:
req->status = jack_do_add_alias (engine, req);
break;

case RemoveAlias:
req->status = jack_do_remove_alias (engine, req);
break;

default: default:
/* some requests are handled entirely on the client side, /* some requests are handled entirely on the client side,
by adjusting the shared memory area(s) by adjusting the shared memory area(s)
@@ -1557,7 +1567,7 @@ jack_server_thread (void *arg)
} }


if (pfd[i].revents & ~POLLIN) { if (pfd[i].revents & ~POLLIN) {
handle_client_jack_error (engine, pfd[i].fd);
handle_client_socket_error (engine, pfd[i].fd);
} else if (pfd[i].revents & POLLIN) { } else if (pfd[i].revents & POLLIN) {
if (handle_external_client_request (engine, pfd[i].fd)) { if (handle_external_client_request (engine, pfd[i].fd)) {
jack_error ("bad hci\n"); jack_error ("bad hci\n");
@@ -1608,8 +1618,6 @@ jack_engine_new (int realtime, int rtpriority, int verbose)
pthread_mutex_init (&engine->request_lock, 0); pthread_mutex_init (&engine->request_lock, 0);


engine->clients = 0; engine->clients = 0;
engine->aliases = 0;

engine->port_segments = 0; engine->port_segments = 0;
engine->port_buffer_freelist = 0; engine->port_buffer_freelist = 0;


@@ -1902,7 +1910,7 @@ jack_main_thread (void *arg)


if (engine->control->real_time != 0 && engine->spare_usecs && ((WORK_SCALE * engine->spare_usecs) <= delayed_usecs)) { if (engine->control->real_time != 0 && engine->spare_usecs && ((WORK_SCALE * engine->spare_usecs) <= delayed_usecs)) {
printf ("delay of %.3f usecs exceeds estimated spare time of %.3f; restart ...\n",
fprintf (stderr, "delay of %.3f usecs exceeds estimated spare time of %.3f; restart ...\n",
delayed_usecs, WORK_SCALE * engine->spare_usecs); delayed_usecs, WORK_SCALE * engine->spare_usecs);


if (++consecutive_excessive_delays > 10) { if (++consecutive_excessive_delays > 10) {
@@ -2099,7 +2107,7 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req


client->control->type = req->type; client->control->type = req->type;
client->control->active = 0; client->control->active = 0;
client->control->dead = 0;
client->control->dead = FALSE;
client->control->timed_out = 0; client->control->timed_out = 0;
client->control->id = engine->next_client_id++; client->control->id = engine->next_client_id++;
strcpy ((char *) client->control->name, req->name); strcpy ((char *) client->control->name, req->name);
@@ -2147,13 +2155,10 @@ jack_port_clear_connections (jack_engine_t *engine, jack_port_internal_t *port)
} }


static void static void
jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)
{ {
JSList *node;
unsigned int i;

if (engine->verbose) { if (engine->verbose) {
fprintf (stderr, "adios senor %s\n", client->control->name);
fprintf (stderr, "senor %s - you are a zombie\n", client->control->name);
} }


/* caller must hold the client_lock */ /* caller must hold the client_lock */
@@ -2161,7 +2166,7 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
/* this stops jack_deliver_event() from doing anything */ /* this stops jack_deliver_event() from doing anything */


client->control->dead = TRUE; client->control->dead = TRUE;
if (client == engine->timebase_client) { if (client == engine->timebase_client) {
engine->timebase_client = 0; engine->timebase_client = 0;
engine->control->current_time.frame = 0; engine->control->current_time.frame = 0;
@@ -2171,33 +2176,32 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
} }


jack_client_disconnect (engine, client); jack_client_disconnect (engine, client);
jack_client_do_deactivate (engine, client, FALSE);
}


/* try to force the server thread to return from poll */

close (client->event_fd);
close (client->request_fd);
static void
jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
{
unsigned int i;
JSList *node;


/* if the client is stuck in its process() callback, its not going to
notice that we closed the pipes. give it a little help ... though
this could prove fatal to some clients.
*/
/* caller must hold the client_lock */


if (client->control->pid > 0) {
if (engine->verbose) {
fprintf (stderr, "sending SIGHUP to client %s at %d\n", client->control->name, client->control->pid);
}
kill (client->control->pid, SIGHUP);
if (engine->verbose) {
fprintf (stderr, "adios senor %s\n", client->control->name);
} }


for (node = engine->clients; node; node = jack_slist_next (node)) {
if (((jack_client_internal_t *) node->data)->control->id == client->control->id) {
engine->clients = jack_slist_remove_link (engine->clients, node);
jack_slist_free_1 (node);
break;
}
/* if its not already a zombie, make it so */

if (!client->control->dead) {
jack_zombify_client (engine, client);
} }

/* try to force the server thread to return from poll */

close (client->event_fd);
close (client->request_fd);
jack_client_do_deactivate (engine, client, FALSE);


if (client->control->type == ClientExternal) { if (client->control->type == ClientExternal) {


@@ -2215,9 +2219,18 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
} }
} }


for (node = engine->clients; node; node = jack_slist_next (node)) {
if (((jack_client_internal_t *) node->data)->control->id == client->control->id) {
engine->clients = jack_slist_remove_link (engine->clients, node);
jack_slist_free_1 (node);
break;
}
}
jack_client_delete (engine, client); jack_client_delete (engine, client);
} }



static void static void
jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client) jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
{ {
@@ -2226,6 +2239,7 @@ jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
free ((char *) client->control); free ((char *) client->control);
} else { } else {
shmdt ((void *) client->control); shmdt ((void *) client->control);
shmctl(client->shm_id,IPC_RMID,0);
} }


free (client); free (client);
@@ -3022,7 +3036,7 @@ jack_get_fifo_fd (jack_engine_t *engine, unsigned int which_fifo)
char path[PATH_MAX+1]; char path[PATH_MAX+1];
struct stat statbuf; struct stat statbuf;


sprintf (path, "%s-%d", engine->fifo_prefix, which_fifo);
snprintf (path, sizeof (path), "%s-%d", engine->fifo_prefix, which_fifo);


DEBUG ("%s", path); DEBUG ("%s", path);


@@ -3272,7 +3286,9 @@ jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int re
{ {
jack_port_internal_t *port; jack_port_internal_t *port;
JSList *node; JSList *node;
unsigned int i;
int ret = -1; int ret = -1;
int internal = FALSE;


jack_lock_graph (engine); jack_lock_graph (engine);


@@ -3280,30 +3296,57 @@ jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int re


DEBUG ("Getting connections for port '%s'.", port->shared->name); DEBUG ("Getting connections for port '%s'.", port->shared->name);


req->x.nports = jack_slist_length (port->connections);
req->x.port_connections.nports = jack_slist_length (port->connections);
req->status = 0;


if (write (reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (req)) {
jack_error ("cannot write GetPortConnections result to client");
goto out;
/* figure out if this is an internal or external client */

for (node = engine->clients; node; node = jack_slist_next (node)) {
if (((jack_client_internal_t *) node->data)->request_fd == reply_fd) {
internal = jack_client_is_internal((jack_client_internal_t *) node->data);
break;
}
} }


if (req->type == GetPortConnections)
{
for (node = port->connections; node; node = jack_slist_next (node) ) {
if (!internal) {
if (write (reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (req)) {
jack_error ("cannot write GetPortConnections result to client via fd = %d (%s)",
reply_fd, strerror (errno));
goto out;
}
} else {
req->x.port_connections.ports = (const char **) malloc (sizeof (char *) * req->x.port_connections.nports);
}

if (req->type == GetPortConnections) {
for (i = 0, node = port->connections; node; node = jack_slist_next (node), ++i) {

jack_port_id_t port_id; jack_port_id_t port_id;
if (((jack_connection_internal_t *) node->data)->source == port)
{
if (((jack_connection_internal_t *) node->data)->source == port) {
port_id = ((jack_connection_internal_t *) node->data)->destination->shared->id; port_id = ((jack_connection_internal_t *) node->data)->destination->shared->id;
}
else
{
} else {
port_id = ((jack_connection_internal_t *) node->data)->source->shared->id; port_id = ((jack_connection_internal_t *) node->data)->source->shared->id;
} }
if (write (reply_fd, &port_id, sizeof (port_id)) < (ssize_t) sizeof (port_id)) {
jack_error ("cannot write port id to client");
goto out;
if (internal) {

/* internal client asking for names. store in malloc'ed space, client frees
*/

req->x.port_connections.ports[i] = engine->control->ports[port_id].name;

} else {

/* external client asking for names. we write the port id's to the reply fd.
*/

if (write (reply_fd, &port_id, sizeof (port_id)) < (ssize_t) sizeof (port_id)) {
jack_error ("cannot write port id to client");
goto out;
}
} }
} }
} }
@@ -3457,84 +3500,4 @@ jack_set_asio_mode (jack_engine_t *engine, int yn)
engine->asio_mode = yn; engine->asio_mode = yn;
} }


int
jack_do_add_alias (jack_engine_t *engine, jack_request_t *req)
{
JSList *list;
jack_port_alias_t *alias;
int ret = -1;

jack_lock_graph (engine);

for (list = engine->aliases; list; list = jack_slist_next (list)) {

alias = (jack_port_alias_t *) list->data;

if (strcmp (alias->port, req->x.alias.port) == 0 && strcmp (alias->alias, req->x.alias.alias) == 0) {
break;
}
}
if (list == NULL) {
alias = (jack_port_alias_t *) malloc (sizeof (jack_port_alias_t));
strcpy (alias->port, req->x.alias.port);
strcpy (alias->alias, req->x.alias.alias);
engine->aliases = jack_slist_append (engine->aliases, alias);
ret = 0;
}


jack_unlock_graph (engine);
return ret;
}

int
jack_do_remove_alias (jack_engine_t *engine, jack_request_t *req)
{
JSList *list;
jack_port_alias_t *alias;
int ret = -1;

jack_lock_graph (engine);

for (list = engine->aliases; list; list = jack_slist_next (list)) {

alias = (jack_port_alias_t *) list->data;

if (strcmp (alias->port, req->x.alias.port) == 0 && strcmp (alias->alias, req->x.alias.alias) == 0) {
engine->aliases = jack_slist_remove_link (engine->aliases, list);
jack_slist_free_1 (list);
free (alias);
ret = 0;
}
}

jack_unlock_graph (engine);
return ret;
}

const char *
jack_lookup_alias (jack_engine_t *engine, const char *alias_name)
{
JSList *list;
jack_port_alias_t *alias;

jack_lock_graph (engine);

for (list = engine->aliases; list; list = jack_slist_next (list)) {

alias = (jack_port_alias_t *) list->data;

if (strcmp (alias->alias, alias_name) == 0) {
break;
}
}

jack_unlock_graph (engine);

if (list) {
return ((jack_port_alias_t *) list->data)->port;
} else {
return 0;
}
}

+ 5
- 1
jackd/jackd.c View File

@@ -140,6 +140,10 @@ jack_main (int argc, char **argv)
sigset_t allsignals; sigset_t allsignals;
struct sigaction action; struct sigaction action;


/* remove any existing files from a previous instance */
jack_cleanup_files ();

pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);


/* what's this for? /* what's this for?
@@ -251,7 +255,7 @@ jack_main (int argc, char **argv)


if (sig != SIGSEGV) { if (sig != SIGSEGV) {


/* unblock signals so we can see them during shutdown.
/* unblock signals so we can see them during shutdown.
this will help prod developers not to lose sight this will help prod developers not to lose sight
of bugs that cause segfaults etc. during shutdown. of bugs that cause segfaults etc. during shutdown.
*/ */


+ 6
- 1
libjack/Makefile.am View File

@@ -1,6 +1,11 @@
MAINTAINERCLEANFILES = Makefile.in MAINTAINERCLEANFILES = Makefile.in


SOURCE_FILES = client.c pool.c driver.c timestamps.c
SOURCE_FILES = \
client.c \
pool.c \
port.c \
driver.c \
timestamps.c


lib_LTLIBRARIES = libjack.la lib_LTLIBRARIES = libjack.la




+ 35
- 626
libjack/client.c View File

@@ -44,6 +44,8 @@
#include <jack/jslist.h> #include <jack/jslist.h>
#include <jack/version.h> #include <jack/version.h>


#include "local.h"

#ifdef WITH_TIMESTAMPS #ifdef WITH_TIMESTAMPS
#include <jack/timestamps.h> #include <jack/timestamps.h>
#endif /* WITH_TIMESTAMPS */ #endif /* WITH_TIMESTAMPS */
@@ -56,40 +58,11 @@ jack_set_server_dir (const char *path)
jack_server_dir = strdup (path); jack_server_dir = strdup (path);
} }


static jack_port_t *jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control_t *control);


static pthread_mutex_t client_lock; static pthread_mutex_t client_lock;
static pthread_cond_t client_ready; static pthread_cond_t client_ready;
void *jack_zero_filled_buffer = 0; void *jack_zero_filled_buffer = 0;


static void jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes);

jack_port_type_info_t builtin_port_types[] = {
{ JACK_DEFAULT_AUDIO_TYPE, jack_audio_port_mixdown, 1 },
{ "", NULL }
};

struct _jack_client {

jack_control_t *engine;
jack_client_control_t *control;
struct pollfd *pollfd;
int pollmax;
int graph_next_fd;
int request_fd;
JSList *port_segments;
JSList *ports;
pthread_t thread;
char fifo_prefix[PATH_MAX+1];
void (*on_shutdown)(void *arg);
void *on_shutdown_arg;
char thread_ok : 1;
char first_active : 1;
float cpu_mhz;
pthread_t thread_id;

};

#define event_fd pollfd[0].fd #define event_fd pollfd[0].fd
#define graph_wait_fd pollfd[1].fd #define graph_wait_fd pollfd[1].fd


@@ -101,13 +74,12 @@ typedef struct {


void void
jack_error (const char *fmt, ...) jack_error (const char *fmt, ...)

{ {
va_list ap; va_list ap;
char buffer[300]; char buffer[300];


va_start (ap, fmt); va_start (ap, fmt);
vsnprintf (buffer, 300, fmt, ap);
vsnprintf (buffer, sizeof(buffer), fmt, ap);
jack_error_callback (buffer); jack_error_callback (buffer);
va_end (ap); va_end (ap);
} }
@@ -136,8 +108,8 @@ oop_client_deliver_request (void *ptr, jack_request_t *req)
return req->status; return req->status;
} }


static int
deliver_request (const jack_client_t *client, jack_request_t *req)
int
jack_client_deliver_request (const jack_client_t *client, jack_request_t *req)
{ {
/* indirect through the function pointer that was set /* indirect through the function pointer that was set
either by jack_client_new() (external) or handle_new_client() either by jack_client_new() (external) or handle_new_client()
@@ -194,47 +166,8 @@ jack_client_free (jack_client_t *client)
free (client); free (client);
} }


jack_port_t *
jack_port_by_id (const jack_client_t *client, jack_port_id_t id)
{
JSList *node;

for (node = client->ports; node; node = jack_slist_next (node)) {
if (((jack_port_t *) node->data)->shared->id == id) {
return (jack_port_t *) node->data;
}
}

if (id >= client->engine->port_max)
return NULL;

if (client->engine->ports[id].in_use)
return jack_port_new (client, id, client->engine);

return NULL;
}

jack_port_t *
jack_port_by_name (jack_client_t *client, const char *port_name)
{
unsigned long i, limit;
jack_port_shared_t *port;
limit = client->engine->port_max;
port = &client->engine->ports[0];
for (i = 0; i < limit; i++) {
if (port[i].in_use && strcmp (port[i].name, port_name) == 0) {
return jack_port_new (client, port[i].id, client->engine);
}
}

return NULL;
}

static void static void
jack_client_invalidate_port_buffers (jack_client_t *client) jack_client_invalidate_port_buffers (jack_client_t *client)

{ {
JSList *node; JSList *node;
jack_port_t *port; jack_port_t *port;
@@ -352,7 +285,6 @@ jack_handle_reorder (jack_client_t *client, jack_event_t *event)
static int static int
server_connect (int which) server_connect (int which)

{ {
int fd; int fd;
struct sockaddr_un addr; struct sockaddr_un addr;
@@ -376,7 +308,6 @@ server_connect (int which)


static int static int
server_event_connect (jack_client_t *client) server_event_connect (jack_client_t *client)

{ {
int fd; int fd;
struct sockaddr_un addr; struct sockaddr_un addr;
@@ -727,11 +658,7 @@ jack_client_thread (void *arg)
} }


if (client->pollfd[0].revents & ~POLLIN || client->control->dead) { if (client->pollfd[0].revents & ~POLLIN || client->control->dead) {
jack_error ("engine has shut down socket; thread exiting");
if (client->on_shutdown) {
client->on_shutdown (client->on_shutdown_arg);
}
pthread_exit (0);
goto zombie;
} }


if (client->pollfd[0].revents & POLLIN) { if (client->pollfd[0].revents & POLLIN) {
@@ -861,6 +788,12 @@ jack_client_thread (void *arg)
*/ */
} }


/* check if we were killed during the process cycle (or whatever) */

if (client->control->dead) {
goto zombie;
}

DEBUG("process cycle fully complete\n"); DEBUG("process cycle fully complete\n");


#ifdef WITH_TIMESTAMPS #ifdef WITH_TIMESTAMPS
@@ -871,6 +804,19 @@ jack_client_thread (void *arg)
} }
return (void *) ((intptr_t)err); return (void *) ((intptr_t)err);

zombie:
if (client->on_shutdown) {
jack_error ("zombified - calling shutdown handler");
client->on_shutdown (client->on_shutdown_arg);
} else {
jack_error ("zombified - exiting from JACK");
jack_client_close (client);
}

pthread_exit (0);
/*NOTREACHED*/
return 0;
} }


static int static int
@@ -1061,7 +1007,7 @@ jack_activate (jack_client_t *client)
req.type = SetClientCapabilities; req.type = SetClientCapabilities;
req.x.client_id = client->control->id; req.x.client_id = client->control->id;
deliver_request (client, &req);
jack_client_deliver_request (client, &req);


if (req.status) { if (req.status) {


@@ -1107,7 +1053,7 @@ jack_activate (jack_client_t *client)
req.type = ActivateClient; req.type = ActivateClient;
req.x.client_id = client->control->id; req.x.client_id = client->control->id;


return deliver_request (client, &req);
return jack_client_deliver_request (client, &req);
} }


int int
@@ -1119,7 +1065,7 @@ jack_deactivate (jack_client_t *client)
req.type = DeactivateClient; req.type = DeactivateClient;
req.x.client_id = client->control->id; req.x.client_id = client->control->id;


return deliver_request (client, &req);
return jack_client_deliver_request (client, &req);
} }


int int
@@ -1179,118 +1125,6 @@ unsigned long jack_get_sample_rate (jack_client_t *client)
return client->engine->current_time.frame_rate; return client->engine->current_time.frame_rate;
} }


static jack_port_t *
jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control_t *control)
{
jack_port_t *port;
jack_port_shared_t *shared;
jack_port_segment_info_t *si;
JSList *node;

shared = &control->ports[port_id];

port = (jack_port_t *) malloc (sizeof (jack_port_t));

port->client_segment_base = 0;
port->shared = shared;
pthread_mutex_init (&port->connection_lock, NULL);
port->connections = 0;
port->shared->tied = NULL;

si = NULL;
for (node = client->port_segments; node; node = jack_slist_next (node)) {
si = (jack_port_segment_info_t *) node->data;
if (si->shm_key == port->shared->shm_key) {
break;
}
}
if (si == NULL) {
jack_error ("cannot find port segment to match newly registered port\n");
return NULL;
}
port->client_segment_base = si->address;
return port;
}

jack_port_t *
jack_port_register (jack_client_t *client,
const char *port_name,
const char *port_type,
unsigned long flags,
unsigned long buffer_size)
{
jack_request_t req;
jack_port_t *port = 0;
jack_port_type_info_t *type_info;
int n;

req.type = RegisterPort;

strcpy ((char *) req.x.port_info.name, (const char *) client->control->name);
strcat ((char *) req.x.port_info.name, ":");
strcat ((char *) req.x.port_info.name, port_name);

snprintf (req.x.port_info.type, sizeof (req.x.port_info.type), "%s", port_type);
req.x.port_info.flags = flags;
req.x.port_info.buffer_size = buffer_size;
req.x.port_info.client_id = client->control->id;

if (deliver_request (client, &req)) {
return NULL;
}

port = jack_port_new (client, req.x.port_info.port_id, client->engine);

type_info = NULL;

for (n = 0; builtin_port_types[n].type_name[0]; n++) {
if (strcmp (req.x.port_info.type, builtin_port_types[n].type_name) == 0) {
type_info = &builtin_port_types[n];
break;
}
}

if (type_info == NULL) {
/* not a builtin type, so allocate a new type_info structure,
and fill it appropriately.
*/
type_info = (jack_port_type_info_t *) malloc (sizeof (jack_port_type_info_t));

snprintf ((char *) type_info->type_name, sizeof (type_info->type_name), req.x.port_info.type);

type_info->mixdown = NULL; /* we have no idea how to mix this */
type_info->buffer_scale_factor = -1; /* use specified port buffer size */
}

memcpy (&port->shared->type_info, type_info, sizeof (jack_port_type_info_t));

client->ports = jack_slist_prepend (client->ports, port);

return port;
}

int
jack_port_unregister (jack_client_t *client, jack_port_t *port)

{
jack_request_t req;

req.type = UnRegisterPort;
req.x.port_info.port_id = port->shared->id;
req.x.port_info.client_id = client->control->id;

return deliver_request (client, &req);
}

int int
jack_connect (jack_client_t *client, const char *source_port, const char *destination_port) jack_connect (jack_client_t *client, const char *source_port, const char *destination_port)


@@ -1302,7 +1136,7 @@ jack_connect (jack_client_t *client, const char *source_port, const char *destin
snprintf (req.x.connect.source_port, sizeof (req.x.connect.source_port), "%s", source_port); snprintf (req.x.connect.source_port, sizeof (req.x.connect.source_port), "%s", source_port);
snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port); snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port);


return deliver_request (client, &req);
return jack_client_deliver_request (client, &req);
} }


int int
@@ -1322,7 +1156,7 @@ jack_port_disconnect (jack_client_t *client, jack_port_t *port)
req.type = DisconnectPort; req.type = DisconnectPort;
req.x.port_info.port_id = port->shared->id; req.x.port_info.port_id = port->shared->id;


return deliver_request (client, &req);
return jack_client_deliver_request (client, &req);
} }


int int
@@ -1335,7 +1169,7 @@ jack_disconnect (jack_client_t *client, const char *source_port, const char *des
snprintf (req.x.connect.source_port, sizeof (req.x.connect.source_port), "%s", source_port); snprintf (req.x.connect.source_port, sizeof (req.x.connect.source_port), "%s", source_port);
snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port); snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port);
return deliver_request (client, &req);
return jack_client_deliver_request (client, &req);
} }


int int
@@ -1347,7 +1181,7 @@ jack_engine_takeover_timebase (jack_client_t *client)
req.type = SetTimeBaseClient; req.type = SetTimeBaseClient;
req.x.client_id = client->control->id; req.x.client_id = client->control->id;


return deliver_request (client, &req);
return jack_client_deliver_request (client, &req);
} }


void void
@@ -1356,111 +1190,6 @@ jack_set_error_function (void (*func) (const char *))
jack_error_callback = func; jack_error_callback = func;
} }


jack_nframes_t
jack_port_get_latency (jack_port_t *port)
{
return port->shared->latency;
}

void
jack_port_set_latency (jack_port_t *port, jack_nframes_t nframes)
{
port->shared->latency = nframes;
}

void *
jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)

{
JSList *node, *next;

/* Output port. The buffer was assigned by the engine
when the port was registered.
*/

if (port->shared->flags & JackPortIsOutput) {
if (port->shared->tied) {
return jack_port_get_buffer (port->shared->tied, nframes);
}
return jack_port_buffer (port);
}

/* Input port.
*/

/* since this can only be called from the process() callback,
and since no connections can be made/broken during this
phase (enforced by the jack server), there is no need
to take the connection lock here
*/

if ((node = port->connections) == NULL) {
/* no connections; return a zero-filled buffer */

return jack_zero_filled_buffer;
}

if ((next = jack_slist_next (node)) == NULL) {

/* one connection: use zero-copy mode - just pass
the buffer of the connected (output) port.
*/

return jack_port_get_buffer (((jack_port_t *) node->data), nframes);
}

/* multiple connections. use a local buffer and mixdown
the incoming data to that buffer. we have already
established the existence of a mixdown function
during the connection process.

no port can have an offset of 0 - that offset refers
to the zero-filled area at the start of a shared port
segment area. so, use the offset to store the location
of a locally allocated buffer, and reset the client_segment_base
so that the jack_port_buffer() computation works correctly.
*/

if (port->shared->offset == 0) {
port->shared->offset = (size_t) jack_pool_alloc (port->shared->type_info.buffer_scale_factor *
sizeof (jack_default_audio_sample_t) * nframes);
port->client_segment_base = 0;
}

port->shared->type_info.mixdown (port, nframes);
return (jack_default_audio_sample_t *) port->shared->offset;
}

int
jack_port_tie (jack_port_t *src, jack_port_t *dst)

{
if (dst->shared->client_id != src->shared->client_id) {
jack_error ("cannot tie ports not owned by the same client");
return -1;
}

if (dst->shared->flags & JackPortIsOutput) {
jack_error ("cannot tie an input port");
return -1;
}

dst->shared->tied = src;
return 0;
}

int
jack_port_untie (jack_port_t *port)

{
if (port->shared->tied == NULL) {
jack_error ("port \"%s\" is not tied", port->shared->name);
return -1;
}
port->shared->tied = NULL;
return 0;
}


int int
jack_set_graph_order_callback (jack_client_t *client, JackGraphOrderCallback callback, void *arg) jack_set_graph_order_callback (jack_client_t *client, JackGraphOrderCallback callback, void *arg)
@@ -1490,8 +1219,8 @@ jack_set_process_callback (jack_client_t *client, JackProcessCallback callback,
int int
jack_set_buffer_size_callback (jack_client_t *client, JackBufferSizeCallback callback, void *arg) jack_set_buffer_size_callback (jack_client_t *client, JackBufferSizeCallback callback, void *arg)
{ {
jack_error("\n*** libjack: WARNING! Use of function jack_set_buffer_size_callback() is deprecated! ***\n\n");
client->control->bufsize_arg = arg;
client->control->bufsize = callback;
return 0; return 0;
} }


@@ -1543,133 +1272,6 @@ jack_get_process_done_fd (jack_client_t *client)
return client->graph_next_fd; return client->graph_next_fd;
} }


int
jack_port_request_monitor_by_name (jack_client_t *client, const char *port_name, int onoff)

{
jack_port_t *port;
unsigned long i, limit;
jack_port_shared_t *ports;

limit = client->engine->port_max;
ports = &client->engine->ports[0];
for (i = 0; i < limit; i++) {
if (ports[i].in_use && strcmp (ports[i].name, port_name) == 0) {
port = jack_port_new (client, ports[i].id, client->engine);
return jack_port_request_monitor (port, onoff);
free (port);
return 0;
}
}

return -1;
}

int
jack_port_request_monitor (jack_port_t *port, int onoff)

{
if (onoff) {
port->shared->monitor_requests++;
} else if (port->shared->monitor_requests) {
port->shared->monitor_requests--;
}

if ((port->shared->flags & JackPortIsOutput) == 0) {

JSList *node;

/* this port is for input, so recurse over each of the
connected ports.
*/

pthread_mutex_lock (&port->connection_lock);
for (node = port->connections; node; node = jack_slist_next (node)) {
/* drop the lock because if there is a feedback loop,
we will deadlock. XXX much worse things will
happen if there is a feedback loop !!!
*/

pthread_mutex_unlock (&port->connection_lock);
jack_port_request_monitor ((jack_port_t *) node->data, onoff);
pthread_mutex_lock (&port->connection_lock);
}
pthread_mutex_unlock (&port->connection_lock);
}

return 0;
}
int
jack_ensure_port_monitor_input (jack_port_t *port, int yn)
{
if (yn) {
if (port->shared->monitor_requests == 0) {
port->shared->monitor_requests++;
}
} else {
if (port->shared->monitor_requests == 1) {
port->shared->monitor_requests--;
}
}

return 0;
}

int
jack_port_monitoring_input (jack_port_t *port)
{
return port->shared->monitor_requests > 0;
}

const char *
jack_port_name (const jack_port_t *port)
{
return port->shared->name;
}

const char *
jack_port_short_name (const jack_port_t *port)
{
/* we know there is always a colon, because we put
it there ...
*/

return strchr (port->shared->name, ':') + 1;
}

int
jack_port_is_mine (const jack_client_t *client, const jack_port_t *port)
{
return port->shared->client_id == client->control->id;
}

int
jack_port_flags (const jack_port_t *port)
{
return port->shared->flags;
}

const char *
jack_port_type (const jack_port_t *port)
{
return port->shared->type_info.type_name;
}

int
jack_port_set_name (jack_port_t *port, const char *new_name)
{
char *colon;
int len;

colon = strchr (port->shared->name, ':');
len = sizeof (port->shared->name) - ((int) (colon - port->shared->name)) - 2;
snprintf (colon+1, len, "%s", new_name);
return 0;
}


void void
jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg) jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg)
@@ -1793,171 +1395,6 @@ jack_frame_time (const jack_client_t *client)
return current.frames + elapsed; return current.frames + elapsed;
} }


int
jack_port_lock (jack_client_t *client, jack_port_t *port)
{
if (port) {
port->shared->locked = 1;
return 0;
}
return -1;
}

int
jack_port_unlock (jack_client_t *client, jack_port_t *port)
{
if (port) {
port->shared->locked = 0;
return 0;
}
return -1;
}

static void
jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes)
{
JSList *node;
jack_port_t *input;
jack_nframes_t n;
jack_default_audio_sample_t *buffer;
jack_default_audio_sample_t *dst, *src;

/* by the time we've called this, we've already established
the existence of more than 1 connection to this input port.
*/

/* no need to take connection lock, since this is called
from the process() callback, and the jack server
ensures that no changes to connections happen
during this time.
*/

node = port->connections;
input = (jack_port_t *) node->data;
buffer = jack_port_buffer (port);

memcpy (buffer, jack_port_buffer (input), sizeof (jack_default_audio_sample_t) * nframes);

for (node = jack_slist_next (node); node; node = jack_slist_next (node)) {

input = (jack_port_t *) node->data;

n = nframes;
dst = buffer;
src = jack_port_buffer (input);

while (n--) {
*dst++ += *src++;
}
}
}

/* LOCAL (in-client) connection querying only */

int
jack_port_connected (const jack_port_t *port)
{
return jack_slist_length (port->connections);
}

int
jack_port_connected_to (const jack_port_t *port, const char *portname)
{
JSList *node;
int ret = FALSE;

/* XXX this really requires a cross-process lock
so that ports/connections cannot go away
while we are checking for them. that's hard,
and has a non-trivial performance impact
for jackd.
*/

pthread_mutex_lock (&((jack_port_t *) port)->connection_lock);

for (node = port->connections; node; node = jack_slist_next (node)) {
jack_port_t *other_port = (jack_port_t *) node->data;
if (strcmp (other_port->shared->name, portname) == 0) {
ret = TRUE;
break;
}
}

pthread_mutex_unlock (&((jack_port_t *) port)->connection_lock);
return ret;
}

const char **
jack_port_get_connections (const jack_port_t *port)
{
const char **ret = NULL;
JSList *node;
unsigned int n;

/* XXX this really requires a cross-process lock
so that ports/connections cannot go away
while we are checking for them. that's hard,
and has a non-trivial performance impact
for jackd.
*/

pthread_mutex_lock (&((jack_port_t *) port)->connection_lock);

if (port->connections != NULL) {

ret = (const char **) malloc (sizeof (char *) * (jack_slist_length (port->connections) + 1));
for (n = 0, node = port->connections; node; node = jack_slist_next (node), ++n) {
ret[n] = ((jack_port_t *) node->data)->shared->name;
}
ret[n] = NULL;
}

pthread_mutex_unlock (&((jack_port_t *) port)->connection_lock);
return ret;
}

/* SERVER-SIDE (all) connection querying */

const char **
jack_port_get_all_connections (const jack_client_t *client, const jack_port_t *port)
{
const char **ret;
jack_request_t req;
unsigned int i;

req.type = GetPortConnections;

req.x.port_info.name[0] = '\0';
req.x.port_info.type[0] = '\0';
req.x.port_info.flags = 0;
req.x.port_info.buffer_size = 0;
req.x.port_info.client_id = 0;
req.x.port_info.port_id = port->shared->id;

deliver_request (client, &req);

if (req.status != 0 || req.x.nports == 0) {
return NULL;
}

ret = (const char **) malloc (sizeof (char *) * (req.x.nports + 1));

for ( i=0; i<req.x.nports; i++ ) {
jack_port_id_t port_id;
if (read (client->request_fd, &port_id, sizeof (port_id)) != sizeof (port_id)) {
jack_error ("cannot read port id from server");
return 0;
}
ret[i] = jack_port_by_id (client, port_id)->shared->name;
}

ret[i] = NULL;

return ret;
}


/* TRANSPORT CONTROL */ /* TRANSPORT CONTROL */


@@ -2005,12 +1442,6 @@ jack_set_transport_info (jack_client_t *client,
return 0; return 0;
} }


jack_nframes_t
jack_port_get_total_latency (jack_client_t *client, jack_port_t *port)
{
return port->shared->total_latency;
}

int int
jack_get_mhz (void) jack_get_mhz (void)
{ {
@@ -2053,31 +1484,9 @@ jack_cpu_load (jack_client_t *client)
return client->engine->cpu_load; return client->engine->cpu_load;
} }


int
jack_add_alias (jack_client_t *client, const char *portname, const char *alias)
{
jack_request_t req;
req.type = AddAlias;
snprintf (req.x.alias.port, sizeof (req.x.alias.port), "%s", portname);
snprintf (req.x.alias.alias, sizeof (req.x.alias.alias), "%s", alias);
return deliver_request (client, &req);
}

int
jack_remove_alias (jack_client_t *client, const char *alias)
{
jack_request_t req;
req.type = RemoveAlias;
snprintf (req.x.alias.alias, sizeof (req.x.alias.alias), "%s", alias);
return deliver_request (client, &req);
}

pthread_t pthread_t
jack_client_thread_id (jack_client_t *client) jack_client_thread_id (jack_client_t *client)
{ {
return client->thread_id; return client->thread_id;
} }


+ 32
- 0
libjack/local.h View File

@@ -0,0 +1,32 @@
#ifndef __jack_libjack_local_h__
#define __jack_libjack_local_h__

struct _jack_client {

jack_control_t *engine;
jack_client_control_t *control;
struct pollfd *pollfd;
int pollmax;
int graph_next_fd;
int request_fd;
JSList *port_segments;
JSList *ports;
pthread_t thread;
char fifo_prefix[PATH_MAX+1];
void (*on_shutdown)(void *arg);
void *on_shutdown_arg;
char thread_ok : 1;
char first_active : 1;
float cpu_mhz;
pthread_t thread_id;

};

extern int jack_client_deliver_request (const jack_client_t *client, jack_request_t *req);
extern jack_port_t *jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control_t *control);

extern void* jack_zero_filled_buffer;
extern jack_port_type_info_t jack_builtin_port_types[];


#endif /* __jack_libjack_local_h__ */

+ 672
- 0
libjack/port.c View File

@@ -0,0 +1,672 @@
/*
Copyright (C) 2001-2003 Paul Davis
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.

$Id$
*/

#include <string.h>
#include <stdio.h>
#include <math.h>

#include <config.h>

#include <jack/jack.h>
#include <jack/types.h>
#include <jack/internal.h>
#include <jack/engine.h>
#include <jack/pool.h>
#include <jack/port.h>
#include <jack/error.h>
#include <jack/jslist.h>

#include "local.h"

jack_port_t *
jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control_t *control)
{
jack_port_t *port;
jack_port_shared_t *shared;
jack_port_segment_info_t *si;
JSList *node;

shared = &control->ports[port_id];

port = (jack_port_t *) malloc (sizeof (jack_port_t));

port->client_segment_base = 0;
port->shared = shared;
pthread_mutex_init (&port->connection_lock, NULL);
port->connections = 0;
port->shared->tied = NULL;
port->shared->peak = port->shared->type_info.peak;
port->shared->power = port->shared->type_info.power;
si = NULL;
for (node = client->port_segments; node; node = jack_slist_next (node)) {
si = (jack_port_segment_info_t *) node->data;
if (si->shm_key == port->shared->shm_key) {
break;
}
}
if (si == NULL) {
jack_error ("cannot find port segment to match newly registered port\n");
return NULL;
}
port->client_segment_base = si->address;
return port;
}

jack_port_t *
jack_port_register (jack_client_t *client,
const char *port_name,
const char *port_type,
unsigned long flags,
unsigned long buffer_size)
{
jack_request_t req;
jack_port_t *port = 0;
jack_port_type_info_t *type_info;
int n;

req.type = RegisterPort;

strcpy ((char *) req.x.port_info.name, (const char *) client->control->name);
strcat ((char *) req.x.port_info.name, ":");
strcat ((char *) req.x.port_info.name, port_name);

snprintf (req.x.port_info.type, sizeof (req.x.port_info.type), "%s", port_type);
req.x.port_info.flags = flags;
req.x.port_info.buffer_size = buffer_size;
req.x.port_info.client_id = client->control->id;

if (jack_client_deliver_request (client, &req)) {
return NULL;
}

port = jack_port_new (client, req.x.port_info.port_id, client->engine);

type_info = NULL;

for (n = 0; jack_builtin_port_types[n].type_name[0]; n++) {
if (strcmp (req.x.port_info.type, jack_builtin_port_types[n].type_name) == 0) {
type_info = &jack_builtin_port_types[n];
break;
}
}

if (type_info == NULL) {
/* not a builtin type, so allocate a new type_info structure,
and fill it appropriately.
*/
type_info = (jack_port_type_info_t *) malloc (sizeof (jack_port_type_info_t));

snprintf ((char *) type_info->type_name, sizeof (type_info->type_name), req.x.port_info.type);

type_info->mixdown = NULL; /* we have no idea how to mix this */
type_info->buffer_scale_factor = -1; /* use specified port buffer size */
}

memcpy (&port->shared->type_info, type_info, sizeof (jack_port_type_info_t));

client->ports = jack_slist_prepend (client->ports, port);

return port;
}

int
jack_port_unregister (jack_client_t *client, jack_port_t *port)
{
jack_request_t req;

req.type = UnRegisterPort;
req.x.port_info.port_id = port->shared->id;
req.x.port_info.client_id = client->control->id;

return jack_client_deliver_request (client, &req);
}

int
jack_port_lock (jack_client_t *client, jack_port_t *port)
{
if (port) {
port->shared->locked = 1;
return 0;
}
return -1;
}

int
jack_port_unlock (jack_client_t *client, jack_port_t *port)
{
if (port) {
port->shared->locked = 0;
return 0;
}
return -1;
}

/* LOCAL (in-client) connection querying only */

int
jack_port_connected (const jack_port_t *port)
{
return jack_slist_length (port->connections);
}

int
jack_port_connected_to (const jack_port_t *port, const char *portname)
{
JSList *node;
int ret = FALSE;

/* XXX this really requires a cross-process lock
so that ports/connections cannot go away
while we are checking for them. that's hard,
and has a non-trivial performance impact
for jackd.
*/

pthread_mutex_lock (&((jack_port_t *) port)->connection_lock);

for (node = port->connections; node; node = jack_slist_next (node)) {
jack_port_t *other_port = (jack_port_t *) node->data;
if (strcmp (other_port->shared->name, portname) == 0) {
ret = TRUE;
break;
}
}

pthread_mutex_unlock (&((jack_port_t *) port)->connection_lock);
return ret;
}

const char **
jack_port_get_connections (const jack_port_t *port)
{
const char **ret = NULL;
JSList *node;
unsigned int n;

/* XXX this really requires a cross-process lock
so that ports/connections cannot go away
while we are checking for them. that's hard,
and has a non-trivial performance impact
for jackd.
*/

pthread_mutex_lock (&((jack_port_t *) port)->connection_lock);

if (port->connections != NULL) {

ret = (const char **) malloc (sizeof (char *) * (jack_slist_length (port->connections) + 1));
for (n = 0, node = port->connections; node; node = jack_slist_next (node), ++n) {
ret[n] = ((jack_port_t *) node->data)->shared->name;
}
ret[n] = NULL;
}

pthread_mutex_unlock (&((jack_port_t *) port)->connection_lock);
return ret;
}

/* SERVER-SIDE (all) connection querying */

const char **
jack_port_get_all_connections (const jack_client_t *client, const jack_port_t *port)
{
const char **ret;
jack_request_t req;
unsigned int i;

if (port == NULL) {
return NULL;
}

req.type = GetPortConnections;

req.x.port_info.name[0] = '\0';
req.x.port_info.type[0] = '\0';
req.x.port_info.flags = 0;
req.x.port_info.buffer_size = 0;
req.x.port_info.client_id = 0;
req.x.port_info.port_id = port->shared->id;

jack_client_deliver_request (client, &req);

if (req.status != 0 || req.x.port_connections.nports == 0) {
return NULL;
}

if (client->request_fd < 0) {
/* internal client */
return req.x.port_connections.ports;
}

ret = (const char **) malloc (sizeof (char *) * (req.x.port_connections.nports + 1));

for (i = 0; i < req.x.port_connections.nports; ++i ) {
jack_port_id_t port_id;
if (read (client->request_fd, &port_id, sizeof (port_id)) != sizeof (port_id)) {
jack_error ("cannot read port id from server");
return 0;
}
ret[i] = jack_port_by_id (client, port_id)->shared->name;
}

ret[i] = NULL;

return ret;
}

jack_port_t *
jack_port_by_id (const jack_client_t *client, jack_port_id_t id)
{
JSList *node;

for (node = client->ports; node; node = jack_slist_next (node)) {
if (((jack_port_t *) node->data)->shared->id == id) {
return (jack_port_t *) node->data;
}
}

if (id >= client->engine->port_max)
return NULL;

if (client->engine->ports[id].in_use)
return jack_port_new (client, id, client->engine);

return NULL;
}

jack_port_t *
jack_port_by_name (jack_client_t *client, const char *port_name)
{
unsigned long i, limit;
jack_port_shared_t *port;
limit = client->engine->port_max;
port = &client->engine->ports[0];
for (i = 0; i < limit; i++) {
if (port[i].in_use && strcmp (port[i].name, port_name) == 0) {
return jack_port_new (client, port[i].id, client->engine);
}
}

return NULL;
}

jack_nframes_t
jack_port_get_latency (jack_port_t *port)
{
return port->shared->latency;
}

jack_nframes_t
jack_port_get_total_latency (jack_client_t *client, jack_port_t *port)
{
return port->shared->total_latency;
}

void
jack_port_set_latency (jack_port_t *port, jack_nframes_t nframes)
{
port->shared->latency = nframes;
}

void *
jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)
{
JSList *node, *next;

/* Output port. The buffer was assigned by the engine
when the port was registered.
*/

if (port->shared->flags & JackPortIsOutput) {
if (port->shared->tied) {
return jack_port_get_buffer (port->shared->tied, nframes);
}
return jack_port_buffer (port);
}

/* Input port.
*/

/* since this can only be called from the process() callback,
and since no connections can be made/broken during this
phase (enforced by the jack server), there is no need
to take the connection lock here
*/

if ((node = port->connections) == NULL) {
/* no connections; return a zero-filled buffer */

return jack_zero_filled_buffer;
}

if ((next = jack_slist_next (node)) == NULL) {

/* one connection: use zero-copy mode - just pass
the buffer of the connected (output) port.
*/

return jack_port_get_buffer (((jack_port_t *) node->data), nframes);
}

/* multiple connections. use a local buffer and mixdown
the incoming data to that buffer. we have already
established the existence of a mixdown function
during the connection process.

no port can have an offset of 0 - that offset refers
to the zero-filled area at the start of a shared port
segment area. so, use the offset to store the location
of a locally allocated buffer, and reset the client_segment_base
so that the jack_port_buffer() computation works correctly.
*/

if (port->shared->offset == 0) {
port->shared->offset = (size_t) jack_pool_alloc (port->shared->type_info.buffer_scale_factor *
sizeof (jack_default_audio_sample_t) * nframes);
port->client_segment_base = 0;
}

port->shared->type_info.mixdown (port, nframes);
return (jack_default_audio_sample_t *) port->shared->offset;
}

int
jack_port_tie (jack_port_t *src, jack_port_t *dst)

{
if (dst->shared->client_id != src->shared->client_id) {
jack_error ("cannot tie ports not owned by the same client");
return -1;
}

if (dst->shared->flags & JackPortIsOutput) {
jack_error ("cannot tie an input port");
return -1;
}

dst->shared->tied = src;
return 0;
}

int
jack_port_untie (jack_port_t *port)

{
if (port->shared->tied == NULL) {
jack_error ("port \"%s\" is not tied", port->shared->name);
return -1;
}
port->shared->tied = NULL;
return 0;
}

int
jack_port_request_monitor (jack_port_t *port, int onoff)

{
if (onoff) {
port->shared->monitor_requests++;
} else if (port->shared->monitor_requests) {
port->shared->monitor_requests--;
}

if ((port->shared->flags & JackPortIsOutput) == 0) {

JSList *node;

/* this port is for input, so recurse over each of the
connected ports.
*/

pthread_mutex_lock (&port->connection_lock);
for (node = port->connections; node; node = jack_slist_next (node)) {
/* drop the lock because if there is a feedback loop,
we will deadlock. XXX much worse things will
happen if there is a feedback loop !!!
*/

pthread_mutex_unlock (&port->connection_lock);
jack_port_request_monitor ((jack_port_t *) node->data, onoff);
pthread_mutex_lock (&port->connection_lock);
}
pthread_mutex_unlock (&port->connection_lock);
}

return 0;
}
int
jack_port_request_monitor_by_name (jack_client_t *client, const char *port_name, int onoff)

{
jack_port_t *port;
unsigned long i, limit;
jack_port_shared_t *ports;

limit = client->engine->port_max;
ports = &client->engine->ports[0];
for (i = 0; i < limit; i++) {
if (ports[i].in_use && strcmp (ports[i].name, port_name) == 0) {
port = jack_port_new (client, ports[i].id, client->engine);
return jack_port_request_monitor (port, onoff);
free (port);
return 0;
}
}

return -1;
}

int
jack_ensure_port_monitor_input (jack_port_t *port, int yn)
{
if (yn) {
if (port->shared->monitor_requests == 0) {
port->shared->monitor_requests++;
}
} else {
if (port->shared->monitor_requests == 1) {
port->shared->monitor_requests--;
}
}

return 0;
}

int
jack_port_monitoring_input (jack_port_t *port)
{
return port->shared->monitor_requests > 0;
}

const char *
jack_port_name (const jack_port_t *port)
{
return port->shared->name;
}

const char *
jack_port_short_name (const jack_port_t *port)
{
/* we know there is always a colon, because we put
it there ...
*/

return strchr (port->shared->name, ':') + 1;
}

int
jack_port_is_mine (const jack_client_t *client, const jack_port_t *port)
{
return port->shared->client_id == client->control->id;
}

int
jack_port_flags (const jack_port_t *port)
{
return port->shared->flags;
}

const char *
jack_port_type (const jack_port_t *port)
{
return port->shared->type_info.type_name;
}

int
jack_port_set_name (jack_port_t *port, const char *new_name)
{
char *colon;
int len;

colon = strchr (port->shared->name, ':');
len = sizeof (port->shared->name) - ((int) (colon - port->shared->name)) - 2;
snprintf (colon+1, len, "%s", new_name);
return 0;
}

void
jack_port_set_peak_function (jack_port_t *port, double (*func)(jack_port_t* port, jack_nframes_t))
{
port->shared->peak = func;
}

void
jack_port_set_power_function (jack_port_t *port, double (*func)(jack_port_t* port, jack_nframes_t))
{
port->shared->power = func;
}

double
jack_port_get_peak (jack_port_t* port, jack_nframes_t nframes)
{
if (port->shared->peak (port, nframes)) {
return port->shared->peak (port, nframes);
} else {
return 0;
}
}

double
jack_port_get_power (jack_port_t* port, jack_nframes_t nframes)
{
if (port->shared->power) {
return port->shared->power (port, nframes);
} else {
return 0;
}
}

/* AUDIO PORT SUPPORT */

static inline float f_max(float x, float a)
{
x -= a;
x += fabs (x);
x *= 0.5;
x += a;

return (x);
}

static double
jack_audio_port_peak (jack_port_t *port, jack_nframes_t nframes)
{
jack_nframes_t n;
jack_default_audio_sample_t *buf = (jack_default_audio_sample_t *) jack_port_get_buffer (port, nframes);
float max = 0;

for (n = 0; n < nframes; ++n) {
max = f_max (buf[n], max);
}

return max;
}

static void
jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes)
{
JSList *node;
jack_port_t *input;
jack_nframes_t n;
jack_default_audio_sample_t *buffer;
jack_default_audio_sample_t *dst, *src;

/* by the time we've called this, we've already established
the existence of more than 1 connection to this input port.
*/

/* no need to take connection lock, since this is called
from the process() callback, and the jack server
ensures that no changes to connections happen
during this time.
*/

node = port->connections;
input = (jack_port_t *) node->data;
buffer = jack_port_buffer (port);

memcpy (buffer, jack_port_buffer (input), sizeof (jack_default_audio_sample_t) * nframes);

for (node = jack_slist_next (node); node; node = jack_slist_next (node)) {

input = (jack_port_t *) node->data;

n = nframes;
dst = buffer;
src = jack_port_buffer (input);

while (n--) {
*dst++ += *src++;
}
}
}

jack_port_type_info_t jack_builtin_port_types[] = {
{ .type_name = JACK_DEFAULT_AUDIO_TYPE,
.mixdown = jack_audio_port_mixdown,
.peak = jack_audio_port_peak,
.power = NULL,
.buffer_scale_factor = 1
},
{ .type_name = "",
.mixdown = NULL
}
};


Loading…
Cancel
Save