Asterisk - The Open Source Telephony Project  21.4.1
app_senddtmf.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  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief App to send DTMF digits
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup applications
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include "asterisk/pbx.h"
35 #include "asterisk/module.h"
36 #include "asterisk/app.h"
37 #include "asterisk/manager.h"
38 #include "asterisk/channel.h"
39 
40 /*** DOCUMENTATION
41  <application name="SendDTMF" language="en_US">
42  <synopsis>
43  Sends arbitrary DTMF digits
44  </synopsis>
45  <syntax>
46  <parameter name="digits" required="true">
47  <para>List of digits 0-9,*#,a-d,A-D to send also w for a half second pause,
48  W for a one second pause, and f or F for a flash-hook if the channel supports
49  flash-hook.</para>
50  </parameter>
51  <parameter name="timeout_ms" required="false">
52  <para>Amount of time to wait in ms between tones. (defaults to .25s)</para>
53  </parameter>
54  <parameter name="duration_ms" required="false">
55  <para>Duration of each digit</para>
56  </parameter>
57  <parameter name="channel" required="false">
58  <para>Channel where digits will be played</para>
59  </parameter>
60  <parameter name="options">
61  <optionlist>
62  <option name="a">
63  <para>Answer the channel specified by the <literal>channel</literal>
64  parameter if it is not already up. If no <literal>channel</literal>
65  parameter is provided, the current channel will be answered.</para>
66  </option>
67  </optionlist>
68  </parameter>
69  </syntax>
70  <description>
71  <para>It will send all digits or terminate if it encounters an error.</para>
72  </description>
73  <see-also>
74  <ref type="application">Read</ref>
75  </see-also>
76  </application>
77  <manager name="PlayDTMF" language="en_US">
78  <synopsis>
79  Play DTMF signal on a specific channel.
80  </synopsis>
81  <syntax>
82  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
83  <parameter name="Channel" required="true">
84  <para>Channel name to send digit to.</para>
85  </parameter>
86  <parameter name="Digit" required="true">
87  <para>The DTMF digit to play.</para>
88  </parameter>
89  <parameter name="Duration" required="false">
90  <para>The duration, in milliseconds, of the digit to be played.</para>
91  </parameter>
92  <parameter name="Receive" required="false">
93  <para>Emulate receiving DTMF on this channel instead of sending it out.</para>
94  </parameter>
95  </syntax>
96  <description>
97  <para>Plays a dtmf digit on the specified channel.</para>
98  </description>
99  </manager>
100  <manager name="SendFlash" language="en_US">
101  <synopsis>
102  Send a hook flash on a specific channel.
103  </synopsis>
104  <syntax>
105  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
106  <parameter name="Channel" required="true">
107  <para>Channel name to send hook flash to.</para>
108  </parameter>
109  <parameter name="Receive" required="false">
110  <para>Emulate receiving a hook flash on this channel instead of sending it out.</para>
111  </parameter>
112  </syntax>
113  <description>
114  <para>Sends a hook flash on the specified channel.</para>
115  </description>
116  </manager>
117  ***/
118 
119 enum read_option_flags {
120  OPT_ANSWER = (1 << 0),
121 };
122 
123 AST_APP_OPTIONS(senddtmf_app_options, {
124  AST_APP_OPTION('a', OPT_ANSWER),
125 });
126 
127 enum {
128  /* note: this entry _MUST_ be the last one in the enum */
129  OPT_ARG_ARRAY_SIZE,
130 };
131 
132 static const char senddtmf_name[] = "SendDTMF";
133 
134 static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
135 {
136  int res;
137  char *data;
138  int dinterval = 0, duration = 0;
139  struct ast_channel *chan_found = NULL;
140  struct ast_channel *chan_dest = chan;
141  struct ast_channel *chan_autoservice = NULL;
142  char *opt_args[OPT_ARG_ARRAY_SIZE];
143  struct ast_flags flags = {0};
145  AST_APP_ARG(digits);
146  AST_APP_ARG(dinterval);
147  AST_APP_ARG(duration);
148  AST_APP_ARG(channel);
149  AST_APP_ARG(options);
150  );
151 
152  if (ast_strlen_zero(vdata)) {
153  ast_log(LOG_WARNING, "SendDTMF requires an argument\n");
154  return 0;
155  }
156 
157  data = ast_strdupa(vdata);
158  AST_STANDARD_APP_ARGS(args, data);
159 
160  if (ast_strlen_zero(args.digits)) {
161  ast_log(LOG_WARNING, "The digits argument is required (0-9,*#,a-d,A-D,wfF)\n");
162  return 0;
163  }
164  if (!ast_strlen_zero(args.dinterval)) {
165  ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
166  }
167  if (!ast_strlen_zero(args.duration)) {
168  ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
169  }
170  if (!ast_strlen_zero(args.channel)) {
171  chan_found = ast_channel_get_by_name(args.channel);
172  if (!chan_found) {
173  ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
174  return 0;
175  }
176  chan_dest = chan_found;
177  if (chan_found != chan) {
178  chan_autoservice = chan;
179  }
180  }
181  if (!ast_strlen_zero(args.options)) {
182  ast_app_parse_options(senddtmf_app_options, &flags, opt_args, args.options);
183  }
184  if (ast_test_flag(&flags, OPT_ANSWER)) {
185  ast_auto_answer(chan_dest);
186  }
187  res = ast_dtmf_stream(chan_dest, chan_autoservice, args.digits,
188  dinterval <= 0 ? 250 : dinterval, duration);
189  if (chan_found) {
190  ast_channel_unref(chan_found);
191  }
192 
193  return chan_autoservice ? 0 : res;
194 }
195 
196 static int manager_play_dtmf(struct mansession *s, const struct message *m)
197 {
198  const char *channel = astman_get_header(m, "Channel");
199  const char *digit = astman_get_header(m, "Digit");
200  const char *duration = astman_get_header(m, "Duration");
201  const char *receive_s = astman_get_header(m, "Receive");
202  struct ast_channel *chan;
203  unsigned int duration_ms = 0;
204 
205  if (!(chan = ast_channel_get_by_name(channel))) {
206  astman_send_error(s, m, "Channel not found");
207  return 0;
208  }
209 
210  if (ast_strlen_zero(digit)) {
211  astman_send_error(s, m, "No digit specified");
212  chan = ast_channel_unref(chan);
213  return 0;
214  }
215 
216  if (!ast_strlen_zero(duration) && (sscanf(duration, "%30u", &duration_ms) != 1)) {
217  astman_send_error(s, m, "Could not convert Duration parameter");
218  chan = ast_channel_unref(chan);
219  return 0;
220  }
221 
222  if (ast_true(receive_s)) {
223  struct ast_frame f = { AST_FRAME_DTMF, };
224  f.len = duration_ms;
225  f.subclass.integer = *digit;
226  ast_queue_frame(chan, &f);
227  } else {
228  ast_senddigit_external(chan, *digit, duration_ms);
229  }
230 
231  chan = ast_channel_unref(chan);
232 
233  astman_send_ack(s, m, "DTMF successfully queued");
234 
235  return 0;
236 }
237 
238 static int manager_send_flash(struct mansession *s, const struct message *m)
239 {
240  const char *channel = astman_get_header(m, "Channel");
241  const char *receive_s = astman_get_header(m, "Receive");
242  struct ast_channel *chan;
243 
244  if (!(chan = ast_channel_get_by_name(channel))) {
245  astman_send_error(s, m, "Channel not found");
246  return 0;
247  }
248 
249  if (ast_true(receive_s)) {
250  struct ast_frame f = { AST_FRAME_CONTROL, };
252  ast_queue_frame(chan, &f);
253  } else {
254  struct ast_frame f = { AST_FRAME_CONTROL, };
256  ast_channel_lock(chan);
257  ast_write(chan, &f);
258  ast_channel_unlock(chan);
259  }
260 
261  chan = ast_channel_unref(chan);
262  astman_send_ack(s, m, "Flash successfully queued");
263  return 0;
264 }
265 
266 static int unload_module(void)
267 {
268  int res;
269 
270  res = ast_unregister_application(senddtmf_name);
271  res |= ast_manager_unregister("PlayDTMF");
272  res |= ast_manager_unregister("SendFlash");
273 
274  return res;
275 }
276 
277 static int load_module(void)
278 {
279  int res;
280 
281  res = ast_manager_register_xml("PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf);
282  res |= ast_manager_register_xml("SendFlash", EVENT_FLAG_CALL, manager_send_flash);
283  res |= ast_register_application_xml(senddtmf_name, senddtmf_exec);
284 
285  return res;
286 }
287 
288 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send DTMF digits Application");
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
Send a string of DTMF digits to a channel.
Definition: main/app.c:1127
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
int ast_auto_answer(struct ast_channel *chan)
Answer a channel, if it's not already answered.
Definition: channel.c:2811
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_senddigit_external(struct ast_channel *chan, char digit, unsigned int duration)
Send a DTMF digit to a channel from an external thread.
Definition: channel.c:4987
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
struct ast_frame_subclass subclass
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1139
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
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:5144
Structure used to handle boolean flags.
Definition: utils.h:199
Data structure associated with a single frame of data.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit)
Common routine to parse time lengths, with optional time unit specifier.
Definition: main/app.c:3273
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
#define AST_APP_ARG(name)
Define an application argument.