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
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.
24 * \brief Zap Barge support
26 * \author Mark Spencer <markster@digium.com>
28 * \note Special thanks to comphealth.com for sponsoring this
31 * \ingroup applications
35 <depend>zaptel</depend>
40 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
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.";
76 static int careful_write(int fd
, unsigned char *data
, int len
)
80 res
= write(fd
, data
, len
);
82 if (errno
!= EAGAIN
) {
83 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
94 static int conf_run(struct ast_channel
*chan
, int confno
, int confflags
)
97 struct zt_confinfo ztc
;
99 struct ast_channel
*c
;
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
);
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
);
125 ast_indicate(chan
, -1);
126 retryzap
= strcasecmp(chan
->tech
->type
, "Zap");
128 origfd
= chan
->fds
[0];
130 fd
= open("/dev/zap/pseudo", O_RDWR
);
132 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
135 /* Make non-blocking */
136 flags
= fcntl(fd
, F_GETFL
);
138 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
142 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
143 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
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
;
153 if (ioctl(fd
, ZT_SET_BUFINFO
, &bi
)) {
154 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
160 /* XXX Make sure we're not running on a pseudo channel XXX */
164 memset(&ztc
, 0, sizeof(ztc
));
165 /* Check to see if we're in a conference... */
167 if (ioctl(fd
, ZT_GETCONF
, &ztc
)) {
168 ast_log(LOG_WARNING
, "Error getting conference\n");
173 /* Whoa, already in a conference... Retry... */
175 ast_log(LOG_DEBUG
, "Zap channel is in a conference already, retrying with pseudo\n");
180 memset(&ztc
, 0, sizeof(ztc
));
181 /* Add us to the conference */
184 ztc
.confmode
= ZT_CONF_MONITORBOTH
;
186 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
187 ast_log(LOG_WARNING
, "Error setting conference\n");
191 ast_log(LOG_DEBUG
, "Placed channel %s in ZAP channel %d monitor\n", chan
->name
, confno
);
196 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
198 if (c
->fds
[0] != origfd
) {
200 /* Kill old pseudo */
203 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
210 if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '#')) {
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
);
220 ast_log(LOG_WARNING
, "Huh? Got a non-ulaw (%d) frame in the conference\n", f
->subclass
);
224 } else if (outfd
> -1) {
225 res
= read(outfd
, buf
, CONF_SIZE
);
227 memset(&fr
, 0, sizeof(fr
));
228 fr
.frametype
= AST_FRAME_VOICE
;
229 fr
.subclass
= AST_FORMAT_ULAW
;
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
));
239 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
242 if (fd
!= chan
->fds
[0])
245 /* Take out of conference */
246 /* Add us to the conference */
250 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
251 ast_log(LOG_WARNING
, "Error setting conference\n");
260 static int conf_exec(struct ast_channel
*chan
, void *data
)
263 struct ast_module_user
*u
;
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
);
280 if (chan
->_state
!= AST_STATE_UP
)
283 while(!confno
&& (++retrycnt
< 4)) {
284 /* Prompt user for conference number */
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)
292 /* XXX Should prompt user for pin if pin is required XXX */
293 /* Run the conference */
294 res
= conf_run(chan
, confno
, confflags
);
297 /* Do the conference */
298 ast_module_user_remove(u
);
302 static int unload_module(void)
306 res
= ast_unregister_application(app
);
308 ast_module_user_hangup_all();
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");