Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Macros | Functions | Variables
func_talkdetect.c File Reference

Function that raises events when talking is detected on a channel. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/audiohook.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
Include dependency graph for func_talkdetect.c:

Go to the source code of this file.

Data Structures

struct  talk_detect_params
 Private data structure used with the function's datastore. More...
 

Macros

#define DEFAULT_SILENCE_THRESHOLD   2500
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void datastore_destroy_cb (void *data)
 
static int load_module (void)
 
static int remove_talk_detect (struct ast_channel *chan)
 
static int set_talk_detect (struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold)
 
static int talk_detect_audiohook_cb (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 
static int talk_detect_fn_write (struct ast_channel *chan, const char *function, char *data, const char *value)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Talk detection dialplan function" , .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 const struct ast_module_infoast_module_info = &__mod_info
 
static const struct ast_datastore_info talk_detect_datastore
 The channel datastore the function uses to store state. More...
 
static struct ast_custom_function talk_detect_function
 Definition of the TALK_DETECT function. More...
 

Detailed Description

Function that raises events when talking is detected on a channel.

Author
Matt Jordan mjord.nosp@m.an@d.nosp@m.igium.nosp@m..com

Definition in file func_talkdetect.c.

Macro Definition Documentation

◆ DEFAULT_SILENCE_THRESHOLD

#define DEFAULT_SILENCE_THRESHOLD   2500

Definition at line 136 of file func_talkdetect.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 424 of file func_talkdetect.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 424 of file func_talkdetect.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 424 of file func_talkdetect.c.

◆ datastore_destroy_cb()

static void datastore_destroy_cb ( void *  data)
static

Definition at line 155 of file func_talkdetect.c.

155 {
156 struct talk_detect_params *td_params = data;
157
158 ast_audiohook_destroy(&td_params->audiohook);
159
160 if (td_params->dsp) {
161 ast_dsp_free(td_params->dsp);
162 }
163 ast_free(data);
164}
#define ast_free(a)
Definition: astmm.h:180
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
Private data structure used with the function's datastore.
struct ast_audiohook audiohook
struct ast_dsp * dsp

References ast_audiohook_destroy(), ast_dsp_free(), ast_free, talk_detect_params::audiohook, and talk_detect_params::dsp.

◆ load_module()

static int load_module ( void  )
static

Definition at line 415 of file func_talkdetect.c.

416{
417 int res = 0;
418
420
422}
static struct ast_custom_function talk_detect_function
Definition of the TALK_DETECT function.
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558

References ast_custom_function_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and talk_detect_function.

◆ remove_talk_detect()

static int remove_talk_detect ( struct ast_channel chan)
static

Definition at line 250 of file func_talkdetect.c.

251{
252 struct ast_datastore *datastore = NULL;
253 struct talk_detect_params *td_params;
254 SCOPED_CHANNELLOCK(chan_lock, chan);
255
257 if (!datastore) {
258 ast_log(AST_LOG_WARNING, "Cannot remove TALK_DETECT from %s: TALK_DETECT not currently enabled\n",
259 ast_channel_name(chan));
260 return -1;
261 }
262 td_params = datastore->data;
263
264 if (ast_audiohook_remove(chan, &td_params->audiohook)) {
265 ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT audiohook from channel %s\n",
266 ast_channel_name(chan));
267 return -1;
268 }
269
270 if (ast_channel_datastore_remove(chan, datastore)) {
271 ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT datastore from channel %s\n",
272 ast_channel_name(chan));
273 return -1;
274 }
275 ast_datastore_free(datastore);
276
277 return 0;
278}
#define ast_log
Definition: astobj2.c:42
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition: audiohook.c:749
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2413
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2418
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
static const struct ast_datastore_info talk_detect_datastore
The channel datastore the function uses to store state.
#define AST_LOG_WARNING
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:619
#define NULL
Definition: resample.c:96
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66

References ast_audiohook_remove(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_name(), ast_datastore_free(), ast_log, AST_LOG_WARNING, talk_detect_params::audiohook, ast_datastore::data, NULL, SCOPED_CHANNELLOCK, and talk_detect_datastore.

Referenced by talk_detect_fn_write().

◆ set_talk_detect()

static int set_talk_detect ( struct ast_channel chan,
int  dsp_silence_threshold,
int  dsp_talking_threshold 
)
static

Definition at line 281 of file func_talkdetect.c.

282{
283 struct ast_datastore *datastore = NULL;
284 struct talk_detect_params *td_params;
285 SCOPED_CHANNELLOCK(chan_lock, chan);
286
288 if (!datastore) {
290 if (!datastore) {
291 return -1;
292 }
293
294 td_params = ast_calloc(1, sizeof(*td_params));
295 if (!td_params) {
296 ast_datastore_free(datastore);
297 return -1;
298 }
299
300 ast_audiohook_init(&td_params->audiohook,
302 "TALK_DETECT",
306
308 if (!td_params->dsp) {
309 ast_datastore_free(datastore);
310 ast_free(td_params);
311 return -1;
312 }
313 datastore->data = td_params;
314
315 ast_channel_datastore_add(chan, datastore);
316 ast_audiohook_attach(chan, &td_params->audiohook);
317 } else {
318 /* Talk detection already enabled; update existing settings */
319 td_params = datastore->data;
320 }
321
324
325 ast_dsp_set_threshold(td_params->dsp, td_params->dsp_talking_threshold);
326
327 return 0;
328}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
@ AST_AUDIOHOOK_MANIPULATE_ALL_RATES
Definition: audiohook.h:75
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:100
@ AST_AUDIOHOOK_TRIGGER_READ
Definition: audiohook.h:56
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:512
@ AST_AUDIOHOOK_TYPE_MANIPULATE
Definition: audiohook.h:38
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2404
struct ast_format * ast_channel_rawreadformat(struct ast_channel *chan)
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition: dsp.c:1788
struct ast_dsp * ast_dsp_new_with_rate(unsigned int sample_rate)
Allocates a new dsp with a specific internal sample rate used during processing.
Definition: dsp.c:1763
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
static int talk_detect_audiohook_cb(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:118
#define ast_set_flag(p, flag)
Definition: utils.h:70

References ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, AST_AUDIOHOOK_TRIGGER_READ, AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_rawreadformat(), ast_datastore_alloc, ast_datastore_free(), ast_dsp_new_with_rate(), ast_dsp_set_threshold(), ast_format_get_sample_rate(), ast_free, ast_set_flag, talk_detect_params::audiohook, ast_datastore::data, talk_detect_params::dsp, talk_detect_params::dsp_silence_threshold, talk_detect_params::dsp_talking_threshold, ast_audiohook::manipulate_callback, NULL, SCOPED_CHANNELLOCK, talk_detect_audiohook_cb(), and talk_detect_datastore.

Referenced by talk_detect_fn_write().

◆ talk_detect_audiohook_cb()

static int talk_detect_audiohook_cb ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
)
static

Definition at line 180 of file func_talkdetect.c.

181{
182 int total_silence;
183 int is_talking;
184 int update_talking = 0;
185 struct ast_datastore *datastore;
186 struct talk_detect_params *td_params;
187 struct stasis_message *message;
188
189 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
190 return 1;
191 }
192
194 return 1;
195 }
196
197 if (frame->frametype != AST_FRAME_VOICE) {
198 return 1;
199 }
200
201 if (!(datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL))) {
202 return 1;
203 }
204 td_params = datastore->data;
205
206 is_talking = !ast_dsp_silence(td_params->dsp, frame, &total_silence);
207 if (is_talking) {
208 if (!td_params->talking) {
209 update_talking = 1;
210 td_params->talking_start = ast_tvnow();
211 }
212 td_params->talking = 1;
213 } else if (total_silence >= td_params->dsp_silence_threshold) {
214 if (td_params->talking) {
215 update_talking = 1;
216 }
217 td_params->talking = 0;
218 }
219
220 if (update_talking) {
221 struct ast_json *blob = NULL;
222
223 if (!td_params->talking) {
224 int64_t diff_ms = ast_tvdiff_ms(ast_tvnow(), td_params->talking_start);
225 diff_ms -= td_params->dsp_silence_threshold;
226
227 blob = ast_json_pack("{s: I}", "duration", (ast_json_int_t)diff_ms);
228 if (!blob) {
229 return 1;
230 }
231 }
232
233 ast_verb(4, "%s is now %s\n", ast_channel_name(chan),
234 td_params->talking ? "talking" : "silent");
237 blob);
238 if (message) {
240 ao2_ref(message, -1);
241 }
242
243 ast_json_unref(blob);
244 }
245
246 return 1;
247}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
@ AST_AUDIOHOOK_DIRECTION_READ
Definition: audiohook.h:49
@ AST_AUDIOHOOK_STATUS_DONE
Definition: audiohook.h:45
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1488
direction
struct stasis_message_type * ast_channel_talking_start(void)
Message type for a channel starting talking.
struct stasis_message_type * ast_channel_talking_stop(void)
Message type for a channel stopping talking.
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
@ AST_FRAME_VOICE
#define ast_verb(level,...)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1512
enum ast_audiohook_status status
Definition: audiohook.h:108
enum ast_frame_type frametype
Abstract JSON element (object, array, string, int, ...).
struct timeval talking_start
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ao2_ref, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_blob_create_from_cache(), ast_channel_datastore_find(), ast_channel_name(), ast_channel_talking_start(), ast_channel_talking_stop(), ast_channel_topic(), ast_channel_uniqueid(), ast_dsp_silence(), AST_FRAME_VOICE, ast_json_pack(), ast_json_unref(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_datastore::data, talk_detect_params::dsp, talk_detect_params::dsp_silence_threshold, ast_frame::frametype, NULL, stasis_publish(), ast_audiohook::status, talk_detect_datastore, talk_detect_params::talking, and talk_detect_params::talking_start.

Referenced by set_talk_detect().

◆ talk_detect_fn_write()

static int talk_detect_fn_write ( struct ast_channel chan,
const char *  function,
char *  data,
const char *  value 
)
static

Definition at line 331 of file func_talkdetect.c.

332{
333 int res;
334
335 if (!chan) {
336 return -1;
337 }
338
339 if (ast_strlen_zero(data)) {
340 ast_log(AST_LOG_WARNING, "TALK_DETECT requires an argument\n");
341 return -1;
342 }
343
344 if (!strcasecmp(data, "set")) {
345 int dsp_silence_threshold = DEFAULT_SILENCE_THRESHOLD;
346 int dsp_talking_threshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
347
348 if (!ast_strlen_zero(value)) {
349 char *parse = ast_strdupa(value);
350
352 AST_APP_ARG(silence_threshold);
353 AST_APP_ARG(talking_threshold);
354 );
355
357
358 if (!ast_strlen_zero(args.silence_threshold)) {
359 if (sscanf(args.silence_threshold, "%30d", &dsp_silence_threshold) != 1) {
360 ast_log(AST_LOG_WARNING, "Failed to parse %s for dsp_silence_threshold\n",
361 args.silence_threshold);
362 return -1;
363 }
364
365 if (dsp_silence_threshold < 1) {
366 ast_log(AST_LOG_WARNING, "Invalid value %d for dsp_silence_threshold\n",
367 dsp_silence_threshold);
368 return -1;
369 }
370 }
371
372 if (!ast_strlen_zero(args.talking_threshold)) {
373 if (sscanf(args.talking_threshold, "%30d", &dsp_talking_threshold) != 1) {
374 ast_log(AST_LOG_WARNING, "Failed to parse %s for dsp_talking_threshold\n",
375 args.talking_threshold);
376 return -1;
377 }
378
379 if (dsp_talking_threshold < 1) {
380 ast_log(AST_LOG_WARNING, "Invalid value %d for dsp_talking_threshold\n",
381 dsp_talking_threshold);
382 return -1;
383 }
384 }
385 }
386
387 res = set_talk_detect(chan, dsp_silence_threshold, dsp_talking_threshold);
388 } else if (!strcasecmp(data, "remove")) {
389 res = remove_talk_detect(chan);
390 } else {
391 ast_log(AST_LOG_WARNING, "TALK_DETECT: unknown option %s\n", data);
392 res = -1;
393 }
394
395 return res;
396}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold)
#define DEFAULT_SILENCE_THRESHOLD
static int remove_talk_detect(struct ast_channel *chan)
#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.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int value
Definition: syslog.c:37
const char * args

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_dsp_get_threshold_from_settings(), ast_log, AST_LOG_WARNING, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), DEFAULT_SILENCE_THRESHOLD, talk_detect_params::dsp_silence_threshold, talk_detect_params::dsp_talking_threshold, remove_talk_detect(), set_talk_detect(), THRESHOLD_SILENCE, and value.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 405 of file func_talkdetect.c.

406{
407 int res = 0;
408
410
411 return res;
412}
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

References ast_custom_function_unregister(), and talk_detect_function.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Talk detection dialplan function" , .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 424 of file func_talkdetect.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 424 of file func_talkdetect.c.

◆ talk_detect_datastore

const struct ast_datastore_info talk_detect_datastore
static
Initial value:
= {
.type = "talk_detect",
}
static void datastore_destroy_cb(void *data)

The channel datastore the function uses to store state.

Definition at line 167 of file func_talkdetect.c.

Referenced by remove_talk_detect(), set_talk_detect(), and talk_detect_audiohook_cb().

◆ talk_detect_function

struct ast_custom_function talk_detect_function
static
Initial value:
= {
.name = "TALK_DETECT",
}
static int talk_detect_fn_write(struct ast_channel *chan, const char *function, char *data, const char *value)

Definition of the TALK_DETECT function.

Definition at line 399 of file func_talkdetect.c.

Referenced by load_module(), and unload_module().