Browse Source

[0.83.0] partial changes for buffer resizing; bug fixes

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@511 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
joq 22 years ago
parent
commit
4211980fe6
19 changed files with 684 additions and 448 deletions
  1. +2
    -2
      configure.in
  2. +33
    -13
      drivers/alsa/alsa_driver.c
  3. +16
    -0
      drivers/dummy/dummy_driver.c
  4. +8
    -0
      drivers/portaudio/portaudio_driver.c
  5. +15
    -1
      jack/driver.h
  6. +38
    -8
      jack/engine.h
  7. +20
    -31
      jack/internal.h
  8. +55
    -28
      jack/jack.h
  9. +44
    -38
      jack/port.h
  10. +9
    -6
      jack/types.h
  11. +286
    -144
      jackd/engine.c
  12. +9
    -3
      jackd/jackd.c
  13. +3
    -1
      jackd/transengine.c
  14. +9
    -0
      libjack/ChangeLog
  15. +76
    -55
      libjack/client.c
  16. +3
    -0
      libjack/driver.c
  17. +2
    -1
      libjack/local.h
  18. +0
    -3
      libjack/pool.c
  19. +56
    -114
      libjack/port.c

+ 2
- 2
configure.in View File

@@ -13,7 +13,7 @@ dnl micro version = incremented when implementation-only
dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=82
JACK_MINOR_VERSION=83
JACK_MICRO_VERSION=0

dnl ---
@@ -24,7 +24,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=9
JACK_PROTOCOL_VERSION=10

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


+ 33
- 13
drivers/alsa/alsa_driver.c View File

@@ -661,9 +661,11 @@ alsa_driver_set_parameters (alsa_driver_t *driver,
return 0;
}

#if 0
static int /* UNUSED */
alsa_driver_reset_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cycle, jack_nframes_t user_nperiods, jack_nframes_t rate)
static int
alsa_driver_reset_parameters (alsa_driver_t *driver,
jack_nframes_t frames_per_cycle,
jack_nframes_t user_nperiods,
jack_nframes_t rate)
{
/* XXX unregister old ports ? */
alsa_driver_release_channel_dependent_memory (driver);
@@ -671,7 +673,6 @@ alsa_driver_reset_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_c
frames_per_cycle,
user_nperiods, rate);
}
#endif

static int
alsa_driver_get_channel_addresses (alsa_driver_t *driver,
@@ -996,9 +997,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay
}

#ifdef DEBUG_WAKEUP
fprintf (stderr, "%Lu: checked %d fds, %Lu usecs since poll"" entered\n",
poll_ret,
nfds,
fprintf (stderr, "%" PRIu64 ": checked %d fds, %" PRIu64
" usecs since poll entered\n", poll_ret, nfds,
poll_ret - poll_enter);
#endif

@@ -1031,7 +1031,9 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay
if (driver->pfd[i].revents == 0) {
p_timed_out++;
#ifdef DEBUG_WAKEUP
fprintf (stderr, "%Lu playback stream timed out\n", poll_ret);
fprintf (stderr, "%" PRIu64
" playback stream timed out\n",
poll_ret);
#endif
}
}
@@ -1039,7 +1041,9 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay
if (p_timed_out == 0) {
need_playback = 0;
#ifdef DEBUG_WAKEUP
fprintf (stderr, "%Lu playback stream ready\n", poll_ret);
fprintf (stderr, "%" PRIu64
" playback stream ready\n",
poll_ret);
#endif
}
}
@@ -1055,7 +1059,9 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay
if (driver->pfd[i].revents == 0) {
c_timed_out++;
#ifdef DEBUG_WAKEUP
fprintf (stderr, "%Lu capture stream timed out\n", poll_ret);
fprintf (stderr, "%" PRIu64
" capture stream timed out\n",
poll_ret);
#endif
}
}
@@ -1063,14 +1069,18 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay
if (c_timed_out == 0) {
need_capture = 0;
#ifdef DEBUG_WAKEUP
fprintf (stderr, "%Lu capture stream ready\n", poll_ret);
fprintf (stderr, "%" PRIu64
" capture stream ready\n",
poll_ret);
#endif
}
}
if ((p_timed_out && (p_timed_out == driver->playback_nfds)) &&
(c_timed_out && (c_timed_out == driver->capture_nfds))){
jack_error ("ALSA: poll time out, polled for %Lu usecs", poll_ret - poll_enter);
jack_error ("ALSA: poll time out, polled for %" PRIu64
" usecs",
poll_ret - poll_enter);
*status = -5;
return 0;
}
@@ -1112,7 +1122,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay
avail = capture_avail < playback_avail ? capture_avail : playback_avail;

#ifdef DEBUG_WAKEUP
fprintf (stderr, "wakup complete, avail = %lu, pavail = %lu cavail = %lu\n",
fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu "
"cavail = %lu\n",
avail, playback_avail, capture_avail);
#endif

@@ -1183,6 +1194,14 @@ alsa_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes)
return 0;
}

static int
alsa_driver_bufsize (alsa_driver_t* driver, jack_nframes_t nframes)
{
return alsa_driver_reset_parameters (driver, nframes,
driver->user_nperiods,
driver->frame_rate);
}

static int
alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
{
@@ -1557,6 +1576,7 @@ alsa_driver_new (char *name, char *playback_alsa_device,
driver->write = (JackDriverReadFunction) alsa_driver_write;
driver->null_cycle =
(JackDriverNullCycleFunction) alsa_driver_null_cycle;
driver->bufsize = (JackDriverBufSizeFunction) alsa_driver_bufsize;
driver->start = (JackDriverStartFunction) alsa_driver_audio_start;
driver->stop = (JackDriverStopFunction) alsa_driver_audio_stop;



+ 16
- 0
drivers/dummy/dummy_driver.c View File

@@ -80,6 +80,21 @@ dummy_driver_null_cycle (dummy_driver_t* driver, jack_nframes_t nframes)
return 0;
}

static int
dummy_driver_bufsize (dummy_driver_t* driver, jack_nframes_t nframes)
{
/* these are arbitrary size restrictions */
if ((nframes < 4) || (nframes > 65536))
return EINVAL;

driver->period_size = nframes;
driver->period_usecs = driver->wait_time =
(jack_time_t) floor ((((float) nframes) / driver->sample_rate)
* 1000000.0f);
driver->engine->set_buffer_size (driver->engine, nframes);
return 0;
}

static int
dummy_driver_read (dummy_driver_t *driver, jack_nframes_t nframes)
{
@@ -199,6 +214,7 @@ dummy_driver_new (jack_client_t * client,
driver->read = (JackDriverReadFunction) dummy_driver_read;
driver->write = (JackDriverReadFunction) dummy_driver_write;
driver->null_cycle = (JackDriverNullCycleFunction) dummy_driver_null_cycle;
driver->bufsize = (JackDriverBufSizeFunction) dummy_driver_bufsize;
driver->start = (JackDriverStartFunction) dummy_driver_audio_start;
driver->stop = (JackDriverStopFunction) dummy_driver_audio_stop;



+ 8
- 0
drivers/portaudio/portaudio_driver.c View File

@@ -21,6 +21,7 @@
*/

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <jack/engine.h>
#include "portaudio_driver.h"
@@ -142,6 +143,12 @@ portaudio_driver_null_cycle (portaudio_driver_t* driver, jack_nframes_t nframes)
return 0;
}

static int
portaudio_driver_bufsize (portaudio_driver_t* driver, jack_nframes_t nframes)
{
return ENOSYS; /* function not implemented */
}

static int
portaudio_driver_read (portaudio_driver_t *driver, jack_nframes_t nframes)
{
@@ -254,6 +261,7 @@ portaudio_driver_new (char *name,
driver->read = (JackDriverReadFunction) portaudio_driver_read;
driver->write = (JackDriverReadFunction) portaudio_driver_write;
driver->null_cycle = (JackDriverNullCycleFunction) portaudio_driver_null_cycle;
driver->bufsize = (JackDriverBufSizeFunction) portaudio_driver_bufsize;
driver->start = (JackDriverStartFunction) portaudio_driver_audio_start;
driver->stop = (JackDriverStopFunction) portaudio_driver_audio_stop;


+ 15
- 1
jack/driver.h View File

@@ -61,6 +61,8 @@ typedef int (*JackDriverStartFunction)(struct _jack_driver *);
typedef jack_nframes_t (*JackDriverWaitFunction)(struct _jack_driver *,
int fd, int *status,
float *delayed_usecs);
typedef int (*JackDriverBufSizeFunction)(struct _jack_driver *,
jack_nframes_t nframes);

/*
Call sequence summary:
@@ -80,6 +82,12 @@ typedef jack_nframes_t (*JackDriverWaitFunction)(struct _jack_driver *,

Note that stop/start may be called multiple times in the event of an
error return from the `wait' function.

If a client requests a new buffer size...

1) engine stops driver
2) engine->bufsize()
3) engine starts driver again
*/


@@ -186,6 +194,11 @@ typedef struct _jack_driver {
JackDriverStartFunction start;

The engine will call this to let the driver know that some client
has requested a new buffer size. The stop function will be called
first, and the start function afterwards.

JackDriverBufSizeFunction bufsize;
*/

/* define the fields here... */
@@ -201,7 +214,8 @@ typedef struct _jack_driver {
JackDriverWriteFunction write; \
JackDriverNullCycleFunction null_cycle; \
JackDriverStopFunction stop; \
JackDriverStartFunction start;
JackDriverStartFunction start; \
JackDriverBufSizeFunction bufsize;

JACK_DRIVER_DECL /* expand the macro */



+ 38
- 8
jack/engine.h View File

@@ -31,6 +31,29 @@ struct _jack_driver;
struct _jack_client_internal;
struct _jack_port_internal;

/* Structures is allocated by the engine in local memory to keep track
* of port buffers and connections. */
typedef struct {
const char *shm_name;
jack_shmsize_t offset;
} jack_port_buffer_info_t;

typedef struct _jack_port_internal {
struct _jack_port_shared *shared;
JSList *connections;
jack_port_buffer_info_t *buffer_info;
} jack_port_internal_t;

/* The engine's internal port type structure. */
typedef struct _jack_port_type_internal {
pthread_mutex_t buffer_lock; /* only lock within server */
JSList *buffer_freelist; /* list of free buffers */
void *buffer_info; /* jack_buffer_info_t array */
void *seg_addr; /* buffer segment address */
} jack_port_type_internal_t;


/* The main engine structure in local memory. */
struct _jack_engine {
jack_control_t *control;
struct _jack_driver *driver;
@@ -45,20 +68,27 @@ struct _jack_engine {

/* "private" sections starts here */

pthread_mutex_t client_lock;
/* engine serialization -- use precedence for deadlock avoidance */
pthread_mutex_t port_lock;
pthread_mutex_t request_lock;
pthread_mutex_t request_lock; /* precedes driver_lock */
pthread_mutex_t driver_lock; /* precedes client_lock */
pthread_mutex_t client_lock;
int process_errors;
int period_msecs;
int client_timeout_msecs; /* Time to wait for clients in msecs. Used when jackd is
* run in non-ASIO mode and without realtime priority enabled.
*/
int client_timeout_msecs; /* Time to wait for clients in
* msecs. Used when jackd is run in
* non-ASIO mode and without realtime
* priority enabled. */

/* internal port type info, indexed by the port type_id */
jack_port_type_internal_t port_type[JACK_MAX_PORT_TYPES];

unsigned int port_max;
shm_name_t control_shm_name;
size_t control_size;
shm_name_t port_segment_name; /* XXX fix me */
size_t port_segment_size; /* XXX fix me */
void *port_segment_address; /* XXX fix me */
shm_name_t port_segment_name; /* XXX fix me */
size_t port_segment_size; /* XXX fix me */
void *port_segment_address; /* XXX fix me */
pthread_t main_thread;
pthread_t server_thread;


+ 20
- 31
jack/internal.h View File

@@ -68,11 +68,6 @@ typedef struct _jack_request jack_request_t;

typedef void * dlhandle;

typedef struct {
const char *shm_name;
size_t offset; /* JOQ: 32/64 problem? */
} jack_port_buffer_info_t;

typedef enum {
TransportCommandNone = 0,
TransportCommandStart = 1,
@@ -86,13 +81,6 @@ typedef struct {
volatile jack_time_t guard2;
} jack_frame_timer_t;

/* the relatively low value of this constant
* reflects the fact that JACK currently only
* knows about *1* port type. (March 2003)
*/

#define JACK_MAX_PORT_TYPES 4

/* JACK engine shared memory data structure. */
typedef struct {

@@ -115,7 +103,7 @@ typedef struct {
int32_t internal;
jack_nframes_t frames_at_cycle_start;
pid_t engine_pid;
uint32_t buffer_size;
jack_nframes_t buffer_size;
int8_t real_time;
int32_t client_priority;
int32_t has_capabilities;
@@ -131,7 +119,7 @@ typedef struct {
typedef enum {
BufferSizeChange,
SampleRateChange,
NewPortType,
AttachPortSegment,
PortConnected,
PortDisconnected,
GraphReordered,
@@ -150,11 +138,11 @@ typedef struct {
} x;
union {
uint32_t n;
jack_port_type_id_t ptid;
jack_port_id_t other_id;
void* addr; /* JOQ: 32/64 problem? */
} y;
union {
size_t size; /* JOQ: 32/64 problem? */
jack_shmsize_t size;
} z;
} jack_event_t;

@@ -187,6 +175,7 @@ typedef volatile struct {
volatile int8_t sync_poll : 1; /* w: engine and client, r: engine */
volatile int8_t sync_new : 1; /* w: engine and client, r: engine */
volatile pid_t pid; /* w: client r: engine; client pid */
volatile pid_t pgrp; /* w: client r: engine; client pgrp */
volatile uint64_t signalled_at;
volatile uint64_t awake_at;
volatile uint64_t finished_at;
@@ -242,23 +231,20 @@ typedef struct {
shm_name_t client_shm_name;
shm_name_t control_shm_name;

int8_t fifo_prefix[PATH_MAX+1];
char fifo_prefix[PATH_MAX+1];

int32_t realtime;
int32_t realtime_priority;

/* these two are valid only if the connect request
was for type == ClientDriver.
*/
was for type == ClientDriver. */
jack_client_control_t *client_control; /* JOQ: 64/32 problem */
jack_control_t *engine_control; /* JOQ: 64/32 problem */

jack_client_control_t *client_control;
jack_control_t *engine_control;
size_t control_size; /* JOQ: 32/64 problem? */
jack_shmsize_t control_size;

/* when we write this response, we deliver n_port_types
of jack_port_type_info_t after it.
*/

of jack_port_type_info_t after it. */
uint32_t n_port_types;
#if defined(__APPLE__) && defined(__POWERPC__)
@@ -292,6 +278,7 @@ typedef enum {
SetSyncClient = 13,
ResetSyncClient = 14,
SetSyncTimeout = 15,
SetBufferSize = 16,
} RequestType;

struct _jack_request {
@@ -301,9 +288,9 @@ struct _jack_request {
struct {
char name[JACK_PORT_NAME_SIZE+1];
char type[JACK_PORT_TYPE_SIZE+1];
uint32_t flags;
uint32_t buffer_size;
jack_port_id_t port_id;
uint32_t flags;
jack_shmsize_t buffer_size;
jack_port_id_t port_id;
jack_client_id_t client_id;
} port_info;
struct {
@@ -359,9 +346,9 @@ extern void jack_cleanup_files ();

extern int jack_client_handle_port_connection (jack_client_t *client,
jack_event_t *event);
extern void jack_client_handle_new_port_type (jack_client_t *client,
shm_name_t, size_t, void* addr);
extern void jack_client_set_port_segment (jack_client_t *client, shm_name_t,
jack_port_type_id_t ptid,
jack_shmsize_t, void *addr);
extern jack_client_t *jack_driver_client_new (jack_engine_t *,
const char *client_name);
jack_client_t *jack_client_alloc_internal (jack_client_control_t*,
@@ -374,6 +361,8 @@ extern char *jack_server_dir;

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

extern jack_port_functions_t jack_builtin_audio_functions;

extern jack_port_type_info_t jack_builtin_port_types[];

extern void jack_client_invalidate_port_buffers (jack_client_t *client);


+ 55
- 28
jack/jack.h View File

@@ -87,44 +87,71 @@ int jack_is_realtime (jack_client_t *client);
*
* NOTE: clients do not need to call this. It exists only
* to help more complex clients understand what is going
* on. If called, it should be called before jack_client_activate().
* on. It should be called before jack_client_activate().
*/
void jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg);

/**
* Tell the Jack server to call 'process_callback' whenever there is work
* be done, passing 'arg' as the second argument.
* Tell the Jack server to call @a process_callback whenever there is
* work be done, passing @a arg as the second argument.
*
* The code in the supplied function must be suitable for real-time
* execution. That means that it cannot call functions that might block for
* a long time.  This includes malloc, free, printf, pthread_mutex_lock,
* sleep, wait, poll, select, pthread_join, pthread_cond_wait, etc, etc. 
* See
* execution. That means that it cannot call functions that might
* block for a long time.  This includes malloc, free, printf,
* pthread_mutex_lock, sleep, wait, poll, select, pthread_join,
* pthread_cond_wait, etc, etc.  See
* http://jackit.sourceforge.net/docs/design/design.html#SECTION00411000000000000000
* for more information.
*
*
* @return 0 on success, otherwise a non-zero error code, causing JACK
* to remove that client from the process() graph.
*/
int jack_set_process_callback (jack_client_t *, JackProcessCallback process_callback, void *arg);
int jack_set_process_callback (jack_client_t *client,
JackProcessCallback process_callback,
void *arg);

/**
* 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.
* Change the buffer size passed to the @a process_callback.
*
* This operation stops the JACK engine process cycle, then calls all
* registered @a bufsize_callback functions before restarting the
* process cycle. This will cause a gap in the audio flow, so it
* should only be done at appropriate stopping points.
*
* @see jack_set_buffer_size_callback()
*
* @param client pointer to JACK client structure.
* @param nframes new buffer size. Must be a power of two.
*
* @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 (jack_client_t *client, jack_nframes_t nframes);

/**
* Tell the Jack server to call 'srate_callback' whenever the sample rate of
* the system changes.
* Tell JACK to call @a bufsize_callback whenever the size of the the
* buffer that will be passed to the @a process_callback is about to
* change. Clients that depend on knowing the buffer size must supply
* a @a bufsize_callback before activating themselves.
*
* @param client pointer to JACK client structure.
* @param bufsize_callback function to call when the buffer size changes.
* @param arg argument for @a bufsize_callback.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_set_sample_rate_callback (jack_client_t *, JackSampleRateCallback srate_callback, void *arg);
int jack_set_buffer_size_callback (jack_client_t *client,
JackBufferSizeCallback bufsize_callback,
void *arg);

/**
* Tell the Jack server to call @a srate_callback whenever the system
* sample rate changes.
*
* @return 0 on success, otherwise a non-zero error code
*/
int jack_set_sample_rate_callback (jack_client_t *client,
JackSampleRateCallback srate_callback,
void *arg);

/**
* Tell the Jack server to call 'registration_callback' whenever a port is registered
@@ -185,16 +212,14 @@ int jack_deactivate (jack_client_t *client);
* character.
*
* A port has a type, which may be any non-NULL and non-zero length
* string, and is passed as the second argument. For types that are
* not built into the jack API (currently just
* JACK_DEFAULT_AUDIO_TYPE) the client MUST supply a non-zero size
* for the buffer as for 'buffer_size' . For builtin types,
* 'buffer_size' is ignored.
* string, and is passed as the second argument. Some port types are
* built into the JACK API (currently only JACK_DEFAULT_AUDIO_TYPE).
* For other types, the client must supply a non-zero @a buffer_size.
* For builtin types, @a buffer_size is ignored.
*
* The 'flags' argument is formed from a bitmask of JackPortFlags values.
* The @a flags argument is formed from a bitmask of JackPortFlags values.
*
* @return a valid jack_port_t* on success, NULL otherwise.
* returns NULL.
*/
jack_port_t *jack_port_register (jack_client_t *,
const char *port_name,
@@ -478,11 +503,13 @@ int jack_port_disconnect (jack_client_t *, jack_port_t *);
jack_nframes_t jack_get_sample_rate (jack_client_t *);

/**
* This returns the current maximum size that will
* ever be passed to the "process" callback. It should only
* be used *before* the client has been activated. After activation,
* the client will be notified of buffer size changes if it
* registers a buffer_size callback.
* This returns the current maximum size that will ever be passed to
* the @a process_callback. It should only be used *before* the
* client has been activated. This size may change, clients that
* depend on it must register a @a bufsize_callback so they will be
* notified if it does.
*
* @see jack_set_buffer_size_callback()
*/
jack_nframes_t jack_get_buffer_size (jack_client_t *);



+ 44
- 38
jack/port.h View File

@@ -28,36 +28,44 @@
#define JACK_PORT_NAME_SIZE 32
#define JACK_PORT_TYPE_SIZE 32

/* The relatively low value of this constant reflects the fact that
* JACK currently only knows about *1* port type. (March 2003)
*/
#define JACK_MAX_PORT_TYPES 4
#define JACK_AUDIO_PORT_TYPE 0

/* these should probably go somewhere else, but not in <jack/types.h> */
#define JACK_CLIENT_NAME_SIZE 32
typedef uint32_t jack_client_id_t;

/* JACK shared memory segments are limited to MAX_INT32, they can be
* shared between 32-bit and 64-bit clients. */
#define JACK_SHM_MAX (MAX_INT32)
typedef int32_t jack_shmsize_t;
typedef int32_t jack_port_type_id_t;

typedef struct {
shm_name_t shm_name;
char *address;
size_t size;
shm_name_t shm_name;
char *address; /* JOQ: no longer set globally */
jack_shmsize_t size;
} jack_port_segment_info_t;

/* Port type structure. Has several uses:
*
* (1) One for each port type is part of the engine's jack_control_t
* shared memory structure.
*
* (2) One for each port type is appended to the engine's
* jack_client_connect_result_t response.
*
* (3) The client reads these into its local memory, and uses them to
* attach the corresponding shared memory segments.
*/
typedef struct _jack_port_type_info {

uint32_t type_id;
jack_port_type_id_t type_id;
const char type_name[JACK_PORT_TYPE_SIZE];

/* Function to mixdown multiple inputs to a buffer. Can be NULL,
* indicating that multiple input connections are not legal for
* this data type. */
void (*mixdown)(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 (*peak)(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. */
double (*power)(jack_port_t *, jack_nframes_t);

/* If == 1, then a buffer to handle nframes worth of data has
* sizeof(jack_default_audio_sample_t) * nframes bytes. If
* anything other than 1, the buffer allocated for input mixing
@@ -68,12 +76,9 @@ typedef struct _jack_port_type_info {
int32_t buffer_scale_factor;

/* ignored unless buffer_scale_factor is < 0. see above */
size_t buffer_size;
jack_shmsize_t buffer_size;

/* these are all run-time information, controlled by the server */
jack_port_segment_info_t shm_info;
pthread_mutex_t buffer_lock;
JSList *buffer_freelist;

} jack_port_type_info_t;

@@ -84,10 +89,11 @@ typedef struct _jack_port_shared {
jack_port_type_info_t type_info;
/* location of buffer as an offset from the start of the port's
* type-specific shared memory region. */
size_t offset;
jack_shmsize_t offset;
/* index into engine port array for this port */
jack_port_id_t id;
uint32_t flags;
int8_t has_mixdown; /* port has a mixdown function */
enum JackPortFlags flags;
char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE+2];
jack_client_id_t client_id; /* who owns me */

@@ -97,17 +103,24 @@ typedef struct _jack_port_shared {

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

} jack_port_shared_t;

/* This is the data structure allocated by the client in local
* memory. The `shared' pointer points to the corresponding structure
* in shared memory.
*/
typedef struct _jack_port_functions {

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

} jack_port_functions_t;

/* This port structure is allocated by the client in local memory. */
struct _jack_port {
char *client_segment_base;
struct _jack_port_shared *shared;
struct _jack_port_shared *shared; /* corresponding shm struct */
struct _jack_port *tied; /* locally tied source port */
jack_port_functions_t fptr; /* local port functions */
pthread_mutex_t connection_lock;
JSList *connections;
};
@@ -117,12 +130,5 @@ struct _jack_port {
#define jack_port_buffer(p) \
((void *) ((p)->client_segment_base + (p)->shared->offset))

/* This is the structure allocated by the engine in local memory. */
typedef struct _jack_port_internal {
struct _jack_port_shared *shared;
JSList *connections;
void *buffer_info;
} jack_port_internal_t;

#endif /* __jack_port_h__ */


+ 9
- 6
jack/types.h View File

@@ -103,13 +103,16 @@ typedef int (*JackGraphOrderCallback)(void *arg);
typedef int (*JackXRunCallback)(void *arg);

/**
* Prototype for the client supplied function that is called
* when the engine buffersize changes.
*
* Note! Use of this callback function is deprecated!
* Prototype for the @a bufsize_callback that is invoked whenever the
* JACK engine buffer size changes. Although this function is called
* in the JACK process thread, the normal process cycle is suspended
* during its operation, causing a gap in the audio flow. So, the @a
* bufsize_callback can allocate storage, touch memory not previously
* referenced, and perform other operations that are not realtime
* safe.
*
* @param nframes new engine buffer size
* @param arg pointer to a client supplied structure
* @param nframes buffer size
* @param arg pointer supplied by jack_set_buffer_size_callback().
*
* @return zero on success, non-zero on error
*/


+ 286
- 144
jackd/engine.c View File

@@ -142,6 +142,12 @@ jack_client_is_internal (jack_client_internal_t *client)
(client->control->type == ClientDriver);
}

static inline int
jack_rolling_interval (jack_time_t period_usecs)
{
return floor ((JACK_ENGINE_ROLLING_INTERVAL * 1000.0f) / period_usecs);
}

static inline void
jack_engine_reset_rolling_usecs (jack_engine_t *engine)
{
@@ -151,9 +157,8 @@ jack_engine_reset_rolling_usecs (jack_engine_t *engine)
engine->rolling_client_usecs_cnt = 0;

if (engine->driver) {
engine->rolling_interval = (int)
floor (JACK_ENGINE_ROLLING_INTERVAL * 1000.0f
/ engine->driver->period_usecs);
engine->rolling_interval =
jack_rolling_interval (engine->driver->period_usecs);
} else {
engine->rolling_interval = JACK_ENGINE_ROLLING_INTERVAL;
}
@@ -164,16 +169,18 @@ jack_engine_reset_rolling_usecs (jack_engine_t *engine)
static inline jack_port_type_info_t *
jack_global_port_type_info (jack_engine_t *engine, jack_port_internal_t *port)
{
/* this returns a pointer to the engine's private port type
information, rather than the copy that the port uses. we
need it for buffer allocation, because we need the mutex
that protects the free buffer list for this port type, and
that requires accessing the single copy owned by the
engine.
*/
/* Returns a pointer to the port type information in the
engine's shared control structure. */
return &engine->control->port_types[port->shared->type_info.type_id];
}

static inline jack_port_type_internal_t *
jack_local_port_type_info (jack_engine_t *engine, jack_port_internal_t *port)
{
/* Points to the engine's private port type struct. */
return &engine->port_type[port->shared->type_info.type_id];
}

static int
make_sockets (int fd[2])
{
@@ -291,19 +298,21 @@ jack_cleanup_files ()
closedir (dir);
}

static int
static void
jack_resize_port_segment (jack_engine_t *engine,
jack_port_type_info_t *port_type,
jack_nframes_t buffer_size,
unsigned long nports)
{
jack_event_t event;
char *addr;
size_t offset;
size_t one_buffer;
size_t size;
void *addr;
jack_shmsize_t offset; /* shared memory offset */
size_t one_buffer; /* size of one buffer */
size_t size; /* segment size */
int shmid;
int perm;
jack_port_buffer_info_t *bi;
jack_port_type_id_t ptid = port_type->type_id;
jack_port_type_internal_t *pti = &engine->port_type[ptid];

if (port_type->buffer_scale_factor < 0) {
one_buffer = port_type->buffer_size;
@@ -324,6 +333,7 @@ jack_resize_port_segment (jack_engine_t *engine,

if (port_type->shm_info.size == 0) {
/* no segment allocated, yet */
snprintf (port_type->shm_info.shm_name,
sizeof(port_type->shm_info.shm_name),
"/jck-[%s]", port_type->type_name);
@@ -335,14 +345,32 @@ jack_resize_port_segment (jack_engine_t *engine,
" bytes, shm_name = %s (%s)",
size, port_type->shm_info.shm_name,
strerror (errno));
return -1;
return;
}

jack_register_shm (port_type->shm_info.shm_name, addr, shmid);
port_type->shm_info.address = addr;

/* Allocate an array of buffer info structures for all
* the buffers in the segment. Chain them to the free
* list in memory address order, offset zero must come
* first. */
pthread_mutex_lock (&pti->buffer_lock);
offset = 0;
bi = pti->buffer_info = (jack_port_buffer_info_t *)
malloc (nports * sizeof (jack_port_buffer_info_t));
while (offset < size) {
bi->shm_name = port_type->shm_info.shm_name;
bi->offset = offset;
pti->buffer_freelist =
jack_slist_append (pti->buffer_freelist, bi);
offset += one_buffer;
++bi;
}
pthread_mutex_unlock (&pti->buffer_lock);

} else {

/* resize existing buffer segment */
if ((addr = jack_resize_shm (port_type->shm_info.shm_name,
size, perm, 0666,
PROT_READ|PROT_WRITE))
@@ -351,84 +379,132 @@ jack_resize_port_segment (jack_engine_t *engine,
" shm_name = %s (%s)", size,
port_type->shm_info.shm_name,
strerror (errno));
return -1;
return;
}
}

port_type->shm_info.size = size;
port_type->shm_info.address = addr;

pthread_mutex_lock (&port_type->buffer_lock);

offset = 0;

while (offset < port_type->shm_info.size) {
jack_port_buffer_info_t *bi;

bi = (jack_port_buffer_info_t *)
malloc (sizeof (jack_port_buffer_info_t));
bi->shm_name = port_type->shm_info.shm_name;
bi->offset = offset;

/* we append because we want the list to be in
* memory-address order */
port_type->buffer_freelist =
jack_slist_append (port_type->buffer_freelist, bi);

offset += one_buffer;
/* recompute the buffer offsets */
pthread_mutex_lock (&pti->buffer_lock);
offset = 0;
bi = pti->buffer_info;
while (offset < size) {
bi->offset = offset;
offset += one_buffer;
++bi;
}
pthread_mutex_unlock (&pti->buffer_lock);
}

pthread_mutex_unlock (&port_type->buffer_lock);

/* tell everybody about it */
port_type->shm_info.size = size;
engine->port_type[ptid].seg_addr = addr;

event.type = NewPortType;
/* Tell everybody about this segment. */
event.type = AttachPortSegment;
strcpy (event.x.shm_name, port_type->shm_info.shm_name);
event.y.addr = addr;
event.y.ptid = ptid;
event.z.size = size; /* JOQ: why wasn't this set before? */
jack_deliver_event_to_all (engine, &event);

return 0;
}

/* The driver invokes this callback both initially and whenever its
* buffer size changes. */
static int
jack_set_buffer_size (jack_engine_t *engine, jack_nframes_t nframes)
jack_driver_buffer_size (jack_engine_t *engine, jack_nframes_t nframes)
{
int i;
jack_event_t event;
jack_port_type_internal_t *pti;
JSList *node;

VERBOSE (engine, "new buffer size %" PRIu32 "\n", nframes);

engine->control->buffer_size = nframes;

for (i = 0; i < engine->control->n_port_types; ++i) {
jack_resize_port_segment (engine,
&engine->control->port_types[i],
nframes, engine->control->port_max);
engine->control->port_max);
}

/* convert the first chunk of the audio port buffer segment
* into a zero-filled area */
/* allocate the first buffer of the audio port segment for a
* zero-filled area */
pti = &engine->port_type[0];
if (engine->silent_buffer == NULL) {
jack_port_type_info_t *port_type =
&engine->control->port_types[0];

engine->silent_buffer = (jack_port_buffer_info_t *)
port_type->buffer_freelist->data;
port_type->buffer_freelist =
jack_slist_remove_link (port_type->buffer_freelist,
port_type->buffer_freelist);
pti->buffer_freelist->data;
pti->buffer_freelist =
jack_slist_remove_link (pti->buffer_freelist,
pti->buffer_freelist);
}

memset (port_type->shm_info.address +
engine->silent_buffer->offset, 0,
sizeof (jack_default_audio_sample_t) * nframes);
/* always zero `nframes' samples, it could have changed */
memset (engine->port_type[0].seg_addr + engine->silent_buffer->offset,
0, sizeof (jack_default_audio_sample_t) * nframes);

/* update shared client copy of nframes */
jack_lock_graph (engine);
for (node = engine->clients; node; node = jack_slist_next (node)) {
jack_client_internal_t *client = node->data;
client->control->nframes = nframes;
}
jack_unlock_graph (engine);

event.type = BufferSizeChange;
jack_deliver_event_to_all (engine, &event);


return 0;
}

/* handle client SetBufferSize request */
int
jack_set_buffer_size_request (jack_engine_t *engine, jack_nframes_t nframes)
{
/* precondition: caller holds the request_lock */
int rc;
jack_driver_t* driver = engine->driver;

if (driver == NULL)
return ENXIO; /* no such device */

if (!jack_power_of_two(nframes)) {
jack_error("buffer size %" PRIu32 " not a power of 2",
nframes);
return EINVAL;
}

/* this halts the jack_main_thread() loop while we reset the
* driver's parameters */
pthread_mutex_lock (&engine->driver_lock);

if (driver->stop (driver)) {
jack_error ("cannot stop driver to set buffer size");
pthread_mutex_unlock (&engine->driver_lock);
return EIO;
}

#if USE_POSIX_SHM
rc = driver->bufsize(driver, nframes);
if (rc == 0)
engine->rolling_interval =
jack_rolling_interval (driver->period_usecs);
else
jack_error("driver does not support %" PRIu32
"-frame buffers", nframes);
#else
/* jack_resize_shm() not implemented for SysV shm */
rc = ENOSYS; /* function not implemented */
#endif

if (driver->start (driver)) {
jack_error ("cannot restart driver after setting buffer size");
pthread_mutex_unlock (&engine->driver_lock);
exit(1);
}

pthread_mutex_unlock (&engine->driver_lock);

return rc;
}


static JSList *
jack_process_internal(jack_engine_t *engine, JSList *node,
@@ -494,6 +570,7 @@ jack_process_external(jack_engine_t *engine, JSList *node)
static JSList *
jack_process_external(jack_engine_t *engine, JSList *node)
{
/* precondition: caller has driver_lock */
int status;
char c;
float delayed_usecs;
@@ -632,14 +709,15 @@ jack_process_external(jack_engine_t *engine, JSList *node)
static int
jack_engine_process (jack_engine_t *engine, jack_nframes_t nframes)
{
/* precondition: caller has graph_lock and driver_lock */
jack_client_internal_t *client;
jack_client_control_t *ctl;
JSList *node;

engine->process_errors = 0;

for (node = engine->clients; node; node = jack_slist_next (node)) {
ctl = ((jack_client_internal_t *) node->data)->control;
jack_client_control_t *ctl =
((jack_client_internal_t *) node->data)->control;
ctl->state = NotTriggered;
ctl->nframes = nframes;
ctl->timed_out = 0;
@@ -878,6 +956,7 @@ jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
static void
jack_client_unload (jack_client_internal_t *client)
{
/* precondition: caller has driver_lock */
if (client->handle) {
if (client->finish) {
client->finish (client->control->process_arg);
@@ -973,19 +1052,19 @@ setup_client (jack_engine_t *engine, int client_fd,

/* call its initialization function */
if (client->control->type == ClientInternal) {
unsigned long i;

/* tell it about current port types and their
* shared memory information */
jack_port_type_id_t i;
for (i = 0; i < engine->control->n_port_types; ++i) {
jack_client_handle_new_port_type (
jack_port_type_info_t *port_type =
&engine->control->port_types[i];
jack_client_set_port_segment (
client->control->private_client,
engine->control->port_types[i]
.shm_info.shm_name,
engine->control->port_types[i]
.shm_info.size,
engine->control->port_types[i]
.shm_info.address);
port_type->shm_info.shm_name,
i,
port_type->shm_info.size,
engine->port_type[i].seg_addr);
}

if (client->initialize (client->control->private_client,
@@ -1022,6 +1101,7 @@ setup_client (jack_engine_t *engine, int client_fd,
static jack_driver_info_t *
jack_load_driver (jack_engine_t *engine, char *so_name)
{
/* precondition: caller has driver_lock */
const char *errstr;
char path_to_so[PATH_MAX+1];
jack_driver_info_t *info;
@@ -1082,6 +1162,7 @@ jack_load_driver (jack_engine_t *engine, char *so_name)
void
jack_driver_unload (jack_driver_t *driver)
{
/* precondition: caller has driver_lock */
driver->finish (driver);
dlclose (driver->handle);
}
@@ -1095,15 +1176,17 @@ jack_engine_load_driver (jack_engine_t *engine, int argc, char *argv[])
jack_driver_t *driver;
jack_driver_info_t *info;

pthread_mutex_lock (&engine->driver_lock);

if ((info = jack_load_driver (engine, argv[0])) == NULL) {
return -1;
goto unlock;
}

req.type = ClientDriver;
snprintf (req.name, sizeof (req.name), "%s", info->client_name);

if ((client = setup_client (engine, -1, &req, &res)) == NULL) {
return -1;
goto unlock;
}

if ((driver = info->initialize (client->control->private_client,
@@ -1117,10 +1200,15 @@ jack_engine_load_driver (jack_engine_t *engine, int argc, char *argv[])
if (jack_use_driver (engine, driver)) {
jack_driver_unload (driver);
jack_client_delete (engine, client);
return -1;
goto unlock;
}

pthread_mutex_unlock (&engine->driver_lock);
return 0;

unlock:
pthread_mutex_unlock (&engine->driver_lock);
return -1;
}

static int
@@ -1629,6 +1717,10 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd)
}
break;

case SetBufferSize:
req->status = jack_set_buffer_size_request (engine,
req->x.nframes);

default:
/* some requests are handled entirely on the client
* side, by adjusting the shared memory area(s) */
@@ -1859,7 +1951,7 @@ jack_engine_new (int realtime, int rtpriority, int verbose, int client_timeout)

engine->driver = 0;
engine->set_sample_rate = jack_set_sample_rate;
engine->set_buffer_size = jack_set_buffer_size;
engine->set_buffer_size = jack_driver_buffer_size;
engine->run_cycle = jack_run_cycle;
engine->transport_cycle_start = jack_transport_cycle_start;
engine->client_timeout_msecs = client_timeout;
@@ -1876,6 +1968,7 @@ jack_engine_new (int realtime, int rtpriority, int verbose, int client_timeout)
pthread_mutex_init (&engine->client_lock, 0);
pthread_mutex_init (&engine->port_lock, 0);
pthread_mutex_init (&engine->request_lock, 0);
pthread_mutex_init (&engine->driver_lock, 0);

engine->clients = 0;

@@ -1931,13 +2024,12 @@ jack_engine_new (int realtime, int rtpriority, int verbose, int client_timeout)
memcpy (&engine->control->port_types[i],
&jack_builtin_port_types[i],
sizeof (jack_port_type_info_t));
/* set offset into port_types array */
engine->control->port_types[i].type_id = i;

/* be sure to initialize mutex correctly */
pthread_mutex_init (&engine->control->port_types[i].buffer_lock,
NULL);
pthread_mutex_init (&engine->port_type[i].buffer_lock, NULL);

/* indicate no shared memory allocation for this port type */
engine->control->port_types[i].shm_info.size = 0;
@@ -2064,8 +2156,10 @@ cancel_cleanup (int status, void *arg)
{
jack_engine_t *engine = (jack_engine_t *) arg;
engine->control->engine_ok = 0;
engine->driver->stop (engine->driver);
engine->driver->finish (engine->driver);
if (pthread_mutex_trylock (&engine->driver_lock) == 0) {
engine->driver->stop (engine->driver);
engine->driver->finish (engine->driver);
}
}
#else
#ifdef HAVE_ATEXIT
@@ -2076,8 +2170,10 @@ cancel_cleanup (void)

{
jack_engine_t *engine = global_engine;
engine->driver->stop (engine->driver);
engine->driver->finish (engine->driver);
if (pthread_mutex_trylock (&engine->driver_lock) == 0) {
engine->driver->stop (engine->driver);
engine->driver->finish (engine->driver);
}
}
#else
#error "Don't know how to make an exit handler"
@@ -2088,11 +2184,17 @@ static void *
watchdog_thread (void *arg)
{
jack_engine_t *engine = (jack_engine_t *) arg;
int watchdog_priority = (engine->rtpriority) > 89 ? 99 : engine->rtpriority + 10;
int watchdog_priority = engine->rtpriority + 10;
int max_priority = sched_get_priority_max(SCHED_FIFO);

if ((max_priority != -1) &&
(max_priority < watchdog_priority))
watchdog_priority = max_priority;

pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

if (jack_become_real_time (pthread_self(), watchdog_priority)) {
VERBOSE(engine, "no realtime watchdog thread\n");
return 0;
}

@@ -2101,11 +2203,17 @@ watchdog_thread (void *arg)
while (1) {
usleep (5000000);
if (engine->watchdog_check == 0) {

jack_error ("jackd watchdog: timeout - killing jackd");
/* kill the process group of the current client */
kill (-engine->current_client->control->pid, SIGKILL);
/* kill our process group */
kill (-getpgrp(), SIGKILL);

/* Kill the current client's process group. */
if (engine->current_client) {
kill (-engine->current_client->
control->pgrp, SIGKILL);
}

/* kill our process group, trying to get a dump */
kill (-getpgrp(), SIGABRT);
/*NOTREACHED*/
exit (1);
}
@@ -2161,16 +2269,15 @@ jack_inc_frame_time (jack_engine_t *engine, jack_nframes_t amount)
}

static int
jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes,
float delayed_usecs)
jack_run_one_cycle (jack_engine_t *engine, jack_nframes_t nframes,
float delayed_usecs)
{
/* precondition: caller has driver lock */
int restart = 0;
jack_driver_t* driver = engine->driver;
int ret = -1;
static int consecutive_excessive_delays = 0;

engine->watchdog_check = 1;

#define WORK_SCALE 1.0f

if (engine->control->real_time &&
@@ -2216,6 +2323,8 @@ jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes,
goto unlock;
}

engine->watchdog_check = 1;

if (jack_engine_process (engine, nframes)) {
driver->stop (driver);
restart = 1;
@@ -2241,6 +2350,32 @@ jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes,
return ret;
}

static int
jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes,
float delayed_usecs)
{
jack_nframes_t left;
jack_nframes_t b_size = engine->control->buffer_size;

if (engine->verbose) {
if (nframes != b_size) {
fprintf(stderr,
"late driver wakeup: nframes to process = %"
PRIu32 ".\n", nframes);
}
}

/* run as many cycles as it takes to consume nframes */
for (left = nframes; left >= b_size; left -= b_size) {
if (jack_run_one_cycle (engine, b_size, delayed_usecs)) {
jack_error ("cycle execution failure, exiting");
return EIO;
}
}

return 0;
}

static void *
jack_main_thread (void *arg)
{
@@ -2267,47 +2402,45 @@ jack_main_thread (void *arg)
engine->watchdog_check = 1;

while (1) {
if ((nframes = driver->wait (driver, -1, &wait_status,
&delayed_usecs)) == 0) {

pthread_mutex_lock (&engine->driver_lock);

nframes = driver->wait (driver, -1, &wait_status,
&delayed_usecs);

if (nframes == 0) {

/* the driver detected an xrun and restarted */
jack_engine_notify_clients_about_delay (engine);
continue;
}

if (wait_status == 0) {
jack_nframes_t left, b_size =
engine->control->buffer_size;
if (engine->verbose) {
if (nframes != b_size) {
fprintf(stderr, "late driver wakeup: "
"nframes to process = %lu.\n",
(unsigned long int)nframes);
}
}
for(left = nframes; left >= b_size; left -= b_size) {
if (jack_run_cycle (engine, b_size,
delayed_usecs)) {
jack_error ("cycle execution failure,"
" exiting");
break;
}
} else if (wait_status == 0) {

if (jack_run_cycle (engine, nframes,
delayed_usecs) != 0) {
break;
}

} else if (wait_status < 0) {

break;

} else {
/* driver restarted, just continue */
}

pthread_mutex_unlock (&engine->driver_lock);
}

pthread_mutex_unlock (&engine->driver_lock);
pthread_exit (0);
return 0;
/*NOTREACHED*/
return 0;
}

int
jack_run (jack_engine_t *engine)
{
int rc;
#ifdef HAVE_ON_EXIT
on_exit (cancel_cleanup, engine);
@@ -2325,7 +2458,10 @@ jack_run (jack_engine_t *engine)
return -1;
}

if (engine->driver->start (engine->driver)) {
pthread_mutex_lock (&engine->driver_lock);
rc = engine->driver->start (engine->driver);
pthread_mutex_unlock (&engine->driver_lock);
if (rc != 0) {
jack_error ("cannot start driver");
return -1;
}
@@ -2382,8 +2518,8 @@ jack_engine_delete (jack_engine_t *engine)
if (engine) {

#if defined(__APPLE__) && defined(__POWERPC__)
/* the jack_run_cycle function is directly called from
* the CoreAudo audio callback */
/* the jack_run_cycle() function is directly called
* from the CoreAudo audio callback */
return 0;
#else
return pthread_cancel (engine->main_thread);
@@ -2591,6 +2727,7 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
static void
jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
{
/* precondition: caller has driver_lock */
if (jack_client_is_internal (client)) {
jack_client_unload (client);
free ((char *) client->control);
@@ -2695,9 +2832,9 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client,

case SampleRateChange:
if (client->control->srate) {
client->control->srate (
event->x.n,
client->control->bufsize_arg);
client->control->srate
(event->x.n,
client->control->srate_arg);
}
break;

@@ -2715,11 +2852,15 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client,
}
break;

case NewPortType:
jack_client_handle_new_port_type (
client->control->private_client,
event->x.shm_name, event->z.size,
event->y.addr);
case AttachPortSegment:

/* Internal clients don't need to attach, but
* they still need to set the port_segment. */
jack_client_set_port_segment
(client->control->private_client,
event->x.shm_name, event->y.ptid,
event->z.size,
engine->port_type[event->y.ptid].seg_addr);
break;

default:
@@ -3384,7 +3525,7 @@ jack_port_do_connect (jack_engine_t *engine,
jack_lock_graph (engine);

if (dstport->connections &&
dstport->shared->type_info.mixdown == NULL) {
!dstport->shared->has_mixdown) {
jack_error ("cannot make multiple connections to a port of"
" type [%s]",
dstport->shared->type_info.type_name);
@@ -3633,6 +3774,7 @@ jack_clear_fifos (jack_engine_t *engine)
static int
jack_use_driver (jack_engine_t *engine, jack_driver_t *driver)
{
/* precondition: caller has driver_lock */
if (engine->driver) {
engine->driver->detach (engine->driver, engine);
engine->driver = 0;
@@ -3642,9 +3784,8 @@ jack_use_driver (jack_engine_t *engine, jack_driver_t *driver)
if (driver->attach (driver, engine))
return -1;

engine->rolling_interval = (int)
floor ((JACK_ENGINE_ROLLING_INTERVAL * 1000.0f)
/ driver->period_usecs);
engine->rolling_interval =
jack_rolling_interval (driver->period_usecs);
}

engine->driver = driver;
@@ -3685,8 +3826,8 @@ jack_port_release (jack_engine_t *engine, jack_port_internal_t *port)
port->shared->in_use = 0;

if (port->buffer_info) {
jack_port_type_info_t *info =
jack_global_port_type_info (engine, port);
jack_port_type_internal_t *info =
jack_local_port_type_info (engine, port);
pthread_mutex_lock (&info->buffer_lock);
info->buffer_freelist =
jack_slist_prepend (info->buffer_freelist,
@@ -3967,8 +4108,8 @@ jack_port_registration_notify (jack_engine_t *engine,
int
jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port)
{
jack_port_type_info_t *port_type =
jack_global_port_type_info (engine, port);
jack_port_type_internal_t *pti =
jack_local_port_type_info (engine, port);
jack_port_buffer_info_t *bi;

if (port->shared->flags & JackPortIsInput) {
@@ -3976,23 +4117,24 @@ jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port)
return 0;
}
pthread_mutex_lock (&port_type->buffer_lock);
pthread_mutex_lock (&pti->buffer_lock);

if (port_type->buffer_freelist == NULL) {
if (pti->buffer_freelist == NULL) {
jack_port_type_info_t *port_type =
jack_global_port_type_info (engine, port);
jack_error ("all %s port buffers in use!",
port_type->type_name);
pthread_mutex_unlock (&port_type->buffer_lock);
pthread_mutex_unlock (&pti->buffer_lock);
return -1;
}

bi = (jack_port_buffer_info_t *) port_type->buffer_freelist->data;
port_type->buffer_freelist =
jack_slist_remove (port_type->buffer_freelist, bi);
bi = (jack_port_buffer_info_t *) pti->buffer_freelist->data;
pti->buffer_freelist = jack_slist_remove (pti->buffer_freelist, bi);

port->shared->offset = bi->offset;
port->buffer_info = bi;

pthread_mutex_unlock (&port_type->buffer_lock);
pthread_mutex_unlock (&pti->buffer_lock);
return 0;
}



+ 9
- 3
jackd/jackd.c View File

@@ -179,15 +179,21 @@ jack_main (int argc, char **argv)
sigaddset(&signals, SIGHUP);
sigaddset(&signals, SIGINT);
sigaddset(&signals, SIGQUIT);
sigaddset(&signals, SIGPIPE);
sigaddset(&signals, SIGTERM);
sigaddset(&signals, SIGUSR1);

#if 0
/* POSIX defines these as "synchronous" signals, which must be
* delivered to the offending thread. I think it's a bad idea
* to block them. (JOQ) */
sigaddset(&signals, SIGILL);
sigaddset(&signals, SIGTRAP);
sigaddset(&signals, SIGABRT);
sigaddset(&signals, SIGIOT);
sigaddset(&signals, SIGFPE);
sigaddset(&signals, SIGPIPE);
sigaddset(&signals, SIGTERM);
sigaddset(&signals, SIGUSR1);
sigaddset(&signals, SIGSEGV);
#endif

/* all child threads will inherit this mask unless they
* explicitly reset it */


+ 3
- 1
jackd/transengine.c View File

@@ -50,7 +50,9 @@ jack_sync_poll_new (jack_engine_t *engine, jack_client_internal_t *client)
engine->control->transport_state = JackTransportStarting;
VERBOSE (engine, "force transport state to Starting\n");
}
VERBOSE (engine, "polling sync client %" PRIu32 "\n", client->control->id);

VERBOSE (engine, "polling sync client %" PRIu32 "\n",
client->control->id);
}

/* stop polling a specific slow-sync client


+ 9
- 0
libjack/ChangeLog View File

@@ -1,3 +1,12 @@
2003-09-18 Jack O'Quin <joq@io.com>

* new function jack_set_buffer_size().

Compatibility issues: programs that rely on the buffer size but do
not register a callback will fail. Cached output buffer addresses
are not valid after the buffer size changes. These rules existed
before, but were never enforced.

2003-08-26 Jack O'Quin <joq@io.com>

* <jack/types.h> typedefs are now defined using the C99 standard


+ 76
- 55
libjack/client.c View File

@@ -75,7 +75,7 @@ jack_set_server_dir (const char *path)

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

#define event_fd pollfd[0].fd
#define graph_wait_fd pollfd[1].fd
@@ -138,16 +138,15 @@ jack_client_t *
jack_client_alloc ()
{
jack_client_t *client;
jack_port_type_id_t ptid;

client = (jack_client_t *) malloc (sizeof (jack_client_t));
client->pollfd = (struct pollfd *) malloc (sizeof (struct pollfd) * 2);
client->pollmax = 2;

client->request_fd = -1;
client->event_fd = -1;
client->graph_wait_fd = -1;
client->graph_next_fd = -1;
client->port_segments = NULL;
client->ports = NULL;
client->engine = NULL;
client->control = 0;
@@ -155,6 +154,13 @@ jack_client_alloc ()
client->first_active = TRUE;
client->on_shutdown = NULL;

client->n_port_types = 0;
for (ptid = 0; ptid < JACK_MAX_PORT_TYPES; ++ptid) {
client->port_segment[ptid].shm_name[0] = '\0';
client->port_segment[ptid].address = NULL;
client->port_segment[ptid].size = 0;
}

return client;
}

@@ -455,6 +461,30 @@ jack_request_client (ClientType type, const char* client_name, const char* so_na
return -1;
}

void
jack_attach_port_segment (jack_client_t *client, shm_name_t shm_name,
jack_port_type_id_t ptid, jack_shmsize_t size)
{
int shmid;
void *addr;

/* Lookup, attach and register the port/buffer segments in use
* right now. */
if (client->control->type != ClientExternal) {
jack_error("Only external clients need attach port segments");
abort();
}

if ((addr = jack_get_shm (shm_name, size, O_RDWR, 0,
(PROT_READ|PROT_WRITE),
&shmid)) == MAP_FAILED) {
jack_error ("cannot attach port segment shared memory"
" (%s)", strerror (errno));
}

jack_client_set_port_segment (client, shm_name, ptid, size, addr);
}

jack_client_t *
jack_client_new (const char *client_name)
{
@@ -463,9 +493,9 @@ jack_client_new (const char *client_name)
jack_client_connect_result_t res;
jack_client_t *client;
void *addr;
int i;
int shmid;
jack_port_type_info_t* type_info;
jack_port_type_id_t ptid;

/* external clients need this initialized; internal clients
will use the setup in the server's address space.
@@ -530,10 +560,11 @@ jack_client_new (const char *client_name)
goto fail;
}

for (i = 0; i < res.n_port_types; ++i) {
jack_client_handle_new_port_type (
client, type_info[i].shm_info.shm_name,
type_info[i].shm_info.size, 0);
client->n_port_types = res.n_port_types;
for (ptid = 0; ptid < res.n_port_types; ++ptid) {
jack_attach_port_segment (client,
type_info[ptid].shm_info.shm_name,
ptid, type_info[ptid].shm_info.size);
}

free (type_info);
@@ -620,44 +651,22 @@ jack_internal_client_close (const char *client_name)
}

void
jack_client_handle_new_port_type (jack_client_t *client, shm_name_t shm_name,
size_t size, void* addr)
jack_client_set_port_segment (jack_client_t *client, shm_name_t shm_name,
jack_port_type_id_t ptid, jack_shmsize_t size,
void *addr)
{
jack_port_segment_info_t *si;
int shmid;

/* Lookup, attach and register the port/buffer segments in use
* right now. */
if (client->control->type == ClientExternal) {
if ((addr = jack_get_shm(shm_name, size, O_RDWR, 0,
(PROT_READ|PROT_WRITE),
&shmid)) == MAP_FAILED) {
jack_error ("cannot attached port segment shared memory"
" (%s)", strerror (errno));
return;
}

} else {

/* client is in same address space as server, so just
* use `addr' directly */
}

si = (jack_port_segment_info_t *)
malloc (sizeof (jack_port_segment_info_t));
strcpy (si->shm_name, shm_name);
si->address = addr;
si->size = size;

/* the first chunk of the first port segment is always set by
* the engine to be a conveniently-sized, zero-filled lump of
* memory. */
if (client->port_segments == NULL) {
jack_zero_filled_buffer = si->address;
client->port_segment[ptid].address = addr;
client->port_segment[ptid].size = size;
strncpy (client->port_segment[ptid].shm_name,
shm_name, sizeof (shm_name_t));

/* The first chunk of the audio port segment will be set by
* the engine to be a zero-filled buffer. This hasn't been
* done yet, but it will happen before the process cycle
* (re)starts. */
if (ptid == JACK_AUDIO_PORT_TYPE) {
jack_zero_filled_buffer = client->port_segment[ptid].address;
}

client->port_segments = jack_slist_prepend (client->port_segments, si);
}

static void *
@@ -680,6 +689,7 @@ jack_client_thread (void *arg)
pthread_mutex_unlock (&client_lock);

client->control->pid = getpid();
client->control->pgrp = getpgrp();

DEBUG ("client thread is now running");

@@ -790,10 +800,11 @@ jack_client_thread (void *arg)
}
break;

case NewPortType:
jack_client_handle_new_port_type (
client, event.x.shm_name,
event.z.size, event.y.addr);
case AttachPortSegment:
jack_attach_port_segment (client,
event.x.shm_name,
event.y.ptid,
event.z.size);
break;
}

@@ -1275,6 +1286,7 @@ jack_client_close (jack_client_t *client)
{
JSList *node;
void *status;
jack_port_type_id_t ptid;
if (client->control->active) {
jack_deactivate (client);
@@ -1295,14 +1307,12 @@ jack_client_close (jack_client_t *client)
munmap ((char *) client->engine,
sizeof (jack_control_t));

for (node = client->port_segments; node;
node = jack_slist_next (node)) {
jack_port_segment_info_t *si =
(jack_port_segment_info_t *) node->data;
munmap ((char *) si->address, si->size);
free (node->data);
for (ptid = 0; ptid < client->n_port_types; ++ptid) {
if (client->port_segment[ptid].size) {
munmap (client->port_segment[ptid].address,
client->port_segment[ptid].size);
}
}
jack_slist_free (client->port_segments);

if (client->graph_wait_fd) {
close (client->graph_wait_fd);
@@ -1337,6 +1347,17 @@ jack_get_buffer_size (jack_client_t *client)
return client->engine->buffer_size;
}

int
jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes)
{
jack_request_t req;

req.type = SetBufferSize;
req.x.nframes = nframes;

return jack_client_deliver_request (client, &req);
}

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


+ 3
- 0
libjack/driver.c View File

@@ -43,6 +43,8 @@ static int dummy_write (jack_driver_t *drv,
static int dummy_read (jack_driver_t *drv, jack_nframes_t nframes) { return 0; }
static int dummy_null_cycle (jack_driver_t *drv,
jack_nframes_t nframes) { return 0; }
static int dummy_bufsize (jack_driver_t *drv,
jack_nframes_t nframes) {return 0;}
static int dummy_stop (jack_driver_t *drv) { return 0; }
static int dummy_start (jack_driver_t *drv) { return 0; }

@@ -57,6 +59,7 @@ jack_driver_init (jack_driver_t *driver)
driver->write = dummy_write;
driver->read = dummy_read;
driver->null_cycle = dummy_null_cycle;
driver->bufsize = dummy_bufsize;
driver->start = dummy_start;
driver->stop = dummy_stop;
}

+ 2
- 1
libjack/local.h View File

@@ -10,7 +10,8 @@ struct _jack_client {
int pollmax;
int graph_next_fd;
int request_fd;
JSList *port_segments;
jack_port_type_id_t n_port_types;
jack_port_segment_info_t port_segment[JACK_MAX_PORT_TYPES];
JSList *ports;
pthread_t thread;
char fifo_prefix[PATH_MAX+1];


+ 0
- 3
libjack/pool.c View File

@@ -19,14 +19,11 @@
*/

#include <stdlib.h>

#include <config.h>

#include <jack/pool.h>

void *
jack_pool_alloc (size_t bytes)

{
/* XXX need RT-pool based allocator here */



+ 56
- 114
libjack/port.c View File

@@ -34,81 +34,58 @@

#include "local.h"

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

/* These function pointers are local to each address space. For
* internal clients they reside within jackd; for external clients in
* the application process. */
jack_port_functions_t jack_builtin_audio_functions = {
.mixdown = jack_audio_port_mixdown,
};

jack_port_functions_t jack_builtin_NULL_functions = {
.mixdown = NULL,
};

/* Only the Audio port type is currently built in. */
jack_port_type_info_t jack_builtin_port_types[] = {
{ .type_name = JACK_DEFAULT_AUDIO_TYPE,
.buffer_scale_factor = 1,
},
{ .type_name = "", }
};

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));
jack_port_shared_t *shared = &control->ports[port_id];
jack_port_type_id_t ptid = shared->type_info.type_id;
jack_port_t *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->tied = NULL;
/* reset function pointers to be within client address space */

switch (client->control->type) {
case ClientExternal:

if (client->control->id == port->shared->client_id) {
if (client->control->id == port->shared->client_id) {
/* its our port, and therefore we need to make
sure that the function pointers in the
shared memory object that refer to
functions called within the client's
address space point to the location of the
correct functions within the
client. without this, they point to those
same functions in the server's address
space, and that's a recipe for disaster.
*/
port->shared->type_info.mixdown =
jack_builtin_port_types[
port->shared->type_info.type_id
].mixdown;
port->shared->type_info.peak =
jack_builtin_port_types[
port->shared->type_info.type_id].peak;
port->shared->type_info.power =
jack_builtin_port_types[
port->shared->type_info.type_id].power;
}
break;
/* It's our port, so initialize the pointers to port
* functions within this address space. These builtin
* definitions can be overridden by the client. */

default:
break;
}
if (port->shared->type_info.type_id == JACK_AUDIO_PORT_TYPE) {

/* now find the shared memory segment that contains the buffer
* for this port */
for (node = client->port_segments; node;
node = jack_slist_next (node)) {
si = (jack_port_segment_info_t *) node->data;
port->fptr = jack_builtin_audio_functions;
port->shared->has_mixdown = TRUE;

if (strcmp (si->shm_name,
port->shared->type_info.shm_info.shm_name) == 0) {
break;
}
}
} else { /* no other builtin functions */

if (node == NULL) {
jack_error ("cannot find port memory segment [%s] for"
" new port\n",
port->shared->type_info.shm_info.shm_name);
return NULL;
port->fptr = jack_builtin_NULL_functions;
port->shared->has_mixdown = FALSE;
}
}

/* set up a base address so that port->offset can be used to
@@ -117,7 +94,7 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id,
port->offset can change if the buffer size or port counts
are changed.
*/
port->client_segment_base = si->address;
port->client_segment_base = client->port_segment[ptid].address;
return port;
}
@@ -387,31 +364,24 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)
{
JSList *node, *next;

/* Output port. The buffer was assigned by the engine
/* 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);
if (port->tied) {
return jack_port_get_buffer (port->tied, nframes);
}
return jack_port_buffer (port);
}

/* Input 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
*/

/* 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;
}

@@ -420,20 +390,19 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)
/* 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.
/* 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
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.
*/

@@ -445,7 +414,7 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)
* nframes);
port->client_segment_base = 0;
}
port->shared->type_info.mixdown (port, nframes);
port->fptr.mixdown (port, nframes);
return (jack_default_audio_sample_t *) port->shared->offset;
}

@@ -463,7 +432,7 @@ jack_port_tie (jack_port_t *src, jack_port_t *dst)
return -1;
}

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

@@ -471,11 +440,11 @@ int
jack_port_untie (jack_port_t *port)

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

@@ -625,21 +594,6 @@ static inline float f_max(float x, float 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)
{
@@ -680,15 +634,3 @@ jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes)
}
}
}

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 = "",
}
};


Loading…
Cancel
Save