Add true native data mode bridging
authorMark Spencer <markster@digium.com>
Sat, 23 Aug 2003 17:49:54 +0000 (17:49 +0000)
committerMark Spencer <markster@digium.com>
Sat, 23 Aug 2003 17:49:54 +0000 (17:49 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1410 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_zap.c

diff --git a/CHANGES b/CHANGES
index 8e50d01..679b6f8 100755 (executable)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+ -- True data mode bridging when possible
  -- H.323 build improvements
  -- Agent Callback-login support
  -- RFC2833 Improvements
index cd3c4a5..e21d69b 100755 (executable)
@@ -329,7 +329,7 @@ struct zt_subchannel {
        int needanswer;
        int linear;
        int inthreeway;
-       int curconfno;                  /* What conference we're currently in */
+       ZT_CONFINFO curconf;
 };
 
 #define CONF_USER_REAL         (1 << 0)
@@ -658,7 +658,7 @@ static int unalloc_sub(struct zt_pvt *p, int x)
        p->subs[x].chan = 0;
        p->subs[x].owner = NULL;
        p->subs[x].inthreeway = 0;
-       p->subs[x].curconfno = -1;
+       memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
        return 0;
 }
 
@@ -818,46 +818,62 @@ static char *sig2str(int sig)
        }
 }
 
-static int conf_add(int *confno, struct zt_subchannel *c, int index)
+static int conf_add(struct zt_pvt *p, struct zt_subchannel *c, int index, int slavechannel)
 {
        /* If the conference already exists, and we're already in it
           don't bother doing anything */
        ZT_CONFINFO zi;
-       if ((*confno > 0) && (c->curconfno == *confno))
-               return 0; 
-       if (c->curconfno > 0) {
-               ast_log(LOG_WARNING, "Subchannel %d is already in conference %d, moving to %d\n", c->zfd, c->curconfno, *confno);
+       
+       memset(&zi, 0, sizeof(zi));
+       zi.chan = 0;
+
+       if (slavechannel > 0) {
+               /* If we have only one slave, do a digital mon */
+               zi.confmode = ZT_CONF_DIGITALMON;
+               zi.confno = slavechannel;
+       } else {
+               if (!index) {
+                       /* Real-side and pseudo-side both participate in conference */
+                       zi.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER |
+                                                               ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
+               } else
+                       zi.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
+               zi.confno = p->confno;
        }
+       if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
+               return 0;
        if (c->zfd < 0)
                return 0;
-       memset(&zi, 0, sizeof(zi));
-       zi.chan = 0;
-       zi.confno = *confno;
-       if (!index) {
-               /* Real-side and pseudo-side both participate in conference */
-               zi.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER |
-                                                       ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
-       } else
-               zi.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
        if (ioctl(c->zfd, ZT_SETCONF, &zi)) {
-               ast_log(LOG_WARNING, "Failed to add %d to conference %d\n", c->zfd, *confno);
+               ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d\n", c->zfd, zi.confmode, zi.confno);
                return -1;
        }
-       c->curconfno = zi.confno;
-       *confno = zi.confno;
-       ast_log(LOG_DEBUG, "Added %d to conference %d\n", c->zfd, *confno);
+       if (slavechannel < 1) {
+               p->confno = zi.confno;
+       }
+       memcpy(&c->curconf, &zi, sizeof(c->curconf));
+       ast_log(LOG_DEBUG, "Added %d to conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
        return 0;
 }
 
-static int conf_del(int *confno, struct zt_subchannel *c, int index)
+static int isourconf(struct zt_pvt *p, struct zt_subchannel *c)
+{
+       /* If they're listening to our channel, they're ours */ 
+       if ((p->channel == c->curconf.confno) && (c->curconf.confmode == ZT_CONF_DIGITALMON))
+               return 1;
+       /* If they're a talker on our (allocated) conference, they're ours */
+       if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & ZT_CONF_TALKER))
+               return 1;
+       return 0;
+}
+
+static int conf_del(struct zt_pvt *p, struct zt_subchannel *c, int index)
 {
        ZT_CONFINFO zi;
-               /* Can't delete from this conference if it's not 0 */
-       if ((*confno < 1) ||
-               /* Can't delete if there's no zfd */
+       if (/* Can't delete if there's no zfd */
                (c->zfd < 0) ||
                /* Don't delete from the conference if it's not our conference */
-               (*confno != c->curconfno) 
+               !isourconf(p, c)
                /* Don't delete if we don't think it's conferenced at all (implied) */
                ) return 0;
        memset(&zi, 0, sizeof(zi));
@@ -865,43 +881,105 @@ static int conf_del(int *confno, struct zt_subchannel *c, int index)
        zi.confno = 0;
        zi.confmode = 0;
        if (ioctl(c->zfd, ZT_SETCONF, &zi)) {
-               ast_log(LOG_WARNING, "Failed to drop %d from conference %d\n", c->zfd, *confno);
+               ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
                return -1;
        }
-       c->curconfno = -1;
-       ast_log(LOG_DEBUG, "Removed %d from conference %d\n", c->zfd, *confno);
+       ast_log(LOG_DEBUG, "Removed %d from conference %d/%d\n", c->zfd, c->curconf.confmode, c->curconf.confno);
+       memcpy(&c->curconf, &zi, sizeof(c->curconf));
        return 0;
 }
 
+static int isslavenative(struct zt_pvt *p, struct zt_pvt **out)
+{
+       int x;
+       int useslavenative;
+       struct zt_pvt *slave = NULL;
+       /* Start out optimistic */
+       useslavenative = 1;
+       /* Update conference state in a stateless fashion */
+       for (x=0;x<3;x++) {
+               /* Any three-way calling makes slave native mode *definitely* out
+                  of the question */
+               if ((p->subs[x].zfd > -1) && p->subs[x].inthreeway)
+                       useslavenative = 0;
+       }
+       /* If we don't have any 3-way calls, check to see if we have
+          precisely one slave */
+       if (useslavenative) {
+               for (x=0;x<MAX_SLAVES;x++) {
+                       if (p->slaves[x]) {
+                               if (slave) {
+                                       /* Whoops already have a slave!  No 
+                                          slave native and stop right away */
+                                       slave = NULL;
+                                       useslavenative = 0;
+                                       break;
+                               } else {
+                                       /* We have one slave so far */
+                                       slave = p->slaves[x];
+                               }
+                       }
+               }
+       }
+       /* If no slave, slave native definitely out */
+       if (!slave)
+               useslavenative = 0;
+       else if (slave->law != p->law) {
+               useslavenative = 0;
+               slave = NULL;
+       }
+       if (out)
+               *out = slave;
+       return useslavenative;
+}
+
 static int update_conf(struct zt_pvt *p)
 {
        int needconf = 0;
        int x;
-       /* Update conference state in a stateless fashion */
+       int useslavenative;
+       struct zt_pvt *slave = NULL;
+
+       useslavenative = isslavenative(p, &slave);
        /* Start with the obvious, general stuff */
        for (x=0;x<3;x++) {
+               /* Look for three way calls */
                if ((p->subs[x].zfd > -1) && p->subs[x].inthreeway) {
-                       conf_add(&p->confno, &p->subs[x], x);
+                       conf_add(p, &p->subs[x], x, 0);
                        needconf++;
                } else {
-                       conf_del(&p->confno, &p->subs[x], x);
+                       conf_del(p, &p->subs[x], x);
                }
        }
-       /* If we have a slave, add him to our conference now */
+       /* If we have a slave, add him to our conference now. or DAX
+          if this is slave native */
        for (x=0;x<MAX_SLAVES;x++) {
                if (p->slaves[x]) {
-                       conf_add(&p->confno, &p->slaves[x]->subs[SUB_REAL], SUB_REAL);
-                       needconf++;
+                       if (useslavenative)
+                               conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, p->channel);
+                       else {
+                               conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
+                               needconf++;
+                       }
                }
        }
        /* If we're supposed to be in there, do so now */
        if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
-               conf_add(&p->confno, &p->subs[SUB_REAL], SUB_REAL);
-               needconf++;
+               if (useslavenative)
+                       conf_add(p, &p->subs[SUB_REAL], SUB_REAL, slave->channel);
+               else {
+                       conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
+                       needconf++;
+               }
        }
        /* If we have a master, add ourselves to his conference */
-       if (p->master) 
-               conf_add(&p->master->confno, &p->subs[SUB_REAL], SUB_REAL);
+       if (p->master) {
+               if (isslavenative(p->master, NULL)) {
+                       conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, p->master->channel);
+               } else {
+                       conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
+               }
+       }
        if (!needconf) {
                /* Nobody is left (or should be left) in our conference.  
                   Kill it.  */
@@ -1989,7 +2067,8 @@ static void zt_unlink(struct zt_pvt *slave, struct zt_pvt *master)
                        if (!slave || (master->slaves[x] == slave)) {
                                /* Take slave out of the conference */
                                ast_log(LOG_DEBUG, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
-                               conf_del(&master->confno, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
+                               conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
+                               conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
                                master->slaves[x]->master = NULL;
                                master->slaves[x] = NULL;
                        } else
@@ -2001,7 +2080,8 @@ static void zt_unlink(struct zt_pvt *slave, struct zt_pvt *master)
        if (!slave) {
                if (master->master) {
                        /* Take master out of the conference */
-                       conf_del(&master->master->confno, &master->subs[SUB_REAL], SUB_REAL);
+                       conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
+                       conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
                        hasslaves = 0;
                        for (x=0;x<MAX_SLAVES;x++) {
                                if (master->master->slaves[x] == master)
@@ -2472,7 +2552,7 @@ static int check_for_conference(struct zt_pvt *p)
        /* If we have no master and don't have a confno, then 
           if we're in a conference, it's probably a MeetMe room or
           some such, so don't let us 3-way out! */
-       if (ci.confno) {
+       if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
                if (option_verbose > 2) 
                        ast_verbose(VERBOSE_PREFIX_3 "Avoiding 3-way call when in an external conference\n");
                return 1;