<p>Sean Bright has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6457">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_waitforsilence: Cleanup & don't treat missing frames as 'noise'<br><br>* WaitForSilence completes successfully if it receives no media in the<br> specified timeout, but when acting as WaitForNoise that logic needs<br> to be reversed.<br><br>* Use standard argument parsing macros and add some error checking for<br> invalid values.<br><br>* The documentation indicated that the first argument to both<br> WaitForSilence and WaitForNoise was required when it was not. Update<br> the documentation to reflect that.<br><br>* Wrap up some behavior in structs to avoid boolean checks all over the<br> place.<br><br>ASTERISK-24066 #close<br>Reported by: M vd S<br><br>Change-Id: I01d40adc5b63342bb5018a1bea2081a0aa191ef9<br>---<br>M apps/app_waitforsilence.c<br>1 file changed, 91 insertions(+), 48 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/57/6457/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/apps/app_waitforsilence.c b/apps/app_waitforsilence.c<br>index 5eaeace..52248ac 100644<br>--- a/apps/app_waitforsilence.c<br>+++ b/apps/app_waitforsilence.c<br>@@ -44,6 +44,7 @@<br> <br> #include "asterisk.h"<br> <br>+#include "asterisk/app.h"<br> #include "asterisk/file.h"<br> #include "asterisk/channel.h"<br> #include "asterisk/pbx.h"<br>@@ -57,7 +58,9 @@<br> Waits for a specified amount of silence.<br> </synopsis><br> <syntax><br>- <parameter name="silencerequired" required="true" /><br>+ <parameter name="silencerequired"><br>+ <para>If not specified, defaults to <literal>1000</literal> milliseconds.</para><br>+ </parameter><br> <parameter name="iterations"><br> <para>If not specified, defaults to <literal>1</literal>.</para><br> </parameter><br>@@ -101,7 +104,9 @@<br> Waits for a specified amount of noise.<br> </synopsis><br> <syntax><br>- <parameter name="noiserequired" required="true" /><br>+ <parameter name="noiserequired"><br>+ <para>If not specified, defaults to <literal>1000</literal> milliseconds.</para><br>+ </parameter><br> <parameter name="iterations"><br> <para>If not specified, defaults to <literal>1</literal>.</para><br> </parameter><br>@@ -125,17 +130,32 @@<br> static char *app_silence = "WaitForSilence";<br> static char *app_noise = "WaitForNoise";<br> <br>-static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) {<br>- struct ast_frame *f = NULL;<br>- int dsptime = 0;<br>- RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);<br>- int res = 0;<br>- struct ast_dsp *sildet; /* silence detector dsp */<br>- time_t now;<br>+struct wait_type {<br>+ const char *name;<br>+ const char *status;<br>+ int stop_on_frame_timeout;<br>+ int (*func)(struct ast_dsp *, struct ast_frame *, int *);<br>+};<br> <br>- /*Either silence or noise calc depending on wait_for_silence flag*/<br>- int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) =<br>- wait_for_silence ? ast_dsp_silence : ast_dsp_noise;<br>+static const struct wait_type wait_for_silence = {<br>+ .name = "silence",<br>+ .status = "SILENCE",<br>+ .stop_on_frame_timeout = 1,<br>+ .func = ast_dsp_silence,<br>+};<br>+<br>+static const struct wait_type wait_for_noise = {<br>+ .name = "noise",<br>+ .status = "NOISE",<br>+ .stop_on_frame_timeout = 0,<br>+ .func = ast_dsp_noise,<br>+};<br>+<br>+static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, const struct wait_type *wait_for)<br>+{<br>+ RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);<br>+ int res;<br>+ struct ast_dsp *sildet;<br> <br> rfmt = ao2_bump(ast_channel_readformat(chan));<br> if ((res = ast_set_read_format(chan, ast_format_slin)) < 0) {<br>@@ -145,15 +165,13 @@<br> <br> /* Create the silence detector */<br> if (!(sildet = ast_dsp_new())) {<br>- ast_log(LOG_WARNING, "Unable to create silence detector :(\n");<br>+ ast_log(LOG_WARNING, "Unable to create silence detector\n");<br> return -1;<br> }<br> ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));<br> <br>- /* Await silence... */<br> for (;;) {<br>- /* Start with no silence received */<br>- dsptime = 0;<br>+ int dsptime = 0;<br> <br> res = ast_waitfor(chan, timereqd);<br> <br>@@ -162,34 +180,36 @@<br> pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP");<br> break;<br> }<br>- <br>+<br> /* We waited and got no frame; sounds like digital silence or a muted digital channel */<br> if (res == 0) {<br>- dsptime = timereqd;<br>+ if (wait_for->stop_on_frame_timeout) {<br>+ dsptime = timereqd;<br>+ }<br> } else {<br> /* Looks like we did get a frame, so let's check it out */<br>- if (!(f = ast_read(chan))) {<br>+ struct ast_frame *f = ast_read(chan);<br>+ if (!f) {<br> pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP");<br> break;<br> }<br> if (f->frametype == AST_FRAME_VOICE) {<br>- ast_dsp_func(sildet, f, &dsptime);<br>+ wait_for->func(sildet, f, &dsptime);<br> }<br> ast_frfree(f);<br> }<br> <br>- ast_debug(1, "Got %dms %s < %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);<br>+ ast_debug(1, "Got %dms of %s < %dms required\n", dsptime, wait_for->name, timereqd);<br> <br> if (dsptime >= timereqd) {<br>- ast_verb(3, "Exiting with %dms %s >= %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);<br>- /* Ended happily with silence */<br>+ ast_verb(3, "Exiting with %dms of %s >= %dms required\n", dsptime, wait_for->name, timereqd);<br>+ pbx_builtin_setvar_helper(chan, "WAITSTATUS", wait_for->status);<br>+ ast_debug(1, "WAITSTATUS was set to %s\n", wait_for->status);<br> res = 1;<br>- pbx_builtin_setvar_helper(chan, "WAITSTATUS", wait_for_silence ? "SILENCE" : "NOISE");<br>- ast_debug(1, "WAITSTATUS was set to %s\n", wait_for_silence ? "SILENCE" : "NOISE");<br> break;<br> }<br> <br>- if (timeout && (difftime(time(&now), waitstart) >= timeout)) {<br>+ if (timeout && difftime(time(NULL), waitstart) >= timeout) {<br> pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT");<br> ast_debug(1, "WAITSTATUS was set to TIMEOUT\n");<br> res = 0;<br>@@ -197,61 +217,86 @@<br> }<br> }<br> <br>-<br> if (rfmt && ast_set_read_format(chan, rfmt)) {<br> ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan));<br> }<br>+<br> ast_dsp_free(sildet);<br> return res;<br> }<br> <br>-static int waitfor_exec(struct ast_channel *chan, const char *data, int wait_for_silence)<br>+static int waitfor_exec(struct ast_channel *chan, const char *data, const struct wait_type *wait_for)<br> {<br> int res = 1;<br> int timereqd = 1000;<br> int timeout = 0;<br> int iterations = 1, i;<br> time_t waitstart;<br>+ char *parse;<br> struct ast_silence_generator *silgen = NULL;<br> <br>+ AST_DECLARE_APP_ARGS(args,<br>+ AST_APP_ARG(timereqd);<br>+ AST_APP_ARG(iterations);<br>+ AST_APP_ARG(timeout);<br>+ );<br>+<br>+ parse = ast_strdupa(data);<br>+ AST_STANDARD_APP_ARGS(args, parse);<br>+<br>+ if (!ast_strlen_zero(args.timereqd)) {<br>+ if (sscanf(args.timereqd, "%30d", &timereqd) != 1 || timereqd < 0) {<br>+ ast_log(LOG_ERROR, "Argument '%srequired' must be an integer greater than or equal to zero.\n",<br>+ wait_for->name);<br>+ return -1;<br>+ }<br>+ }<br>+<br>+ if (!ast_strlen_zero(args.iterations)) {<br>+ if (sscanf(args.iterations, "%30d", &iterations) != 1 || iterations < 1) {<br>+ ast_log(LOG_ERROR, "Argument 'iterations' must be an integer greater than 0.\n");<br>+ return -1;<br>+ }<br>+ }<br>+<br>+ if (!ast_strlen_zero(args.timeout)) {<br>+ if (sscanf(args.timeout, "%30d", &timeout) != 1 || timeout < 0) {<br>+ ast_log(LOG_ERROR, "Argument 'timeout' must be an integer greater than or equal to zero.\n");<br>+ return -1;<br>+ }<br>+ }<br>+<br> if (ast_channel_state(chan) != AST_STATE_UP) {<br>- res = ast_answer(chan); /* Answer the channel */<br>+ ast_answer(chan); /* Answer the channel */<br> }<br> <br>- if (!data || ( (sscanf(data, "%30d,%30d,%30d", &timereqd, &iterations, &timeout) != 3) &&<br>- (sscanf(data, "%30d,%30d", &timereqd, &iterations) != 2) &&<br>- (sscanf(data, "%30d", &timereqd) != 1) ) ) {<br>- ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n");<br>- }<br>-<br>- ast_verb(3, "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, timereqd, timeout);<br>+ ast_verb(3, "Waiting %d time(s) for %dms of %s with %ds timeout\n",<br>+ iterations, timereqd, wait_for->name, timeout);<br> <br> if (ast_opt_transmit_silence) {<br> silgen = ast_channel_start_silence_generator(chan);<br> }<br>+<br> time(&waitstart);<br>- res = 1;<br>- for (i=0; (i<iterations) && (res == 1); i++) {<br>- res = do_waiting(chan, timereqd, waitstart, timeout, wait_for_silence);<br>+ for (i = 0; i < iterations && res == 1; i++) {<br>+ res = do_waiting(chan, timereqd, waitstart, timeout, wait_for);<br> }<br>+<br> if (silgen) {<br> ast_channel_stop_silence_generator(chan, silgen);<br> }<br> <br>-<br>- if (res > 0)<br>- res = 0;<br>- return res;<br>+ return res > 0 ? 0 : res;<br> }<br> <br> static int waitforsilence_exec(struct ast_channel *chan, const char *data)<br> {<br>- return waitfor_exec(chan, data, 1);<br>+ return waitfor_exec(chan, data, &wait_for_silence);<br> }<br> <br> static int waitfornoise_exec(struct ast_channel *chan, const char *data)<br> {<br>- return waitfor_exec(chan, data, 0);<br>+ return waitfor_exec(chan, data, &wait_for_noise);<br> }<br> <br> static int unload_module(void)<br>@@ -272,6 +317,4 @@<br> return res;<br> }<br> <br>-AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Wait For Silence");<br>-<br>-<br>+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Wait For Silence/Noise");<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6457">change 6457</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6457"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I01d40adc5b63342bb5018a1bea2081a0aa191ef9 </div>
<div style="display:none"> Gerrit-Change-Number: 6457 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Sean Bright <sean.bright@gmail.com> </div>