Thu Apr 28 2011 16:56:39

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