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++; | |||