git-svn-id: svn+ssh://jackaudio.org/trunk/jack@512 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
@@ -14,7 +14,7 @@ dnl changes are made | |||||
dnl --- | dnl --- | ||||
JACK_MAJOR_VERSION=0 | JACK_MAJOR_VERSION=0 | ||||
JACK_MINOR_VERSION=83 | JACK_MINOR_VERSION=83 | ||||
JACK_MICRO_VERSION=0 | |||||
JACK_MICRO_VERSION=1 | |||||
dnl --- | dnl --- | ||||
dnl HOWTO: updating the jack protocal version | dnl HOWTO: updating the jack protocal version | ||||
@@ -38,6 +38,7 @@ typedef struct { | |||||
jack_shmsize_t offset; | jack_shmsize_t offset; | ||||
} jack_port_buffer_info_t; | } jack_port_buffer_info_t; | ||||
/* The engine keeps an array of these in its local memory. */ | |||||
typedef struct _jack_port_internal { | typedef struct _jack_port_internal { | ||||
struct _jack_port_shared *shared; | struct _jack_port_shared *shared; | ||||
JSList *connections; | JSList *connections; | ||||
@@ -46,24 +46,22 @@ typedef int32_t jack_port_type_id_t; | |||||
typedef struct { | typedef struct { | ||||
shm_name_t shm_name; | shm_name_t shm_name; | ||||
char *address; /* JOQ: no longer set globally */ | |||||
jack_shmsize_t size; | jack_shmsize_t size; | ||||
} jack_port_segment_info_t; | } jack_port_segment_info_t; | ||||
/* Port type structure. Has several uses: | |||||
/* Port type structure. | |||||
* | * | ||||
* (1) One for each port type is part of the engine's jack_control_t | * (1) One for each port type is part of the engine's jack_control_t | ||||
* shared memory structure. | * shared memory structure. | ||||
* | * | ||||
* (2) One for each port type is appended to the engine's | * (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. | |||||
* jack_client_connect_result_t response. The client reads them into | |||||
* its local memory, using them to attach the corresponding shared | |||||
* memory segments. | |||||
*/ | */ | ||||
typedef struct _jack_port_type_info { | typedef struct _jack_port_type_info { | ||||
jack_port_type_id_t type_id; | |||||
jack_port_type_id_t ptype_id; | |||||
const char type_name[JACK_PORT_TYPE_SIZE]; | const char type_name[JACK_PORT_TYPE_SIZE]; | ||||
/* If == 1, then a buffer to handle nframes worth of data has | /* If == 1, then a buffer to handle nframes worth of data has | ||||
@@ -82,17 +80,12 @@ typedef struct _jack_port_type_info { | |||||
} jack_port_type_info_t; | } jack_port_type_info_t; | ||||
/* This is the data structure allocated in shared memory | |||||
* by the engine. | |||||
*/ | |||||
/* Allocated by the engine in shared memory. */ | |||||
typedef struct _jack_port_shared { | 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. */ | |||||
jack_shmsize_t offset; | |||||
/* index into engine port array for this port */ | |||||
jack_port_id_t id; | |||||
int8_t has_mixdown; /* port has a mixdown function */ | |||||
jack_port_type_id_t ptype_id; /* index into port type array */ | |||||
jack_shmsize_t offset; /* buffer offset in shm segment */ | |||||
jack_port_id_t id; /* index into engine port array */ | |||||
enum JackPortFlags flags; | enum JackPortFlags flags; | ||||
char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE+2]; | char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE+2]; | ||||
jack_client_id_t client_id; /* who owns me */ | jack_client_id_t client_id; /* who owns me */ | ||||
@@ -101,6 +94,7 @@ typedef struct _jack_port_shared { | |||||
volatile jack_nframes_t total_latency; | volatile jack_nframes_t total_latency; | ||||
volatile uint8_t monitor_requests; | volatile uint8_t monitor_requests; | ||||
int8_t has_mixdown; /* port has a mixdown function */ | |||||
char in_use : 1; | char in_use : 1; | ||||
char locked : 1; | char locked : 1; | ||||
@@ -115,20 +109,27 @@ typedef struct _jack_port_functions { | |||||
} jack_port_functions_t; | } jack_port_functions_t; | ||||
/* This port structure is allocated by the client in local memory. */ | |||||
/* Allocated by the client in local memory. */ | |||||
struct _jack_port { | struct _jack_port { | ||||
char *client_segment_base; | |||||
void **client_segment_base; | |||||
void *mix_buffer; | |||||
jack_port_type_info_t *type_info; /* shared memory type info */ | |||||
struct _jack_port_shared *shared; /* corresponding shm struct */ | struct _jack_port_shared *shared; /* corresponding shm struct */ | ||||
struct _jack_port *tied; /* locally tied source port */ | struct _jack_port *tied; /* locally tied source port */ | ||||
jack_port_functions_t fptr; /* local port functions */ | |||||
pthread_mutex_t connection_lock; | |||||
jack_port_functions_t fptr; | |||||
pthread_mutex_t connection_lock; | |||||
JSList *connections; | JSList *connections; | ||||
}; | }; | ||||
/* Inline would be cleaner, but it needs to be fast even in | |||||
* non-optimized code. */ | |||||
/* Inline would be cleaner, but it needs to be fast even in | |||||
* non-optimized code. jack_output_port_buffer() only handles output | |||||
* ports. jack_port_buffer() works for both input and output ports. | |||||
*/ | |||||
#define jack_port_buffer(p) \ | #define jack_port_buffer(p) \ | ||||
((void *) ((p)->client_segment_base + (p)->shared->offset)) | |||||
((void *) ((p)->mix_buffer? (p)->mix_buffer: \ | |||||
*(p)->client_segment_base + (p)->shared->offset)) | |||||
#define jack_output_port_buffer(p) \ | |||||
((void *) (*(p)->client_segment_base + (p)->shared->offset)) | |||||
#endif /* __jack_port_h__ */ | #endif /* __jack_port_h__ */ | ||||
@@ -171,14 +171,14 @@ jack_global_port_type_info (jack_engine_t *engine, jack_port_internal_t *port) | |||||
{ | { | ||||
/* Returns a pointer to the port type information in the | /* Returns a pointer to the port type information in the | ||||
engine's shared control structure. */ | engine's shared control structure. */ | ||||
return &engine->control->port_types[port->shared->type_info.type_id]; | |||||
return &engine->control->port_types[port->shared->ptype_id]; | |||||
} | } | ||||
static inline jack_port_type_internal_t * | static inline jack_port_type_internal_t * | ||||
jack_local_port_type_info (jack_engine_t *engine, jack_port_internal_t *port) | jack_local_port_type_info (jack_engine_t *engine, jack_port_internal_t *port) | ||||
{ | { | ||||
/* Points to the engine's private port type struct. */ | /* Points to the engine's private port type struct. */ | ||||
return &engine->port_type[port->shared->type_info.type_id]; | |||||
return &engine->port_type[port->shared->ptype_id]; | |||||
} | } | ||||
static int | static int | ||||
@@ -311,8 +311,9 @@ jack_resize_port_segment (jack_engine_t *engine, | |||||
int shmid; | int shmid; | ||||
int perm; | int perm; | ||||
jack_port_buffer_info_t *bi; | jack_port_buffer_info_t *bi; | ||||
jack_port_type_id_t ptid = port_type->type_id; | |||||
jack_port_type_id_t ptid = port_type->ptype_id; | |||||
jack_port_type_internal_t *pti = &engine->port_type[ptid]; | jack_port_type_internal_t *pti = &engine->port_type[ptid]; | ||||
jack_port_id_t i; | |||||
if (port_type->buffer_scale_factor < 0) { | if (port_type->buffer_scale_factor < 0) { | ||||
one_buffer = port_type->buffer_size; | one_buffer = port_type->buffer_size; | ||||
@@ -369,8 +370,8 @@ jack_resize_port_segment (jack_engine_t *engine, | |||||
pthread_mutex_unlock (&pti->buffer_lock); | pthread_mutex_unlock (&pti->buffer_lock); | ||||
} else { | } else { | ||||
/* resize existing buffer segment */ | /* resize existing buffer segment */ | ||||
if ((addr = jack_resize_shm (port_type->shm_info.shm_name, | if ((addr = jack_resize_shm (port_type->shm_info.shm_name, | ||||
size, perm, 0666, | size, perm, 0666, | ||||
PROT_READ|PROT_WRITE)) | PROT_READ|PROT_WRITE)) | ||||
@@ -391,6 +392,15 @@ jack_resize_port_segment (jack_engine_t *engine, | |||||
offset += one_buffer; | offset += one_buffer; | ||||
++bi; | ++bi; | ||||
} | } | ||||
/* update any existing output port offsets */ | |||||
for (i = 0; i < engine->port_max; i++) { | |||||
if (engine->control->ports[i].flags|JackPortIsOutput && | |||||
engine->control->ports[i].ptype_id == ptid) { | |||||
bi = engine->internal_ports[i].buffer_info; | |||||
engine->control->ports[i].offset = bi->offset; | |||||
} | |||||
} | |||||
pthread_mutex_unlock (&pti->buffer_lock); | pthread_mutex_unlock (&pti->buffer_lock); | ||||
} | } | ||||
@@ -401,7 +411,7 @@ jack_resize_port_segment (jack_engine_t *engine, | |||||
event.type = AttachPortSegment; | event.type = AttachPortSegment; | ||||
strcpy (event.x.shm_name, port_type->shm_info.shm_name); | strcpy (event.x.shm_name, port_type->shm_info.shm_name); | ||||
event.y.ptid = ptid; | event.y.ptid = ptid; | ||||
event.z.size = size; /* JOQ: why wasn't this set before? */ | |||||
event.z.size = size; | |||||
jack_deliver_event_to_all (engine, &event); | jack_deliver_event_to_all (engine, &event); | ||||
} | } | ||||
@@ -2025,8 +2035,8 @@ jack_engine_new (int realtime, int rtpriority, int verbose, int client_timeout) | |||||
&jack_builtin_port_types[i], | &jack_builtin_port_types[i], | ||||
sizeof (jack_port_type_info_t)); | sizeof (jack_port_type_info_t)); | ||||
/* set offset into port_types array */ | |||||
engine->control->port_types[i].type_id = i; | |||||
/* the port type id is index into port_types array */ | |||||
engine->control->port_types[i].ptype_id = i; | |||||
/* be sure to initialize mutex correctly */ | /* be sure to initialize mutex correctly */ | ||||
pthread_mutex_init (&engine->port_type[i].buffer_lock, NULL); | pthread_mutex_init (&engine->port_type[i].buffer_lock, NULL); | ||||
@@ -3388,7 +3398,7 @@ void jack_dump_configuration(jack_engine_t *engine, int take_lock) | |||||
jack_slist_length(client->fed_by), | jack_slist_length(client->fed_by), | ||||
client->subgraph_start_fd, | client->subgraph_start_fd, | ||||
client->subgraph_wait_fd); | client->subgraph_wait_fd); | ||||
for(m = 0, portnode = client->ports; portnode; | for(m = 0, portnode = client->ports; portnode; | ||||
portnode = jack_slist_next (portnode)) { | portnode = jack_slist_next (portnode)) { | ||||
port = (jack_port_internal_t *) portnode->data; | port = (jack_port_internal_t *) portnode->data; | ||||
@@ -3472,8 +3482,7 @@ jack_port_do_connect (jack_engine_t *engine, | |||||
return -1; | return -1; | ||||
} | } | ||||
if (srcport->shared->type_info.type_id | |||||
!= dstport->shared->type_info.type_id) { | |||||
if (srcport->shared->ptype_id != dstport->shared->ptype_id) { | |||||
jack_error ("ports used in attemped connection are not of " | jack_error ("ports used in attemped connection are not of " | ||||
"the same data type"); | "the same data type"); | ||||
return -1; | return -1; | ||||
@@ -3508,7 +3517,8 @@ jack_port_do_connect (jack_engine_t *engine, | |||||
} | } | ||||
for (it = srcport->connections; it; it = it->next) { | for (it = srcport->connections; it; it = it->next) { | ||||
if (((jack_connection_internal_t *)it->data)->destination == dstport) { | |||||
if (((jack_connection_internal_t *)it->data)->destination | |||||
== dstport) { | |||||
return EEXIST; | return EEXIST; | ||||
} | } | ||||
} | } | ||||
@@ -3524,11 +3534,11 @@ jack_port_do_connect (jack_engine_t *engine, | |||||
jack_lock_graph (engine); | jack_lock_graph (engine); | ||||
if (dstport->connections && | |||||
!dstport->shared->has_mixdown) { | |||||
if (dstport->connections && !dstport->shared->has_mixdown) { | |||||
jack_port_type_info_t *port_type = | |||||
jack_global_port_type_info (engine, dstport); | |||||
jack_error ("cannot make multiple connections to a port of" | jack_error ("cannot make multiple connections to a port of" | ||||
" type [%s]", | |||||
dstport->shared->type_info.type_name); | |||||
" type [%s]", port_type->type_name); | |||||
free (connection); | free (connection); | ||||
jack_unlock_graph (engine); | jack_unlock_graph (engine); | ||||
return -1; | return -1; | ||||
@@ -3900,8 +3910,7 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req) | |||||
shared = &engine->control->ports[port_id]; | shared = &engine->control->ports[port_id]; | ||||
strcpy (shared->name, req->x.port_info.name); | strcpy (shared->name, req->x.port_info.name); | ||||
memcpy (&shared->type_info, &engine->control->port_types[i], | |||||
sizeof (jack_port_type_info_t)); | |||||
shared->ptype_id = engine->control->port_types[i].ptype_id; | |||||
shared->client_id = req->x.port_info.client_id; | shared->client_id = req->x.port_info.client_id; | ||||
shared->flags = req->x.port_info.flags; | shared->flags = req->x.port_info.flags; | ||||
shared->latency = 0; | shared->latency = 0; | ||||
@@ -202,11 +202,9 @@ jack_client_invalidate_port_buffers (jack_client_t *client) | |||||
port = (jack_port_t *) node->data; | port = (jack_port_t *) node->data; | ||||
if (port->shared->flags & JackPortIsInput) { | if (port->shared->flags & JackPortIsInput) { | ||||
if (port->client_segment_base == 0) { | |||||
jack_pool_release ( | |||||
(void *) port->shared->offset); | |||||
port->client_segment_base = 0; | |||||
port->shared->offset = 0; | |||||
if (port->mix_buffer) { | |||||
jack_pool_release (port->mix_buffer); | |||||
port->mix_buffer = NULL; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -1527,16 +1525,19 @@ jack_get_ports (jack_client_t *client, | |||||
engine = client->engine; | engine = client->engine; | ||||
if (port_name_pattern && port_name_pattern[0]) { | if (port_name_pattern && port_name_pattern[0]) { | ||||
regcomp (&port_regex, port_name_pattern, REG_EXTENDED|REG_NOSUB); | |||||
regcomp (&port_regex, port_name_pattern, | |||||
REG_EXTENDED|REG_NOSUB); | |||||
} | } | ||||
if (type_name_pattern && type_name_pattern[0]) { | if (type_name_pattern && type_name_pattern[0]) { | ||||
regcomp (&type_regex, type_name_pattern, REG_EXTENDED|REG_NOSUB); | |||||
regcomp (&type_regex, type_name_pattern, | |||||
REG_EXTENDED|REG_NOSUB); | |||||
} | } | ||||
psp = engine->ports; | psp = engine->ports; | ||||
match_cnt = 0; | match_cnt = 0; | ||||
matching_ports = (const char **) malloc (sizeof (char *) * engine->port_max); | |||||
matching_ports = (const char **) | |||||
malloc (sizeof (char *) * engine->port_max); | |||||
for (i = 0; i < engine->port_max; i++) { | for (i = 0; i < engine->port_max; i++) { | ||||
matching = 1; | matching = 1; | ||||
@@ -1558,7 +1559,10 @@ jack_get_ports (jack_client_t *client, | |||||
} | } | ||||
if (matching && type_name_pattern && type_name_pattern[0]) { | if (matching && type_name_pattern && type_name_pattern[0]) { | ||||
if (regexec (&type_regex, psp[i].type_info.type_name, 0, NULL, 0)) { | |||||
jack_port_type_id_t ptid = psp[i].ptype_id; | |||||
if (regexec (&type_regex, | |||||
engine->port_types[ptid].type_name, | |||||
0, NULL, 0)) { | |||||
matching = 0; | matching = 0; | ||||
} | } | ||||
} | } | ||||
@@ -10,9 +10,15 @@ struct _jack_client { | |||||
int pollmax; | int pollmax; | ||||
int graph_next_fd; | int graph_next_fd; | ||||
int request_fd; | int request_fd; | ||||
jack_port_type_id_t n_port_types; | jack_port_type_id_t n_port_types; | ||||
jack_port_segment_info_t port_segment[JACK_MAX_PORT_TYPES]; | |||||
struct { | |||||
shm_name_t shm_name; | |||||
void *address; | |||||
jack_shmsize_t size; | |||||
} port_segment[JACK_MAX_PORT_TYPES]; | |||||
JSList *ports; | JSList *ports; | ||||
pthread_t thread; | pthread_t thread; | ||||
char fifo_prefix[PATH_MAX+1]; | char fifo_prefix[PATH_MAX+1]; | ||||
void (*on_shutdown)(void *arg); | void (*on_shutdown)(void *arg); | ||||
@@ -61,11 +61,13 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id, | |||||
jack_control_t *control) | jack_control_t *control) | ||||
{ | { | ||||
jack_port_shared_t *shared = &control->ports[port_id]; | jack_port_shared_t *shared = &control->ports[port_id]; | ||||
jack_port_type_id_t ptid = shared->type_info.type_id; | |||||
jack_port_type_id_t ptid = shared->ptype_id; | |||||
jack_port_t *port = (jack_port_t *) malloc (sizeof (jack_port_t)); | jack_port_t *port = (jack_port_t *) malloc (sizeof (jack_port_t)); | ||||
port->client_segment_base = 0; | |||||
port->mix_buffer = NULL; | |||||
port->client_segment_base = NULL; | |||||
port->shared = shared; | port->shared = shared; | ||||
port->type_info = &client->engine->port_types[ptid]; | |||||
pthread_mutex_init (&port->connection_lock, NULL); | pthread_mutex_init (&port->connection_lock, NULL); | ||||
port->connections = 0; | port->connections = 0; | ||||
port->tied = NULL; | port->tied = NULL; | ||||
@@ -76,7 +78,7 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id, | |||||
* functions within this address space. These builtin | * functions within this address space. These builtin | ||||
* definitions can be overridden by the client. */ | * definitions can be overridden by the client. */ | ||||
if (port->shared->type_info.type_id == JACK_AUDIO_PORT_TYPE) { | |||||
if (ptid == JACK_AUDIO_PORT_TYPE) { | |||||
port->fptr = jack_builtin_audio_functions; | port->fptr = jack_builtin_audio_functions; | ||||
port->shared->has_mixdown = TRUE; | port->shared->has_mixdown = TRUE; | ||||
@@ -94,7 +96,8 @@ 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 | port->offset can change if the buffer size or port counts | ||||
are changed. | are changed. | ||||
*/ | */ | ||||
port->client_segment_base = client->port_segment[ptid].address; | |||||
port->client_segment_base = | |||||
(void *) &client->port_segment[ptid].address; | |||||
return port; | return port; | ||||
} | } | ||||
@@ -371,7 +374,7 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes) | |||||
if (port->tied) { | if (port->tied) { | ||||
return jack_port_get_buffer (port->tied, nframes); | return jack_port_get_buffer (port->tied, nframes); | ||||
} | } | ||||
return jack_port_buffer (port); | |||||
return jack_output_port_buffer (port); | |||||
} | } | ||||
/* Input port. Since this can only be called from the | /* Input port. Since this can only be called from the | ||||
@@ -394,28 +397,20 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes) | |||||
nframes); | 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. | |||||
/* Multiple connections. Use a local buffer and mix the | |||||
incoming data into that buffer. We have already | |||||
established the existence of a mixdown function during the | |||||
connection process. | |||||
*/ | */ | ||||
if (port->shared->offset == 0) { | |||||
port->shared->offset = (size_t) | |||||
if (port->mix_buffer == NULL) { | |||||
port->mix_buffer = | |||||
jack_pool_alloc ( | jack_pool_alloc ( | ||||
port->shared->type_info.buffer_scale_factor | |||||
port->type_info->buffer_scale_factor | |||||
* sizeof (jack_default_audio_sample_t) | * sizeof (jack_default_audio_sample_t) | ||||
* nframes); | * nframes); | ||||
port->client_segment_base = 0; | |||||
} | } | ||||
port->fptr.mixdown (port, nframes); | port->fptr.mixdown (port, nframes); | ||||
return (jack_default_audio_sample_t *) port->shared->offset; | |||||
return (jack_default_audio_sample_t *) port->mix_buffer; | |||||
} | } | ||||
int | int | ||||
@@ -565,7 +560,7 @@ jack_port_flags (const jack_port_t *port) | |||||
const char * | const char * | ||||
jack_port_type (const jack_port_t *port) | jack_port_type (const jack_port_t *port) | ||||
{ | { | ||||
return port->shared->type_info.type_name; | |||||
return port->type_info->type_name; | |||||
} | } | ||||
int | int | ||||
@@ -604,7 +599,8 @@ jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes) | |||||
jack_default_audio_sample_t *dst, *src; | jack_default_audio_sample_t *dst, *src; | ||||
/* by the time we've called this, we've already established | /* by the time we've called this, we've already established | ||||
the existence of more than 1 connection to this input port. | |||||
the existence of more than one connection to this input | |||||
port and allocated a mix_buffer. | |||||
*/ | */ | ||||
/* no need to take connection lock, since this is called | /* no need to take connection lock, since this is called | ||||
@@ -615,9 +611,9 @@ jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes) | |||||
node = port->connections; | node = port->connections; | ||||
input = (jack_port_t *) node->data; | input = (jack_port_t *) node->data; | ||||
buffer = jack_port_buffer (port); | |||||
buffer = port->mix_buffer; | |||||
memcpy (buffer, jack_port_buffer (input), | |||||
memcpy (buffer, jack_output_port_buffer (input), | |||||
sizeof (jack_default_audio_sample_t) * nframes); | sizeof (jack_default_audio_sample_t) * nframes); | ||||
for (node = jack_slist_next (node); node; | for (node = jack_slist_next (node); node; | ||||
@@ -627,7 +623,7 @@ jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes) | |||||
n = nframes; | n = nframes; | ||||
dst = buffer; | dst = buffer; | ||||
src = jack_port_buffer (input); | |||||
src = jack_output_port_buffer (input); | |||||
while (n--) { | while (n--) { | ||||
*dst++ += *src++; | *dst++ += *src++; | ||||