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