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: 227580 $")
00041
00042 #include <dahdi/user.h>
00043
00044 #include "asterisk/lock.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/module.h"
00049 #include "asterisk/config.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/cli.h"
00052 #include "asterisk/say.h"
00053 #include "asterisk/utils.h"
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 static const char app[] = "DAHDIBarge";
00074
00075 #define CONF_SIZE 160
00076
00077 static int careful_write(int fd, unsigned char *data, int len)
00078 {
00079 int res;
00080 while(len) {
00081 res = write(fd, data, len);
00082 if (res < 1) {
00083 if (errno != EAGAIN) {
00084 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00085 return -1;
00086 } else
00087 return 0;
00088 }
00089 len -= res;
00090 data += res;
00091 }
00092 return 0;
00093 }
00094
00095 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00096 {
00097 int fd;
00098 struct dahdi_confinfo dahdic;
00099 struct ast_frame *f;
00100 struct ast_channel *c;
00101 struct ast_frame fr;
00102 int outfd;
00103 int ms;
00104 int nfds;
00105 int res;
00106 int flags;
00107 int retrydahdi;
00108 int origfd;
00109 int ret = -1;
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 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
00212 ret = 0;
00213 ast_frfree(f);
00214 break;
00215 } else if (fd != chan->fds[0]) {
00216 if (f->frametype == AST_FRAME_VOICE) {
00217 if (f->subclass.codec == AST_FORMAT_ULAW) {
00218
00219 careful_write(fd, f->data.ptr, f->datalen);
00220 } else
00221 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%s) frame in the conference\n", ast_getformatname(f->subclass.codec));
00222 }
00223 }
00224 ast_frfree(f);
00225 } else if (outfd > -1) {
00226 res = read(outfd, buf, CONF_SIZE);
00227 if (res > 0) {
00228 memset(&fr, 0, sizeof(fr));
00229 fr.frametype = AST_FRAME_VOICE;
00230 fr.subclass.codec = AST_FORMAT_ULAW;
00231 fr.datalen = res;
00232 fr.samples = res;
00233 fr.data.ptr = buf;
00234 fr.offset = AST_FRIENDLY_OFFSET;
00235 if (ast_write(chan, &fr) < 0) {
00236 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00237
00238 }
00239 } else
00240 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00241 }
00242 }
00243 if (fd != chan->fds[0])
00244 close(fd);
00245 else {
00246
00247
00248 dahdic.chan = 0;
00249 dahdic.confno = 0;
00250 dahdic.confmode = 0;
00251 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00252 ast_log(LOG_WARNING, "Error setting conference\n");
00253 }
00254 }
00255
00256 outrun:
00257
00258 return ret;
00259 }
00260
00261 static int conf_exec(struct ast_channel *chan, const char *data)
00262 {
00263 int res = -1;
00264 int retrycnt = 0;
00265 int confflags = 0;
00266 int confno = 0;
00267 char confnostr[80] = "";
00268
00269 if (!ast_strlen_zero(data)) {
00270 if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
00271 (sscanf(data, "%30d", &confno) != 1)) {
00272 ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
00273 return 0;
00274 }
00275 }
00276
00277 if (chan->_state != AST_STATE_UP)
00278 ast_answer(chan);
00279
00280 while(!confno && (++retrycnt < 4)) {
00281
00282 confnostr[0] = '\0';
00283 res = ast_app_getdata(chan, "conf-getchannel",confnostr, sizeof(confnostr) - 1, 0);
00284 if (res <0) goto out;
00285 if (sscanf(confnostr, "%30d", &confno) != 1)
00286 confno = 0;
00287 }
00288 if (confno) {
00289
00290
00291 res = conf_run(chan, confno, confflags);
00292 }
00293 out:
00294
00295 return res;
00296 }
00297
00298 static int unload_module(void)
00299 {
00300 return ast_unregister_application(app);
00301 }
00302
00303 static int load_module(void)
00304 {
00305 return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
00306 }
00307
00308 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");