Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
Include dependency graph for app_talkdetect.c:

Go to the source code of this file.

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int background_detect_exec (struct ast_channel *chan, const char *data)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Playback with Talk Detection" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static char * app = "BackgroundDetect"
 
static const struct ast_module_infoast_module_info = &__mod_info
 

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

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 257 of file app_talkdetect.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 257 of file app_talkdetect.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 257 of file app_talkdetect.c.

◆ 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.

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);
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 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
static int tmp()
Definition: bt_open.c:389
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3163
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4292
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5839
const char * ast_channel_language(const struct ast_channel *chan)
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2806
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1773
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1748
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1486
#define min(a, b)
Definition: f2c.h:197
#define max(a, b)
Definition: f2c.h:198
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1291
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
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
@ AST_FORMAT_CMP_EQUAL
Definition: format.h:36
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_VOICE
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
#define LOG_WARNING
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_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
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:4197
#define NULL
Definition: resample.c:96
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
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:433
#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:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Definition: dsp.c:407
int totalsilence
Definition: dsp.c:411
Definition of a media format.
Definition: format.c:43
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Number structure.
Definition: app_followme.c:154
const char * args
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:105
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157
#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:936

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.

◆ load_module()

static int load_module ( void  )
static

Definition at line 252 of file app_talkdetect.c.

253 {
255 }
static int background_detect_exec(struct ast_channel *chan, const char *data)
static char * app
#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.

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

References app, and ast_unregister_application().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Playback with Talk Detection" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 252 of file app_talkdetect.c.

◆ app

char* app = "BackgroundDetect"
static

Definition at line 78 of file app_talkdetect.c.

Referenced by unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 257 of file app_talkdetect.c.