[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