Sat Aug 6 00:39:19 2011

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

Generated on Sat Aug 6 00:39:19 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7