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 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 137055 $")
00040
00041 #include <dahdi/user.h>
00042
00043 #include "asterisk/lock.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/pbx.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/utils.h"
00051 #include "asterisk/cli.h"
00052 #include "asterisk/say.h"
00053 #include "asterisk/options.h"
00054
00055 static char *app = "DAHDIScan";
00056
00057 static char *synopsis = "Scan DAHDI channels to monitor calls";
00058
00059 static char *descrip =
00060 " DAHDIScan([group]) allows a call center manager to monitor DAHDI channels in\n"
00061 "a convenient way. Use '#' to select the next channel and use '*' to exit\n"
00062 "Limit scanning to a channel GROUP by setting the option group argument.\n";
00063
00064
00065 #define CONF_SIZE 160
00066
00067 static struct ast_channel *get_dahdi_channel_locked(int num) {
00068 char name[80];
00069
00070 snprintf(name, sizeof(name), "DAHDI/%d-1", num);
00071 return ast_get_channel_by_name_locked(name);
00072 }
00073
00074 static int careful_write(int fd, unsigned char *data, int len)
00075 {
00076 int res;
00077 while (len) {
00078 res = write(fd, data, len);
00079 if (res < 1) {
00080 if (errno != EAGAIN) {
00081 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00082 return -1;
00083 } else {
00084 return 0;
00085 }
00086 }
00087 len -= res;
00088 data += res;
00089 }
00090 return 0;
00091 }
00092
00093 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00094 {
00095 int fd;
00096 struct dahdi_confinfo dahdic;
00097 struct ast_frame *f;
00098 struct ast_channel *c;
00099 struct ast_frame fr;
00100 int outfd;
00101 int ms;
00102 int nfds;
00103 int res;
00104 int flags;
00105 int retrydahdi;
00106 int origfd;
00107 int ret = -1;
00108 char input[4];
00109 int ic = 0;
00110
00111 struct dahdi_bufferinfo bi;
00112 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00113 char *buf = __buf + AST_FRIENDLY_OFFSET;
00114
00115
00116 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00117 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00118 goto outrun;
00119 }
00120
00121
00122 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00123 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00124 goto outrun;
00125 }
00126 ast_indicate(chan, -1);
00127 retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
00128 dahdiretry:
00129 origfd = chan->fds[0];
00130 if (retrydahdi) {
00131 fd = open("/dev/dahdi/pseudo", O_RDWR);
00132 if (fd < 0) {
00133 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00134 goto outrun;
00135 }
00136
00137 flags = fcntl(fd, F_GETFL);
00138 if (flags < 0) {
00139 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00140 close(fd);
00141 goto outrun;
00142 }
00143 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00144 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00145 close(fd);
00146 goto outrun;
00147 }
00148
00149 memset(&bi, 0, sizeof(bi));
00150 bi.bufsize = CONF_SIZE;
00151 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
00152 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
00153 bi.numbufs = 4;
00154 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
00155 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00156 close(fd);
00157 goto outrun;
00158 }
00159 nfds = 1;
00160 } else {
00161
00162 fd = chan->fds[0];
00163 nfds = 0;
00164 }
00165 memset(&dahdic, 0, sizeof(dahdic));
00166
00167 dahdic.chan = 0;
00168 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
00169 ast_log(LOG_WARNING, "Error getting conference\n");
00170 close(fd);
00171 goto outrun;
00172 }
00173 if (dahdic.confmode) {
00174
00175 if (!retrydahdi) {
00176 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
00177 retrydahdi = 1;
00178 goto dahdiretry;
00179 }
00180 }
00181 memset(&dahdic, 0, sizeof(dahdic));
00182
00183 dahdic.chan = 0;
00184 dahdic.confno = confno;
00185 dahdic.confmode = DAHDI_CONF_MONITORBOTH;
00186
00187 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00188 ast_log(LOG_WARNING, "Error setting conference\n");
00189 close(fd);
00190 goto outrun;
00191 }
00192 ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
00193
00194 for (;;) {
00195 outfd = -1;
00196 ms = -1;
00197 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00198 if (c) {
00199 if (c->fds[0] != origfd) {
00200 if (retrydahdi) {
00201
00202 close(fd);
00203 }
00204 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
00205 retrydahdi = 0;
00206 goto dahdiretry;
00207 }
00208 f = ast_read(c);
00209 if (!f) {
00210 break;
00211 }
00212 if (f->frametype == AST_FRAME_DTMF) {
00213 if (f->subclass == '#') {
00214 ret = 0;
00215 break;
00216 } else if (f->subclass == '*') {
00217 ret = -1;
00218 break;
00219 } else {
00220 input[ic++] = f->subclass;
00221 }
00222 if (ic == 3) {
00223 input[ic++] = '\0';
00224 ic = 0;
00225 ret = atoi(input);
00226 ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
00227 break;
00228 }
00229 }
00230
00231 if (fd != chan->fds[0]) {
00232 if (f->frametype == AST_FRAME_VOICE) {
00233 if (f->subclass == AST_FORMAT_ULAW) {
00234
00235 careful_write(fd, f->data.ptr, f->datalen);
00236 } else {
00237 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00238 }
00239 }
00240 }
00241 ast_frfree(f);
00242 } else if (outfd > -1) {
00243 res = read(outfd, buf, CONF_SIZE);
00244 if (res > 0) {
00245 memset(&fr, 0, sizeof(fr));
00246 fr.frametype = AST_FRAME_VOICE;
00247 fr.subclass = AST_FORMAT_ULAW;
00248 fr.datalen = res;
00249 fr.samples = res;
00250 fr.data.ptr = buf;
00251 fr.offset = AST_FRIENDLY_OFFSET;
00252 if (ast_write(chan, &fr) < 0) {
00253 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00254
00255 }
00256 } else {
00257 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00258 }
00259 }
00260 }
00261 if (f) {
00262 ast_frfree(f);
00263 }
00264 if (fd != chan->fds[0]) {
00265 close(fd);
00266 } else {
00267
00268
00269 dahdic.chan = 0;
00270 dahdic.confno = 0;
00271 dahdic.confmode = 0;
00272 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00273 ast_log(LOG_WARNING, "Error setting conference\n");
00274 }
00275 }
00276
00277 outrun:
00278
00279 return ret;
00280 }
00281
00282 static int conf_exec(struct ast_channel *chan, void *data)
00283 {
00284 int res=-1;
00285 int confflags = 0;
00286 int confno = 0;
00287 char confnostr[80] = "", *tmp = NULL;
00288 struct ast_channel *tempchan = NULL, *lastchan = NULL, *ichan = NULL;
00289 struct ast_frame *f;
00290 char *desired_group;
00291 int input = 0, search_group = 0;
00292
00293 if (chan->_state != AST_STATE_UP)
00294 ast_answer(chan);
00295
00296 desired_group = ast_strdupa(data);
00297 if (!ast_strlen_zero(desired_group)) {
00298 ast_verb(3, "Scanning for group %s\n", desired_group);
00299 search_group = 1;
00300 }
00301
00302 for (;;) {
00303 if (ast_waitfor(chan, 100) < 0)
00304 break;
00305
00306 f = ast_read(chan);
00307 if (!f)
00308 break;
00309 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
00310 ast_frfree(f);
00311 break;
00312 }
00313 ast_frfree(f);
00314 ichan = NULL;
00315 if(input) {
00316 ichan = get_dahdi_channel_locked(input);
00317 input = 0;
00318 }
00319
00320 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
00321
00322 if (!tempchan && !lastchan) {
00323 break;
00324 }
00325
00326 if (tempchan && search_group) {
00327 const char *mygroup;
00328 if ((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
00329 ast_verb(3, "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
00330 } else {
00331 ast_channel_unlock(tempchan);
00332 lastchan = tempchan;
00333 continue;
00334 }
00335 }
00336 if (tempchan && (!strcmp(tempchan->tech->type, "DAHDI")) && (tempchan != chan)) {
00337 ast_verb(3, "DAHDI channel %s is in-use, monitoring...\n", tempchan->name);
00338 ast_copy_string(confnostr, tempchan->name, sizeof(confnostr));
00339 ast_channel_unlock(tempchan);
00340 if ((tmp = strchr(confnostr, '-'))) {
00341 *tmp = '\0';
00342 }
00343 confno = atoi(strchr(confnostr, '/') + 1);
00344 ast_stopstream(chan);
00345 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
00346 res = conf_run(chan, confno, confflags);
00347 if (res < 0) {
00348 break;
00349 }
00350 input = res;
00351 } else if (tempchan) {
00352 ast_channel_unlock(tempchan);
00353 }
00354 lastchan = tempchan;
00355 }
00356 return res;
00357 }
00358
00359 static int unload_module(void)
00360 {
00361 return ast_unregister_application(app);
00362 }
00363
00364 static int load_module(void)
00365 {
00366 return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
00367 }
00368
00369 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan DAHDI channels application");
00370