Thu Jul 9 13:40:17 2009

Asterisk developer's documentation


app_dahdibarge.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Special thanks to comphealth.com for sponsoring this
00009  * GPL application.
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 /*! \file
00023  *
00024  * \brief DAHDI Barge support
00025  *
00026  * \author Mark Spencer <markster@digium.com>
00027  *
00028  * \note Special thanks to comphealth.com for sponsoring this
00029  * GPL application.
00030  * 
00031  * \ingroup applications
00032  */
00033 
00034 /*** MODULEINFO
00035    <depend>dahdi</depend>
00036  ***/
00037 
00038 #include "asterisk.h"
00039 
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 134283 $")
00041 
00042 #include <sys/ioctl.h>
00043 #include <dahdi/user.h>
00044 
00045 #include "asterisk/lock.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/channel.h"
00048 #include "asterisk/pbx.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/utils.h"
00055 
00056 static char *app = "DAHDIBarge";
00057 
00058 static char *synopsis = "Barge in (monitor) DAHDI channel";
00059 
00060 static char *descrip = 
00061 "  DAHDIBarge([channel]): Barges in on a specified DAHDI\n"
00062 "channel or prompts if one is not specified.  Returns\n"
00063 "-1 when caller user hangs up and is independent of the\n"
00064 "state of the channel being monitored.";
00065 
00066 
00067 #define CONF_SIZE 160
00068 
00069 static int careful_write(int fd, unsigned char *data, int len)
00070 {
00071    int res;
00072    while(len) {
00073       res = write(fd, data, len);
00074       if (res < 1) {
00075          if (errno != EAGAIN) {
00076             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00077             return -1;
00078          } else
00079             return 0;
00080       }
00081       len -= res;
00082       data += res;
00083    }
00084    return 0;
00085 }
00086 
00087 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00088 {
00089    int fd;
00090    struct dahdi_confinfo dahdic;
00091    struct ast_frame *f;
00092    struct ast_channel *c;
00093    struct ast_frame fr;
00094    int outfd;
00095    int ms;
00096    int nfds;
00097    int res;
00098    int flags;
00099    int retrydahdi;
00100    int origfd;
00101    int ret = -1;
00102 
00103    struct dahdi_bufferinfo bi;
00104    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00105    char *buf = __buf + AST_FRIENDLY_OFFSET;
00106 
00107    /* Set it into U-law mode (write) */
00108    if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00109       ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00110       goto outrun;
00111    }
00112 
00113    /* Set it into U-law mode (read) */
00114    if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00115       ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00116       goto outrun;
00117    }
00118    ast_indicate(chan, -1);
00119    retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
00120 dahdiretry:
00121    origfd = chan->fds[0];
00122    if (retrydahdi) {
00123       fd = open("/dev/dahdi/pseudo", O_RDWR);
00124       if (fd < 0) {
00125          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00126          goto outrun;
00127       }
00128       /* Make non-blocking */
00129       flags = fcntl(fd, F_GETFL);
00130       if (flags < 0) {
00131          ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00132          close(fd);
00133          goto outrun;
00134       }
00135       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00136          ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00137          close(fd);
00138          goto outrun;
00139       }
00140       /* Setup buffering information */
00141       memset(&bi, 0, sizeof(bi));
00142       bi.bufsize = CONF_SIZE;
00143       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
00144       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
00145       bi.numbufs = 4;
00146       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
00147          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00148          close(fd);
00149          goto outrun;
00150       }
00151       nfds = 1;
00152    } else {
00153       /* XXX Make sure we're not running on a pseudo channel XXX */
00154       fd = chan->fds[0];
00155       nfds = 0;
00156    }
00157    memset(&dahdic, 0, sizeof(dahdic));
00158    /* Check to see if we're in a conference... */
00159    dahdic.chan = 0;  
00160    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
00161       ast_log(LOG_WARNING, "Error getting conference\n");
00162       close(fd);
00163       goto outrun;
00164    }
00165    if (dahdic.confmode) {
00166       /* Whoa, already in a conference...  Retry... */
00167       if (!retrydahdi) {
00168          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
00169          retrydahdi = 1;
00170          goto dahdiretry;
00171       }
00172    }
00173    memset(&dahdic, 0, sizeof(dahdic));
00174    /* Add us to the conference */
00175    dahdic.chan = 0;  
00176    dahdic.confno = confno;
00177    dahdic.confmode = DAHDI_CONF_MONITORBOTH;
00178 
00179    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00180       ast_log(LOG_WARNING, "Error setting conference\n");
00181       close(fd);
00182       goto outrun;
00183    }
00184    ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
00185 
00186    for(;;) {
00187       outfd = -1;
00188       ms = -1;
00189       c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00190       if (c) {
00191          if (c->fds[0] != origfd) {
00192             if (retrydahdi) {
00193                /* Kill old pseudo */
00194                close(fd);
00195             }
00196             ast_debug(1, "Ooh, something swapped out under us, starting over\n");
00197             retrydahdi = 0;
00198             goto dahdiretry;
00199          }
00200          f = ast_read(c);
00201          if (!f) 
00202             break;
00203          if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00204             ret = 0;
00205             ast_frfree(f);
00206             break;
00207          } else if (fd != chan->fds[0]) {
00208             if (f->frametype == AST_FRAME_VOICE) {
00209                if (f->subclass == AST_FORMAT_ULAW) {
00210                   /* Carefully write */
00211                   careful_write(fd, f->data, f->datalen);
00212                } else
00213                   ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00214             }
00215          }
00216          ast_frfree(f);
00217       } else if (outfd > -1) {
00218          res = read(outfd, buf, CONF_SIZE);
00219          if (res > 0) {
00220             memset(&fr, 0, sizeof(fr));
00221             fr.frametype = AST_FRAME_VOICE;
00222             fr.subclass = AST_FORMAT_ULAW;
00223             fr.datalen = res;
00224             fr.samples = res;
00225             fr.data = buf;
00226             fr.offset = AST_FRIENDLY_OFFSET;
00227             if (ast_write(chan, &fr) < 0) {
00228                ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00229                /* break; */
00230             }
00231          } else 
00232             ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00233       }
00234    }
00235    if (fd != chan->fds[0])
00236       close(fd);
00237    else {
00238       /* Take out of conference */
00239       /* Add us to the conference */
00240       dahdic.chan = 0;  
00241       dahdic.confno = 0;
00242       dahdic.confmode = 0;
00243       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00244          ast_log(LOG_WARNING, "Error setting conference\n");
00245       }
00246    }
00247 
00248 outrun:
00249 
00250    return ret;
00251 }
00252 
00253 static int conf_exec(struct ast_channel *chan, void *data)
00254 {
00255    int res=-1;
00256    int retrycnt = 0;
00257    int confflags = 0;
00258    int confno = 0;
00259    char confstr[80] = "";
00260    
00261    if (!ast_strlen_zero(data)) {
00262       if ((sscanf(data, "DAHDI/%d", &confno) != 1) &&
00263           (sscanf(data, "%d", &confno) != 1)) {
00264          ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
00265          return 0;
00266       }
00267    }
00268    
00269    if (chan->_state != AST_STATE_UP)
00270       ast_answer(chan);
00271 
00272    while(!confno && (++retrycnt < 4)) {
00273       /* Prompt user for conference number */
00274       confstr[0] = '\0';
00275       res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
00276       if (res <0) goto out;
00277       if (sscanf(confstr, "%d", &confno) != 1)
00278          confno = 0;
00279    }
00280    if (confno) {
00281       /* XXX Should prompt user for pin if pin is required XXX */
00282       /* Run the conference */
00283       res = conf_run(chan, confno, confflags);
00284    }
00285 out:
00286    /* Do the conference */
00287    return res;
00288 }
00289 
00290 static int unload_module(void)
00291 {
00292    return ast_unregister_application(app);
00293 }
00294 
00295 static int load_module(void)
00296 {
00297    return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
00298 }
00299 
00300 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");

Generated on Thu Jul 9 13:40:17 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7