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 --- | |||
JACK_MAJOR_VERSION=0 | |||
JACK_MINOR_VERSION=83 | |||
JACK_MICRO_VERSION=0 | |||
JACK_MICRO_VERSION=1 | |||
dnl --- | |||
dnl HOWTO: updating the jack protocal version | |||
@@ -38,6 +38,7 @@ typedef struct { | |||
jack_shmsize_t offset; | |||
} jack_port_buffer_info_t; | |||
/* The engine keeps an array of these in its local memory. */ | |||
typedef struct _jack_port_internal { | |||
struct _jack_port_shared *shared; | |||
JSList *connections; | |||
@@ -46,24 +46,22 @@ typedef int32_t jack_port_type_id_t; | |||
typedef struct { | |||
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: | |||
/* Port type structure. | |||
* | |||
* (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. | |||
* 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 { | |||
jack_port_type_id_t type_id; | |||
jack_port_type_id_t ptype_id; | |||
const char type_name[JACK_PORT_TYPE_SIZE]; | |||
/* 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; | |||
/* This is the data structure allocated in shared memory | |||
* by the engine. | |||
*/ | |||
/* Allocated by the engine in shared memory. */ | |||
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; | |||
char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE+2]; | |||
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 uint8_t monitor_requests; | |||
int8_t has_mixdown; /* port has a mixdown function */ | |||
char in_use : 1; | |||
char locked : 1; | |||
@@ -115,20 +109,27 @@ typedef struct _jack_port_functions { | |||
} 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 { | |||
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 *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; | |||
}; | |||
/* 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) \ | |||
((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__ */ | |||
@@ -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 | |||
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 * | |||
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]; | |||
return &engine->port_type[port->shared->ptype_id]; | |||
} | |||
static int | |||
@@ -311,8 +311,9 @@ jack_resize_port_segment (jack_engine_t *engine, | |||
int shmid; | |||
int perm; | |||
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_id_t i; | |||
if (port_type->buffer_scale_factor < 0) { | |||
one_buffer = port_type->buffer_size; | |||
@@ -369,8 +370,8 @@ jack_resize_port_segment (jack_engine_t *engine, | |||
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)) | |||
@@ -391,6 +392,15 @@ jack_resize_port_segment (jack_engine_t *engine, | |||
offset += one_buffer; | |||
++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); | |||
} | |||
@@ -401,7 +411,7 @@ jack_resize_port_segment (jack_engine_t *engine, | |||
event.type = AttachPortSegment; | |||
strcpy (event.x.shm_name, port_type->shm_info.shm_name); | |||
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); | |||
} | |||
@@ -2025,8 +2035,8 @@ jack_engine_new (int realtime, int rtpriority, int verbose, int client_timeout) | |||
&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; | |||
/* the port type id is index into port_types array */ | |||
engine->control->port_types[i].ptype_id = i; | |||
/* be sure to initialize mutex correctly */ | |||
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), | |||
client->subgraph_start_fd, | |||
client->subgraph_wait_fd); | |||
for(m = 0, portnode = client->ports; portnode; | |||
portnode = jack_slist_next (portnode)) { | |||
port = (jack_port_internal_t *) portnode->data; | |||
@@ -3472,8 +3482,7 @@ jack_port_do_connect (jack_engine_t *engine, | |||
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 " | |||
"the same data type"); | |||
return -1; | |||
@@ -3508,7 +3517,8 @@ jack_port_do_connect (jack_engine_t *engine, | |||
} | |||
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; | |||
} | |||
} | |||
@@ -3524,11 +3534,11 @@ jack_port_do_connect (jack_engine_t *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" | |||
" type [%s]", | |||
dstport->shared->type_info.type_name); | |||
" type [%s]", port_type->type_name); | |||
free (connection); | |||
jack_unlock_graph (engine); | |||
return -1; | |||
@@ -3900,8 +3910,7 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req) | |||
shared = &engine->control->ports[port_id]; | |||
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->flags = req->x.port_info.flags; | |||
shared->latency = 0; | |||
@@ -202,11 +202,9 @@ jack_client_invalidate_port_buffers (jack_client_t *client) | |||
port = (jack_port_t *) node->data; | |||
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; | |||
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]) { | |||
regcomp (&type_regex, type_name_pattern, REG_EXTENDED|REG_NOSUB); | |||
regcomp (&type_regex, type_name_pattern, | |||
REG_EXTENDED|REG_NOSUB); | |||
} | |||
psp = engine->ports; | |||
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++) { | |||
matching = 1; | |||
@@ -1558,7 +1559,10 @@ jack_get_ports (jack_client_t *client, | |||
} | |||
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; | |||
} | |||
} | |||
@@ -10,9 +10,15 @@ struct _jack_client { | |||
int pollmax; | |||
int graph_next_fd; | |||
int request_fd; | |||
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; | |||
pthread_t thread; | |||
char fifo_prefix[PATH_MAX+1]; | |||
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_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)); | |||
port->client_segment_base = 0; | |||
port->mix_buffer = NULL; | |||
port->client_segment_base = NULL; | |||
port->shared = shared; | |||
port->type_info = &client->engine->port_types[ptid]; | |||
pthread_mutex_init (&port->connection_lock, NULL); | |||
port->connections = 0; | |||
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 | |||
* 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->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 | |||
are changed. | |||
*/ | |||
port->client_segment_base = client->port_segment[ptid].address; | |||
port->client_segment_base = | |||
(void *) &client->port_segment[ptid].address; | |||
return port; | |||
} | |||
@@ -371,7 +374,7 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes) | |||
if (port->tied) { | |||
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 | |||
@@ -394,28 +397,20 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t 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 ( | |||
port->shared->type_info.buffer_scale_factor | |||
port->type_info->buffer_scale_factor | |||
* sizeof (jack_default_audio_sample_t) | |||
* nframes); | |||
port->client_segment_base = 0; | |||
} | |||
port->fptr.mixdown (port, nframes); | |||
return (jack_default_audio_sample_t *) port->shared->offset; | |||
return (jack_default_audio_sample_t *) port->mix_buffer; | |||
} | |||
int | |||
@@ -565,7 +560,7 @@ jack_port_flags (const jack_port_t *port) | |||
const char * | |||
jack_port_type (const jack_port_t *port) | |||
{ | |||
return port->shared->type_info.type_name; | |||
return port->type_info->type_name; | |||
} | |||
int | |||
@@ -604,7 +599,8 @@ jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes) | |||
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. | |||
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 | |||
@@ -615,9 +611,9 @@ jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes) | |||
node = port->connections; | |||
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); | |||
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; | |||
dst = buffer; | |||
src = jack_port_buffer (input); | |||
src = jack_output_port_buffer (input); | |||
while (n--) { | |||
*dst++ += *src++; | |||