Asterisk - The Open Source Telephony Project  GIT-master-9ed6387
Functions | Variables
app_talkdetect.c File Reference

Playback a file with audio detect. More...

#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
#include "asterisk/format.h"
#include "asterisk/format_cache.h"

Go to the source code of this file.

Functions

 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "Playback with Talk Detection")
 
static int background_detect_exec (struct ast_channel *chan, const char *data)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static char * app = "BackgroundDetect"
 

Detailed Description

Playback a file with audio detect.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file app_talkdetect.c.

Function Documentation

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"Playback with Talk Detection"   
)

Referenced by load_module().

◆ background_detect_exec()

static int background_detect_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 80 of file app_talkdetect.c.

References ao2_bump, ao2_cleanup, args, ast_answer(), AST_APP_ARG, ast_canmatch_extension(), ast_channel_caller(), ast_channel_context(), ast_channel_language(), ast_channel_name(), ast_channel_readformat(), ast_channel_sched(), ast_channel_stream(), ast_channel_timingfunc(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_get_name(), ast_format_slin, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_log, ast_read(), ast_sched_runq(), ast_sched_wait(), ast_set_read_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero, ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor(), ast_frame_subclass::format, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, max, min, NULL, pbx_builtin_setvar_helper(), RAII_VAR, S_COR, ast_frame::subclass, tmp(), and ast_dsp::totalsilence.

Referenced by load_module().

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  RAII_VAR(struct ast_format *, origrformat, NULL, ao2_cleanup);
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 (ast_channel_state(chan) != AST_STATE_UP) {
128  if ((res = ast_answer(chan))) {
129  break;
130  }
131  }
132 
133  origrformat = ao2_bump(ast_channel_readformat(chan));
134  if ((ast_set_read_format(chan, ast_format_slin))) {
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, ast_channel_language(chan))) {
147  ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char *)data);
148  break;
149  }
150  detection_start = ast_tvnow();
151  while (ast_channel_stream(chan)) {
152  res = ast_sched_wait(ast_channel_sched(chan));
153  if ((res < 0) && !ast_channel_timingfunc(chan)) {
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", ast_channel_name(chan));
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", ast_channel_name(chan));
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, ast_channel_context(chan), t, 1,
183  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->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) &&
190  (ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) && continue_analysis) {
191  int totalsilence;
192  int ms;
193  res = ast_dsp_silence(dsp, fr, &totalsilence);
194  if (res && (totalsilence > sil)) {
195  /* We've been quiet a little while */
196  if (notsilent) {
197  /* We had heard some talking */
198  ms = ast_tvdiff_ms(ast_tvnow(), start);
199  ms -= sil;
200  if (ms < 0)
201  ms = 0;
202  if ((ms > min) && ((max < 0) || (ms < max))) {
203  char ms_str[12];
204  ast_debug(1, "Found qualified token of %d ms\n", ms);
205 
206  /* Save detected talk time (in milliseconds) */
207  snprintf(ms_str, sizeof(ms_str), "%d", ms);
208  pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
209 
210  ast_goto_if_exists(chan, ast_channel_context(chan), "talk", 1);
211  res = 0;
212  ast_frfree(fr);
213  break;
214  } else {
215  ast_debug(1, "Found unqualified token of %d ms\n", ms);
216  }
217  notsilent = 0;
218  }
219  } else {
220  if (!notsilent) {
221  /* Heard some audio, mark the begining of the token */
222  start = ast_tvnow();
223  ast_debug(1, "Start of voice token!\n");
224  notsilent = 1;
225  }
226  }
227  }
228  ast_frfree(fr);
229  }
231  }
232  ast_stopstream(chan);
233  } while (0);
234 
235  if (res > -1) {
236  if (origrformat && ast_set_read_format(chan, origrformat)) {
237  ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
238  ast_channel_name(chan), ast_format_get_name(origrformat));
239  }
240  }
241  if (dsp) {
242  ast_dsp_free(dsp);
243  }
244  return res;
245 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:755
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1744
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1719
static int tmp()
Definition: bt_open.c:389
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4251
ast_channel_state
ast_channel states
Definition: channelstate.h:35
Definition of a media format.
Definition: format.c:43
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
const char * args
#define NULL
Definition: resample.c:96
#define AST_FRAME_DTMF
#define ast_verb(level,...)
Definition: logger.h:455
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:4185
struct ast_frame_subclass subclass
int totalsilence
Definition: dsp.c:409
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
Number structure.
Definition: app_followme.c:154
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5724
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:851
Definition: dsp.c:405
#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:85
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8774
#define ast_strlen_zero(a)
Definition: muted.c:73
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
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...
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1473
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3137
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_frfree(fr)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2780
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:431
Data structure associated with a single frame of data.
const char * ast_channel_language(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
enum ast_frame_type frametype
struct ast_format * format
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
#define min(a, b)
Definition: f2c.h:197
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
#define AST_APP_ARG(name)
Define an application argument.
#define max(a, b)
Definition: f2c.h:198

◆ load_module()

static int load_module ( void  )
static

Definition at line 252 of file app_talkdetect.c.

References app, AST_MODULE_INFO_STANDARD_EXTENDED(), ast_register_application_xml, ASTERISK_GPL_KEY, and background_detect_exec().

253 {
255 }
static char * app
static int background_detect_exec(struct ast_channel *chan, const char *data)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 247 of file app_talkdetect.c.

References app, and ast_unregister_application().

248 {
250 }
static char * app
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

Variable Documentation

◆ app

char* app = "BackgroundDetect"
static

Definition at line 78 of file app_talkdetect.c.

Referenced by load_module(), and unload_module().