Sat Apr 26 2014 22:01:26

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    <defaultenabled>yes</defaultenabled>
00037    <support_level>deprecated</support_level>
00038    <replacement>app_chanspy</replacement>
00039  ***/
00040 
00041 #include "asterisk.h"
00042 
00043 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 357721 $")
00044 
00045 #include <dahdi/user.h>
00046 
00047 #include "asterisk/lock.h"
00048 #include "asterisk/file.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/pbx.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/config.h"
00053 #include "asterisk/app.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/say.h"
00056 #include "asterisk/utils.h"
00057 
00058 /*** DOCUMENTATION
00059    <application name="DAHDIBarge" language="en_US">
00060       <synopsis>
00061          Barge in (monitor) DAHDI channel.
00062       </synopsis>
00063       <syntax>
00064          <parameter name="channel">
00065             <para>Channel to barge.</para>
00066          </parameter>
00067       </syntax>
00068       <description>
00069          <para>Barges in on a specified DAHDI <replaceable>channel</replaceable> or prompts
00070          if one is not specified. Returns <literal>-1</literal> when caller user hangs
00071          up and is independent of the state of the channel being monitored.
00072          </para>
00073       </description>
00074    </application>
00075  ***/
00076 static const char app[] = "DAHDIBarge";
00077 
00078 #define CONF_SIZE 160
00079 
00080 static int careful_write(int fd, unsigned char *data, int len)
00081 {
00082    int res;
00083    while(len) {
00084       res = write(fd, data, len);
00085       if (res < 1) {
00086          if (errno != EAGAIN) {
00087             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00088             return -1;
00089          } else
00090             return 0;
00091       }
00092       len -= res;
00093       data += res;
00094    }
00095    return 0;
00096 }
00097 
00098 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00099 {
00100    int fd;
00101    struct dahdi_confinfo dahdic;
00102    struct ast_frame *f;
00103    struct ast_channel *c;
00104    struct ast_frame fr;
00105    int outfd;
00106    int ms;
00107    int nfds;
00108    int res;
00109    int flags;
00110    int retrydahdi;
00111    int origfd;
00112    int ret = -1;
00113 
00114    struct dahdi_bufferinfo bi;
00115    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00116    char *buf = __buf + AST_FRIENDLY_OFFSET;
00117 
00118    /* Set it into U-law mode (write) */
00119    if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
00120       ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", ast_channel_name(chan));
00121       goto outrun;
00122    }
00123 
00124    /* Set it into U-law mode (read) */
00125    if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
00126       ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", ast_channel_name(chan));
00127       goto outrun;
00128    }
00129    ast_indicate(chan, -1);
00130    retrydahdi = strcasecmp(ast_channel_tech(chan)->type, "DAHDI");
00131 dahdiretry:
00132    origfd = ast_channel_fd(chan, 0);
00133    if (retrydahdi) {
00134       fd = open("/dev/dahdi/pseudo", O_RDWR);
00135       if (fd < 0) {
00136          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00137          goto outrun;
00138       }
00139       /* Make non-blocking */
00140       flags = fcntl(fd, F_GETFL);
00141       if (flags < 0) {
00142          ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00143          close(fd);
00144          goto outrun;
00145       }
00146       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00147          ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00148          close(fd);
00149          goto outrun;
00150       }
00151       /* Setup buffering information */
00152       memset(&bi, 0, sizeof(bi));
00153       bi.bufsize = CONF_SIZE;
00154       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
00155       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
00156       bi.numbufs = 4;
00157       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
00158          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00159          close(fd);
00160          goto outrun;
00161       }
00162       nfds = 1;
00163    } else {
00164       /* XXX Make sure we're not running on a pseudo channel XXX */
00165       fd = ast_channel_fd(chan, 0);
00166       nfds = 0;
00167    }
00168    memset(&dahdic, 0, sizeof(dahdic));
00169    /* Check to see if we're in a conference... */
00170    dahdic.chan = 0;  
00171    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
00172       ast_log(LOG_WARNING, "Error getting conference\n");
00173       close(fd);
00174       goto outrun;
00175    }
00176    if (dahdic.confmode) {
00177       /* Whoa, already in a conference...  Retry... */
00178       if (!retrydahdi) {
00179          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
00180          retrydahdi = 1;
00181          goto dahdiretry;
00182       }
00183    }
00184    memset(&dahdic, 0, sizeof(dahdic));
00185    /* Add us to the conference */
00186    dahdic.chan = 0;  
00187    dahdic.confno = confno;
00188    dahdic.confmode = DAHDI_CONF_MONITORBOTH;
00189 
00190    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00191       ast_log(LOG_WARNING, "Error setting conference\n");
00192       close(fd);
00193       goto outrun;
00194    }
00195    ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", ast_channel_name(chan), confno);
00196 
00197    for(;;) {
00198       outfd = -1;
00199       ms = -1;
00200       c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00201       if (c) {
00202          if (ast_channel_fd(c, 0) != origfd) {
00203             if (retrydahdi) {
00204                /* Kill old pseudo */
00205                close(fd);
00206             }
00207             ast_debug(1, "Ooh, something swapped out under us, starting over\n");
00208             retrydahdi = 0;
00209             goto dahdiretry;
00210          }
00211          f = ast_read(c);
00212          if (!f) 
00213             break;
00214          if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
00215             ret = 0;
00216             ast_frfree(f);
00217             break;
00218          } else if (fd != ast_channel_fd(chan, 0)) {
00219             if (f->frametype == AST_FRAME_VOICE) {
00220                if (f->subclass.format.id == AST_FORMAT_ULAW) {
00221                   /* Carefully write */
00222                   careful_write(fd, f->data.ptr, f->datalen);
00223                } else
00224                   ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%s) frame in the conference\n", ast_getformatname(&f->subclass.format));
00225             }
00226          }
00227          ast_frfree(f);
00228       } else if (outfd > -1) {
00229          res = read(outfd, buf, CONF_SIZE);
00230          if (res > 0) {
00231             memset(&fr, 0, sizeof(fr));
00232             fr.frametype = AST_FRAME_VOICE;
00233             ast_format_set(&fr.subclass.format, AST_FORMAT_ULAW, 0);
00234             fr.datalen = res;
00235             fr.samples = res;
00236             fr.data.ptr = buf;
00237             fr.offset = AST_FRIENDLY_OFFSET;
00238             if (ast_write(chan, &fr) < 0) {
00239                ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00240                /* break; */
00241             }
00242          } else 
00243             ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00244       }
00245    }
00246    if (fd != ast_channel_fd(chan, 0))
00247       close(fd);
00248    else {
00249       /* Take out of conference */
00250       /* Add us to the conference */
00251       dahdic.chan = 0;  
00252       dahdic.confno = 0;
00253       dahdic.confmode = 0;
00254       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00255          ast_log(LOG_WARNING, "Error setting conference\n");
00256       }
00257    }
00258 
00259 outrun:
00260 
00261    return ret;
00262 }
00263 
00264 static int conf_exec(struct ast_channel *chan, const char *data)
00265 {
00266    int res = -1;
00267    int retrycnt = 0;
00268    int confflags = 0;
00269    int confno = 0;
00270    char confnostr[80] = "";
00271    
00272    if (!ast_strlen_zero(data)) {
00273       if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
00274           (sscanf(data, "%30d", &confno) != 1)) {
00275          ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
00276          return 0;
00277       }
00278    }
00279    
00280    if (ast_channel_state(chan) != AST_STATE_UP)
00281       ast_answer(chan);
00282 
00283    while(!confno && (++retrycnt < 4)) {
00284       /* Prompt user for conference number */
00285       confnostr[0] = '\0';
00286       res = ast_app_getdata(chan, "conf-getchannel",confnostr, sizeof(confnostr) - 1, 0);
00287       if (res <0) goto out;
00288       if (sscanf(confnostr, "%30d", &confno) != 1)
00289          confno = 0;
00290    }
00291    if (confno) {
00292       /* XXX Should prompt user for pin if pin is required XXX */
00293       /* Run the conference */
00294       res = conf_run(chan, confno, confflags);
00295    }
00296 out:
00297    /* Do the conference */
00298    return res;
00299 }
00300 
00301 static int unload_module(void)
00302 {
00303    return ast_unregister_application(app);
00304 }
00305 
00306 static int load_module(void)
00307 {
00308    return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
00309 }
00310 
00311 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");