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: 134283 $")
00041
00042 #include <sys/ioctl.h>
00043 #include <dahdi/user.h>
00044
00045 #include "asterisk/lock.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/channel.h"
00048 #include "asterisk/pbx.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/utils.h"
00055
00056 static char *app = "DAHDIBarge";
00057
00058 static char *synopsis = "Barge in (monitor) DAHDI channel";
00059
00060 static char *descrip =
00061 " DAHDIBarge([channel]): Barges in on a specified DAHDI\n"
00062 "channel or prompts if one is not specified. Returns\n"
00063 "-1 when caller user hangs up and is independent of the\n"
00064 "state of the channel being monitored.";
00065
00066
00067 #define CONF_SIZE 160
00068
00069 static int careful_write(int fd, unsigned char *data, int len)
00070 {
00071 int res;
00072 while(len) {
00073 res = write(fd, data, len);
00074 if (res < 1) {
00075 if (errno != EAGAIN) {
00076 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00077 return -1;
00078 } else
00079 return 0;
00080 }
00081 len -= res;
00082 data += res;
00083 }
00084 return 0;
00085 }
00086
00087 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00088 {
00089 int fd;
00090 struct dahdi_confinfo dahdic;
00091 struct ast_frame *f;
00092 struct ast_channel *c;
00093 struct ast_frame fr;
00094 int outfd;
00095 int ms;
00096 int nfds;
00097 int res;
00098 int flags;
00099 int retrydahdi;
00100 int origfd;
00101 int ret = -1;
00102
00103 struct dahdi_bufferinfo bi;
00104 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00105 char *buf = __buf + AST_FRIENDLY_OFFSET;
00106
00107
00108 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00109 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00110 goto outrun;
00111 }
00112
00113
00114 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00115 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00116 goto outrun;
00117 }
00118 ast_indicate(chan, -1);
00119 retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
00120 dahdiretry:
00121 origfd = chan->fds[0];
00122 if (retrydahdi) {
00123 fd = open("/dev/dahdi/pseudo", O_RDWR);
00124 if (fd < 0) {
00125 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00126 goto outrun;
00127 }
00128
00129 flags = fcntl(fd, F_GETFL);
00130 if (flags < 0) {
00131 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00132 close(fd);
00133 goto outrun;
00134 }
00135 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00136 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00137 close(fd);
00138 goto outrun;
00139 }
00140
00141 memset(&bi, 0, sizeof(bi));
00142 bi.bufsize = CONF_SIZE;
00143 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
00144 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
00145 bi.numbufs = 4;
00146 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
00147 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00148 close(fd);
00149 goto outrun;
00150 }
00151 nfds = 1;
00152 } else {
00153
00154 fd = chan->fds[0];
00155 nfds = 0;
00156 }
00157 memset(&dahdic, 0, sizeof(dahdic));
00158
00159 dahdic.chan = 0;
00160 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
00161 ast_log(LOG_WARNING, "Error getting conference\n");
00162 close(fd);
00163 goto outrun;
00164 }
00165 if (dahdic.confmode) {
00166
00167 if (!retrydahdi) {
00168 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
00169 retrydahdi = 1;
00170 goto dahdiretry;
00171 }
00172 }
00173 memset(&dahdic, 0, sizeof(dahdic));
00174
00175 dahdic.chan = 0;
00176 dahdic.confno = confno;
00177 dahdic.confmode = DAHDI_CONF_MONITORBOTH;
00178
00179 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00180 ast_log(LOG_WARNING, "Error setting conference\n");
00181 close(fd);
00182 goto outrun;
00183 }
00184 ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
00185
00186 for(;;) {
00187 outfd = -1;
00188 ms = -1;
00189 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00190 if (c) {
00191 if (c->fds[0] != origfd) {
00192 if (retrydahdi) {
00193
00194 close(fd);
00195 }
00196 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
00197 retrydahdi = 0;
00198 goto dahdiretry;
00199 }
00200 f = ast_read(c);
00201 if (!f)
00202 break;
00203 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00204 ret = 0;
00205 ast_frfree(f);
00206 break;
00207 } else if (fd != chan->fds[0]) {
00208 if (f->frametype == AST_FRAME_VOICE) {
00209 if (f->subclass == AST_FORMAT_ULAW) {
00210
00211 careful_write(fd, f->data, f->datalen);
00212 } else
00213 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00214 }
00215 }
00216 ast_frfree(f);
00217 } else if (outfd > -1) {
00218 res = read(outfd, buf, CONF_SIZE);
00219 if (res > 0) {
00220 memset(&fr, 0, sizeof(fr));
00221 fr.frametype = AST_FRAME_VOICE;
00222 fr.subclass = AST_FORMAT_ULAW;
00223 fr.datalen = res;
00224 fr.samples = res;
00225 fr.data = buf;
00226 fr.offset = AST_FRIENDLY_OFFSET;
00227 if (ast_write(chan, &fr) < 0) {
00228 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00229
00230 }
00231 } else
00232 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00233 }
00234 }
00235 if (fd != chan->fds[0])
00236 close(fd);
00237 else {
00238
00239
00240 dahdic.chan = 0;
00241 dahdic.confno = 0;
00242 dahdic.confmode = 0;
00243 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00244 ast_log(LOG_WARNING, "Error setting conference\n");
00245 }
00246 }
00247
00248 outrun:
00249
00250 return ret;
00251 }
00252
00253 static int conf_exec(struct ast_channel *chan, void *data)
00254 {
00255 int res=-1;
00256 int retrycnt = 0;
00257 int confflags = 0;
00258 int confno = 0;
00259 char confstr[80] = "";
00260
00261 if (!ast_strlen_zero(data)) {
00262 if ((sscanf(data, "DAHDI/%d", &confno) != 1) &&
00263 (sscanf(data, "%d", &confno) != 1)) {
00264 ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
00265 return 0;
00266 }
00267 }
00268
00269 if (chan->_state != AST_STATE_UP)
00270 ast_answer(chan);
00271
00272 while(!confno && (++retrycnt < 4)) {
00273
00274 confstr[0] = '\0';
00275 res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
00276 if (res <0) goto out;
00277 if (sscanf(confstr, "%d", &confno) != 1)
00278 confno = 0;
00279 }
00280 if (confno) {
00281
00282
00283 res = conf_run(chan, confno, confflags);
00284 }
00285 out:
00286
00287 return res;
00288 }
00289
00290 static int unload_module(void)
00291 {
00292 return ast_unregister_application(app);
00293 }
00294
00295 static int load_module(void)
00296 {
00297 return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
00298 }
00299
00300 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");