Skip to content

Commit 41ce371

Browse files
InterLinked1Friendly Automation
authored andcommitted
app_amd: Add option to play audio during AMD.
Adds an option that will play an audio file to the party while AMD is running on the channel, so the called party does not just hear silence. ASTERISK-30179 #close Change-Id: I4af306274552b61b3d9f0883c33f698abd4699b6
1 parent a15fffa commit 41ce371

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

apps/app_amd.c

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@
9292
<para>Is the maximum duration of a word to accept.</para>
9393
<para>If exceeded, then the result is detection as a MACHINE</para>
9494
</parameter>
95+
<parameter name="audioFile" required="false">
96+
<para>Is an audio file to play to the caller while AMD is in progress.</para>
97+
<para>By default, no audio file is played.</para>
98+
<para>If an audio file is configured in amd.conf, then that file will be used
99+
if one is not specified here. That file may be overridden by this argument.</para>
100+
</parameter>
95101
</syntax>
96102
<description>
97103
<para>This application attempts to detect answering machines at the beginning
@@ -155,6 +161,9 @@ static int dfltBetweenWordsSilence = 50;
155161
static int dfltMaximumNumberOfWords = 2;
156162
static int dfltSilenceThreshold = 256;
157163
static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
164+
static char *dfltAudioFile = NULL;
165+
166+
static ast_mutex_t config_lock;
158167

159168
/* Set to the lowest ms value provided in amd.conf or application parameters */
160169
static int dfltMaxWaitTimeForFrame = 50;
@@ -179,7 +188,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
179188
char amdCause[256] = "", amdStatus[256] = "";
180189
char *parse = ast_strdupa(data);
181190

182-
/* Lets set the initial values of the variables that will control the algorithm.
191+
/* Let's set the initial values of the variables that will control the algorithm.
183192
The initial values are the default ones. If they are passed as arguments
184193
when invoking the application, then the default values will be overwritten
185194
by the ones passed as parameters. */
@@ -193,6 +202,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
193202
int silenceThreshold = dfltSilenceThreshold;
194203
int maximumWordLength = dfltMaximumWordLength;
195204
int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
205+
const char *audioFile = NULL;
196206

197207
AST_DECLARE_APP_ARGS(args,
198208
AST_APP_ARG(argInitialSilence);
@@ -204,8 +214,15 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
204214
AST_APP_ARG(argMaximumNumberOfWords);
205215
AST_APP_ARG(argSilenceThreshold);
206216
AST_APP_ARG(argMaximumWordLength);
217+
AST_APP_ARG(audioFile);
207218
);
208219

220+
ast_mutex_lock(&config_lock);
221+
if (!ast_strlen_zero(dfltAudioFile)) {
222+
audioFile = ast_strdupa(dfltAudioFile);
223+
}
224+
ast_mutex_unlock(&config_lock);
225+
209226
ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
210227
S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"),
211228
S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"),
@@ -233,6 +250,9 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
233250
silenceThreshold = atoi(args.argSilenceThreshold);
234251
if (!ast_strlen_zero(args.argMaximumWordLength))
235252
maximumWordLength = atoi(args.argMaximumWordLength);
253+
if (!ast_strlen_zero(args.audioFile)) {
254+
audioFile = args.audioFile;
255+
}
236256
} else {
237257
ast_debug(1, "AMD using the default parameters.\n");
238258
}
@@ -280,6 +300,11 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
280300
/* Set our start time so we can tie the loop to real world time and not RTP updates */
281301
amd_tvstart = ast_tvnow();
282302

303+
/* Optional audio file to play to caller while AMD is doing its thing. */
304+
if (!ast_strlen_zero(audioFile)) {
305+
ast_streamfile(chan, audioFile, ast_channel_language(chan));
306+
}
307+
283308
/* Now we go into a loop waiting for frames from the channel */
284309
while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
285310
int ms = 0;
@@ -462,10 +487,14 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
462487
/* Free the DSP used to detect silence */
463488
ast_dsp_free(silenceDetector);
464489

490+
/* If we were playing something to pass the time, stop it now. */
491+
if (!ast_strlen_zero(audioFile)) {
492+
ast_stopstream(chan);
493+
}
494+
465495
return;
466496
}
467497

468-
469498
static int amd_exec(struct ast_channel *chan, const char *data)
470499
{
471500
isAnsweringMachine(chan, data);
@@ -516,7 +545,16 @@ static int load_config(int reload)
516545
dfltMaximumNumberOfWords = atoi(var->value);
517546
} else if (!strcasecmp(var->name, "maximum_word_length")) {
518547
dfltMaximumWordLength = atoi(var->value);
519-
548+
} else if (!strcasecmp(var->name, "playback_file")) {
549+
ast_mutex_lock(&config_lock);
550+
if (dfltAudioFile) {
551+
ast_free(dfltAudioFile);
552+
dfltAudioFile = NULL;
553+
}
554+
if (!ast_strlen_zero(var->value)) {
555+
dfltAudioFile = ast_strdup(var->value);
556+
}
557+
ast_mutex_unlock(&config_lock);
520558
} else {
521559
ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
522560
app, cat, var->name, var->lineno);
@@ -539,6 +577,12 @@ static int load_config(int reload)
539577

540578
static int unload_module(void)
541579
{
580+
ast_mutex_lock(&config_lock);
581+
if (dfltAudioFile) {
582+
ast_free(dfltAudioFile);
583+
}
584+
ast_mutex_unlock(&config_lock);
585+
ast_mutex_destroy(&config_lock);
542586
return ast_unregister_application(app);
543587
}
544588

@@ -554,6 +598,7 @@ static int unload_module(void)
554598
*/
555599
static int load_module(void)
556600
{
601+
ast_mutex_init(&config_lock);
557602
if (load_config(0) || ast_register_application_xml(app, amd_exec)) {
558603
return AST_MODULE_LOAD_DECLINE;
559604
}

configs/samples/amd.conf.sample

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ total_analysis_time = 5000 ; Maximum time allowed for the algorithm to decide
88
silence_threshold = 256 ; If the average level of noise in a sample does not reach
99
; this value, from a scale of 0 to 32767, then we will consider
1010
; it to be silence.
11+
;playback_file = ; Audio file to play while AMD is running, so the caller
12+
; does not just hear silence. Note that specifying this here
13+
; will apply to ALL AMD runs, so you may wish to set it
14+
; in the dialplan as an argument to AMD() instead.
15+
; Default is no audio file (not to play anything).
1116

1217
; Greeting ;
1318
initial_silence = 2500 ; Maximum silence duration before the greeting.
@@ -19,7 +24,7 @@ greeting = 1500 ; Maximum length of a greeting. If exceeded, then the
1924

2025
; Word detection ;
2126
min_word_length = 100 ; Minimum duration of Voice to considered as a word
22-
maximum_word_length = 5000 ; Maximum duration of a single Voice utterance allowed.
27+
maximum_word_length = 5000 ; Maximum duration of a single Voice utterance allowed.
2328
between_words_silence = 50 ; Minimum duration of silence after a word to consider
2429
; the audio what follows as a new word
2530

doc/CHANGES-staging/app_amd.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Subject: app_amd
2+
3+
An audio file to play during AMD processing can
4+
now be specified to the AMD application or configured
5+
in the amd.conf configuration file.

0 commit comments

Comments
 (0)