Wed Jan 8 2020 09:49:40

Asterisk developer's documentation


app_talkdetect.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 Playback a file with audio detect
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup applications
26  */
27 
28 /*** MODULEINFO
29  <support_level>extended</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
35 
36 #include "asterisk/lock.h"
37 #include "asterisk/file.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/module.h"
41 #include "asterisk/translate.h"
42 #include "asterisk/utils.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/app.h"
45 
46 /*** DOCUMENTATION
47  <application name="BackgroundDetect" language="en_US">
48  <synopsis>
49  Background a file with talk detect.
50  </synopsis>
51  <syntax>
52  <parameter name="filename" required="true" />
53  <parameter name="sil">
54  <para>If not specified, defaults to <literal>1000</literal>.</para>
55  </parameter>
56  <parameter name="min">
57  <para>If not specified, defaults to <literal>100</literal>.</para>
58  </parameter>
59  <parameter name="max">
60  <para>If not specified, defaults to <literal>infinity</literal>.</para>
61  </parameter>
62  <parameter name="analysistime">
63  <para>If not specified, defaults to <literal>infinity</literal>.</para>
64  </parameter>
65  </syntax>
66  <description>
67  <para>Plays back <replaceable>filename</replaceable>, waiting for interruption from a given digit (the digit
68  must start the beginning of a valid extension, or it will be ignored). During
69  the playback of the file, audio is monitored in the receive direction, and if
70  a period of non-silence which is greater than <replaceable>min</replaceable> ms yet less than
71  <replaceable>max</replaceable> ms is followed by silence for at least <replaceable>sil</replaceable> ms,
72  which occurs during the first <replaceable>analysistime</replaceable> ms, then the audio playback is
73  aborted and processing jumps to the <replaceable>talk</replaceable> extension, if available.</para>
74  </description>
75  </application>
76  ***/
77 
78 static char *app = "BackgroundDetect";
79 
80 static int background_detect_exec(struct ast_channel *chan, const char *data)
81 {
82  int res = 0;
83  char *tmp;
84  struct ast_frame *fr;
85  int notsilent = 0;
86  struct timeval start = { 0, 0 };
87  struct timeval detection_start = { 0, 0 };
88  int sil = 1000;
89  int min = 100;
90  int max = -1;
91  int analysistime = -1;
92  int continue_analysis = 1;
93  int x;
94  int origrformat = 0;
95  struct ast_dsp *dsp = NULL;
97  AST_APP_ARG(filename);
98  AST_APP_ARG(silence);
99  AST_APP_ARG(min);
100  AST_APP_ARG(max);
101  AST_APP_ARG(analysistime);
102  );
103 
104  if (ast_strlen_zero(data)) {
105  ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
106  return -1;
107  }
108 
109  tmp = ast_strdupa(data);
111 
112  if (!ast_strlen_zero(args.silence) && (sscanf(args.silence, "%30d", &x) == 1) && (x > 0)) {
113  sil = x;
114  }
115  if (!ast_strlen_zero(args.min) && (sscanf(args.min, "%30d", &x) == 1) && (x > 0)) {
116  min = x;
117  }
118  if (!ast_strlen_zero(args.max) && (sscanf(args.max, "%30d", &x) == 1) && (x > 0)) {
119  max = x;
120  }
121  if (!ast_strlen_zero(args.analysistime) && (sscanf(args.analysistime, "%30d", &x) == 1) && (x > 0)) {
122  analysistime = x;
123  }
124 
125  ast_debug(1, "Preparing detect of '%s', sil=%d, min=%d, max=%d, analysistime=%d\n", args.filename, sil, min, max, analysistime);
126  do {
127  if (chan->_state != AST_STATE_UP) {
128  if ((res = ast_answer(chan))) {
129  break;
130  }
131  }
132 
133  origrformat = chan->readformat;
135  ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
136  res = -1;
137  break;
138  }
139 
140  if (!(dsp = ast_dsp_new())) {
141  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
142  res = -1;
143  break;
144  }
145  ast_stopstream(chan);
146  if (ast_streamfile(chan, tmp, chan->language)) {
147  ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
148  break;
149  }
150  detection_start = ast_tvnow();
151  while (chan->stream) {
152  res = ast_sched_wait(chan->sched);
153  if ((res < 0) && !chan->timingfunc) {
154  res = 0;
155  break;
156  }
157  if (res < 0) {
158  res = 1000;
159  }
160  res = ast_waitfor(chan, res);
161  if (res < 0) {
162  ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
163  break;
164  } else if (res > 0) {
165  fr = ast_read(chan);
166  if (continue_analysis && analysistime >= 0) {
167  /* If we have a limit for the time to analyze voice
168  * frames and the time has not expired */
169  if (ast_tvdiff_ms(ast_tvnow(), detection_start) >= analysistime) {
170  continue_analysis = 0;
171  ast_verb(3, "BackgroundDetect: Talk analysis time complete on %s.\n", chan->name);
172  }
173  }
174 
175  if (!fr) {
176  res = -1;
177  break;
178  } else if (fr->frametype == AST_FRAME_DTMF) {
179  char t[2];
180  t[0] = fr->subclass.integer;
181  t[1] = '\0';
182  if (ast_canmatch_extension(chan, chan->context, t, 1,
183  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
184  /* They entered a valid extension, or might be anyhow */
185  res = fr->subclass.integer;
186  ast_frfree(fr);
187  break;
188  }
189  } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass.codec == AST_FORMAT_SLINEAR) && continue_analysis) {
190  int totalsilence;
191  int ms;
192  res = ast_dsp_silence(dsp, fr, &totalsilence);
193  if (res && (totalsilence > sil)) {
194  /* We've been quiet a little while */
195  if (notsilent) {
196  /* We had heard some talking */
197  ms = ast_tvdiff_ms(ast_tvnow(), start);
198  ms -= sil;
199  if (ms < 0)
200  ms = 0;
201  if ((ms > min) && ((max < 0) || (ms < max))) {
202  char ms_str[12];
203  ast_debug(1, "Found qualified token of %d ms\n", ms);
204 
205  /* Save detected talk time (in milliseconds) */
206  snprintf(ms_str, sizeof(ms_str), "%d", ms);
207  pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
208 
209  ast_goto_if_exists(chan, chan->context, "talk", 1);
210  res = 0;
211  ast_frfree(fr);
212  break;
213  } else {
214  ast_debug(1, "Found unqualified token of %d ms\n", ms);
215  }
216  notsilent = 0;
217  }
218  } else {
219  if (!notsilent) {
220  /* Heard some audio, mark the begining of the token */
221  start = ast_tvnow();
222  ast_debug(1, "Start of voice token!\n");
223  notsilent = 1;
224  }
225  }
226  }
227  ast_frfree(fr);
228  }
229  ast_sched_runq(chan->sched);
230  }
231  ast_stopstream(chan);
232  } while (0);
233 
234  if (res > -1) {
235  if (origrformat && ast_set_read_format(chan, origrformat)) {
236  ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
237  chan->name, ast_getformatname(origrformat));
238  }
239  }
240  if (dsp) {
241  ast_dsp_free(dsp);
242  }
243  return res;
244 }
245 
246 static int unload_module(void)
247 {
248  return ast_unregister_application(app);
249 }
250 
251 static int load_module(void)
252 {
254 }
255 
256 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");
union ast_frame_subclass subclass
Definition: frame.h:146
Main Channel structure associated with a channel.
Definition: channel.h:742
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
Asterisk main include file. File version handling, generic pbx functions.
static char * app
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
Support for translation of data formats. translate.c.
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1650
Convenient Signal Processing routines.
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define LOG_WARNING
Definition: logger.h:144
static int unload_module(void)
struct ast_dsp * ast_dsp_new(void)
Definition: dsp.c:1607
#define AST_FRAME_DTMF
Definition: frame.h:128
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
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
#define ast_verb(level,...)
Definition: logger.h:243
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:5415
int totalsilence
Definition: dsp.c:393
Utility functions.
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
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.
Definition: dsp.c:390
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:83
struct sched_context * sched
Definition: channel.h:756
int(* timingfunc)(const void *data)
Definition: channel.h:759
static int load_module(void)
Core PBX routines and definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
static int background_detect_exec(struct ast_channel *chan, const char *data)
static struct @350 args
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
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:11261
int ast_sched_runq(struct sched_context *con)
Runs the queue.
Definition: sched.c:600
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Return non-zero if this is silence. Updates &quot;totalsilence&quot; with the total number of seconds of silenc...
Definition: dsp.c:1355
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
format_t readformat
Definition: channel.h:853
int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place Determine the number of s...
Definition: sched.c:334
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
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
struct ast_filestream * stream
Definition: channel.h:757
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
const ast_string_field language
Definition: channel.h:787
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
#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
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292