Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


app_dahdibarge.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * Special thanks to comphealth.com for sponsoring this
9  * GPL application.
10  *
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.
16  *
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.
20  */
21 
22 /*! \file
23  *
24  * \brief DAHDI Barge support
25  *
26  * \author Mark Spencer <markster@digium.com>
27  *
28  * \note Special thanks to comphealth.com for sponsoring this
29  * GPL application.
30  *
31  * \ingroup applications
32  */
33 
34 /*** MODULEINFO
35  <depend>dahdi</depend>
36  <support_level>deprecated</support_level>
37  <replacement>app_chanspy</replacement>
38  ***/
39 
40 #include "asterisk.h"
41 
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328446 $")
43 
44 #include <dahdi/user.h>
45 
46 #include "asterisk/lock.h"
47 #include "asterisk/file.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/module.h"
51 #include "asterisk/config.h"
52 #include "asterisk/app.h"
53 #include "asterisk/cli.h"
54 #include "asterisk/say.h"
55 #include "asterisk/utils.h"
56 
57 /*** DOCUMENTATION
58  <application name="DAHDIBarge" language="en_US">
59  <synopsis>
60  Barge in (monitor) DAHDI channel.
61  </synopsis>
62  <syntax>
63  <parameter name="channel">
64  <para>Channel to barge.</para>
65  </parameter>
66  </syntax>
67  <description>
68  <para>Barges in on a specified DAHDI <replaceable>channel</replaceable> or prompts
69  if one is not specified. Returns <literal>-1</literal> when caller user hangs
70  up and is independent of the state of the channel being monitored.
71  </para>
72  </description>
73  </application>
74  ***/
75 static const char app[] = "DAHDIBarge";
76 
77 #define CONF_SIZE 160
78 
79 static int careful_write(int fd, unsigned char *data, int len)
80 {
81  int res;
82  while(len) {
83  res = write(fd, data, len);
84  if (res < 1) {
85  if (errno != EAGAIN) {
86  ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
87  return -1;
88  } else
89  return 0;
90  }
91  len -= res;
92  data += res;
93  }
94  return 0;
95 }
96 
97 static int conf_run(struct ast_channel *chan, int confno, int confflags)
98 {
99  int fd;
100  struct dahdi_confinfo dahdic;
101  struct ast_frame *f;
102  struct ast_channel *c;
103  struct ast_frame fr;
104  int outfd;
105  int ms;
106  int nfds;
107  int res;
108  int flags;
109  int retrydahdi;
110  int origfd;
111  int ret = -1;
112 
113  struct dahdi_bufferinfo bi;
114  char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
115  char *buf = __buf + AST_FRIENDLY_OFFSET;
116 
117  /* Set it into U-law mode (write) */
118  if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
119  ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
120  goto outrun;
121  }
122 
123  /* Set it into U-law mode (read) */
124  if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
125  ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
126  goto outrun;
127  }
128  ast_indicate(chan, -1);
129  retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
130 dahdiretry:
131  origfd = chan->fds[0];
132  if (retrydahdi) {
133  fd = open("/dev/dahdi/pseudo", O_RDWR);
134  if (fd < 0) {
135  ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
136  goto outrun;
137  }
138  /* Make non-blocking */
139  flags = fcntl(fd, F_GETFL);
140  if (flags < 0) {
141  ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
142  close(fd);
143  goto outrun;
144  }
145  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
146  ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
147  close(fd);
148  goto outrun;
149  }
150  /* Setup buffering information */
151  memset(&bi, 0, sizeof(bi));
152  bi.bufsize = CONF_SIZE;
153  bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
154  bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
155  bi.numbufs = 4;
156  if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
157  ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
158  close(fd);
159  goto outrun;
160  }
161  nfds = 1;
162  } else {
163  /* XXX Make sure we're not running on a pseudo channel XXX */
164  fd = chan->fds[0];
165  nfds = 0;
166  }
167  memset(&dahdic, 0, sizeof(dahdic));
168  /* Check to see if we're in a conference... */
169  dahdic.chan = 0;
170  if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
171  ast_log(LOG_WARNING, "Error getting conference\n");
172  close(fd);
173  goto outrun;
174  }
175  if (dahdic.confmode) {
176  /* Whoa, already in a conference... Retry... */
177  if (!retrydahdi) {
178  ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
179  retrydahdi = 1;
180  goto dahdiretry;
181  }
182  }
183  memset(&dahdic, 0, sizeof(dahdic));
184  /* Add us to the conference */
185  dahdic.chan = 0;
186  dahdic.confno = confno;
187  dahdic.confmode = DAHDI_CONF_MONITORBOTH;
188 
189  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
190  ast_log(LOG_WARNING, "Error setting conference\n");
191  close(fd);
192  goto outrun;
193  }
194  ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
195 
196  for(;;) {
197  outfd = -1;
198  ms = -1;
199  c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
200  if (c) {
201  if (c->fds[0] != origfd) {
202  if (retrydahdi) {
203  /* Kill old pseudo */
204  close(fd);
205  }
206  ast_debug(1, "Ooh, something swapped out under us, starting over\n");
207  retrydahdi = 0;
208  goto dahdiretry;
209  }
210  f = ast_read(c);
211  if (!f)
212  break;
213  if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
214  ret = 0;
215  ast_frfree(f);
216  break;
217  } else if (fd != chan->fds[0]) {
218  if (f->frametype == AST_FRAME_VOICE) {
219  if (f->subclass.codec == AST_FORMAT_ULAW) {
220  /* Carefully write */
221  careful_write(fd, f->data.ptr, f->datalen);
222  } else
223  ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%s) frame in the conference\n", ast_getformatname(f->subclass.codec));
224  }
225  }
226  ast_frfree(f);
227  } else if (outfd > -1) {
228  res = read(outfd, buf, CONF_SIZE);
229  if (res > 0) {
230  memset(&fr, 0, sizeof(fr));
233  fr.datalen = res;
234  fr.samples = res;
235  fr.data.ptr = buf;
237  if (ast_write(chan, &fr) < 0) {
238  ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
239  /* break; */
240  }
241  } else
242  ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
243  }
244  }
245  if (fd != chan->fds[0])
246  close(fd);
247  else {
248  /* Take out of conference */
249  /* Add us to the conference */
250  dahdic.chan = 0;
251  dahdic.confno = 0;
252  dahdic.confmode = 0;
253  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
254  ast_log(LOG_WARNING, "Error setting conference\n");
255  }
256  }
257 
258 outrun:
259 
260  return ret;
261 }
262 
263 static int conf_exec(struct ast_channel *chan, const char *data)
264 {
265  int res = -1;
266  int retrycnt = 0;
267  int confflags = 0;
268  int confno = 0;
269  char confnostr[80] = "";
270 
271  if (!ast_strlen_zero(data)) {
272  if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
273  (sscanf(data, "%30d", &confno) != 1)) {
274  ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
275  return 0;
276  }
277  }
278 
279  if (chan->_state != AST_STATE_UP)
280  ast_answer(chan);
281 
282  while(!confno && (++retrycnt < 4)) {
283  /* Prompt user for conference number */
284  confnostr[0] = '\0';
285  res = ast_app_getdata(chan, "conf-getchannel",confnostr, sizeof(confnostr) - 1, 0);
286  if (res <0) goto out;
287  if (sscanf(confnostr, "%30d", &confno) != 1)
288  confno = 0;
289  }
290  if (confno) {
291  /* XXX Should prompt user for pin if pin is required XXX */
292  /* Run the conference */
293  res = conf_run(chan, confno, confflags);
294  }
295 out:
296  /* Do the conference */
297  return res;
298 }
299 
300 static int unload_module(void)
301 {
302  return ast_unregister_application(app);
303 }
304 
305 static int load_module(void)
306 {
308 }
309 
310 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");
union ast_frame_subclass subclass
Definition: frame.h:146
Main Channel structure associated with a channel.
Definition: channel.h:742
static int unload_module(void)
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
const char *const type
Definition: channel.h:508
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int offset
Definition: frame.h:156
int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
Definition: app.c:178
static int load_module(void)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4393
void * ptr
Definition: frame.h:160
#define LOG_WARNING
Definition: logger.h:144
#define AST_FRAME_DTMF
Definition: frame.h:128
#define CONF_SIZE
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
Configuration File Parser.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
format_t codec
Definition: frame.h:137
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **chan, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:3188
Utility functions.
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
int ast_set_read_format(struct ast_channel *chan, format_t format)
Sets read format on channel chan Set read format for channel to whichever component of &quot;format&quot; is be...
Definition: channel.c:5301
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
General Asterisk PBX channel definitions.
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Definition: frame.h:204
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
int datalen
Definition: frame.h:148
Core PBX routines and definitions.
static const char app[]
int fds[AST_MAX_FDS]
Definition: channel.h:829
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define AST_FORMAT_ULAW
Definition: frame.h:246
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_channel_state _state
Definition: channel.h:839
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int conf_exec(struct ast_channel *chan, const char *data)
int errno
unsigned int flags
Definition: frame.h:166
static struct ast_format f[]
Definition: format_g726.c:181
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:4916
static int conf_run(struct ast_channel *chan, int confno, int confflags)
Standard Command Line Interface.
static int careful_write(int fd, unsigned char *data, int len)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
Definition: frame.h:142
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
union ast_frame::@172 data
struct ast_channel_tech * tech
Definition: channel.h:743
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int samples
Definition: frame.h:150