Mon Mar 20 08:25:37 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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: 7221 $")
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             break;
00216          } else if (fd != chan->fds[0]) {
00217             if (f->frametype == AST_FRAME_VOICE) {
00218                if (f->subclass == AST_FORMAT_ULAW) {
00219                   /* Carefully write */
00220                   careful_write(fd, f->data, f->datalen);
00221                } else
00222                   ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00223             }
00224          }
00225          ast_frfree(f);
00226       } else if (outfd > -1) {
00227          res = read(outfd, buf, CONF_SIZE);
00228          if (res > 0) {
00229             memset(&fr, 0, sizeof(fr));
00230             fr.frametype = AST_FRAME_VOICE;
00231             fr.subclass = AST_FORMAT_ULAW;
00232             fr.datalen = res;
00233             fr.samples = res;
00234             fr.data = buf;
00235             fr.offset = AST_FRIENDLY_OFFSET;
00236             if (ast_write(chan, &fr) < 0) {
00237                ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00238                /* break; */
00239             }
00240          } else 
00241             ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00242       }
00243    }
00244    if (fd != chan->fds[0])
00245       close(fd);
00246    else {
00247       /* Take out of conference */
00248       /* Add us to the conference */
00249       ztc.chan = 0;  
00250       ztc.confno = 0;
00251       ztc.confmode = 0;
00252       if (ioctl(fd, ZT_SETCONF, &ztc)) {
00253          ast_log(LOG_WARNING, "Error setting conference\n");
00254       }
00255    }
00256 
00257 outrun:
00258 
00259    return ret;
00260 }
00261 
00262 static int conf_exec(struct ast_channel *chan, void *data)
00263 {
00264    int res=-1;
00265    struct localuser *u;
00266    int retrycnt = 0;
00267    int confflags = 0;
00268    int confno = 0;
00269    char confstr[80] = "";
00270 
00271    LOCAL_USER_ADD(u);
00272    
00273    if (!ast_strlen_zero(data)) {
00274       if ((sscanf(data, "Zap/%d", &confno) != 1) &&
00275           (sscanf(data, "%d", &confno) != 1)) {
00276          ast_log(LOG_WARNING, "ZapBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
00277          LOCAL_USER_REMOVE(u);
00278          return 0;
00279       }
00280    }
00281    
00282    if (chan->_state != AST_STATE_UP)
00283       ast_answer(chan);
00284 
00285    while(!confno && (++retrycnt < 4)) {
00286       /* Prompt user for conference number */
00287       confstr[0] = '\0';
00288       res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
00289       if (res <0) goto out;
00290       if (sscanf(confstr, "%d", &confno) != 1)
00291          confno = 0;
00292    }
00293    if (confno) {
00294       /* XXX Should prompt user for pin if pin is required XXX */
00295       /* Run the conference */
00296       res = conf_run(chan, confno, confflags);
00297    }
00298 out:
00299    /* Do the conference */
00300    LOCAL_USER_REMOVE(u);
00301    return res;
00302 }
00303 
00304 int unload_module(void)
00305 {
00306    int res;
00307    
00308    res = ast_unregister_application(app);
00309    
00310    STANDARD_HANGUP_LOCALUSERS;
00311 
00312    return res; 
00313 }
00314 
00315 int load_module(void)
00316 {
00317    return ast_register_application(app, conf_exec, synopsis, descrip);
00318 }
00319 
00320 char *description(void)
00321 {
00322    return tdesc;
00323 }
00324 
00325 int usecount(void)
00326 {
00327    int res;
00328    STANDARD_USECOUNT(res);
00329    return res;
00330 }
00331 
00332 char *key()
00333 {
00334    return ASTERISK_GPL_KEY;
00335 }

Generated on Mon Mar 20 08:25:37 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1