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: 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
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 break;
00216 } else if (fd != chan->fds[0]) {
00217 if (f->frametype == AST_FRAME_VOICE) {
00218 if (f->subclass == AST_FORMAT_ULAW) {
00219
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
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
00248
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
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
00295
00296 res = conf_run(chan, confno, confflags);
00297 }
00298 out:
00299
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 }