00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
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
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
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
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
00164 fd = chan->fds[0];
00165 nfds = 0;
00166 }
00167 memset(&ztc, 0, sizeof(ztc));
00168
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
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
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
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
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
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
00249
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
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
00296
00297 res = conf_run(chan, confno, confflags);
00298 }
00299 out:
00300
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 }