diff --git a/CHANGES b/CHANGES index 8e50d011d36412e48649efe7f88e33e419c2b1c4..679b6f80631d4c93fb8945e43266e2f55413ea86 100755 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,4 @@ + -- True data mode bridging when possible -- H.323 build improvements -- Agent Callback-login support -- RFC2833 Improvements diff --git a/channels/chan_zap.c b/channels/chan_zap.c index cd3c4a5478a60d58d1726f710e6d71c1a3796b6a..e21d69b4fb69f8015065ac9d1587ed8ec8dfb4d6 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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;