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>dahdi</depend>
40 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
47 #include <sys/ioctl.h>
49 #include "asterisk/lock.h"
50 #include "asterisk/file.h"
51 #include "asterisk/logger.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/pbx.h"
54 #include "asterisk/module.h"
55 #include "asterisk/config.h"
56 #include "asterisk/app.h"
57 #include "asterisk/options.h"
58 #include "asterisk/cli.h"
59 #include "asterisk/say.h"
60 #include "asterisk/utils.h"
62 #include "asterisk/dahdi_compat.h"
64 static char *dahdi_app
= "DAHDIBarge";
65 static char *zap_app
= "ZapBarge";
67 static char *dahdi_synopsis
= "Barge in (monitor) DAHDI channel";
68 static char *zap_synopsis
= "Barge in (monitor) Zap channel";
70 static char *dahdi_descrip
=
71 " DAHDIBarge([channel]): Barges in on a specified DAHDI\n"
72 "channel or prompts if one is not specified. Returns\n"
73 "-1 when caller user hangs up and is independent of the\n"
74 "state of the channel being monitored.";
76 static char *zap_descrip
=
77 " ZapBarge([channel]): Barges in on a specified Zaptel\n"
78 "channel or prompts if one is not specified. Returns\n"
79 "-1 when caller user hangs up and is independent of the\n"
80 "state of the channel being monitored.";
84 static int careful_write(int fd
, unsigned char *data
, int len
)
88 res
= write(fd
, data
, len
);
90 if (errno
!= EAGAIN
) {
91 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
102 static int conf_run(struct ast_channel
*chan
, int confno
, int confflags
)
105 struct dahdi_confinfo ztc
;
107 struct ast_channel
*c
;
117 struct dahdi_bufferinfo bi
;
118 char __buf
[CONF_SIZE
+ AST_FRIENDLY_OFFSET
];
119 char *buf
= __buf
+ AST_FRIENDLY_OFFSET
;
121 /* Set it into U-law mode (write) */
122 if (ast_set_write_format(chan
, AST_FORMAT_ULAW
) < 0) {
123 ast_log(LOG_WARNING
, "Unable to set '%s' to write ulaw mode\n", chan
->name
);
127 /* Set it into U-law mode (read) */
128 if (ast_set_read_format(chan
, AST_FORMAT_ULAW
) < 0) {
129 ast_log(LOG_WARNING
, "Unable to set '%s' to read ulaw mode\n", chan
->name
);
132 ast_indicate(chan
, -1);
133 retryzap
= strcasecmp(chan
->tech
->type
, dahdi_chan_name
);
135 origfd
= chan
->fds
[0];
138 fd
= open("/dev/zap/pseudo", O_RDWR
);
140 fd
= open("/dev/dahdi/pseudo", O_RDWR
);
143 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
146 /* Make non-blocking */
147 flags
= fcntl(fd
, F_GETFL
);
149 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
153 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
154 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
158 /* Setup buffering information */
159 memset(&bi
, 0, sizeof(bi
));
160 bi
.bufsize
= CONF_SIZE
;
161 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
162 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
164 if (ioctl(fd
, DAHDI_SET_BUFINFO
, &bi
)) {
165 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
171 /* XXX Make sure we're not running on a pseudo channel XXX */
175 memset(&ztc
, 0, sizeof(ztc
));
176 /* Check to see if we're in a conference... */
178 if (ioctl(fd
, DAHDI_GETCONF
, &ztc
)) {
179 ast_log(LOG_WARNING
, "Error getting conference\n");
184 /* Whoa, already in a conference... Retry... */
186 ast_log(LOG_DEBUG
, "Channel is in a conference already, retrying with pseudo\n");
191 memset(&ztc
, 0, sizeof(ztc
));
192 /* Add us to the conference */
195 ztc
.confmode
= DAHDI_CONF_MONITORBOTH
;
197 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
198 ast_log(LOG_WARNING
, "Error setting conference\n");
202 ast_log(LOG_DEBUG
, "Placed channel %s in channel %d monitor\n", chan
->name
, confno
);
207 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
209 if (c
->fds
[0] != origfd
) {
211 /* Kill old pseudo */
214 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
221 if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '#')) {
225 } else if (fd
!= chan
->fds
[0]) {
226 if (f
->frametype
== AST_FRAME_VOICE
) {
227 if (f
->subclass
== AST_FORMAT_ULAW
) {
228 /* Carefully write */
229 careful_write(fd
, f
->data
, f
->datalen
);
231 ast_log(LOG_WARNING
, "Huh? Got a non-ulaw (%d) frame in the conference\n", f
->subclass
);
235 } else if (outfd
> -1) {
236 res
= read(outfd
, buf
, CONF_SIZE
);
238 memset(&fr
, 0, sizeof(fr
));
239 fr
.frametype
= AST_FRAME_VOICE
;
240 fr
.subclass
= AST_FORMAT_ULAW
;
244 fr
.offset
= AST_FRIENDLY_OFFSET
;
245 if (ast_write(chan
, &fr
) < 0) {
246 ast_log(LOG_WARNING
, "Unable to write frame to channel: %s\n", strerror(errno
));
250 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
253 if (fd
!= chan
->fds
[0])
256 /* Take out of conference */
257 /* Add us to the conference */
261 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
262 ast_log(LOG_WARNING
, "Error setting conference\n");
271 static int exec(struct ast_channel
*chan
, void *data
, int dahdimode
)
274 struct ast_module_user
*u
;
278 char confstr
[80] = "";
280 u
= ast_module_user_add(chan
);
282 if (!ast_strlen_zero(data
)) {
284 if ((sscanf(data
, "DAHDI/%d", &confno
) != 1) &&
285 (sscanf(data
, "%d", &confno
) != 1)) {
286 ast_log(LOG_WARNING
, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data
);
287 ast_module_user_remove(u
);
291 if ((sscanf(data
, "Zap/%d", &confno
) != 1) &&
292 (sscanf(data
, "%d", &confno
) != 1)) {
293 ast_log(LOG_WARNING
, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data
);
294 ast_module_user_remove(u
);
300 if (chan
->_state
!= AST_STATE_UP
)
303 while(!confno
&& (++retrycnt
< 4)) {
304 /* Prompt user for conference number */
306 res
= ast_app_getdata(chan
, "conf-getchannel",confstr
, sizeof(confstr
) - 1, 0);
307 if (res
<0) goto out
;
308 if (sscanf(confstr
, "%d", &confno
) != 1)
312 /* XXX Should prompt user for pin if pin is required XXX */
313 /* Run the conference */
314 res
= conf_run(chan
, confno
, confflags
);
317 /* Do the conference */
318 ast_module_user_remove(u
);
322 static int exec_zap(struct ast_channel
*chan
, void *data
)
324 ast_log(LOG_WARNING
, "Use of the command %s is deprecated, please use %s instead.\n", zap_app
, dahdi_app
);
326 return exec(chan
, data
, 0);
329 static int exec_dahdi(struct ast_channel
*chan
, void *data
)
331 return exec(chan
, data
, 1);
334 static int unload_module(void)
338 if (*dahdi_chan_mode
== CHAN_DAHDI_PLUS_ZAP_MODE
) {
339 res
|= ast_unregister_application(dahdi_app
);
342 res
|= ast_unregister_application(zap_app
);
344 ast_module_user_hangup_all();
349 static int load_module(void)
353 if (*dahdi_chan_mode
== CHAN_DAHDI_PLUS_ZAP_MODE
) {
354 res
|= ast_register_application(dahdi_app
, exec_dahdi
, dahdi_synopsis
, dahdi_descrip
);
357 res
|= ast_register_application(zap_app
, exec_zap
, zap_synopsis
, zap_descrip
);
362 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Barge in on channel application");