| 
							- /*
 -     Copyright (C) 2001 Paul Davis
 -     
 -     This program is free software; you can redistribute it and/or modify
 -     it under the terms of the GNU General Public License as published by
 -     the Free Software Foundation; either version 2 of the License, or
 -     (at your option) any later version.
 - 
 -     This program is distributed in the hope that it will be useful,
 -     but WITHOUT ANY WARRANTY; without even the implied warranty of
 -     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -     GNU General Public License for more details.
 - 
 -     You should have received a copy of the GNU General Public License
 -     along with this program; if not, write to the Free Software
 -     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 - 
 -     $Id$
 - */
 - 
 - #include <unistd.h>
 - #include <sys/socket.h>
 - #include <sys/poll.h>
 - #include <sys/un.h>
 - #include <sys/stat.h>
 - #include <errno.h>
 - #include <fcntl.h>
 - #include <sys/shm.h>
 - #include <stdio.h>
 - #include <stdarg.h>
 - #include <sys/ipc.h>
 - #include <signal.h>
 - #include <sys/types.h>
 - #include <string.h>
 - #include <limits.h>
 - #include <sys/mman.h>
 - 
 - #include <asm/msr.h>
 - 
 - #include <jack/internal.h>
 - #include <jack/engine.h>
 - #include <jack/driver.h>
 - 
 - typedef struct {
 - 
 -     jack_port_internal_t *source;
 -     jack_port_internal_t *destination;
 - 
 - } jack_connection_internal_t;
 - 
 - typedef struct _jack_client_internal {
 - 
 -     jack_client_control_t *control;
 - 
 -     int      request_fd;
 -     int      event_fd;
 -     int      subgraph_start_fd;
 -     int      subgraph_wait_fd;
 -     GSList  *ports;    /* protected by engine->graph_lock */
 -     GSList  *fed_by;   /* protected by engine->graph_lock */
 -     int      shm_id;
 -     int      shm_key;
 -     unsigned long rank;
 -     struct _jack_client_internal *next_client; /* not a linked list! */
 -     dlhandle handle;
 -     
 - } jack_client_internal_t;
 - 
 - static int                    jack_port_assign_buffer (jack_engine_t *, jack_port_internal_t *);
 - static jack_port_internal_t *jack_get_port_by_name (jack_engine_t *, const char *name);
 - 
 - static void jack_client_delete (jack_engine_t *, jack_client_internal_t *);
 - static void jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client);
 - 
 - static jack_client_internal_t *jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_request_t *);
 - static jack_client_internal_t *jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id);
 - 
 - static void jack_sort_graph (jack_engine_t *engine, int take_lock);
 - static int  jack_rechain_graph (jack_engine_t *engine, int take_lock);
 - static int  jack_get_fifo_fd (jack_engine_t *engine, int which_fifo);
 - static int  jack_create_fifo (jack_engine_t *engine, int which_fifo);
 - static int  jack_port_do_connect (jack_engine_t *engine, const char *source_port, const char *destination_port);
 - static int  jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, const char *destination_port);
 - 
 - static int  jack_port_do_unregister (jack_engine_t *engine, jack_request_t *);
 - static int  jack_port_do_register (jack_engine_t *engine, jack_request_t *);
 - static void jack_port_release (jack_engine_t *engine, jack_port_internal_t *);
 - static void jack_port_clear_connections (jack_engine_t *engine, jack_port_internal_t *port);
 - static int  jack_port_disconnect_internal (jack_engine_t *engine, jack_port_internal_t *src, 
 - 					    jack_port_internal_t *dst, int sort_graph);
 - 
 - static void jack_port_registration_notify (jack_engine_t *, jack_port_id_t, int);
 - static int  jack_send_connection_notification (jack_engine_t *, jack_client_id_t, jack_port_id_t, jack_port_id_t, int);
 - static int  jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *);
 - 
 - static void jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes);
 - 
 - /* This is a disgusting kludge to work around issues with shmat.
 -    A more robust solution is needed.
 - */
 - 
 - static char *top_end_of_unmapped_memory = (char *) (1048576 * 1536); /* 1.5GB */
 - static char *low_end_of_unmapped_memory = (char *) (1048576 * 1024); /* 1GB */
 - 
 - static char *
 - fixed_shmat (int shmid, char *shmaddr, int shmflg, size_t size)
 - {
 - 	char *addr;
 - 	char *attempt;
 - 
 - 	if (shmaddr != 0) {
 - 		return shmat (shmid, shmaddr, shmflg);
 - 	}
 - 
 - 	attempt = (char *) (top_end_of_unmapped_memory - size);
 - 
 - 	while (attempt > low_end_of_unmapped_memory) {
 - 		if ((addr = (char *) shmat (shmid, attempt, shmflg|SHM_RND)) != (char *) -1) {
 - 			top_end_of_unmapped_memory = addr;
 - 			return addr;
 - 		}
 - 		attempt -= size;
 - 	}
 - 	return (char *) -1;
 - }
 - 
 - jack_port_type_info_t builtin_port_types[] = {
 - 	{ JACK_DEFAULT_AUDIO_TYPE, jack_audio_port_mixdown, 1 },
 - 	{ 0, NULL }
 - };
 - 
 - static inline int 
 - jack_client_is_inprocess (jack_client_internal_t *client)
 - {
 - 	return (client->control->type == ClientDynamic) || (client->control->type == ClientDriver);
 - }
 - 
 - static
 - void shm_destroy (int status, void *arg)
 - 
 - {
 - 	int shm_id = (int) arg;
 - 	shmctl (shm_id, IPC_RMID, 0);
 - }
 - 
 - static 
 - void unlink_path (int status, void *arg)
 - {
 - 	char *path = (char *) arg;
 - 	unlink (path);
 - 	free (arg);
 - }
 - 
 - static int
 - make_sockets (int fd[2])
 - {
 - 	struct sockaddr_un addr;
 - 	int i;
 - 
 - 	/* First, the master server socket */
 - 
 - 	if ((fd[0] = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
 - 		jack_error ("cannot create server socket (%s)", strerror (errno));
 - 		return -1;
 - 	}
 - 
 - 	addr.sun_family = AF_UNIX;
 - 	for (i = 0; i < 999; i++) {
 - 		snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "/tmp/jack_%d", i);
 - 		if (access (addr.sun_path, F_OK) != 0) {
 - 			break;
 - 		}
 - 	}
 - 
 - 	if (i == 999) {
 - 		jack_error ("all possible server socket names in use!!!");
 - 		close (fd[0]);
 - 		return -1;
 - 	}
 - 
 - 	on_exit (unlink_path, (void *) strdup (addr.sun_path));
 - 
 - 	if (bind (fd[0], (struct sockaddr *) &addr, sizeof (addr)) < 0) {
 - 		jack_error ("cannot bind server to socket (%s)", strerror (errno));
 - 		close (fd[0]);
 - 		return -1;
 - 	}
 - 
 - 	if (listen (fd[0], 1) < 0) {
 - 		jack_error ("cannot enable listen on server socket (%s)", strerror (errno));
 - 		close (fd[0]);
 - 		return -1;
 - 	}
 - 
 - 	/* Now the client/server event ack server socket */
 - 
 - 	if ((fd[1] = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
 - 		jack_error ("cannot create event ACK socket (%s)", strerror (errno));
 - 		close (fd[0]);
 - 		return -1;
 - 	}
 - 
 - 	addr.sun_family = AF_UNIX;
 - 	for (i = 0; i < 999; i++) {
 - 		snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "/tmp/jack_ack_%d", i);
 - 		if (access (addr.sun_path, F_OK) != 0) {
 - 			break;
 - 		}
 - 	}
 - 
 - 	if (i == 999) {
 - 		jack_error ("all possible server ACK socket names in use!!!");
 - 		close (fd[0]);
 - 		close (fd[1]);
 - 		return -1;
 - 	}
 - 
 - 	on_exit (unlink_path, (void *) strdup (addr.sun_path));
 - 
 - 	if (bind (fd[1], (struct sockaddr *) &addr, sizeof (addr)) < 0) {
 - 		jack_error ("cannot bind server to socket (%s)", strerror (errno));
 - 		close (fd[0]);
 - 		close (fd[1]);
 - 		return -1;
 - 	}
 - 
 - 	if (listen (fd[1], 1) < 0) {
 - 		jack_error ("cannot enable listen on server socket (%s)", strerror (errno));
 - 		close (fd[0]);
 - 		close (fd[1]);
 - 		return -1;
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - static void
 - jack_cleanup_clients (jack_engine_t *engine)
 - 
 - {
 - 	jack_client_control_t *ctl;
 - 	jack_client_internal_t *client;
 - 	GSList *node;
 - 	GSList *remove = 0;
 - 	static int x = 0;
 - 
 - 	x++;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock); 
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		
 - 		client = (jack_client_internal_t *) node->data;
 - 		ctl = client->control;
 - 		
 - 		printf ("client %s state = %d\n", ctl->name, ctl->state);
 - 		
 - 		if (ctl->state > JACK_CLIENT_STATE_NOT_TRIGGERED) {
 - 			remove = g_slist_prepend (remove, node->data);
 - 			printf ("%d: removing failed client %s\n", x, ctl->name);
 - 		}
 - 	}
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 	
 - 	if (remove) {
 - 		for (node = remove; node; node = g_slist_next (node)) {
 - 			jack_remove_client (engine, (jack_client_internal_t *) node->data);
 - 		}
 - 		g_slist_free (remove);
 - 	}
 - }	
 - 
 - static int
 - jack_add_port_segment (jack_engine_t *engine, unsigned long nports)
 - 
 - {
 - 	jack_port_segment_info_t *si;
 - 	key_t key;
 - 	int id;
 - 	char *addr;
 - 	int offset;
 - 	size_t size;
 - 	size_t step;
 - 
 - 	key = random();
 - 	size = nports * sizeof (sample_t) * engine->control->buffer_size;
 - 
 - 	if ((id = shmget (key, size, IPC_CREAT|0666)) < 0) {
 - 		jack_error ("cannot create new port segment of %d bytes, key = 0x%x (%s)", size, key, strerror (errno));
 - 		return -1;
 - 	}
 - 	
 - 	if ((addr = fixed_shmat (id, 0, 0, size)) == (char *) -1) {
 - 		jack_error ("cannot attach new port segment (%s)", strerror (errno));
 - 		shmctl (id, IPC_RMID, 0);
 - 		return -1;
 - 	}
 - 		
 - 	on_exit (shm_destroy, (void *) id);
 - 		
 - 	si = (jack_port_segment_info_t *) malloc (sizeof (jack_port_segment_info_t));
 - 	si->shm_key = key;
 - 	si->address = addr;
 - 
 - 	engine->port_segments = g_slist_prepend (engine->port_segments, si);
 - 	engine->port_segment_key = key; /* XXX fix me */
 - 	engine->port_segment_address = addr; /* XXX fix me */
 - 
 - 	pthread_mutex_lock (&engine->buffer_lock);
 - 
 - 	offset = 0;
 - 
 - 	step = engine->control->buffer_size * sizeof (sample_t);
 - 
 - 	while (offset < size) {
 - 		jack_port_buffer_info_t *bi;
 - 
 - 		bi = (jack_port_buffer_info_t *) malloc (sizeof (jack_port_buffer_info_t));
 - 		bi->shm_key = key;
 - 		bi->offset = offset;
 - 
 - 		/* we append because we want the list to be in memory-address order */
 - 
 - 		engine->port_buffer_freelist = g_slist_append (engine->port_buffer_freelist, bi);
 - 
 - 		offset += step;
 - 	}
 - 
 - 	/* convert the first chunk of the segment into a zero-filled area */
 - 
 - 	if (engine->silent_buffer == 0) {
 - 		engine->silent_buffer = (jack_port_buffer_info_t *) engine->port_buffer_freelist->data;
 - 
 - 		engine->port_buffer_freelist = g_slist_remove_link (engine->port_buffer_freelist, engine->port_buffer_freelist);
 - 
 - 		memset (engine->port_segment_address + engine->silent_buffer->offset, 0, 
 - 			sizeof (sample_t) * engine->control->buffer_size);
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->buffer_lock);
 - 
 - 	/* XXX notify all clients of new segment */
 - 
 - 	return 0;
 - }
 - 
 - static int
 - jack_set_buffer_size (jack_engine_t *engine, nframes_t nframes)
 - {
 - 	/* XXX this is not really right, since it only works for
 - 	   audio ports.
 - 	*/
 - 
 - 	engine->control->buffer_size = nframes;
 - 	jack_add_port_segment (engine, engine->control->port_max);
 - 	return 0;
 - }
 - 
 - static int
 - jack_set_sample_rate (jack_engine_t *engine, nframes_t nframes)
 - 
 - {
 - 	engine->control->sample_rate = nframes;
 - 	return 0;
 - }
 - 
 - static int
 - jack_process (jack_engine_t *engine, nframes_t nframes)
 - {
 - 	int err = 0;
 - 	jack_client_internal_t *client;
 - 	jack_client_control_t *ctl;
 - 	GSList *node;
 - 	struct pollfd pollfd[1];
 - 	char c;
 - 
 - 	unsigned long then, now;
 - //	rdtscl (then);
 - 
 - 	if (pthread_mutex_trylock (&engine->graph_lock) != 0) {
 - 		return 0;
 - 	}
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		ctl = ((jack_client_internal_t *) node->data)->control;
 - 		ctl->state = JACK_CLIENT_STATE_NOT_TRIGGERED;
 - 		ctl->nframes = nframes;
 - 	}
 - 
 - 	if (engine->timebase_client) {
 - 		engine->control->frame_time = engine->timebase_client->control->frame_time;
 - 	} 
 - 
 - 	for (node = engine->clients; err == 0 && node; ) {
 - 
 - 		client = (jack_client_internal_t *) node->data;
 - 
 - 		if (!client->control->active) {
 - 			node = g_slist_next (node);
 - 			continue;
 - 		}
 - 
 - 		ctl = client->control;
 - 
 - 		if (jack_client_is_inprocess (client)) {
 - 
 - 			/* in-process client ("plugin") */
 - 
 - 			if (ctl->process (nframes, ctl->process_arg) == 0) {
 - 				ctl->state = JACK_CLIENT_STATE_FINISHED;
 - 			} else {
 - 				jack_error ("in-process client %s failed", client->control->name);
 - 				ctl->state = JACK_CLIENT_STATE_TRIGGERED;
 - 				err++;
 - 				break;
 - 			}
 - 
 - 			node = g_slist_next (node);
 - 
 - 		} else {
 - 
 - 			/* out of process subgraph */
 - 
 - 			if (write (client->subgraph_start_fd, &c, sizeof (c)) != sizeof (c)) {
 - 				jack_error ("cannot initiate graph processing (%s)", strerror (errno));
 - 				err++;
 - 				break;
 - 			} 
 - 
 - 			/* now wait for the result. use poll instead of read so that we 
 - 			   can timeout effectively.
 - 			 */
 - 
 - 			pollfd[0].fd = client->subgraph_wait_fd;
 - 			pollfd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
 - 
 - 			rdtscl (then);
 - 			if (poll (pollfd, 1, engine->driver->period_interval) < 0) {
 - 				jack_error ("engine cannot poll for graph completion (%s)", strerror (errno));
 - 				err++;
 - 				break;
 - 			}
 - 			rdtscl (now);
 - 			
 - 			if (pollfd[0].revents == 0) {
 - 				jack_error ("subgraph starting at %s timed out (state = %d) (time = %f usecs)", 
 - 					     client->control->name, client->control->state,
 - 					    ((float)(now - then))/450.0f);
 - 				err++;
 - 				break;
 - 			} else if (pollfd[0].revents & ~POLLIN) {
 - 				jack_error ("error/hangup on graph wait fd");
 - 				err++;
 - 				break;
 - 			} else {
 - 				if (read (client->subgraph_wait_fd, &c, sizeof (c)) != sizeof (c)) {
 - 					jack_error ("cannot clean up byte from graph wait fd (%s)", strerror (errno));
 - 					err++;
 - 					break;
 - 				}
 - 			}
 - 
 - 			/* Move to next in-process client (or end of client list) */
 - 
 - 			while (node) {
 - 				if (jack_client_is_inprocess (((jack_client_internal_t *) node->data))) {
 - 					break;
 - 				}
 - 				node = g_slist_next (node);
 - 			}
 - 		}
 - 	}
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 	
 - 	if (err) {
 - 		jack_cleanup_clients (engine);
 - 	} 
 - 
 - //	rdtscl (now);
 - //	printf ("engine cycle time: %.6f usecs\n", ((float) (now - then)) / 450.00f);
 - 	return 0;
 - }
 - 
 - static int
 - jack_load_client (jack_engine_t *engine, jack_client_internal_t *client, const char *path_to_so)
 - {
 - 	const char *errstr;
 - 	dlhandle handle;
 - 
 - 	handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL);
 - 	
 - 	if (handle == 0) {
 - 		if ((errstr = dlerror ()) != 0) {
 - 			jack_error ("can't load \"%s\": %s", path_to_so, errstr);
 - 		} else {
 - 			jack_error ("bizarre error loading driver shared object %s", path_to_so);
 - 		}
 - 		return -1;
 - 	}
 - 
 - 	client->handle = handle;
 - 
 - #if 0
 - 	initialize = dlsym (handle, "client_initialize");
 - 
 - 	if ((errstr = dlerror ()) != 0) {
 - 		jack_error ("no initialize function in shared object %s\n", path_to_so);
 - 		dlclose (handle);
 - 		return -1;
 - 	}
 - 
 - 	finish = dlsym (handle, "client_finish");
 - 
 - 	if ((errstr = dlerror ()) != 0) {
 - 		jack_error ("no finish function in in shared driver object %s", path_to_so);
 - 		dlclose (handle);
 - 		return -1;
 - 	}
 - #endif
 - 
 - 	return 0;
 - 
 - }
 - 
 - static void
 - jack_client_unload (jack_client_internal_t *client)
 - {
 - 	if (client->handle) {
 - //		client->finish (client);
 - 		dlclose (client->handle);
 - 	}
 - }
 - 
 - static int
 - handle_new_client (jack_engine_t *engine, int client_fd)
 - 
 - {
 - 	jack_client_internal_t *client;
 - 	jack_client_connect_request_t req;
 - 	jack_client_connect_result_t res;
 - 
 - 	if (read (client_fd, &req, sizeof (req)) != sizeof (req)) {
 - 		jack_error ("cannot read connection request from client");
 - 		return -1;
 - 	}
 - 
 - 	res.status = 0;
 - 	
 - 	if ((client = jack_client_internal_new (engine, client_fd, &req)) == 0) {
 - 		jack_error ("cannot create new client object");
 - 		return -1;
 - 	}
 - 
 - 	printf ("new client: %s, type %d @ %p\n", client->control->name, req.type, client->control);
 - 
 - 	res.status = 0;
 - 	res.client_key = client->shm_key;
 - 	res.control_key = engine->control_key;
 - 	res.port_segment_key = engine->port_segment_key;
 - 	res.port_segment_address = engine->port_segment_address;
 - 	res.realtime = engine->control->real_time;
 - 	res.realtime_priority = engine->rtpriority - 1;
 - 
 - 	if (jack_client_is_inprocess (client)) {
 - 
 - 		res.client_control = client->control;
 - 		res.engine_control = engine->control;
 - 
 - 	} else {
 - 		strcpy (res.fifo_prefix, engine->fifo_prefix);
 - 	}
 - 
 - 	res.status = 0;
 - 
 - 	if (write (client->request_fd, &res, sizeof (res)) != sizeof (res)) {
 - 		jack_error ("cannot write connection response to client");
 - 		jack_client_delete (engine, client);
 - 		return -1;
 - 	}
 - 
 - 	if (res.status) {
 - 		return res.status;
 - 	}
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	engine->clients = g_slist_prepend (engine->clients, client);
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	if (client->control->type != ClientDynamic) {
 - 		if (engine->pfd_max >= engine->pfd_size) {
 - 			engine->pfd = (struct pollfd *) realloc (engine->pfd, sizeof (struct pollfd) * engine->pfd_size + 16);
 - 			engine->pfd_size += 16;
 - 		}
 - 		
 - 		engine->pfd[engine->pfd_max].fd = client->request_fd;
 - 		engine->pfd[engine->pfd_max].events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL;
 - 		engine->pfd_max++;
 - 	}
 - 
 - 
 - 	return 0;
 - }
 - 
 - static int
 - handle_client_ack_connection (jack_engine_t *engine, int client_fd)
 - 
 - {
 - 	jack_client_internal_t *client;
 - 	jack_client_connect_ack_request_t req;
 - 	jack_client_connect_ack_result_t res;
 - 
 - 	if (read (client_fd, &req, sizeof (req)) != sizeof (req)) {
 - 		jack_error ("cannot read ACK connection request from client");
 - 		return -1;
 - 	}
 - 	
 - 	if ((client = jack_client_internal_by_id (engine, req.client_id)) == NULL) {
 - 		jack_error ("unknown client ID in ACK connection request");
 - 		return -1;
 - 	}
 - 
 - 	fprintf (stderr, "client %s is on event fd %d\n", client->control->name, client_fd);
 - 
 - 	client->event_fd = client_fd;
 - 
 - 	res.status = 0;
 - 
 - 	if (write (client->event_fd, &res, sizeof (res)) != sizeof (res)) {
 - 		jack_error ("cannot write ACK connection response to client");
 - 		return -1;
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - static int
 - jack_client_drop (jack_engine_t *engine, jack_client_id_t id)
 - 
 - {
 - 	jack_client_internal_t *client;
 - 
 - 	if ((client = jack_client_internal_by_id (engine, id)) == 0) {
 - 		jack_error ("unknown client ID in DropClient request");
 - 		return -1;
 - 	}
 - 
 - 	jack_remove_client (engine, client);
 - 	return 0;
 - }
 - 
 - #if 0
 - static int
 - jack_client_has_connections (jack_client_internal_t *client)
 - 
 - {
 - 	GSList *node;
 - 
 - 	for (node = client->ports; node; node = g_slist_next (node)) {
 - 		if (((jack_port_internal_t *) node->data)->connections) {
 - 			return TRUE;
 - 		}
 - 	}
 - 
 - 	return FALSE;
 - }
 - #endif
 - 
 - static int
 - jack_client_activate (jack_engine_t *engine, jack_client_id_t id)
 - 
 - {
 - 	jack_client_internal_t *client;
 - 	GSList *node;
 - 	int ret = -1;
 - 	
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 
 - 		if (((jack_client_internal_t *) node->data)->control->id == id) {
 - 		       
 - 			client = (jack_client_internal_t *) node->data;
 - 
 - 			if (!jack_client_is_inprocess (client)) {
 - 				jack_create_fifo (engine, ++engine->external_client_cnt);
 - 			} 
 - 
 - 			client->control->active = TRUE;
 - 
 - 			jack_rechain_graph (engine, FALSE);
 - 
 - 			ret = 0;
 - 			break;
 - 		}
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 	return ret;
 - }	
 - 
 - static int
 - jack_client_do_deactivate (jack_engine_t *engine, jack_client_internal_t *client)
 - 
 - {
 - 	/* called must hold engine->graph_lock and must have checked for and/or
 - 	   cleared all connections held by client.
 - 	*/
 - 	
 - 	client->control->active = FALSE;
 - 	
 - 	if (!jack_client_is_inprocess (client)) {
 - 		engine->external_client_cnt--;
 - 	}
 - 	
 - 	jack_sort_graph (engine, FALSE);
 - 	return 0;
 - }
 - 
 - static void
 - jack_client_disconnect (jack_engine_t *engine, jack_client_internal_t *client)
 - 
 - {
 - 	GSList *node;
 - 	jack_port_internal_t *port;
 - 
 - 	/* call tree **** MUST HOLD *** engine->graph_lock */
 - 
 - 	for (node = client->ports; node; node = g_slist_next (node)) {
 - 		port = (jack_port_internal_t *) node->data;
 - 		jack_port_clear_connections (engine, port);
 - 		jack_port_release (engine, port);
 - 	}
 - 
 - 	g_slist_free (client->ports);
 - 	g_slist_free (client->fed_by);
 - 	client->fed_by = 0;
 - 	client->ports = 0;
 - }			
 - 
 - static int
 - jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id, int to_wait)
 - 
 - {
 - 	GSList *node;
 - 	int ret = -1;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 
 - 		jack_client_internal_t *client = (jack_client_internal_t *) node->data;
 - 
 - 		if (client->control->id == id) {
 - 			
 - 			if (client == engine->timebase_client) {
 - 				engine->timebase_client = 0;
 - 				engine->control->frame_time = 0;
 - 			}
 - 			
 - 			jack_client_disconnect (engine, client);
 - 			ret = jack_client_do_deactivate (engine, node->data);
 - 			break;
 - 		}
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	return ret;
 - }	
 - 
 - static int
 - jack_set_timebase (jack_engine_t *engine, jack_client_id_t client)
 - {
 - 	int ret = -1;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	if ((engine->timebase_client = jack_client_internal_by_id (engine, client)) != 0) {
 - 		engine->control->frame_time = engine->timebase_client->control->frame_time;
 - 		ret = 0;
 - 	}
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 	return ret;
 - }
 - 
 - static int
 - handle_client_jack_error (jack_engine_t *engine, int fd)
 - 
 - {
 - 	jack_client_internal_t *client = 0;
 - 	GSList *node;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		if (((jack_client_internal_t *) node->data)->request_fd == fd) {
 - 			client = (jack_client_internal_t *) node->data;
 - 			break;
 - 		}
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	if (client == 0) {
 - 		jack_error ("i/o error on unknown client fd %d", fd);
 - 		return -1;
 - 	} 
 - 
 - 	jack_remove_client (engine, client);
 - 	return 0;
 - }
 - 
 - static int
 - jack_client_port_monitor (jack_engine_t *engine, jack_port_id_t port_id, int onoff)
 - 
 - {
 - 	jack_port_shared_t *port;
 - 	jack_client_internal_t *client = NULL;
 - 	jack_event_t event;
 - 	
 - 	if (port_id < 0 || port_id >= engine->port_max) {
 - 		jack_error ("illegal port ID in port monitor request");
 - 		return -1;
 - 	}
 - 
 - 	port = &engine->control->ports[port_id];
 - 
 - 	if (!(port->flags & JackPortCanMonitor)) {
 - 		jack_error ("port monitor request made on a port (%s) that doesn't support monitoring",
 - 			     port->name);
 - 		return -1;
 - 	}
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	if ((client = jack_client_internal_by_id (engine, port->client_id)) == NULL) {
 - 		jack_error ("unknown client owns port %d!!", port_id);
 - 		pthread_mutex_unlock (&engine->graph_lock);
 - 		return -1;
 - 	}
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	event.type = (onoff ? PortMonitor : PortUnMonitor);
 - 	event.x.port_id = port_id;
 - 
 - 	return jack_deliver_event (engine, client, &event);
 - }
 - 
 - static int
 - handle_client_io (jack_engine_t *engine, int fd)
 - 
 - {
 - 	jack_request_t req;
 - 	jack_client_internal_t *client = 0;
 - 	int reply_fd;
 - 	GSList *node;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		if (((jack_client_internal_t *) node->data)->request_fd == fd) {
 - 			client = (jack_client_internal_t *) node->data;
 - 			break;
 - 		}
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	if (client == 0) {
 - 		jack_error ("client input on unknown fd %d!", fd);
 - 		return -1;
 - 	}
 - 
 - 	if (read (client->request_fd, &req, sizeof (req)) < sizeof (req)) {
 - 		jack_error ("cannot read request from client");
 - 		jack_remove_client (engine, client);
 - 		return -1;
 - 	}
 - 
 - 	reply_fd = client->request_fd;
 - 
 - 	switch (req.type) {
 - 	case RegisterPort:
 - 		req.status = jack_port_do_register (engine, &req);
 - 		break;
 - 
 - 	case UnRegisterPort:
 - 		req.status = jack_port_do_unregister (engine, &req);
 - 		break;
 - 
 - 	case ConnectPorts:
 - 		req.status = jack_port_do_connect (engine, req.x.connect.source_port, req.x.connect.destination_port);
 - 		break;
 - 
 - 	case DisconnectPorts:
 - 		req.status = jack_port_do_disconnect (engine, req.x.connect.source_port, req.x.connect.destination_port);
 - 		break;
 - 
 - 	case DropClient:
 - 		req.status = jack_client_drop (engine, req.x.client_id);
 - 		reply_fd = -1;
 - 		break;
 - 
 - 	case ActivateClient:
 - 		req.status = jack_client_activate (engine, req.x.client_id);
 - 		break;
 - 
 - 	case DeactivateClient:
 - 		req.status = jack_client_deactivate (engine, req.x.client_id, TRUE);
 - 		break;
 - 
 - 	case SetTimeBaseClient:
 - 		req.status = jack_set_timebase (engine, req.x.client_id);
 - 		break;
 - 
 - 	case RequestPortMonitor:
 - 		req.status = jack_client_port_monitor (engine, req.x.port_info.port_id, TRUE);
 - 		break;
 - 
 - 	case RequestPortUnMonitor:
 - 		req.status = jack_client_port_monitor (engine, req.x.port_info.port_id, FALSE);
 - 		break;
 - 	}
 - 
 - 	if (reply_fd >= 0) {
 - 		if (write (reply_fd, &req, sizeof (req)) < sizeof (req)) {
 - 			jack_error ("cannot write request result to client");
 - 			return -1;
 - 		}
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - static void *
 - jack_server_thread (void *arg)
 - 
 - {
 - 	jack_engine_t *engine = (jack_engine_t *) arg;
 - 	struct sockaddr_un client_addr;
 - 	socklen_t client_addrlen;
 - 	struct pollfd *pfd;
 - 	int client_socket;
 - 	int done = 0;
 - 	int i;
 - 	int max;
 - 	
 - 	pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 - 
 - 	engine->pfd[0].fd = engine->fds[0];
 - 	engine->pfd[0].events = POLLIN|POLLERR;
 - 	engine->pfd[1].fd = engine->fds[1];
 - 	engine->pfd[1].events = POLLIN|POLLERR;
 - 	engine->pfd_max = 2;
 - 
 - 	while (!done) {
 - 
 - 		/* XXX race here with new external clients
 - 		   causing engine->pfd to be reallocated.
 - 		   I don't know how to solve this
 - 		   short of copying the entire
 - 		   contents of the pfd struct. Ick.
 - 		*/
 - 
 - 		max = engine->pfd_max;
 - 		pfd = engine->pfd;
 - 	
 - 		if (poll (pfd, max, 10000) < 0) {
 - 			if (errno == EINTR) {
 - 				continue;
 - 			}
 - 			jack_error ("poll failed (%s)", strerror (errno));
 - 			break;
 - 		}
 - 
 - 		/* check the master server socket */
 - 
 - 		if (pfd[0].revents & POLLERR) {
 - 			jack_error ("error on server socket");
 - 			break;
 - 		}
 - 
 - 		if (pfd[0].revents & POLLIN) {
 - 
 - 			memset (&client_addr, 0, sizeof (client_addr));
 - 			client_addrlen = sizeof (client_addr);
 - 
 - 			if ((client_socket = accept (engine->fds[0], (struct sockaddr *) &client_addr, &client_addrlen)) < 0) {
 - 				jack_error ("cannot accept new connection (%s)", strerror (errno));
 - 			} else if (handle_new_client (engine, client_socket) < 0) {
 - 				jack_error ("cannot complete new client connection process");
 - 				close (client_socket);
 - 			}
 - 		}
 - 
 - 		/* check the ACK server socket */
 - 
 - 		if (pfd[1].revents & POLLERR) {
 - 			jack_error ("error on server ACK socket");
 - 			break;
 - 		}
 - 
 - 		if (pfd[1].revents & POLLIN) {
 - 
 - 			memset (&client_addr, 0, sizeof (client_addr));
 - 			client_addrlen = sizeof (client_addr);
 - 
 - 			if ((client_socket = accept (engine->fds[1], (struct sockaddr *) &client_addr, &client_addrlen)) < 0) {
 - 				jack_error ("cannot accept new ACK connection (%s)", strerror (errno));
 - 			} else if (handle_client_ack_connection (engine, client_socket)) {
 - 				jack_error ("cannot complete client ACK connection process");
 - 				close (client_socket);
 - 			}
 - 		}
 - 
 - 		/* check each client socket */
 - 
 - 		for (i = 2; i < max; i++) {
 - 			if (pfd[i].fd < 0) {
 - 				continue;
 - 			}
 - 
 - 			if (pfd[i].revents & ~POLLIN) {
 - 				handle_client_jack_error (engine, pfd[i].fd);
 - 			} else if (pfd[i].revents & POLLIN) {
 - 				if (handle_client_io (engine, pfd[i].fd)) {
 - 					jack_error ("bad hci\n");
 - 				}
 - 			}
 - 		}
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - static void
 - jack_start_server (jack_engine_t *engine)
 - 
 - {
 - 	pthread_create (&engine->server_thread, 0, &jack_server_thread, engine);
 - 	pthread_detach (engine->server_thread);
 - }
 - 
 - jack_engine_t *
 - jack_engine_new (int realtime, int rtpriority)
 - {
 - 	jack_engine_t *engine;
 - 	size_t control_size;
 - 	void *addr;
 - 	int i;
 - 
 - 	engine = (jack_engine_t *) malloc (sizeof (jack_engine_t));
 - 
 - 	engine->driver = 0;
 - 	engine->process = jack_process;
 - 	engine->set_sample_rate = jack_set_sample_rate;
 - 	engine->set_buffer_size = jack_set_buffer_size;
 - 
 - 	engine->next_client_id = 1;
 - 	engine->timebase_client = 0;
 - 	engine->port_max = 128;
 - 	engine->rtpriority = rtpriority;
 - 	engine->silent_buffer = 0;
 - 	engine->getthehelloutathere = FALSE;
 - 
 - 	pthread_mutex_init (&engine->graph_lock, 0);
 - 	pthread_mutex_init (&engine->buffer_lock, 0);
 - 	pthread_mutex_init (&engine->port_lock, 0);
 - 
 - 	engine->clients = 0;
 - 
 - 	engine->port_segments = 0;
 - 	engine->port_buffer_freelist = 0;
 - 
 - 	engine->pfd_size = 16;
 - 	engine->pfd_max = 0;
 - 	engine->pfd = (struct pollfd *) malloc (sizeof (struct pollfd) * engine->pfd_size);
 - 
 - 	engine->fifo_size = 16;
 - 	engine->fifo = (int *) malloc (sizeof (int) * engine->fifo_size);
 - 	for (i = 0; i < engine->fifo_size; i++) {
 - 		engine->fifo[i] = -1;
 - 	}
 - 
 - 	/* Build a linked list of known port types. We use a list so that 
 - 	   we can easily manage other data types without messing with
 - 	   reallocation of arrays, etc.
 - 	*/
 - 
 - 	engine->port_types = NULL;
 - 	for (i = 0; builtin_port_types[i].type_name; i++) {
 - 		engine->port_types = g_slist_append (engine->port_types, &builtin_port_types[i]);
 - 	}
 - 
 - 	engine->external_client_cnt = 0;
 - 
 - 	srandom (time ((time_t *) 0));
 - 
 - 	engine->control_key = random();
 - 	control_size = sizeof (jack_control_t) + (sizeof (jack_port_shared_t) * engine->port_max);
 - 
 - 	if ((engine->control_shm_id = shmget (engine->control_key, control_size, IPC_CREAT|0644)) < 0) {
 - 		jack_error ("cannot create engine control shared memory segment (%s)", strerror (errno));
 - 		return 0;
 - 	}
 - 	
 - 	if ((addr = fixed_shmat (engine->control_shm_id, 0, 0, control_size)) == (void *) -1) {
 - 		jack_error ("cannot attach control shared memory segment (%s)", strerror (errno));
 - 		shmctl (engine->control_shm_id, IPC_RMID, 0);
 - 		return 0;
 - 	}
 - 
 - 	on_exit (shm_destroy, (void *) engine->control_shm_id);
 - 
 - 	engine->control = (jack_control_t *) addr;
 - 
 - 	/* Mark all ports as available */
 - 
 - 	for (i = 0; i < engine->port_max; i++) {
 - 		engine->control->ports[i].in_use = 0;
 - 		engine->control->ports[i].id = i;
 - 	}
 - 
 - 	/* allocate internal port structures so that we can keep
 - 	   track of port connections.
 - 	*/
 - 
 - 	engine->internal_ports = (jack_port_internal_t *) malloc (sizeof (jack_port_internal_t) * engine->port_max);
 - 
 - 	for (i = 0; i < engine->port_max; i++) {
 - 		engine->internal_ports[i].connections = 0;
 - 	}
 - 
 - 	if (make_sockets (engine->fds) < 0) {
 - 		jack_error ("cannot create server sockets");
 - 		return 0;
 - 	}
 - 
 - 	engine->control->port_max = engine->port_max;
 - 	engine->control->real_time = realtime;
 - 	engine->control->client_priority = engine->rtpriority - 1;
 -  
 - 	engine->control->sample_rate = 0;
 - 	engine->control->buffer_size = 0;
 - 	engine->control->frame_time = 0;
 - 
 - 	sprintf (engine->fifo_prefix, "/tmp/jack_fifo_%d", getpid());
 - 
 - 	jack_create_fifo (engine, 0);
 - 	jack_start_server (engine);
 - 
 - 	return engine;
 - }
 - 
 - static int
 - jack_become_real_time (pthread_t thread, int priority)
 - 
 - {
 - 	struct sched_param rtparam;
 - 	int x;
 - 
 - 	memset (&rtparam, 0, sizeof (rtparam));
 - 	rtparam.sched_priority = priority;
 - 
 - 	if ((x = pthread_setschedparam (thread, SCHED_FIFO, &rtparam)) != 0) {
 - 		jack_error ("cannot set thread to real-time priority (FIFO/%d) (%d: %s)", rtparam.sched_priority, x, strerror (errno));
 - 	}
 - 
 - 	if (mlockall (MCL_CURRENT | MCL_FUTURE) != 0) {
 - 	    jack_error ("cannot lock down memory for RT thread (%s)", strerror (errno));
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - void
 - cancel_cleanup1 (void *arg)
 - 
 - {
 - 	jack_engine_t *engine = (jack_engine_t *) arg;
 - 	printf ("audio thread cancelled or finished\n");
 - 	engine->driver->audio_stop (engine->driver);
 - }
 - 
 - void
 - cancel_cleanup2 (int status, void *arg)
 - 
 - {
 - 	jack_engine_t *engine = (jack_engine_t *) arg;
 - 	engine->driver->audio_stop (engine->driver);
 - 	engine->driver->finish (engine->driver);
 - }
 - 
 - static void *
 - jack_audio_thread (void *arg)
 - 
 - {
 - 	jack_engine_t *engine = (jack_engine_t *) arg;
 - 	jack_driver_t *driver = engine->driver;
 - //	unsigned long start, end;
 - 
 - 	if (engine->control->real_time) {
 - 		jack_become_real_time (pthread_self(), engine->rtpriority);
 - 	}
 - 
 - 	pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 - 	on_exit (cancel_cleanup2, engine);
 - 
 - 	if (driver->audio_start (driver)) {
 - 		jack_error ("cannot start driver");
 - 		pthread_exit (0);
 - 	}
 - 
 - 	while (1) {
 - //		start = end;
 - 		if (driver->wait (driver)) {
 - 			break;
 - 		}
 - //		rdtscl (end);
 - //		printf ("driver cycle time: %.6f usecs\n", ((float) (end - start)) / 450.00f);
 - 	}
 - 
 - 	pthread_exit (0);
 - }
 - 
 - int
 - jack_run (jack_engine_t *engine)
 - 
 - {
 - 	if (engine->driver == 0) {
 - 		jack_error ("engine driver not set; cannot start");
 - 		return -1;
 - 	}
 - 	return pthread_create (&engine->audio_thread, 0, jack_audio_thread, engine);
 - }
 - int
 - jack_wait (jack_engine_t *engine)
 - 
 - {
 - 	void *ret = 0;
 - 	int err;
 - 
 - 	if ((err = pthread_join (engine->audio_thread, &ret)) != 0)  {
 - 		switch (err) {
 - 		case EINVAL:
 - 			jack_error ("cannot join with audio thread (thread detached, or another thread is waiting)");
 - 			break;
 - 		case ESRCH:
 - 			jack_error ("cannot join with audio thread (thread no longer exists)");
 - 			break;
 - 		case EDEADLK:
 - 			jack_error ("programming error: jack_wait() called by audio thread");
 - 			break;
 - 		default:
 - 			jack_error ("cannot join with audio thread (%s)", strerror (errno));
 - 		}
 - 	}
 - 	return (int) ret;
 - }
 - 
 - int 
 - jack_engine_delete (jack_engine_t *engine)
 - 
 - {
 - 	pthread_cancel (engine->audio_thread);
 - 	return 0;
 - }
 - 
 - static jack_client_internal_t *
 - jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_request_t *req)
 - 
 - {
 - 	jack_client_internal_t *client;
 - 	key_t shm_key = 0;
 - 	int shm_id = 0;
 - 	void *addr = 0;
 - 
 - 	switch (req->type) {
 - 	case ClientDynamic:
 - 	case ClientDriver:
 - 		break;
 - 
 - 	case ClientOutOfProcess:
 - 
 - 		shm_key = random();
 - 		
 - 		if ((shm_id = shmget (shm_key, sizeof (jack_client_control_t), IPC_CREAT|0666)) < 0) {
 - 			jack_error ("cannot create client control block");
 - 			return 0;
 - 		}
 - 
 - 		if ((addr = fixed_shmat (shm_id, 0, 0, sizeof (jack_client_control_t))) == (void *) -1) {
 - 			jack_error ("cannot attach new client control block");
 - 			shmctl (shm_id, IPC_RMID, 0);
 - 			return 0;
 - 		}
 - 
 - 		break;
 - 	}
 - 
 - 	client = (jack_client_internal_t *) malloc (sizeof (jack_client_internal_t));
 - 
 - 	client->request_fd = fd;
 - 	client->event_fd = -1;
 - 	client->ports = 0;
 - 	client->fed_by = 0;
 - 	client->rank = UINT_MAX;
 - 	client->next_client = NULL;
 - 	client->handle = NULL;
 - 
 - 	if (req->type != ClientOutOfProcess) {
 - 		
 - 		client->control = (jack_client_control_t *) malloc (sizeof (jack_client_control_t));		
 - 
 - 	} else {
 - 
 - 		client->shm_id = shm_id;
 - 		client->shm_key = shm_key;
 - 		client->control = (jack_client_control_t *) addr;
 - 	}
 - 
 - 	client->control->type = req->type;
 - 	client->control->active = FALSE;
 - 	client->control->dead = FALSE;
 - 	client->control->id = engine->next_client_id++;
 - 	strcpy ((char *) client->control->name, req->name);
 - 
 - 	client->control->process = NULL;
 - 	client->control->process_arg = NULL;
 - 	client->control->bufsize = NULL;
 - 	client->control->bufsize_arg = NULL;
 - 	client->control->srate = NULL;
 - 	client->control->srate_arg = NULL;
 - 	client->control->port_register = NULL;
 - 	client->control->port_register_arg = NULL;
 - 	client->control->port_monitor = NULL;
 - 	client->control->port_monitor_arg = NULL;
 - 
 - 	if (req->type == ClientDynamic) {
 - 		if (jack_load_client (engine, client, req->object_path)) {
 - 			jack_error ("cannot dynamically load client from \"%s\"", req->object_path);
 - 			jack_client_delete (engine, client);
 - 			return 0;
 - 		}
 - 	}
 - 
 - 	return client;
 - }
 - 
 - static void
 - jack_port_clear_connections (jack_engine_t *engine, jack_port_internal_t *port)
 - {
 - 	GSList *node, *next;
 - 
 - 	for (node = port->connections; node; ) {
 - 		next = g_slist_next (node);
 - 		jack_port_disconnect_internal (engine, 
 - 						((jack_connection_internal_t *) node->data)->source,
 - 						((jack_connection_internal_t *) node->data)->destination, 
 - 						FALSE);
 - 		node = next;
 - 	}
 - 
 - 	g_slist_free (port->connections);
 - 	port->connections = 0;
 - }
 - 
 - 
 - static void
 - jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
 - {
 - 	GSList *node;
 - 	int i;
 - 
 - 	printf ("removing client %s\n", client->control->name);
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	
 - 	client->control->dead = TRUE;
 - 
 - 	if (client == engine->timebase_client) {
 - 		engine->timebase_client = 0;
 - 		engine->control->frame_time = 0;
 - 	}
 - 
 - 	jack_client_disconnect (engine, client);
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		if (((jack_client_internal_t *) node->data)->control->id == client->control->id) {
 - 			engine->clients = g_slist_remove_link (engine->clients, node);
 - 			g_slist_free_1 (node);
 - 			break;
 - 		}
 - 	}
 - 
 - 	jack_client_do_deactivate (engine, client);
 - 
 - 	/* rearrange the pollfd array so that things work right the 
 - 	   next time we go into poll(2).
 - 	*/
 - 
 - 	for (i = 0; i < engine->pfd_max; i++) {
 - 		if (engine->pfd[i].fd == client->request_fd) {
 - 			if (i+1 < engine->pfd_max) {
 - 				memmove (&engine->pfd[i], &engine->pfd[i+1], sizeof (struct pollfd) * (engine->pfd_max - i));
 - 			}
 - 			engine->pfd_max--;
 - 		}
 - 	}
 - 
 - 	close (client->event_fd);
 - 	close (client->request_fd);
 - 
 - 	jack_client_delete (engine, client);
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - }
 - 
 - static void
 - jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
 - 
 - {
 - 	jack_client_disconnect (engine, client);
 - 
 - 	if (jack_client_is_inprocess (client)) {
 - 		jack_client_unload (client);
 - 		free ((char *) client->control);
 - 	} else {
 - 		shmdt ((void *) client->control);
 - 	}
 - 
 - 	free (client);
 - }
 - 
 - jack_client_internal_t *
 - jack_client_by_name (jack_engine_t *engine, const char *name)
 - 
 - {
 - 	jack_client_internal_t *client = NULL;
 - 	GSList *node;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		if (strcmp ((const char *) ((jack_client_internal_t *) node->data)->control->name, name) == 0) {
 - 			client = (jack_client_internal_t *) node->data;
 - 			break;
 - 		}
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 	return client;
 - }
 - 
 - jack_client_internal_t *
 - jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id)
 - 
 - {
 - 	jack_client_internal_t *client = NULL;
 - 	GSList *node;
 - 
 - 	/* call tree ***MUST HOLD*** engine->graph_lock */
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		if (((jack_client_internal_t *) node->data)->control->id == id) {
 - 			client = (jack_client_internal_t *) node->data;
 - 			break;
 - 		}
 - 	}
 - 
 - 	return client;
 - }
 - 
 - static int
 - jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event)
 - {
 - 	char status;
 - 	
 - 	if (client->control->dead) {
 - 		return 0;
 - 	}
 - 
 - 	if (jack_client_is_inprocess (client)) {
 - 
 - 		switch (event->type) {
 - 		case PortConnected:
 - 		case PortDisconnected:
 - 			jack_client_handle_port_connection (client->control->private_internal_client, event);
 - 			break;
 - 
 - 		case GraphReordered:
 - 			jack_error ("reorder event delivered to internal client!");
 - 			break;
 - 
 - 		case BufferSizeChange:
 - 			if (client->control->bufsize) {
 - 				client->control->bufsize (event->x.n, client->control->bufsize_arg);
 - 			}
 - 			break;
 - 
 - 		case SampleRateChange:
 - 			if (client->control->srate) {
 - 				client->control->srate (event->x.n, client->control->bufsize_arg);
 - 			}
 - 			break;
 - 
 - 		case PortMonitor:
 - 			if (client->control->port_monitor) {
 - 				client->control->port_monitor (event->x.port_id, TRUE, client->control->port_monitor_arg);
 - 			}
 - 			break;
 - 
 - 		case PortUnMonitor:
 - 			if (client->control->port_monitor) {
 - 				client->control->port_monitor (event->x.port_id, FALSE, client->control->port_monitor_arg);
 - 			}
 - 			break;
 - 
 - 		default:
 - 			/* internal clients don't need to know */
 - 			break;
 - 		}
 - 
 - 	} else {
 - 		if (write (client->event_fd, event, sizeof (*event)) != sizeof (*event)) {
 - 			jack_error ("cannot send event to client [%s] (%s)", client->control->name, strerror (errno));
 - 			return -1;
 - 		}
 - 		
 - 		if (read (client->event_fd, &status, sizeof (status)) != sizeof (status)) {
 - 			jack_error ("cannot read event response from client [%s] (%s)", client->control->name, strerror (errno));
 - 			return -1;
 - 		}
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - int
 - jack_client_set_order (jack_engine_t *engine, jack_client_internal_t *client)
 - 
 - {
 - 	jack_event_t event;
 - 
 - 	event.type = GraphReordered;
 - 	event.x.n = client->rank;
 - 
 - 	return jack_deliver_event (engine, client, &event);
 - }
 - 
 - int
 - jack_rechain_graph (jack_engine_t *engine, int take_lock)
 - 
 - {
 - 	GSList *node, *next;
 - 	unsigned long n;
 - 	int err = 0;
 - 	int set;
 - 	jack_client_internal_t *client, *subgraph_client, *next_client;
 - 
 - 	if (take_lock) {
 - 		pthread_mutex_lock (&engine->graph_lock);
 - 	}
 - 
 - 	/* We're going to try to avoid reconnecting clients that 
 - 	   don't need to be reconnected. This is slightly tricky, 
 - 	   but worth it for performance reasons.
 - 	*/
 - 
 - 	subgraph_client = 0;
 - 
 - 	if ((node = engine->clients) == 0) {
 - 		goto done;
 - 	}
 - 
 - 	client = (jack_client_internal_t *) node->data;
 - 	if ((next = g_slist_next (node)) == NULL) {
 - 		next_client = 0;
 - 	} else {
 - 		next_client = (jack_client_internal_t *) next->data;
 - 	}
 - 	n = 0;
 - 
 - 	do {
 - 		if (client->rank != n || client->next_client != next_client) {
 - 			client->rank = n;
 - 			client->next_client = next_client;
 - 			set = TRUE;
 - 		} else {
 - 			set = FALSE;
 - 		}
 - 
 - 		if (jack_client_is_inprocess (client)) {
 - 
 - 			/* break the chain for the current subgraph. the server
 - 			   will wait for chain on the nth FIFO, and will
 - 			   then execute this in-process client.
 - 			*/
 - 
 - 			if (subgraph_client) {
 - 				subgraph_client->subgraph_wait_fd = jack_get_fifo_fd (engine, n);
 - 			}
 - 
 - 			subgraph_client = 0;
 - 			
 - 		} else {
 - 
 - 			if (subgraph_client == 0) {
 - 
 - 				/* start a new subgraph. the engine will start the chain
 - 				   by writing to the nth FIFO.
 - 				*/
 - 
 - 				subgraph_client = client;
 - 				subgraph_client->subgraph_start_fd = jack_get_fifo_fd (engine, n);
 - 			} 
 - 
 - 			if (set) {
 - 				jack_client_set_order (engine, client);
 - 			}
 - 			
 - 			n++;
 - 		}
 - 
 - 		if (next == 0) {
 - 			break;
 - 		}
 - 
 - 		node = next;
 - 		client = (jack_client_internal_t *) node->data;
 - 
 - 		if ((next = g_slist_next (node)) == 0) {
 - 			next_client = 0;
 - 		} else {
 - 			next_client = (jack_client_internal_t *) next->data;
 - 		}
 - 
 - 	} while (1);
 - 	
 - 	if (subgraph_client) {
 - 		subgraph_client->subgraph_wait_fd = jack_get_fifo_fd (engine, n);
 - 	}
 - 
 -   done:
 - 	if (take_lock) {
 - 		pthread_mutex_unlock (&engine->graph_lock);
 - 	}
 - 
 - 	return err;
 - }
 - 
 - static void
 - jack_trace_terminal (jack_client_internal_t *c1, jack_client_internal_t *rbase)
 - {
 - 	jack_client_internal_t *c2;
 - 
 - 	/* make a copy of the existing list of routes that feed c1 */
 - 
 - 	GSList *existing;
 - 	GSList *node;
 - 
 - 	if (c1->fed_by == 0) {
 - 		return;
 - 	}
 - 
 - 	existing = g_slist_copy (c1->fed_by);
 - 
 - 	/* for each route that feeds c1, recurse, marking it as feeding
 - 	   rbase as well.
 - 	*/
 - 
 - 	for (node = existing; node; node = g_slist_next  (node)) {
 - 
 - 		c2 = (jack_client_internal_t *) node->data;
 - 
 - 		/* c2 is a route that feeds c1 which somehow feeds base. mark
 - 		   base as being fed by c2
 - 		*/
 - 
 - 		rbase->fed_by = g_slist_prepend (rbase->fed_by, c2);
 - 
 - 		if (c2 != rbase && c2 != c1) {
 - 
 - 			/* now recurse, so that we can mark base as being fed by
 - 			   all routes that feed c2
 - 			*/
 - 
 - 			jack_trace_terminal (c2, rbase);
 - 		}
 - 
 - 	}
 - }
 - 
 - static int 
 - jack_client_sort (jack_client_internal_t *a, jack_client_internal_t *b)
 - 
 - {
 - 	/* the driver client always comes after everything else */
 - 
 - 	if (a->control->type == ClientDriver) {
 - 		return 1;
 - 	}
 - 
 - 	if (b->control->type == ClientDriver) {
 - 		return -1;
 - 	}
 - 
 - 	if (g_slist_find (a->fed_by, b)) {
 - 		/* a comes after b */
 - 		return 1;
 - 	} else if (g_slist_find (b->fed_by, a)) {
 - 		/* b comes after a */
 - 		return -1;
 - 	} else {
 - 		/* we don't care */
 - 		return 0;
 - 	}
 - }
 - 
 - static int
 - jack_client_feeds (jack_client_internal_t *might, jack_client_internal_t *target)
 - {
 - 	GSList *pnode, *cnode;
 - 
 - 	/* Check every port of `might' for an outbound connection to `target'
 - 	*/
 - 
 - 	for (pnode = might->ports; pnode; pnode = g_slist_next (pnode)) {
 - 
 - 		jack_port_internal_t *port;
 - 		
 - 		port = (jack_port_internal_t *) pnode->data;
 - 
 - 		for (cnode = port->connections; cnode; cnode = g_slist_next (cnode)) {
 - 
 - 			jack_connection_internal_t *c;
 - 
 - 			c = (jack_connection_internal_t *) cnode->data;
 - 
 - 			if (c->source->shared->client_id == might->control->id &&
 - 			    c->destination->shared->client_id == target->control->id) {
 - 				return 1;
 - 			}
 - 		}
 - 	}
 - 	
 - 	return 0;
 - }
 - 
 - static void
 - jack_sort_graph (jack_engine_t *engine, int take_lock)
 - {
 - 	GSList *node, *onode;
 - 	jack_client_internal_t *client;
 - 	jack_client_internal_t *oclient;
 - 
 - 	if (take_lock) {
 - 		pthread_mutex_lock (&engine->graph_lock);
 - 	}
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 
 - 		client = (jack_client_internal_t *) node->data;
 - 
 - 		g_slist_free (client->fed_by);
 - 		client->fed_by = 0;
 - 
 - 		for (onode = engine->clients; onode; onode = g_slist_next (onode)) {
 - 			
 - 			oclient = (jack_client_internal_t *) onode->data;
 - 
 - 			if (jack_client_feeds (oclient, client)) {
 - 				client->fed_by = g_slist_prepend (client->fed_by, oclient);
 - 			}
 - 		}
 - 	}
 - 
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		jack_trace_terminal ((jack_client_internal_t *) node->data,
 - 				     (jack_client_internal_t *) node->data);
 - 	}
 - 
 - 	engine->clients = g_slist_sort (engine->clients, (GCompareFunc) jack_client_sort);
 - 	jack_rechain_graph (engine, FALSE);
 - 
 - 	if (take_lock) {
 - 		pthread_mutex_unlock (&engine->graph_lock);
 - 	}
 - }
 - 
 - static int 
 - jack_port_do_connect (jack_engine_t *engine,
 - 		       const char *source_port,
 - 		       const char *destination_port)
 - {
 - 	jack_connection_internal_t *connection;
 - 	jack_port_internal_t *srcport, *dstport;
 - 	jack_port_id_t src_id, dst_id;
 - 
 - 	fprintf (stderr, "trying to connect %s and %s\n", source_port, destination_port);
 - 
 - 	if ((srcport = jack_get_port_by_name (engine, source_port)) == 0) {
 - 		jack_error ("unknown source port in attempted connection [%s]", source_port);
 - 		return -1;
 - 	}
 - 
 - 	if ((dstport = jack_get_port_by_name (engine, destination_port)) == 0) {
 - 		jack_error ("unknown destination port in attempted connection [%s]", destination_port);
 - 		return -1;
 - 	}
 - 
 - 	if ((dstport->shared->flags & JackPortIsInput) == 0) {
 - 		jack_error ("destination port in attempted connection is not an input port");
 - 		return -1;
 - 	}
 - 
 - 	if ((srcport->shared->flags & JackPortIsOutput) == 0) {
 - 		jack_error ("source port in attempted connection is not an output port");
 - 		return -1;
 - 	}
 - 
 - 	if (strcmp (srcport->shared->type_info.type_name,
 - 		    dstport->shared->type_info.type_name) != 0) {
 - 		jack_error ("ports used in attemped connection are not of the same data type");
 - 		return -1;
 - 	}
 - 
 - 	connection = (jack_connection_internal_t *) malloc (sizeof (jack_connection_internal_t));
 - 
 - 	connection->source = srcport;
 - 	connection->destination = dstport;
 - 
 - 	src_id = srcport->shared->id;
 - 	dst_id = dstport->shared->id;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	if (dstport->shared->type_info.mixdown == NULL && dstport->connections) {
 - 		jack_error ("cannot make multiple connections to a port of type [%s]", dstport->shared->type_info.type_name);
 - 		free (connection);
 - 		return -1;
 - 	} else {
 - 		dstport->connections = g_slist_prepend (dstport->connections, connection);
 - 		srcport->connections = g_slist_prepend (srcport->connections, connection);
 - 		
 - 		jack_sort_graph (engine, FALSE);
 - 		
 - 		jack_send_connection_notification (engine, srcport->shared->client_id, src_id, dst_id, TRUE);
 - 		jack_send_connection_notification (engine, dstport->shared->client_id, dst_id, src_id, TRUE);
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	return 0;
 - }
 - 
 - int
 - jack_port_disconnect_internal (jack_engine_t *engine, 
 - 				jack_port_internal_t *srcport, 
 - 				jack_port_internal_t *dstport, 
 - 				int sort_graph)
 - 
 - {
 - 	GSList *node;
 - 	jack_connection_internal_t *connect;
 - 	int ret = -1;
 - 	jack_port_id_t src_id, dst_id;
 - 
 - 	/* call tree **** MUST HOLD **** engine->graph_lock. */
 - 	
 - 	printf ("disconnecting %s and %s\n", srcport->shared->name, dstport->shared->name);
 - 			
 - 	for (node = srcport->connections; node; node = g_slist_next (node)) {
 - 
 - 		connect = (jack_connection_internal_t *) node->data;
 - 
 - 		if (connect->source == srcport && connect->destination == dstport) {
 - 
 - 			srcport->connections = g_slist_remove (srcport->connections, connect);
 - 			dstport->connections = g_slist_remove (dstport->connections, connect);
 - 
 - 			src_id = srcport->shared->id;
 - 			dst_id = dstport->shared->id;
 - 
 - 			jack_send_connection_notification (engine, srcport->shared->client_id, src_id, dst_id, FALSE);
 - 			jack_send_connection_notification (engine, dstport->shared->client_id, dst_id, src_id, FALSE);
 - 
 - 			free (connect);
 - 			ret = 0;
 - 			break;
 - 		}
 - 	}
 - 
 - 	if (sort_graph) {
 - 		jack_sort_graph (engine, FALSE);
 - 	}
 - 
 - 	if (ret == -1) {
 - 		printf ("disconnect failed\n");
 - 	}
 - 
 - 	return ret;
 - }
 - 
 - static int 
 - jack_port_do_disconnect (jack_engine_t *engine,
 - 			 const char *source_port,
 - 			 const char *destination_port)
 - {
 - 	jack_port_internal_t *srcport, *dstport;
 - 	int ret = -1;
 - 
 - 	if ((srcport = jack_get_port_by_name (engine, source_port)) == 0) {
 - 		jack_error ("unknown source port in attempted connection [%s]", source_port);
 - 		return -1;
 - 	}
 - 
 - 	if ((dstport = jack_get_port_by_name (engine, destination_port)) == 0) {
 - 		jack_error ("unknown destination port in attempted connection [%s]", destination_port);
 - 		return -1;
 - 	}
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 
 - 	ret = jack_port_disconnect_internal (engine, srcport, dstport, TRUE);
 - 
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 	return ret;
 - }
 - 
 - static int
 - jack_create_fifo (jack_engine_t *engine, int which_fifo)
 - 
 - {
 - 	char path[FIFO_NAME_SIZE+1];
 - 
 - 	sprintf (path, "%s-%d", engine->fifo_prefix, which_fifo);
 - 
 - 	if (mknod (path, 0666|S_IFIFO, 0) < 0) {
 - 		if (errno != EEXIST) {
 - 			jack_error ("cannot create inter-client FIFO [%s] (%s)", path, strerror (errno));
 - 			return -1;
 - 		}
 - 
 - 	} else {
 - 		on_exit (unlink_path, strdup (path));
 - 	}
 - 
 - 	jack_get_fifo_fd (engine, which_fifo);
 - 
 - 	return 0;
 - }
 - 
 - static int 
 - jack_get_fifo_fd (jack_engine_t *engine, int which_fifo)
 - 
 - {
 - 	char path[FIFO_NAME_SIZE+1];
 - 
 - 	sprintf (path, "%s-%d", engine->fifo_prefix, which_fifo);
 - 
 - 	if (which_fifo >= engine->fifo_size) {
 - 		int i;
 - 
 - 		engine->fifo = (int *) realloc (engine->fifo, sizeof (int) * engine->fifo_size + 16);
 - 		for (i = engine->fifo_size; i < engine->fifo_size + 16; i++) {
 - 			engine->fifo[i] = -1;
 - 		}
 - 		engine->fifo_size += 16;
 - 	}
 - 
 - 	if (engine->fifo[which_fifo] < 0) {
 - 		if ((engine->fifo[which_fifo] = open (path, O_RDWR|O_CREAT, 0666)) < 0) {
 - 			jack_error ("cannot open fifo [%s] (%s)", path, strerror (errno));
 - 			return -1;
 - 		}
 - 	}
 - 
 - 	return engine->fifo[which_fifo];
 - }
 - 
 - int
 - jack_use_driver (jack_engine_t *engine, jack_driver_t *driver)
 - 
 - {
 - 	if (driver) {
 - 		driver->detach (driver, engine);
 - 		engine->driver = 0;
 - 	}
 - 
 - 	if (driver->attach (driver, engine)) {
 - 		return -1;
 - 	}
 - 
 - 	engine->driver = driver;
 - 	return 0;
 - }
 - 
 - /* PORT RELATED FUNCTIONS */
 - 
 - 
 - jack_port_id_t
 - jack_get_free_port (jack_engine_t *engine)
 - 
 - {
 - 	jack_port_id_t i;
 - 
 - 	pthread_mutex_lock (&engine->port_lock);
 - 
 - 	for (i = 0; i < engine->port_max; i++) {
 - 		if (engine->control->ports[i].in_use == 0) {
 - 			engine->control->ports[i].in_use = 1;
 - 			break;
 - 		}
 - 	}
 - 	
 - 	pthread_mutex_unlock (&engine->port_lock);
 - 	
 - 	if (i == engine->port_max) {
 - 		return NoPort;
 - 	}
 - 
 - 	return i;
 - }
 - 
 - static void
 - jack_port_release (jack_engine_t *engine, jack_port_internal_t *port)
 - 
 - {
 - 	/* XXX add the buffer used by the port back the (correct) freelist */
 - 
 - 	pthread_mutex_lock (&engine->port_lock);
 - 	port->shared->in_use = 0;
 - 	pthread_mutex_unlock (&engine->port_lock);
 - }
 - 
 - jack_port_internal_t *
 - jack_get_port_internal_by_name (jack_engine_t *engine, const char *name)
 - {
 - 	jack_port_id_t id;
 - 
 - 	pthread_mutex_lock (&engine->port_lock);
 - 
 - 	for (id = 0; id < engine->port_max; id++) {
 - 		if (strcmp (engine->control->ports[id].name, name) == 0) {
 - 			break;
 - 		}
 - 	}
 - 
 - 	pthread_mutex_unlock (&engine->port_lock);
 - 	
 - 	if (id != engine->port_max) {
 - 		return &engine->internal_ports[id];
 - 	} else {
 - 		return NULL;
 - 	}
 - }
 - 
 - int
 - jack_port_do_register (jack_engine_t *engine, jack_request_t *req)
 - 	
 - {
 - 	GSList *node;
 - 	jack_port_id_t port_id;
 - 	jack_port_shared_t *shared;
 - 	jack_port_internal_t *port;
 - 	jack_client_internal_t *client;
 - 	jack_port_type_info_t *type_info;
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	if ((client = jack_client_internal_by_id (engine, req->x.port_info.client_id)) == 0) {
 - 		jack_error ("unknown client id in port registration request");
 - 		return -1;
 - 	}
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	if ((port_id = jack_get_free_port (engine)) == NoPort) {
 - 		jack_error ("no ports available!");
 - 		return -1;
 - 	}
 - 
 - 	shared = &engine->control->ports[port_id];
 - 
 - 	strcpy (shared->name, req->x.port_info.name);
 - 
 - 	shared->client_id = req->x.port_info.client_id;
 - 	shared->flags = req->x.port_info.flags;
 - 	shared->locked = 0;
 - 	shared->buffer_size = req->x.port_info.buffer_size;
 - 
 - 	port = &engine->internal_ports[port_id];
 - 
 - 	port->shared = shared;
 - 	port->connections = 0;
 - 
 - 	type_info = NULL;
 - 
 - 	for (node = engine->port_types; node; node = g_slist_next (node)) {
 - 		
 - 		if (strcmp (req->x.port_info.type, ((jack_port_type_info_t *) node->data)->type_name) == 0) {
 - 			type_info = (jack_port_type_info_t *) node->data;
 - 			break;
 - 		}
 - 	}
 - 
 - 	if (type_info == NULL) {
 - 
 - 		/* not a builtin type, so allocate a new type_info structure,
 - 		   and fill it appropriately.
 - 		*/
 - 		
 - 		type_info = (jack_port_type_info_t *) malloc (sizeof (jack_port_type_info_t));
 - 
 - 		type_info->type_name = strdup (req->x.port_info.type);
 - 		type_info->mixdown = NULL;            /* we have no idea how to mix this */
 - 		type_info->buffer_scale_factor = -1;  /* use specified port buffer size */
 - 
 - 		engine->port_types = g_slist_prepend (engine->port_types, type_info);
 - 	}
 - 
 - 
 - 	memcpy (&port->shared->type_info, type_info, sizeof (jack_port_type_info_t));
 - 
 - 	if (jack_port_assign_buffer (engine, port)) {
 - 		jack_error ("cannot assign buffer for port");
 - 		return -1;
 - 	}
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	client->ports = g_slist_prepend (client->ports, port);
 - 	jack_port_registration_notify (engine, port_id, TRUE);
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	req->x.port_info.port_id = port_id;
 - 
 - 	return 0;
 - }
 - 
 - int
 - jack_port_do_unregister (jack_engine_t *engine, jack_request_t *req)
 - 
 - 
 - {
 - 	jack_client_internal_t *client;
 - 	jack_port_shared_t *shared;
 - 	jack_port_internal_t *port;
 - 
 - 	if (req->x.port_info.port_id < 0 || req->x.port_info.port_id > engine->port_max) {
 - 		jack_error ("invalid port ID %d in unregister request\n", req->x.port_info.port_id);
 - 		return -1;
 - 	}
 - 
 - 	shared = &engine->control->ports[req->x.port_info.port_id];
 - 
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	if ((client = jack_client_internal_by_id (engine, shared->client_id)) == NULL) {
 - 		jack_error ("unknown client id in port registration request");
 - 		return -1;
 - 	}
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	port = &engine->internal_ports[req->x.port_info.port_id];
 - 
 - 	jack_port_release (engine, &engine->internal_ports[req->x.port_info.port_id]);
 - 	
 - 	pthread_mutex_lock (&engine->graph_lock);
 - 	client->ports = g_slist_remove (client->ports, port);
 - 	jack_port_registration_notify (engine, req->x.port_info.port_id, FALSE);
 - 	pthread_mutex_unlock (&engine->graph_lock);
 - 
 - 	return 0;
 - }
 - 
 - void
 - jack_port_registration_notify (jack_engine_t *engine, jack_port_id_t port_id, int yn)
 - 
 - {
 - 	jack_event_t event;
 - 	jack_client_internal_t *client;
 - 	GSList *node;
 - 
 - 	event.type = (yn ? PortRegistered : PortUnregistered);
 - 	event.x.port_id = port_id;
 - 	
 - 	for (node = engine->clients; node; node = g_slist_next (node)) {
 - 		
 - 		client = (jack_client_internal_t *) node->data;
 - 
 - 		if (!client->control->active) {
 - 			continue;
 - 		}
 - 
 - 		if (client->control->port_register) {
 - 			if (jack_deliver_event (engine, client, &event)) {
 - 				jack_error ("cannot send port registration notification to %s (%s)",
 - 					     client->control->name, strerror (errno));
 - 			}
 - 		}
 - 	}
 - }
 - 
 - int
 - jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port)
 - {
 - 	GSList *node;
 - 	jack_port_segment_info_t *psi;
 - 	jack_port_buffer_info_t *bi;
 - 
 - 	port->shared->buffer = NULL;
 - 
 - 	if (port->shared->flags & JackPortIsInput) {
 - 		return 0;
 - 	}
 - 	
 - 	pthread_mutex_lock (&engine->buffer_lock);
 - 
 - 	if (engine->port_buffer_freelist == NULL) {
 - 		jack_error ("no more buffers available!");
 - 		goto out;
 - 	}
 - 
 - 	bi = (jack_port_buffer_info_t *) engine->port_buffer_freelist->data;
 - 	
 - 	for (node = engine->port_segments; node; node = g_slist_next (node)) {
 - 
 - 		psi = (jack_port_segment_info_t *) node->data;
 - 
 - 		if (bi->shm_key == psi->shm_key) {
 - 			port->shared->buffer = psi->address + bi->offset;
 - 			break;
 - 		}
 - 	}
 - 	
 - 	if (port->shared->buffer) {
 - 		engine->port_buffer_freelist = g_slist_remove (engine->port_buffer_freelist, bi);
 - 	} else {
 - 		jack_error ("port segment info for 0x%x:%d not found!", bi->shm_key, bi->offset);
 - 	}
 - 
 -   out:
 - 	pthread_mutex_unlock (&engine->buffer_lock);
 - 
 - 	if (port->shared->buffer == NULL) {
 - 		return -1;
 - 	} else {
 - 		return 0;
 - 	}
 - }
 - 
 - static jack_port_internal_t *
 - jack_get_port_by_name (jack_engine_t *engine, const char *name)
 - 
 - {
 - 	jack_port_id_t id;
 - 
 - 	/* Note the potential race on "in_use". Other design
 - 	   elements prevent this from being a problem.
 - 	*/
 - 
 - 	for (id = 0; id < engine->port_max; id++) {
 - 		if (engine->control->ports[id].in_use && strcmp (engine->control->ports[id].name, name) == 0) {
 - 			return &engine->internal_ports[id];
 - 		}
 - 	}
 - 
 - 	return NULL;
 - }
 - 
 - static int
 - jack_send_connection_notification (jack_engine_t *engine, jack_client_id_t client_id, 
 - 				    jack_port_id_t self_id, jack_port_id_t other_id, int connected)
 - 
 - {
 - 	jack_client_internal_t *client;
 - 	jack_event_t event;
 - 
 - 	if ((client = jack_client_internal_by_id (engine, client_id)) == 0) {
 - 		jack_error ("no such client %d during connection notification", client_id);
 - 		return -1;
 - 	}
 - 
 - 	event.type = (connected ? PortConnected : PortDisconnected);
 - 	event.x.self_id = self_id;
 - 	event.y.other_id = other_id;
 - 
 - 	if (jack_deliver_event (engine, client, &event)) {
 - 		jack_error ("cannot send port connection notification to client %s (%s)", 
 - 			     client->control->name, strerror (errno));
 - 		return -1;
 - 	}
 - 
 - 	return 0;
 - }
 - 
 - static void 
 - jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes)
 - {
 - 	GSList *node;
 - 	jack_port_shared_t *input;
 - 	nframes_t n;
 - 	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.
 - 	*/
 - 
 - 	node = port->connections;
 - 	input = (jack_port_shared_t *) node->data;
 - 	memcpy (port->shared->buffer, input->buffer, sizeof (sample_t) * nframes);
 - 	
 - 	for (node = g_slist_next (node); node; node = g_slist_next (node)) {
 - 		input = (jack_port_shared_t *) node->data;
 - 		n = nframes;
 - 		dst = port->shared->buffer;
 - 		src = input->buffer;
 - 		while (n--) {
 - 			*dst++ += *src++;
 - 		}
 - 	}
 - }
 - 
 
 
  |