Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:49 2009

## 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: 211526 $")
    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/%3d", &confno) != 1) &&
    00276           (sscanf(data, "%3d", &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, "%3d", &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 }