Sat Sep 16 05:47:41 2006

Asterisk developer's documentation


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

Generated on Sat Sep 16 05:47:41 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7