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
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "asterisk.h"
00039
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211528 $")
00041
00042 #include <stdlib.h>
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include <unistd.h>
00046 #include <errno.h>
00047 #include <sys/ioctl.h>
00048
00049 #include "asterisk/lock.h"
00050 #include "asterisk/file.h"
00051 #include "asterisk/logger.h"
00052 #include "asterisk/channel.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/module.h"
00055 #include "asterisk/config.h"
00056 #include "asterisk/app.h"
00057 #include "asterisk/options.h"
00058 #include "asterisk/cli.h"
00059 #include "asterisk/say.h"
00060 #include "asterisk/utils.h"
00061
00062 #include "asterisk/dahdi_compat.h"
00063
00064 static char *dahdi_app = "DAHDIBarge";
00065 static char *zap_app = "ZapBarge";
00066
00067 static char *dahdi_synopsis = "Barge in (monitor) DAHDI channel";
00068 static char *zap_synopsis = "Barge in (monitor) Zap channel";
00069
00070 static char *dahdi_descrip =
00071 " DAHDIBarge([channel]): Barges in on a specified DAHDI\n"
00072 "channel or prompts if one is not specified. Returns\n"
00073 "-1 when caller user hangs up and is independent of the\n"
00074 "state of the channel being monitored.";
00075
00076 static char *zap_descrip =
00077 " ZapBarge([channel]): Barges in on a specified Zaptel\n"
00078 "channel or prompts if one is not specified. Returns\n"
00079 "-1 when caller user hangs up and is independent of the\n"
00080 "state of the channel being monitored.";
00081
00082 #define CONF_SIZE 160
00083
00084 static int careful_write(int fd, unsigned char *data, int len)
00085 {
00086 int res;
00087 while(len) {
00088 res = write(fd, data, len);
00089 if (res < 1) {
00090 if (errno != EAGAIN) {
00091 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00092 return -1;
00093 } else
00094 return 0;
00095 }
00096 len -= res;
00097 data += res;
00098 }
00099 return 0;
00100 }
00101
00102 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00103 {
00104 int fd;
00105 struct dahdi_confinfo ztc;
00106 struct ast_frame *f;
00107 struct ast_channel *c;
00108 struct ast_frame fr;
00109 int outfd;
00110 int ms;
00111 int nfds;
00112 int res;
00113 int flags;
00114 int retryzap;
00115 int origfd;
00116 int ret = -1;
00117 struct dahdi_bufferinfo bi;
00118 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00119 char *buf = __buf + AST_FRIENDLY_OFFSET;
00120
00121
00122 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00123 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00124 goto outrun;
00125 }
00126
00127
00128 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00129 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00130 goto outrun;
00131 }
00132 ast_indicate(chan, -1);
00133 retryzap = strcasecmp(chan->tech->type, dahdi_chan_name);
00134 zapretry:
00135 origfd = chan->fds[0];
00136 if (retryzap) {
00137 fd = open(DAHDI_FILE_PSEUDO, O_RDWR);
00138 if (fd < 0) {
00139 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00140 goto outrun;
00141 }
00142
00143 flags = fcntl(fd, F_GETFL);
00144 if (flags < 0) {
00145 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00146 close(fd);
00147 goto outrun;
00148 }
00149 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00150 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00151 close(fd);
00152 goto outrun;
00153 }
00154
00155 memset(&bi, 0, sizeof(bi));
00156 bi.bufsize = CONF_SIZE;
00157 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
00158 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
00159 bi.numbufs = 4;
00160 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
00161 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00162 close(fd);
00163 goto outrun;
00164 }
00165 nfds = 1;
00166 } else {
00167
00168 fd = chan->fds[0];
00169 nfds = 0;
00170 }
00171 memset(&ztc, 0, sizeof(ztc));
00172
00173 ztc.chan = 0;
00174 if (ioctl(fd, DAHDI_GETCONF, &ztc)) {
00175 ast_log(LOG_WARNING, "Error getting conference\n");
00176 close(fd);
00177 goto outrun;
00178 }
00179 if (ztc.confmode) {
00180
00181 if (!retryzap) {
00182 ast_log(LOG_DEBUG, "Channel is in a conference already, retrying with pseudo\n");
00183 retryzap = 1;
00184 goto zapretry;
00185 }
00186 }
00187 memset(&ztc, 0, sizeof(ztc));
00188
00189 ztc.chan = 0;
00190 ztc.confno = confno;
00191 ztc.confmode = DAHDI_CONF_MONITORBOTH;
00192
00193 if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
00194 ast_log(LOG_WARNING, "Error setting conference\n");
00195 close(fd);
00196 goto outrun;
00197 }
00198 ast_log(LOG_DEBUG, "Placed channel %s in channel %d monitor\n", chan->name, confno);
00199
00200 for(;;) {
00201 outfd = -1;
00202 ms = -1;
00203 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00204 if (c) {
00205 if (c->fds[0] != origfd) {
00206 if (retryzap) {
00207
00208 close(fd);
00209 }
00210 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
00211 retryzap = 0;
00212 goto zapretry;
00213 }
00214 f = ast_read(c);
00215 if (!f)
00216 break;
00217 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00218 ret = 0;
00219 ast_frfree(f);
00220 break;
00221 } else if (fd != chan->fds[0]) {
00222 if (f->frametype == AST_FRAME_VOICE) {
00223 if (f->subclass == AST_FORMAT_ULAW) {
00224
00225 careful_write(fd, f->data, f->datalen);
00226 } else
00227 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00228 }
00229 }
00230 ast_frfree(f);
00231 } else if (outfd > -1) {
00232 res = read(outfd, buf, CONF_SIZE);
00233 if (res > 0) {
00234 memset(&fr, 0, sizeof(fr));
00235 fr.frametype = AST_FRAME_VOICE;
00236 fr.subclass = AST_FORMAT_ULAW;
00237 fr.datalen = res;
00238 fr.samples = res;
00239 fr.data = buf;
00240 fr.offset = AST_FRIENDLY_OFFSET;
00241 if (ast_write(chan, &fr) < 0) {
00242 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00243
00244 }
00245 } else
00246 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00247 }
00248 }
00249 if (fd != chan->fds[0])
00250 close(fd);
00251 else {
00252
00253
00254 ztc.chan = 0;
00255 ztc.confno = 0;
00256 ztc.confmode = 0;
00257 if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
00258 ast_log(LOG_WARNING, "Error setting conference\n");
00259 }
00260 }
00261
00262 outrun:
00263
00264 return ret;
00265 }
00266
00267 static int exec(struct ast_channel *chan, void *data, int dahdimode)
00268 {
00269 int res=-1;
00270 struct ast_module_user *u;
00271 int retrycnt = 0;
00272 int confflags = 0;
00273 int confno = 0;
00274 char confstr[80] = "";
00275
00276 u = ast_module_user_add(chan);
00277
00278 if (!ast_strlen_zero(data)) {
00279 if (dahdimode) {
00280 if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
00281 (sscanf(data, "%30d", &confno) != 1)) {
00282 ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data);
00283 ast_module_user_remove(u);
00284 return 0;
00285 }
00286 } else {
00287 if ((sscanf(data, "Zap/%30d", &confno) != 1) &&
00288 (sscanf(data, "%30d", &confno) != 1)) {
00289 ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data);
00290 ast_module_user_remove(u);
00291 return 0;
00292 }
00293 }
00294 }
00295
00296 if (chan->_state != AST_STATE_UP)
00297 ast_answer(chan);
00298
00299 while(!confno && (++retrycnt < 4)) {
00300
00301 confstr[0] = '\0';
00302 res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
00303 if (res <0) goto out;
00304 if (sscanf(confstr, "%30d", &confno) != 1)
00305 confno = 0;
00306 }
00307 if (confno) {
00308
00309
00310 res = conf_run(chan, confno, confflags);
00311 }
00312 out:
00313
00314 ast_module_user_remove(u);
00315 return res;
00316 }
00317
00318 static int exec_zap(struct ast_channel *chan, void *data)
00319 {
00320 ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", zap_app, dahdi_app);
00321
00322 return exec(chan, data, 0);
00323 }
00324
00325 static int exec_dahdi(struct ast_channel *chan, void *data)
00326 {
00327 return exec(chan, data, 1);
00328 }
00329
00330 static int unload_module(void)
00331 {
00332 int res = 0;
00333
00334 if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
00335 res |= ast_unregister_application(dahdi_app);
00336 }
00337
00338 res |= ast_unregister_application(zap_app);
00339
00340 ast_module_user_hangup_all();
00341
00342 return res;
00343 }
00344
00345 static int load_module(void)
00346 {
00347 int res = 0;
00348
00349 if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
00350 res |= ast_register_application(dahdi_app, exec_dahdi, dahdi_synopsis, dahdi_descrip);
00351 }
00352
00353 res |= ast_register_application(zap_app, exec_zap, zap_synopsis, zap_descrip);
00354
00355 return res;
00356 }
00357
00358 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on channel application");