[asterisk-commits] file: branch file/bridging r79046 - in /team/file/bridging: bridges/ include/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 10 13:11:53 CDT 2007


Author: file
Date: Fri Aug 10 13:11:53 2007
New Revision: 79046

URL: http://svn.digium.com/view/asterisk?view=rev&rev=79046
Log:
Add a fully working zaptel bridging module and introduce a multithreaded mode.

Modified:
    team/file/bridging/bridges/bridge_simple.c
    team/file/bridging/bridges/bridge_zaptel.c
    team/file/bridging/include/asterisk/bridging.h
    team/file/bridging/main/bridging.c

Modified: team/file/bridging/bridges/bridge_simple.c
URL: http://svn.digium.com/view/asterisk/team/file/bridging/bridges/bridge_simple.c?view=diff&rev=79046&r1=79045&r2=79046
==============================================================================
--- team/file/bridging/bridges/bridge_simple.c (original)
+++ team/file/bridging/bridges/bridge_simple.c Fri Aug 10 13:11:53 2007
@@ -76,7 +76,7 @@
 
 static struct ast_bridge_technology simple_bridge = {
 	.name = "simple_bridge",
-	.capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE,
+	.capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_THREAD,
 	.preference = AST_BRIDGE_PREFERENCE_HIGH,
 	.formats = AST_FORMAT_AUDIO_MASK | AST_FORMAT_VIDEO_MASK | AST_FORMAT_TEXT_MASK,
 	.join = simple_bridge_join,

Modified: team/file/bridging/bridges/bridge_zaptel.c
URL: http://svn.digium.com/view/asterisk/team/file/bridging/bridges/bridge_zaptel.c?view=diff&rev=79046&r1=79045&r2=79046
==============================================================================
--- team/file/bridging/bridges/bridge_zaptel.c (original)
+++ team/file/bridging/bridges/bridge_zaptel.c Fri Aug 10 13:11:53 2007
@@ -39,6 +39,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/fcntl.h>
+#include <errno.h>
 
 #include "asterisk/zapata.h"
 
@@ -49,6 +50,8 @@
 #include "asterisk/lock.h"
 #include "asterisk/linkedlists.h"
 
+#define CONF_SIZE 320
+
 struct zaptel_mixer {
 	int fd;   /*!< File descriptor for the pseudo channel */
 	int conf; /*!< Zaptel conference number */
@@ -60,6 +63,33 @@
 	AST_LIST_ENTRY(zaptel_mixer_channel) list;
 };
 
+static int careful_write(int fd, unsigned char *data, int len, int block)
+{
+	int res;
+	int x;
+	
+	while (len) {
+		if (block) {
+			x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
+			res = ioctl(fd, ZT_IOMUX, &x);
+		} else
+			res = 0;
+		if (res >= 0)
+			res = write(fd, data, len);
+		if (res < 1) {
+			if (errno != EAGAIN) {
+				ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
+				return -1;
+			} else
+				return 0;
+		}
+		len -= res;
+		data += res;
+	}
+	
+	return 0;
+}
+
 static int zaptel_bridge_create(struct ast_bridge *bridge)
 {
 	struct zaptel_mixer *zm = NULL;
@@ -78,7 +108,7 @@
 	/* Setup zaptel conference parameters and apply them */
 	ztc.confno = -1;
 	ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
-	if (ioctl(zm->fd, ZT_SETCONF, &zm)) {
+	if (ioctl(zm->fd, ZT_SETCONF, &ztc)) {
 		close(zm->fd);
 		free(zm);
 		return -1;
@@ -131,7 +161,7 @@
 
 	/* Setup buffering parameters */
 	memset(&bi, 0, sizeof(bi));
-	bi.bufsize = 160;
+	bi.bufsize = CONF_SIZE/2;
 	bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
 	bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
 	bi.numbufs = 32;
@@ -163,6 +193,7 @@
 	AST_LIST_INSERT_TAIL(&zm->channels, zmc, list);
 	
 	/* We "should" be a go */
+	bridge_channel->fds[0] = zmc->fd;
 	bridge_channel->bridge_pvt = zmc;
 
 	return 0;
@@ -191,12 +222,38 @@
 
 static int zaptel_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
+	struct zaptel_mixer_channel *zmc = bridge_channel->bridge_pvt;
+
+	/* Write audio into zaptel conference */
+	careful_write(zmc->fd, frame->data, frame->datalen, 0);
+
+	return 0;
+}
+
+static int zaptel_bridge_fd(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int fd)
+{
+	int res = 0;
+	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
+	char *buf = __buf + AST_FRIENDLY_OFFSET;
+
+	if ((res = read(fd, buf, CONF_SIZE)) > 0) {
+		struct ast_frame out_frame = {
+			.frametype = AST_FRAME_VOICE,
+			.subclass = AST_FORMAT_SLINEAR,
+			.data = buf,
+			.datalen = res,
+			.samples = res/2,
+			.offset = AST_FRIENDLY_OFFSET,
+		};
+		ast_write(bridge_channel->chan, ast_frdup(&out_frame));
+	}
+
 	return 0;
 }
 
 static struct ast_bridge_technology zaptel_bridge = {
 	.name = "zaptel_bridge",
-	.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX,
+	.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_MULTITHREADED,
 	.preference = AST_BRIDGE_PREFERENCE_HIGH,
 	.formats = AST_FORMAT_SLINEAR,
 	.create = zaptel_bridge_create,
@@ -204,6 +261,7 @@
 	.join = zaptel_bridge_join,
 	.leave = zaptel_bridge_leave,
 	.write = zaptel_bridge_write,
+	.fd = zaptel_bridge_fd,
 };
 
 static int unload_module(void)

Modified: team/file/bridging/include/asterisk/bridging.h
URL: http://svn.digium.com/view/asterisk/team/file/bridging/include/asterisk/bridging.h?view=diff&rev=79046&r1=79045&r2=79046
==============================================================================
--- team/file/bridging/include/asterisk/bridging.h (original)
+++ team/file/bridging/include/asterisk/bridging.h Fri Aug 10 13:11:53 2007
@@ -29,10 +29,12 @@
 
 /*! \brief Capabilities for a bridge technology */
 enum ast_bridge_capability {
-	AST_BRIDGE_CAPABILITY_TRANSMIX = (1 << 0), /*! Move between bridge technologies as sources change to ensure the "best" use of technologies */
-	AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 1),  /*! Bridge is only capable of mixing 2 sources */
-	AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 2), /*! Bridge is capable of mixing 2+ sources */
-	AST_BRIDGE_CAPABILITY_NATIVE = (1 << 3),   /*! Bridge can natively bridge two channels */
+	AST_BRIDGE_CAPABILITY_TRANSMIX = (1 << 0),      /*! Move between bridge technologies as sources change to ensure the "best" use of technologies */
+	AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 1),       /*! Bridge is only capable of mixing 2 sources */
+	AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 2),      /*! Bridge is capable of mixing 2+ sources */
+	AST_BRIDGE_CAPABILITY_NATIVE = (1 << 3),        /*! Bridge can natively bridge two channels */
+	AST_BRIDGE_CAPABILITY_MULTITHREADED = (1 << 4), /*! Run in a multithreaded model */
+	AST_BRIDGE_CAPABILITY_THREAD = (1 << 5),        /*! Run central bridge thread */
 };
 
 /*! \brief Preference for choosing the bridge technology */
@@ -74,6 +76,7 @@
 	int (*leave)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);                           /*! Callback for when a channel leaves a bridge */
 	int (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridged_channel, struct ast_frame *frame); /*! Callback for writing a frame to the bridge */
 	int (*signal)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);                          /*! Callback for a bridge channel thread signal */
+	int (*fd)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int fd);                      /*! Callback for when a file descriptor trips */
 	int formats;                                                                                                  /*! Formats this bridge technology can support */
 	int suspended:1;                                                                                              /*! Is this bridge technology suspended from use or not? */
 	AST_RWLIST_ENTRY(ast_bridge_technology) list;                                                                 /*! Linked list information */
@@ -86,6 +89,7 @@
 	ast_cond_t cond;                         /*! Condition, used if we want to wake up a thread waiting on the bridged channel */
 	void *bridge_pvt;                        /*! Private information unique to the bridge technology (not always needed) */
 	pthread_t thread;                        /*! Thread handling the bridged channel */
+	int fds[4];                              /*! Additional file descriptors to look at */
 	int suspended:1;                         /*! Is this bridged channel suspended from the bridge or not? */
 	AST_LIST_ENTRY(ast_bridge_channel) list; /*! Linked list information */
 };

Modified: team/file/bridging/main/bridging.c
URL: http://svn.digium.com/view/asterisk/team/file/bridging/main/bridging.c?view=diff&rev=79046&r1=79045&r2=79046
==============================================================================
--- team/file/bridging/main/bridging.c (original)
+++ team/file/bridging/main/bridging.c Fri Aug 10 13:11:53 2007
@@ -329,72 +329,66 @@
 	return 0;
 }
 
-/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
-static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	int formats[2] = {bridge_channel->chan->readformat, bridge_channel->chan->writeformat};
-
-	/* Are the formats currently in use something this bridge can handle? */
-	if (!(bridge->technology->formats & formats[0])) {
-		int best_format = ast_best_codec(bridge->technology->formats);
-
-		/* Read format is a no go... */
-		if (option_debug) {
-			char codec_buf[512];
-			ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->formats);
-			ast_log(LOG_DEBUG, "Bridge technology %s wants to read any of formats %s(%d) but channel has %s(%d)\n", bridge->technology->name, codec_buf, bridge->technology->formats, ast_getformatname(formats[0]), formats[0]);
-		}
-		/* Switch read format to the best one chosen */
-		if (ast_set_read_format(bridge_channel->chan, best_format)) {
-			ast_log(LOG_WARNING, "Failed to set channel %s to read format %s(%d)\n", bridge_channel->chan->name, ast_getformatname(best_format), best_format);
-			return -1;
-		}
-		if (option_debug)
-			ast_log(LOG_DEBUG, "Bridge %p put channel %s into read format %s(%d)\n", bridge, bridge_channel->chan->name, ast_getformatname(best_format), best_format);
-	}
-
-	if (!(bridge->technology->formats & formats[1])) {
-		int best_format = ast_best_codec(bridge->technology->formats);
-
-		/* Write format is a no go... */
-		if (option_debug) {
-			char codec_buf[512];
-			ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->formats);
-			ast_log(LOG_DEBUG, "Bridge technology %s wants to write any of formats %s(%d) but channel has %s(%d)\n", bridge->technology->name, codec_buf, bridge->technology->formats, ast_getformatname(formats[1]), formats[1]);
-		}
-		/* Switch write format to the best one chosen */
-		if (ast_set_write_format(bridge_channel->chan, best_format)) {
-			ast_log(LOG_WARNING, "Failed to set channel %s to write format %s(%d)\n", bridge_channel->chan->name, ast_getformatname(best_format), best_format);
-			return -1;
-		}
-		ast_debug(1, "Bridge %p put channel %s into write format %s(%d)\n", bridge, bridge_channel->chan->name, ast_getformatname(best_format), best_format);
-	}
-
-	/* Before we actually become part of this bridge make sure we are in the signalling wait state */
-	bridge_channel->state = AST_BRIDGE_CHANNEL_STATE_WAIT;
-
-	/* Make the bridged channel part of the bridge */
-	AST_LIST_INSERT_TAIL(&bridge->channels, bridge_channel, list);
-
-	/* Notify the bridge thread that a new bridged channel is part of the bridge, this will cause it to rebuild the bridge array and some critical things */
-	ast_set_flag(&bridge->notify_flags, AST_BRIDGE_NOTIFY_REBUILD);
-
-	/* Of course if this is the first channel we actually have to create the bridge thread */
-	if ((bridge->thread == AST_PTHREADT_NULL) && (ast_pthread_create(&bridge->thread, NULL, bridge_thread, bridge))) {
-		ast_debug(1, "Failed to create bridge thread for %p\n", bridge);
-		return -1;
-	} else {
-		/* Poke the bridge out of it's poll if there */
-		pthread_kill(bridge->thread, SIGURG);
-	}
-
-	/* If the bridge technology wants notification that this channel is joining the bridge, give it it */
-	if (bridge->technology->join) {
-		ast_debug(1, "Giving bridge technology %s notification that %p is joining bridge %p\n", bridge->technology->name, bridge_channel, bridge);
-		if (bridge->technology->join(bridge, bridge_channel))
-			ast_debug(1, "Bridge technology %s failed to join %p to bridge %p\n", bridge->technology->name, bridge_channel, bridge);
-	}
-
+/*! \brief Run in a multithreaded model. Each joined channel does writing/reading in their own thread. */
+static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	int fds[4] = {-1, }, outfd = -1, ms = -1, nfds = 0, i = 0;
+
+	/* Add any file descriptors to be watched if a callback function exists for them */
+	if (bridge->technology->fd) {
+		for (i = 0; i < 4; i++) {
+			if (bridge_channel->fds[i] >= 0) {
+				fds[nfds] = bridge_channel->fds[i];
+				nfds++;
+			}
+		}
+	}
+
+	/* Before we go into the loop drop our lock on the bridge, we don't care about it anymore really */
+	ast_mutex_unlock(&bridge->lock);
+
+	/* Go into a loop waiting for frames from the channel, or the associated file descriptors to trip */
+	for (;;) {
+		struct ast_channel *chan = NULL;
+
+		outfd = -1;
+		ms = -1;
+
+		/* Ensure this bridged channel is still up before and after we do our blocking operation */
+		if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT)
+			break;
+
+		/* Wait for data on any of the file descriptors */
+		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
+
+		if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT)
+			break;
+
+		/* See if it was the channel that caused us to awaken */
+		if (chan) {
+			struct ast_frame *frame = NULL;
+			/* Try to read in a frame, if this fails it means they hungup */
+                        if (!(frame = ast_read(chan)) || (frame->frametype == AST_FRAME_CONTROL && frame->subclass == AST_CONTROL_HANGUP)) {
+                                /* Switch the bridged channel state to end and signal it's thread */
+                                ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+                        } else {
+                                /* Write out the frame to the bridge technology */
+                                bridge->technology->write(bridge, bridge_channel, frame);
+                        }
+		} else if (outfd > -1) {
+			bridge->technology->fd(bridge, bridge_channel, outfd);
+		}
+	}
+
+	/* Reclaim our bridge lock */
+	ast_mutex_lock(&bridge->lock);
+
+	return 0;
+}
+
+/*! \brief Run in a singlethreaded model. Each joined channel yields itself to the main bridge thread. */
+static enum ast_bridge_channel_state bridge_channel_join_singlethreaded(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
 	/* Go into a loop waiting for the bridge thread to make us do something */
 	for (;;) {
 		if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
@@ -418,6 +412,82 @@
 			break;
 		}
 	}
+	return 0;
+}
+
+/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
+static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	int formats[2] = {bridge_channel->chan->readformat, bridge_channel->chan->writeformat};
+
+	/* Are the formats currently in use something this bridge can handle? */
+	if (!(bridge->technology->formats & formats[0])) {
+		int best_format = ast_best_codec(bridge->technology->formats);
+
+		/* Read format is a no go... */
+		if (option_debug) {
+			char codec_buf[512];
+			ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->formats);
+			ast_log(LOG_DEBUG, "Bridge technology %s wants to read any of formats %s(%d) but channel has %s(%d)\n", bridge->technology->name, codec_buf, bridge->technology->formats, ast_getformatname(formats[0]), formats[0]);
+		}
+		/* Switch read format to the best one chosen */
+		if (ast_set_read_format(bridge_channel->chan, best_format)) {
+			ast_log(LOG_WARNING, "Failed to set channel %s to read format %s(%d)\n", bridge_channel->chan->name, ast_getformatname(best_format), best_format);
+			return -1;
+		}
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Bridge %p put channel %s into read format %s(%d)\n", bridge, bridge_channel->chan->name, ast_getformatname(best_format), best_format);
+	}
+
+	if (!(bridge->technology->formats & formats[1])) {
+		int best_format = ast_best_codec(bridge->technology->formats);
+
+		/* Write format is a no go... */
+		if (option_debug) {
+			char codec_buf[512];
+			ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->formats);
+			ast_log(LOG_DEBUG, "Bridge technology %s wants to write any of formats %s(%d) but channel has %s(%d)\n", bridge->technology->name, codec_buf, bridge->technology->formats, ast_getformatname(formats[1]), formats[1]);
+		}
+		/* Switch write format to the best one chosen */
+		if (ast_set_write_format(bridge_channel->chan, best_format)) {
+			ast_log(LOG_WARNING, "Failed to set channel %s to write format %s(%d)\n", bridge_channel->chan->name, ast_getformatname(best_format), best_format);
+			return -1;
+		}
+		ast_debug(1, "Bridge %p put channel %s into write format %s(%d)\n", bridge, bridge_channel->chan->name, ast_getformatname(best_format), best_format);
+	}
+
+	/* Before we actually become part of this bridge make sure we are in the signalling wait state */
+	bridge_channel->state = AST_BRIDGE_CHANNEL_STATE_WAIT;
+
+	/* Make the bridged channel part of the bridge */
+	AST_LIST_INSERT_TAIL(&bridge->channels, bridge_channel, list);
+
+	/* Notify the bridge thread that a new bridged channel is part of the bridge, this will cause it to rebuild the bridge array and some critical things */
+	ast_set_flag(&bridge->notify_flags, AST_BRIDGE_NOTIFY_REBUILD);
+
+	/* Of course if this is the first channel we actually have to create the bridge thread if the technology wants it */
+	if ((bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_THREAD)) {
+		if ((bridge->thread == AST_PTHREADT_NULL) && (ast_pthread_create(&bridge->thread, NULL, bridge_thread, bridge))) {
+			ast_debug(1, "Failed to create bridge thread for %p\n", bridge);
+			return -1;
+		} else {
+			/* Poke the bridge out of it's poll if there */
+			pthread_kill(bridge->thread, SIGURG);
+		}
+	}
+
+	/* If the bridge technology wants notification that this channel is joining the bridge, give it it */
+	if (bridge->technology->join) {
+		ast_debug(1, "Giving bridge technology %s notification that %p is joining bridge %p\n", bridge->technology->name, bridge_channel, bridge);
+		if (bridge->technology->join(bridge, bridge_channel))
+			ast_debug(1, "Bridge technology %s failed to join %p to bridge %p\n", bridge->technology->name, bridge_channel, bridge);
+	}
+
+	/* Pass ourselves off to our respective threading model */
+	if ((bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED))
+		bridge_channel_join_multithreaded(bridge, bridge_channel);
+	else
+		bridge_channel_join_singlethreaded(bridge, bridge_channel);
 
 	/* If the bridge technology wants notification that this channel is leaving the bridge, give it it */
 	if (bridge->technology->leave) {
@@ -454,9 +524,14 @@
 {
 	struct ast_bridge_channel bridge_channel;
 	enum ast_bridge_channel_state state;
+	int i = 0;
 
 	/* Wipe out the bridge channel structure just in case */
 	memset(&bridge_channel, 0, sizeof(bridge_channel));
+
+	/* Ensure no additional file descriptors are present */
+	for (i = 0; i < 4; i++)
+		bridge_channel.fds[i] = -1;
 
 	/* Setup the bridge channel with information about the channel and stuff */
 	bridge_channel.chan = chan;
@@ -515,10 +590,15 @@
 int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan)
 {
 	struct ast_bridge_channel *bridge_channel = NULL;
+	int i = 0;
 
 	/* Create a nwe bridge channel structure... we have to allocate it since it will exist in another thread soon enough */
 	if (!(bridge_channel = ast_calloc(1, sizeof(*bridge_channel))))
 		return -1;
+
+	/* Ensure no additional file descriptors are present */
+	for (i = 0; i < 4; i++)
+		bridge_channel->fds[i] = -1;
 
 	/* Copy over pointers to vital information */
 	bridge_channel->chan = chan;
@@ -593,8 +673,11 @@
  */
 int ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
 {
-	/* Change the state on the bridge channel and signal it's thread to wakeup so it realizes the change */
+	/* Change the state on the bridge channel */
 	bridge_channel->state = new_state;
+	
+	/* Signal it's thread using a few different ways... */
+	pthread_kill(bridge_channel->thread, SIGURG);
 	return ast_cond_signal(&bridge_channel->cond);
 }
 




More information about the asterisk-commits mailing list