283 unsigned short int squelch;
284 unsigned short int tx;
285 unsigned short int rx;
295 OPT_END_FILTER = (1 << 3),
296 OPT_GOTO_RX = (1 << 4),
297 OPT_GOTO_TX = (1 << 5),
298 OPT_DECIBEL = (1 << 6),
299 OPT_SQUELCH = (1 << 7),
300 OPT_HITS_REQ = (1 << 8),
302 OPT_BUSY = (1 << 10),
303 OPT_DIALTONE = (1 << 11),
304 OPT_RINGING = (1 << 12),
334 ast_dsp_free(di->dsp);
336 ast_free(di->gotorx);
339 ast_free(di->gototx);
370 di = datastore->
data;
383 if (frame->
frametype == AST_FRAME_DTMF) {
389 di->rxcount = di->rxcount + 1;
392 di->txcount = di->txcount + 1;
395 ast_debug(1,
"TONE_DETECT just got a hit (#%d in this direction, waiting for %d total)\n", now, di->hitsrequired);
396 if (now >= di->hitsrequired) {
399 }
else if (di->gototx) {
405 if (di->signalfeatures && !match) {
410 ast_debug(3,
"tcount: %d, tstate: %d\n", tcount, tstate);
412 case DSP_TONE_STATE_RINGING:
414 ast_debug(1,
"Detected ringing on %s in %s direction\n", ast_channel_name(chan),
419 case DSP_TONE_STATE_DIALTONE:
421 ast_debug(1,
"Detected dial tone on %s in %s direction\n", ast_channel_name(chan),
426 case DSP_TONE_STATE_BUSY:
428 ast_debug(1,
"Detected busy tone on %s in %s direction\n", ast_channel_name(chan),
433 case DSP_TONE_STATE_SPECIAL3:
435 ast_debug(1,
"Detected SIT on %s in %s direction\n", ast_channel_name(chan),
446 }
else if (di->gototx) {
449 ast_debug(3,
"Detected call progress signal in %s direction, but don't know where to go\n",
468 ast_log(AST_LOG_WARNING,
"Cannot remove TONE_DETECT from %s: TONE_DETECT not currently enabled\n",
469 ast_channel_name(chan));
472 data = datastore->
data;
475 ast_log(AST_LOG_WARNING,
"Failed to remove TONE_DETECT audiohook from channel %s\n", ast_channel_name(chan));
480 ast_log(AST_LOG_WARNING,
"Failed to remove TONE_DETECT datastore from channel %s\n",
481 ast_channel_name(chan));
489 static int freq_parser(
char *freqs,
int *freq1,
int *freq2) {
491 if (ast_strlen_zero(freqs)) {
492 ast_log(LOG_ERROR,
"No frequency specified\n");
496 f1 = strsep(&f3,
"+");
497 f2 = strsep(&f3,
"+");
498 if (!ast_strlen_zero(f3)) {
499 ast_log(LOG_WARNING,
"Only up to 2 frequencies may be specified: %s\n", freqs);
503 ast_log(LOG_WARNING,
"Frequency must be an integer: %s\n", f1);
507 ast_log(LOG_WARNING,
"Sorry, no negative frequencies: %d\n", *freq1);
510 if (!ast_strlen_zero(f2)) {
511 ast_log(LOG_WARNING,
"Sorry, currently only 1 frequency is supported\n");
515 ast_log(LOG_WARNING,
"Frequency must be an integer: %s\n", f2);
519 ast_log(LOG_WARNING,
"Sorry, positive frequencies only: %d\n", *freq2);
526 static char* goto_parser(
struct ast_channel *chan,
char *loc) {
527 char *exten, *pri, *context, *parse;
531 context = strsep(&parse,
",");
532 exten = strsep(&parse,
",");
533 pri = strsep(&parse,
",");
543 ast_channel_lock(chan);
544 if (ast_strlen_zero(exten)) {
547 if (ast_strlen_zero(context)) {
550 ast_channel_unlock(chan);
553 size = strlen(context) + strlen(exten) + strlen(pri) + 3;
556 ast_log(LOG_ERROR,
"Failed to parse goto: %s,%s,%s\n", context, exten, pri);
559 snprintf(dest, size,
"%s,%s,%s", context, exten, pri);
563 static int detect_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buffer,
size_t buflen)
569 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
573 ast_channel_lock(chan);
575 ast_channel_unlock(chan);
578 ast_channel_unlock(chan);
579 di = datastore->
data;
582 if (strchr(data,
't')) {
583 snprintf(buffer, buflen,
"%d", di->txcount);
584 }
else if (strchr(data,
'r')) {
585 snprintf(buffer, buflen,
"%d", di->rxcount);
587 ast_log(LOG_WARNING,
"Invalid direction: %s\n", data);
593 static int parse_signal_features(
struct ast_flags *flags)
597 if (ast_test_flag(flags, OPT_SIT)) {
600 if (ast_test_flag(flags, OPT_BUSY)) {
603 if (ast_test_flag(flags, OPT_DIALTONE)) {
606 if (ast_test_flag(flags, OPT_RINGING)) {
613 static int detect_write(
struct ast_channel *chan,
const char *cmd,
char *data,
const char *value)
619 char *opt_args[OPT_ARG_ARRAY_SIZE];
621 int freq1 = 0, freq2 = 0, duration = 500, db = 16, squelch = 0, hitsrequired = 1;
622 int signalfeatures = 0;
631 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
637 if (!ast_strlen_zero(args.options)) {
640 if (ast_test_flag(&flags, OPT_END_FILTER)) {
641 return remove_detect(chan);
643 if (freq_parser(args.freqs, &freq1, &freq2)) {
646 if (!ast_strlen_zero(args.duration) && (
ast_str_to_int(args.duration, &duration) || duration < 1)) {
647 ast_log(LOG_WARNING,
"Invalid duration: %s\n", args.duration);
650 if (ast_test_flag(&flags, OPT_HITS_REQ) && !ast_strlen_zero(opt_args[OPT_ARG_HITS_REQ])) {
651 if ((
ast_str_to_int(opt_args[OPT_ARG_HITS_REQ], &hitsrequired) || hitsrequired < 1)) {
652 ast_log(LOG_WARNING,
"Invalid number hits required: %s\n", opt_args[OPT_ARG_HITS_REQ]);
656 if (ast_test_flag(&flags, OPT_DECIBEL) && !ast_strlen_zero(opt_args[OPT_ARG_DECIBEL])) {
658 ast_log(LOG_WARNING,
"Invalid decibel level: %s\n", opt_args[OPT_ARG_DECIBEL]);
662 signalfeatures = parse_signal_features(&flags);
664 ast_channel_lock(chan);
666 if (!(datastore = ast_datastore_alloc(&detect_datastore, NULL))) {
667 ast_channel_unlock(chan);
672 ast_channel_unlock(chan);
679 ast_channel_unlock(chan);
680 ast_log(LOG_WARNING,
"Unable to allocate DSP!\n");
683 di->signalfeatures = signalfeatures;
692 ast_debug(1,
"Keeping our ears open for %s Hz, %d db\n", args.freqs, db);
693 datastore->
data = di;
697 di = datastore->
data;
699 di->signalfeatures = signalfeatures;
706 di->duration = duration;
710 if (ast_test_flag(&flags, OPT_GOTO_RX) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO_RX])) {
711 di->gotorx = goto_parser(chan, opt_args[OPT_ARG_GOTO_RX]);
713 if (ast_test_flag(&flags, OPT_GOTO_TX) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO_TX])) {
714 di->gototx = goto_parser(chan, opt_args[OPT_ARG_GOTO_TX]);
717 di->hitsrequired = hitsrequired;
718 di->squelch = ast_test_flag(&flags, OPT_SQUELCH);
721 if (ast_strlen_zero(args.options) || ast_test_flag(&flags, OPT_TX)) {
725 if (ast_strlen_zero(args.options) || ast_test_flag(&flags, OPT_RX)) {
729 ast_channel_unlock(chan);
735 OPT_APP_DECIBEL = (1 << 0),
736 OPT_APP_SQUELCH = (1 << 1),
742 OPT_APP_ARG_ARRAY_SIZE,
750 static int wait_exec(
struct ast_channel *chan,
const char *data)
754 char *opt_args[OPT_APP_ARG_ARRAY_SIZE];
756 int freq1 = 0, freq2 = 0, timeout = 0, duration = 500, times = 1, db = 16, squelch = 0;
759 struct timeval start;
760 int remaining_time = 0;
773 if (!ast_strlen_zero(args.options)) {
776 if (freq_parser(args.freqs, &freq1, &freq2)) {
780 if (!ast_strlen_zero(args.timeout) && (sscanf(args.timeout,
"%30lf", &timeoutf) != 1 || timeoutf < 0)) {
781 ast_log(LOG_WARNING,
"Invalid timeout: %s\n", args.timeout);
785 timeout = 1000 * timeoutf;
786 if (!ast_strlen_zero(args.duration) && (
ast_str_to_int(args.duration, &duration) || duration < 1)) {
787 ast_log(LOG_WARNING,
"Invalid duration: %s\n", args.duration);
791 if (!ast_strlen_zero(args.times) && (
ast_str_to_int(args.times, ×) || times < 1)) {
792 ast_log(LOG_WARNING,
"Invalid number of times: %s\n", args.times);
796 if (ast_test_flag(&flags, OPT_APP_DECIBEL) && !ast_strlen_zero(opt_args[OPT_APP_ARG_DECIBEL])) {
797 if ((
ast_str_to_int(opt_args[OPT_APP_ARG_DECIBEL], &db) || db < 1)) {
798 ast_log(LOG_WARNING,
"Invalid decibel level: %s\n", opt_args[OPT_APP_ARG_DECIBEL]);
803 squelch = ast_test_flag(&flags, OPT_APP_SQUELCH);
805 ast_log(LOG_WARNING,
"Unable to allocate DSP!\n");
811 ast_debug(1,
"Waiting for %s Hz, %d time(s), timeout %d ms, %d db\n", args.freqs, times, timeout, db);
816 if (remaining_time <= 0) {
823 ast_debug(1,
"Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
828 if (frame->
frametype == AST_FRAME_DTMF) {
832 ast_debug(1,
"We just detected %s Hz (hit #%d)\n", args.freqs, hits);
845 }
while (timeout == 0 || remaining_time > 0);
851 static char *waitapp =
"WaitForTone";
852 static char *scanapp =
"ToneScan";
854 static int scan_exec(
struct ast_channel *chan,
const char *data)
859 struct ast_frame *frame = NULL, *frame2 = NULL;
860 struct ast_dsp *dsp = NULL, *dsp2 = NULL;
861 struct timeval start;
862 int remaining_time = 0;
863 int features, match = 0, fax = 0, voice = 0, threshold = 1;
874 if (!ast_strlen_zero(args.timeout) && (sscanf(args.timeout,
"%30lf", &timeoutf) != 1 || timeout < 0)) {
875 ast_log(LOG_WARNING,
"Invalid timeout: %s\n", args.timeout);
879 if (!ast_strlen_zero(args.threshold) && (
ast_str_to_int(args.threshold, &threshold) || threshold < 1)) {
880 ast_log(LOG_WARNING,
"Invalid threshold: %s\n", args.threshold);
884 timeout = 1000 * timeoutf;
886 if (!ast_strlen_zero(args.options) && strchr(args.options,
'f')) {
889 if (!ast_strlen_zero(args.options) && strchr(args.options,
'v')) {
894 ast_log(LOG_WARNING,
"Unable to allocate DSP!\n");
899 if (!ast_strlen_zero(args.zone)) {
901 ast_log(LOG_WARNING,
"Invalid call progress zone: %s\n", args.zone);
911 ast_log(LOG_WARNING,
"Unable to allocate DSP!\n");
924 features |= DSP_TONE_STATE_TALKING;
935 ast_debug(1,
"Starting tone scan, timeout: %d ms, threshold: %d\n", timeout, threshold);
940 if (remaining_time <= 0) {
947 ast_debug(1,
"Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
955 if (frame->
frametype == AST_FRAME_DTMF) {
966 result = frame2->subclass.integer;
967 if (frame2->frametype == AST_FRAME_DTMF) {
972 ast_debug(1,
"Ignoring inactionable event\n");
982 ast_debug(3,
"tcount: %d, tstate: %d\n", tcount, tstate);
983 if (tcount >= threshold) {
986 case DSP_TONE_STATE_RINGING:
989 case DSP_TONE_STATE_DIALTONE:
992 case DSP_TONE_STATE_TALKING:
996 if (voice && tcount > 15 && tcount >= threshold) {
1002 case DSP_TONE_STATE_BUSY:
1005 case DSP_TONE_STATE_SPECIAL3:
1008 case DSP_TONE_STATE_HUNGUP:
1013 ast_debug(1,
"Something else we weren't expecting? tstate: %d, #%d\n", tstate, tcount);
1023 }
while (!match && (timeout == 0 || remaining_time > 0));
1033 .
name =
"TONE_DETECT",
1034 .read = detect_read,
1035 .write = detect_write,
1038 static int unload_module(
void)
1049 static int load_module(
void)
1060 AST_MODULE_INFO_STANDARD_EXTENDED(
ASTERISK_GPL_KEY,
"Tone detection module");
#define DSP_PROGRESS_RINGING
struct ast_frame * ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *inf)
Return AST_FRAME_NULL frames when there is silence, AST_FRAME_BUSY on busies, and call progress...
Main Channel structure associated with a channel.
#define ast_frdup(fr)
Copies a frame.
Asterisk main include file. File version handling, generic pbx functions.
int ast_dsp_get_tcount(struct ast_dsp *dsp)
Get tcount (Threshold counter)
Convenient Signal Processing routines.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define DSP_PROGRESS_BUSY
#define DSP_PROGRESS_TALK
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
#define DSP_PROGRESS_CONGESTION
Structure for a data store type.
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Structure for a data store object.
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.
int ast_unregister_application(const char *app)
Unregister an application.
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
struct ast_frame_subclass subclass
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
ast_audiohook_manipulate_callback manipulate_callback
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.
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Data structure associated with a custom dialplan function.
Asterisk internal frame definitions.
Conversion utility functions.
int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode)
Set fax mode.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
int ast_dsp_get_tstate(struct ast_dsp *dsp)
Get tstate (Tone State)
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Core PBX routines and definitions.
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
static void destroy_callback(void *data)
Helper function used by datastores to destroy the speech structure upon hangup.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
#define ast_calloc(num, len)
A wrapper for calloc()
int ast_dsp_set_freqmode(struct ast_dsp *dsp, int freq, int dur, int db, int squelch)
Set arbitrary frequency detection mode.
Structure used to handle boolean flags.
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
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_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Data structure associated with a single frame of data.
enum ast_audiohook_status status
enum ast_frame_type frametype
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define DSP_FEATURE_FREQ_DETECT
#define DSP_FEATURE_WAITDIALTONE
#define ASTERISK_GPL_KEY
The text the key() function should return.
#define ast_audiohook_lock(ah)
Lock an audiohook.
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone)
Set zone for doing progress detection.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
#define ast_custom_function_register(acf)
Register a custom function.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.