update comment to match the state of the code
[asterisk-bristuff.git] / apps / app_zapbarge.c
blob735020f604489d857819d662f8002a720a65036c
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * Special thanks to comphealth.com for sponsoring this
9 * GPL application.
11 * See http://www.asterisk.org for more information about
12 * the Asterisk project. Please do not directly contact
13 * any of the maintainers of this project for assistance;
14 * the project provides a web site, mailing lists and IRC
15 * channels for your use.
17 * This program is free software, distributed under the terms of
18 * the GNU General Public License Version 2. See the LICENSE file
19 * at the top of the source tree.
22 /*! \file
24 * \brief Zap Barge support
26 * \author Mark Spencer <markster@digium.com>
28 * \note Special thanks to comphealth.com for sponsoring this
29 * GPL application.
31 * \ingroup applications
34 /*** MODULEINFO
35 <depend>zaptel</depend>
36 ***/
38 #include "asterisk.h"
40 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <errno.h>
47 #include <sys/ioctl.h>
48 #include <zaptel/zaptel.h>
50 #include "asterisk/lock.h"
51 #include "asterisk/file.h"
52 #include "asterisk/logger.h"
53 #include "asterisk/channel.h"
54 #include "asterisk/pbx.h"
55 #include "asterisk/module.h"
56 #include "asterisk/config.h"
57 #include "asterisk/app.h"
58 #include "asterisk/options.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/say.h"
61 #include "asterisk/utils.h"
63 static char *app = "ZapBarge";
65 static char *synopsis = "Barge in (monitor) Zap channel";
67 static char *descrip =
68 " ZapBarge([channel]): Barges in on a specified zap\n"
69 "channel or prompts if one is not specified. Returns\n"
70 "-1 when caller user hangs up and is independent of the\n"
71 "state of the channel being monitored.";
74 #define CONF_SIZE 160
76 static int careful_write(int fd, unsigned char *data, int len)
78 int res;
79 while(len) {
80 res = write(fd, data, len);
81 if (res < 1) {
82 if (errno != EAGAIN) {
83 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
84 return -1;
85 } else
86 return 0;
88 len -= res;
89 data += res;
91 return 0;
94 static int conf_run(struct ast_channel *chan, int confno, int confflags)
96 int fd;
97 struct zt_confinfo ztc;
98 struct ast_frame *f;
99 struct ast_channel *c;
100 struct ast_frame fr;
101 int outfd;
102 int ms;
103 int nfds;
104 int res;
105 int flags;
106 int retryzap;
107 int origfd;
108 int ret = -1;
110 ZT_BUFFERINFO bi;
111 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
112 char *buf = __buf + AST_FRIENDLY_OFFSET;
114 /* Set it into U-law mode (write) */
115 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
116 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
117 goto outrun;
120 /* Set it into U-law mode (read) */
121 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
122 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
123 goto outrun;
125 ast_indicate(chan, -1);
126 retryzap = strcasecmp(chan->tech->type, "Zap");
127 zapretry:
128 origfd = chan->fds[0];
129 if (retryzap) {
130 fd = open("/dev/zap/pseudo", O_RDWR);
131 if (fd < 0) {
132 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
133 goto outrun;
135 /* Make non-blocking */
136 flags = fcntl(fd, F_GETFL);
137 if (flags < 0) {
138 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
139 close(fd);
140 goto outrun;
142 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
143 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
144 close(fd);
145 goto outrun;
147 /* Setup buffering information */
148 memset(&bi, 0, sizeof(bi));
149 bi.bufsize = CONF_SIZE;
150 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
151 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
152 bi.numbufs = 4;
153 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
154 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
155 close(fd);
156 goto outrun;
158 nfds = 1;
159 } else {
160 /* XXX Make sure we're not running on a pseudo channel XXX */
161 fd = chan->fds[0];
162 nfds = 0;
164 memset(&ztc, 0, sizeof(ztc));
165 /* Check to see if we're in a conference... */
166 ztc.chan = 0;
167 if (ioctl(fd, ZT_GETCONF, &ztc)) {
168 ast_log(LOG_WARNING, "Error getting conference\n");
169 close(fd);
170 goto outrun;
172 if (ztc.confmode) {
173 /* Whoa, already in a conference... Retry... */
174 if (!retryzap) {
175 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
176 retryzap = 1;
177 goto zapretry;
180 memset(&ztc, 0, sizeof(ztc));
181 /* Add us to the conference */
182 ztc.chan = 0;
183 ztc.confno = confno;
184 ztc.confmode = ZT_CONF_MONITORBOTH;
186 if (ioctl(fd, ZT_SETCONF, &ztc)) {
187 ast_log(LOG_WARNING, "Error setting conference\n");
188 close(fd);
189 goto outrun;
191 ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno);
193 for(;;) {
194 outfd = -1;
195 ms = -1;
196 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
197 if (c) {
198 if (c->fds[0] != origfd) {
199 if (retryzap) {
200 /* Kill old pseudo */
201 close(fd);
203 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
204 retryzap = 0;
205 goto zapretry;
207 f = ast_read(c);
208 if (!f)
209 break;
210 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
211 ret = 0;
212 ast_frfree(f);
213 break;
214 } else if (fd != chan->fds[0]) {
215 if (f->frametype == AST_FRAME_VOICE) {
216 if (f->subclass == AST_FORMAT_ULAW) {
217 /* Carefully write */
218 careful_write(fd, f->data, f->datalen);
219 } else
220 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
223 ast_frfree(f);
224 } else if (outfd > -1) {
225 res = read(outfd, buf, CONF_SIZE);
226 if (res > 0) {
227 memset(&fr, 0, sizeof(fr));
228 fr.frametype = AST_FRAME_VOICE;
229 fr.subclass = AST_FORMAT_ULAW;
230 fr.datalen = res;
231 fr.samples = res;
232 fr.data = buf;
233 fr.offset = AST_FRIENDLY_OFFSET;
234 if (ast_write(chan, &fr) < 0) {
235 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
236 /* break; */
238 } else
239 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
242 if (fd != chan->fds[0])
243 close(fd);
244 else {
245 /* Take out of conference */
246 /* Add us to the conference */
247 ztc.chan = 0;
248 ztc.confno = 0;
249 ztc.confmode = 0;
250 if (ioctl(fd, ZT_SETCONF, &ztc)) {
251 ast_log(LOG_WARNING, "Error setting conference\n");
255 outrun:
257 return ret;
260 static int conf_exec(struct ast_channel *chan, void *data)
262 int res=-1;
263 struct ast_module_user *u;
264 int retrycnt = 0;
265 int confflags = 0;
266 int confno = 0;
267 char confstr[80] = "";
269 u = ast_module_user_add(chan);
271 if (!ast_strlen_zero(data)) {
272 if ((sscanf(data, "Zap/%d", &confno) != 1) &&
273 (sscanf(data, "%d", &confno) != 1)) {
274 ast_log(LOG_WARNING, "ZapBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
275 ast_module_user_remove(u);
276 return 0;
280 if (chan->_state != AST_STATE_UP)
281 ast_answer(chan);
283 while(!confno && (++retrycnt < 4)) {
284 /* Prompt user for conference number */
285 confstr[0] = '\0';
286 res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
287 if (res <0) goto out;
288 if (sscanf(confstr, "%d", &confno) != 1)
289 confno = 0;
291 if (confno) {
292 /* XXX Should prompt user for pin if pin is required XXX */
293 /* Run the conference */
294 res = conf_run(chan, confno, confflags);
296 out:
297 /* Do the conference */
298 ast_module_user_remove(u);
299 return res;
302 static int unload_module(void)
304 int res;
306 res = ast_unregister_application(app);
308 ast_module_user_hangup_all();
310 return res;
313 static int load_module(void)
315 return ast_register_application(app, conf_exec, synopsis, descrip);
318 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on Zap channel application");