[Asterisk-code-review] app_sendmf: New SendMF application (asterisk[master])
N A
asteriskteam at digium.com
Mon Jun 28 10:39:15 CDT 2021
N A has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/16080 )
Change subject: app_sendmf: New SendMF application
......................................................................
app_sendmf: New SendMF application
Adds a SendMF application to send arbitrary
R1 MF tones on a channel.
ASTERISK-29496
Change-Id: I5d89afdbccee3f86cc702ed96d882f3d351327a4
---
A apps/app_sendmf.c
A doc/CHANGES-staging/app_sendmf.txt
2 files changed, 321 insertions(+), 0 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/80/16080/1
diff --git a/apps/app_sendmf.c b/apps/app_sendmf.c
new file mode 100644
index 0000000..4b3f070
--- /dev/null
+++ b/apps/app_sendmf.c
@@ -0,0 +1,315 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2021, Naveen Albert
+ *
+ * Naveen Albert <asterisk at phreaknet.org>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief App to send MF digits
+ *
+ * \author Naveen Albert <asterisk at phreaknet.org>
+ *
+ * \ingroup applications
+ */
+
+/*** MODULEINFO
+ <support_level>extended</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/app.h"
+#include "asterisk/channel.h"
+#include "asterisk/indications.h"
+
+/*** DOCUMENTATION
+ <application name="SendMF" language="en_US">
+ <synopsis>
+ Sends arbitrary MF digits
+ </synopsis>
+ <syntax>
+ <parameter name="digits" required="true">
+ <para>List of digits 0-9,KSTUV to send; also f or F for a flash-hook
+ if the channel supports flash-hook, and w or W for a wink if the channel
+ supports wink.</para>
+ <para>Key pulse and start digits are not included automatically.
+ K is used for KP, S for ST, T for STP, U for ST2P, and V for ST3P.</para>
+ </parameter>
+ <parameter name="timeout_ms" required="false">
+ <para>Amount of time to wait in ms between tones. (defaults to 50ms).</para>
+ </parameter>
+ <parameter name="duration_ms" required="false">
+ <para>Duration of each numeric digit (defaults to 55ms).</para>
+ </parameter>
+ <parameter name="duration_ms_kp" required="false">
+ <para>Duration of KP digits (defaults to 120ms).</para>
+ </parameter>
+ <parameter name="duration_ms_st" required="false">
+ <para>Duration of ST, STP, ST2P, and ST3P digits (defaults to 55ms).</para>
+ </parameter>
+ <parameter name="channel" required="false">
+ <para>Channel where digits will be played</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>It will send all digits or terminate if it encounters an error.</para>
+ </description>
+ <see-also>
+ <ref type="application">SendDTMF</ref>
+ </see-also>
+ </application>
+ ***/
+
+static const char sendmf_name[] = "SendMF";
+
+#define AST_DEFAULT_EMULATE_MF_DURATION 100
+
+static int ast_senddigit_mf_begin(struct ast_channel *chan, char digit)
+{
+ static const char * const mf_tones[] = {
+ "1300+1500", /* 0 */
+ "700+900", /* 1 */
+ "700+1100", /* 2 */
+ "900+1100", /* 3 */
+ "700+1300", /* 4 */
+ "900+1300", /* 5 */
+ "1100+1300", /* 6 */
+ "700+1500", /* 7 */
+ "900+1500", /* 8 */
+ "1100+1500", /* 9 */
+ "1100+1700", /* K (KP) */
+ "1500+1700", /* S (ST) */
+ "900+1700", /* T (STP) */
+ "1300+1700", /* U (ST2P) */
+ "700+1700" /* V (ST3P) */
+ };
+
+ if (digit >= '0' && digit <='9')
+ ast_playtones_start(chan, 0, mf_tones[digit-'0'], 0);
+ else if (digit == 'K')
+ ast_playtones_start(chan, 0, mf_tones[10], 0);
+ else if (digit == 'S')
+ ast_playtones_start(chan, 0, mf_tones[11], 0);
+ else if (digit == 'T')
+ ast_playtones_start(chan, 0, mf_tones[12], 0);
+ else if (digit == 'U')
+ ast_playtones_start(chan, 0, mf_tones[13], 0);
+ else if (digit == 'V')
+ ast_playtones_start(chan, 0, mf_tones[14], 0);
+ else {
+ /* not handled */
+ ast_debug(1, "Unable to generate MF tone '%c' for '%s'\n", digit, ast_channel_name(chan));
+ }
+
+ return 0;
+}
+
+static int ast_senddigit_mf_end(struct ast_channel *chan, char digit, unsigned int duration)
+{
+ if (ast_channel_generator(chan)) {
+ ast_playtones_stop(chan);
+ return 0;
+ }
+ return -1;
+}
+
+static int ast_senddigit_mf(struct ast_channel *chan, char digit, unsigned int duration, unsigned int durationkp, unsigned int durationst)
+{
+ if (duration < AST_DEFAULT_EMULATE_MF_DURATION) {
+ duration = AST_DEFAULT_EMULATE_MF_DURATION;
+ }
+ if (ast_channel_tech(chan)->send_digit_begin) {
+ if (digit == 'K')
+ duration = durationkp;
+ else if (digit == 'S' || digit == 'T' || digit == 'U' || digit == 'V')
+ duration = durationst;
+ ast_senddigit_mf_begin(chan, digit);
+ ast_safe_sleep(chan, duration);
+ }
+ return ast_senddigit_mf_end(chan, digit, duration);
+}
+
+static int ast_senddigit_external_mf(struct ast_channel *chan, char digit, unsigned int duration, unsigned int durationkp, unsigned int durationst)
+{
+ if (duration < AST_DEFAULT_EMULATE_MF_DURATION) {
+ duration = AST_DEFAULT_EMULATE_MF_DURATION;
+ }
+ if (ast_channel_tech(chan)->send_digit_begin) {
+ ast_senddigit_mf_begin(chan, digit);
+ if (digit == 'K')
+ duration = durationkp;
+ else if (digit == 'S' || digit == 'T' || digit == 'U' || digit == 'V')
+ duration = durationst;
+ usleep(duration * 1000);
+ }
+ return ast_senddigit_mf_end(chan, digit, duration);
+}
+
+static int external_sleep(struct ast_channel *chan, int ms)
+{
+ usleep(ms * 1000);
+ return 0;
+}
+
+static int mf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, unsigned int durationkp, unsigned int durationst, int is_external)
+{
+ const char *ptr;
+ int res;
+ struct ast_silence_generator *silgen = NULL;
+ int (*my_sleep)(struct ast_channel *chan, int ms);
+ int (*my_senddigit)(struct ast_channel *chan, char digit, unsigned int duration, unsigned int durationkp, unsigned int durationst);
+
+ if (is_external) {
+ my_sleep = external_sleep;
+ my_senddigit = ast_senddigit_external_mf;
+ } else {
+ my_sleep = ast_safe_sleep;
+ my_senddigit = ast_senddigit_mf;
+ }
+
+ if (!between) {
+ between = 100;
+ }
+
+ /* Need a quiet time before sending digits. */
+ if (ast_opt_transmit_silence) {
+ silgen = ast_channel_start_silence_generator(chan);
+ }
+ res = my_sleep(chan, 100);
+ if (res) {
+ goto mf_stream_cleanup;
+ }
+
+ for (ptr = digits; *ptr; ptr++) {
+ if (strchr("0123456789KSTUVwWfF", *ptr)) {
+ if (*ptr == 'f' || *ptr == 'F') {
+ /* ignore return values if not supported by channel */
+ ast_indicate(chan, AST_CONTROL_FLASH);
+ } else if (*ptr == 'w' || *ptr == 'W') {
+ /* ignore return values if not supported by channel */
+ ast_indicate(chan, AST_CONTROL_WINK);
+ } else {
+ /* Character represents valid DTMF */
+ my_senddigit(chan, *ptr, duration, durationkp, durationst);
+ }
+ /* pause between digits */
+ res = my_sleep(chan, between);
+ if (res) {
+ break;
+ }
+ } else {
+ ast_log(LOG_WARNING, "Illegal MF character '%c' in string. (0-9KSTUVwWfF allowed)\n", *ptr);
+ }
+ }
+
+mf_stream_cleanup:
+ if (silgen) {
+ ast_channel_stop_silence_generator(chan, silgen);
+ }
+
+ return res;
+}
+
+static int ast_mf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration, unsigned int durationkp, unsigned int durationst)
+{
+ int res;
+
+ if (peer && ast_autoservice_start(peer)) {
+ return -1;
+ }
+ res = mf_stream(chan, digits, between, duration, durationkp, durationst, 0);
+ if (peer && ast_autoservice_stop(peer)) {
+ res = -1;
+ }
+
+ return res;
+}
+
+static int sendmf_exec(struct ast_channel *chan, const char *vdata)
+{
+ int res;
+ char *data;
+ int dinterval = 0, duration = 0, durationkp = 0, durationst = 0;
+ struct ast_channel *chan_found = NULL;
+ struct ast_channel *chan_dest = chan;
+ struct ast_channel *chan_autoservice = NULL;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(digits);
+ AST_APP_ARG(dinterval);
+ AST_APP_ARG(duration);
+ AST_APP_ARG(durationkp);
+ AST_APP_ARG(durationst);
+ AST_APP_ARG(channel);
+ );
+
+ if (ast_strlen_zero(vdata)) {
+ ast_log(LOG_WARNING, "SendMF requires an argument\n");
+ return 0;
+ }
+
+ data = ast_strdupa(vdata);
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (ast_strlen_zero(args.digits)) {
+ ast_log(LOG_WARNING, "The digits argument is required (0-9,KSTUV,wf)\n");
+ return 0;
+ }
+ if (!ast_strlen_zero(args.dinterval)) {
+ ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
+ }
+ if (!ast_strlen_zero(args.duration)) {
+ ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
+ }
+ if (!ast_strlen_zero(args.durationkp)) {
+ ast_app_parse_timelen(args.durationkp, &durationkp, TIMELEN_MILLISECONDS);
+ }
+ if (!ast_strlen_zero(args.duration)) {
+ ast_app_parse_timelen(args.durationst, &durationst, TIMELEN_MILLISECONDS);
+ }
+ if (!ast_strlen_zero(args.channel)) {
+ chan_found = ast_channel_get_by_name(args.channel);
+ if (!chan_found) {
+ ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
+ return 0;
+ }
+ chan_dest = chan_found;
+ if (chan_found != chan) {
+ chan_autoservice = chan;
+ }
+ }
+ res = ast_mf_stream(chan_dest, chan_autoservice, args.digits,
+ dinterval <= 0 ? 50 : dinterval, duration <= 0 ? 55 : duration,
+ durationkp <= 0 ? 120 : durationkp, durationst <= 0 ? 55 : durationst);
+ if (chan_found) {
+ ast_channel_unref(chan_found);
+ }
+
+ return chan_autoservice ? 0 : res;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(sendmf_name);
+}
+
+static int load_module(void)
+{
+ return ast_register_application_xml(sendmf_name, sendmf_exec);
+}
+
+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Send MF digits Application");
diff --git a/doc/CHANGES-staging/app_sendmf.txt b/doc/CHANGES-staging/app_sendmf.txt
new file mode 100644
index 0000000..4344276
--- /dev/null
+++ b/doc/CHANGES-staging/app_sendmf.txt
@@ -0,0 +1,6 @@
+Subject: send_mf application
+
+A SendMF application is now included
+to send arbitrary standard R1 MF
+tones on a channel.
+
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/16080
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I5d89afdbccee3f86cc702ed96d882f3d351327a4
Gerrit-Change-Number: 16080
Gerrit-PatchSet: 1
Gerrit-Owner: N A <mail at interlinked.x10host.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20210628/05d989d8/attachment-0001.html>
More information about the asterisk-code-review
mailing list