Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Macros | Enumerations | Functions | Variables
app_sf.c File Reference

SF sender and receiver applications. More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"
#include "asterisk/conversions.h"
Include dependency graph for app_sf.c:

Go to the source code of this file.

Macros

#define BUFFER_SIZE   256
 
#define SF_BETWEEN   600
 
#define SF_MIN_DETECT   50
 
#define SF_MIN_OFF   25
 
#define SF_ON   67
 

Enumerations

enum  read_option_flags {
  OPT_DELAY = (1 << 0) , OPT_MUTE = (1 << 1) , OPT_QUELCH = (1 << 2) , OPT_RELAXED = (1 << 3) ,
  OPT_LAX_KP = (1 << 4) , OPT_PROCESS = (1 << 5) , OPT_NO_KP = (1 << 6) , OPT_NO_ST = (1 << 7) ,
  OPT_KP_OVERRIDE = (1 << 8) , OPT_MAXDIGITS = (1 << 9) , OPT_SKIP = (1 << 0) , OPT_INDICATION = (1 << 1) ,
  OPT_NOANSWER = (1 << 2) , OPT_TERMINATOR = (1 << 3) , OPT_DELAY = (1 << 0) , OPT_MUTE = (1 << 1) ,
  OPT_QUELCH = (1 << 2) , OPT_RELAXED = (1 << 3) , OPT_EXTRAPULSES = (1 << 4)
}
 

Functions

 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "SF Sender and Receiver Applications")
 
static int load_module (void)
 
static int read_sf_digits (struct ast_channel *chan, char *buf, int buflen, int timeout, int maxdigits, int freq, int features, int extrapulses)
 Detects SF digits on channel using DSP. More...
 
static int read_sf_exec (struct ast_channel *chan, const char *data)
 
static int sendsf_exec (struct ast_channel *chan, const char *vdata)
 
static int unload_module (void)
 

Variables

static const struct ast_app_option read_app_options [128] = { [ 'd' ] = { .flag = OPT_DELAY }, [ 'e' ] = { .flag = OPT_EXTRAPULSES }, [ 'm' ] = { .flag = OPT_MUTE }, [ 'q' ] = { .flag = OPT_QUELCH }, [ 'r' ] = { .flag = OPT_RELAXED }, }
 
static const char * readsf_name = "ReceiveSF"
 
static const char sendsf_name [] = "SendSF"
 

Detailed Description

SF sender and receiver applications.

Author
Naveen Albert aster.nosp@m.isk@.nosp@m.phrea.nosp@m.knet.nosp@m..org

Definition in file app_sf.c.

Macro Definition Documentation

◆ BUFFER_SIZE

#define BUFFER_SIZE   256

◆ SF_BETWEEN

#define SF_BETWEEN   600

◆ SF_MIN_DETECT

#define SF_MIN_DETECT   50

◆ SF_MIN_OFF

#define SF_MIN_OFF   25

◆ SF_ON

#define SF_ON   67

Enumeration Type Documentation

◆ read_option_flags

Enumerator
OPT_DELAY 
OPT_MUTE 
OPT_QUELCH 
OPT_RELAXED 
OPT_LAX_KP 
OPT_PROCESS 
OPT_NO_KP 
OPT_NO_ST 
OPT_KP_OVERRIDE 
OPT_MAXDIGITS 
OPT_SKIP 
OPT_INDICATION 
OPT_NOANSWER 
OPT_TERMINATOR 
OPT_DELAY 
OPT_MUTE 
OPT_QUELCH 
OPT_RELAXED 
OPT_EXTRAPULSES 

Definition at line 149 of file app_sf.c.

149  {
150  OPT_DELAY = (1 << 0),
151  OPT_MUTE = (1 << 1),
152  OPT_QUELCH = (1 << 2),
153  OPT_RELAXED = (1 << 3),
154  OPT_EXTRAPULSES = (1 << 4),
155 };
@ OPT_EXTRAPULSES
Definition: app_sf.c:154
@ OPT_MUTE
Definition: app_sf.c:151
@ OPT_RELAXED
Definition: app_sf.c:153
@ OPT_QUELCH
Definition: app_sf.c:152
@ OPT_DELAY
Definition: app_sf.c:150

Function Documentation

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"SF Sender and Receiver Applications"   
)

◆ load_module()

static int load_module ( void  )
static

Definition at line 457 of file app_sf.c.

458 {
459  int res;
460 
463 
464  return res;
465 }
static const char sendsf_name[]
Definition: app_sf.c:166
static const char * readsf_name
Definition: app_sf.c:165
static int read_sf_exec(struct ast_channel *chan, const char *data)
Definition: app_sf.c:320
static int sendsf_exec(struct ast_channel *chan, const char *vdata)
Definition: app_sf.c:400
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

References ast_register_application_xml, read_sf_exec(), readsf_name, sendsf_exec(), and sendsf_name.

◆ read_sf_digits()

static int read_sf_digits ( struct ast_channel chan,
char *  buf,
int  buflen,
int  timeout,
int  maxdigits,
int  freq,
int  features,
int  extrapulses 
)
static

Detects SF digits on channel using DSP.

Parameters
chanchannel on which to read digits
bufBuffer in which to store digits
buflenSize of buffer
timeoutms to wait for all digits before giving up
maxdigitsMaximum number of digits
freqFrequency to use
featuresDSP features
extrapulsesWhether to recognize extra pulses
Return values
0if successful
-1if unsuccessful (including hangup).

Definition at line 183 of file app_sf.c.

183  {
184  /* Bell System Technical Journal 39 (Nov. 1960) */
185  #define SF_MIN_OFF 25
186  #define SF_ON 67
187  #define SF_BETWEEN 600
188  #define SF_MIN_DETECT 50
189 
190  struct ast_dsp *dsp = NULL;
191  struct ast_frame *frame = NULL;
192  struct timeval start, pulsetimer, digittimer;
193  int remaining_time = timeout;
194  char *str = buf;
195  int hits = 0, digits_read = 0;
196  unsigned short int sf_on = 0;
197  int res = 0;
198 
199  if (!(dsp = ast_dsp_new())) {
200  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
201  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "ERROR");
202  return -1;
203  }
205  /* tolerance is 46 to 76% make break at 8 to 12 pps */
206  ast_dsp_set_freqmode(dsp, freq, SF_MIN_DETECT, 16, 0);
207 
208  start = ast_tvnow();
209  *str = 0; /* start with empty output buffer */
210 
211  while (timeout == 0 || remaining_time > 0) {
212  if (timeout > 0) {
213  remaining_time = ast_remaining_ms(start, timeout);
214  if (remaining_time <= 0) {
215  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "TIMEOUT");
216  break;
217  }
218  }
219  if (digits_read >= (buflen - 1)) { /* we don't have room to store any more digits (very unlikely to happen for a legitimate reason) */
220  /* This result will probably not be usable, so status should not be START */
221  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "MAXDIGITS");
222  break;
223  }
224  if (ast_waitfor(chan, 1000) > 0) {
225  frame = ast_read(chan);
226  if (!frame) {
227  ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
228  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "HANGUP");
229  break;
230  } else if (frame->frametype == AST_FRAME_VOICE) {
231  frame = ast_dsp_process(chan, dsp, frame);
232  if (frame->frametype == AST_FRAME_DTMF) {
233  char result = frame->subclass.integer;
234  if (result == 'q') {
235  sf_on = 1;
236  pulsetimer = ast_tvnow(); /* reset the pulse timer */
237  /* now, we need at least a 33ms pause to register the pulse */
238  }
239  } else {
240  if (sf_on) {
241  int timeleft = ast_remaining_ms(pulsetimer, SF_MIN_OFF);
242  if (timeleft <= 0) {
243  sf_on = 0;
244  /* The pulse needs to end no more than 30ms after we detected it */
245  if (timeleft > -30) {
246  hits++;
247  digittimer = ast_tvnow(); /* reset the digit timer */
248  ast_debug(5, "Detected SF pulse (pulse #%d)\n", hits);
249  ast_dsp_free(dsp);
250  if (!(dsp = ast_dsp_new())) {
251  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
252  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "ERROR");
253  ast_frfree(frame);
254  return -1;
255  }
257  ast_dsp_set_freqmode(dsp, freq, SF_MIN_DETECT, 16, 0);
258  } else {
259  ast_debug(5, "SF noise, ignoring, time elapsed was %d ms\n", timeleft);
260  }
261  }
262  } else if (hits > 0 && ast_remaining_ms(digittimer, SF_BETWEEN) <= 0) {
263  /* has the digit finished? */
264  ast_debug(2, "Received SF digit: %d\n", hits);
265  digits_read++;
266  if (hits > 10) {
267  if (extrapulses) {
268  /* dahdi-base.c translates 11 to * and 12 to # */
269  if (hits == 11) {
270  hits = '*';
271  } else if (hits == 12) {
272  hits = '#';
273  } else if (hits == 13) {
274  hits = 'D';
275  } else if (hits == 14) {
276  hits = 'C';
277  } else if (hits == 15) {
278  hits = 'B';
279  } else if (hits == 16) {
280  hits = 'A';
281  } else {
282  ast_debug(3, "Got %d SF pulses, is someone playing with the phone?\n", hits);
283  hits = 'A';
284  }
285  *str++ = hits;
286  } else {
287  ast_debug(2, "Got more than 10 pulses, truncating to 10\n");
288  hits = 0; /* 10 dial pulses = digit 0 */
289  *str++ = hits + '0';
290  }
291  } else {
292  if (hits == 10) {
293  hits = 0; /* 10 dial pulses = digit 0 */
294  }
295  *str++ = hits + '0';
296  }
297  *str = 0;
298  hits = 0;
299  if (maxdigits > 0 && digits_read >= maxdigits) {
300  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "START");
301  ast_frfree(frame);
302  break;
303  }
304  }
305  }
306  }
307  ast_frfree(frame);
308  } else {
309  pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "HANGUP");
310  res = -1;
311  }
312  }
313  if (dsp) {
314  ast_dsp_free(dsp);
315  }
316  ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
317  return res;
318 }
const char * str
Definition: app_jack.c:147
#define SF_MIN_OFF
#define SF_BETWEEN
#define SF_MIN_DETECT
#define ast_log
Definition: astobj2.c:42
static PGresult * result
Definition: cel_pgsql.c:84
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
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
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,...
Definition: dsp.c:1497
#define DSP_FEATURE_FREQ_DETECT
Definition: dsp.h:45
int ast_dsp_set_freqmode(struct ast_dsp *dsp, int freq, int dur, int db, int squelch)
Set arbitrary frequency detection mode.
Definition: dsp.c:1862
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1758
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_VOICE
#define ast_debug(level,...)
Log a DEBUG message.
#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.
#define NULL
Definition: resample.c:96
Definition: dsp.c:407
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2179
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157

References ast_channel_name(), ast_debug, ast_dsp_free(), ast_dsp_new(), ast_dsp_process(), ast_dsp_set_features(), ast_dsp_set_freqmode(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_log, ast_read(), ast_remaining_ms(), ast_tvnow(), ast_waitfor(), buf, DSP_FEATURE_FREQ_DETECT, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, NULL, pbx_builtin_setvar_helper(), result, SF_BETWEEN, SF_MIN_DETECT, SF_MIN_OFF, str, and ast_frame::subclass.

Referenced by read_sf_exec().

◆ read_sf_exec()

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

Definition at line 320 of file app_sf.c.

321 {
322 #define BUFFER_SIZE 256
323  char tmp[BUFFER_SIZE] = "";
324  double tosec;
325  struct ast_flags flags = {0};
326  char *argcopy = NULL;
327  int res, features = 0, digits = 0, to = 0, freq = 2600;
328 
329  AST_DECLARE_APP_ARGS(arglist,
330  AST_APP_ARG(variable);
331  AST_APP_ARG(digits);
332  AST_APP_ARG(timeout);
333  AST_APP_ARG(freq);
335  );
336 
337  if (ast_strlen_zero(data)) {
338  ast_log(LOG_WARNING, "ReceiveSF requires an argument (variable)\n");
339  return -1;
340  }
341 
342  argcopy = ast_strdupa(data);
343 
344  AST_STANDARD_APP_ARGS(arglist, argcopy);
345 
346  if (!ast_strlen_zero(arglist.options)) {
347  ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
348  }
349 
350  if (!ast_strlen_zero(arglist.timeout)) {
351  tosec = atof(arglist.timeout);
352  if (tosec <= 0) {
353  to = 0;
354  } else {
355  to = tosec * 1000.0;
356  }
357  }
358 
359  if (!ast_strlen_zero(arglist.digits) && (ast_str_to_int(arglist.digits, &digits) || digits <= 0)) {
360  ast_log(LOG_WARNING, "Invalid number of digits: %s\n", arglist.digits);
361  return -1;
362  }
363 
364  if (!ast_strlen_zero(arglist.freq) && (ast_str_to_int(arglist.freq, &freq) || freq <= 0)) {
365  ast_log(LOG_WARNING, "Invalid freq: %s\n", arglist.freq);
366  return -1;
367  }
368 
369  if (ast_strlen_zero(arglist.variable)) {
370  ast_log(LOG_WARNING, "Invalid! Usage: ReceiveSF(variable[,timeout][,option])\n");
371  return -1;
372  }
373 
374  if (ast_test_flag(&flags, OPT_DELAY)) {
375  features |= DSP_DIGITMODE_MUTEMAX;
376  }
377 
378  if (ast_test_flag(&flags, OPT_MUTE)) {
379  features |= DSP_DIGITMODE_MUTECONF;
380  }
381 
382  if (!ast_test_flag(&flags, OPT_QUELCH)) {
383  features |= DSP_DIGITMODE_NOQUELCH;
384  }
385 
387  features |= DSP_DIGITMODE_RELAXDTMF;
388  }
389 
390  res = read_sf_digits(chan, tmp, BUFFER_SIZE, to, digits, freq, features, ast_test_flag(&flags, OPT_EXTRAPULSES));
391  pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
392  if (!ast_strlen_zero(tmp)) {
393  ast_verb(3, "SF digits received: '%s'\n", tmp);
394  } else if (!res) { /* if channel hung up, don't print anything out */
395  ast_verb(3, "No SF digits received.\n");
396  }
397  return res;
398 }
#define BUFFER_SIZE
static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int maxdigits, int freq, int features, int extrapulses)
Detects SF digits on channel using DSP.
Definition: app_sf.c:183
static const struct ast_app_option read_app_options[128]
Definition: app_sf.c:163
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int tmp()
Definition: bt_open.c:389
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition: conversions.c:44
#define DSP_DIGITMODE_NOQUELCH
Definition: dsp.h:34
#define DSP_DIGITMODE_MUTEMAX
Definition: dsp.h:36
#define DSP_DIGITMODE_MUTECONF
Definition: dsp.h:35
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
#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.
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.
Definition: main/app.c:3126
#define ast_verb(level,...)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63

References AST_APP_ARG, ast_app_parse_options(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_str_to_int(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, BUFFER_SIZE, DSP_DIGITMODE_MUTECONF, DSP_DIGITMODE_MUTEMAX, DSP_DIGITMODE_NOQUELCH, DSP_DIGITMODE_RELAXDTMF, ast_flags::flags, LOG_WARNING, NULL, OPT_DELAY, OPT_EXTRAPULSES, OPT_MUTE, OPT_QUELCH, OPT_RELAXED, options, pbx_builtin_setvar_helper(), read_app_options, read_sf_digits(), and tmp().

Referenced by load_module().

◆ sendsf_exec()

static int sendsf_exec ( struct ast_channel chan,
const char *  vdata 
)
static

Definition at line 400 of file app_sf.c.

401 {
402  int res;
403  char *data;
404  int frequency = 2600;
405  struct ast_channel *chan_found = NULL;
406  struct ast_channel *chan_dest = chan;
407  struct ast_channel *chan_autoservice = NULL;
409  AST_APP_ARG(digits);
410  AST_APP_ARG(frequency);
411  AST_APP_ARG(channel);
412  );
413 
414  if (ast_strlen_zero(vdata)) {
415  ast_log(LOG_WARNING, "SendSF requires an argument\n");
416  return 0;
417  }
418 
419  data = ast_strdupa(vdata);
421 
422  if (ast_strlen_zero(args.digits)) {
423  ast_log(LOG_WARNING, "The digits argument is required (0-9,wf)\n");
424  return 0;
425  }
426  if (!ast_strlen_zero(args.frequency) && (ast_str_to_int(args.frequency, &frequency) || frequency < 1)) {
427  ast_log(LOG_WARNING, "Invalid duration: %s\n", args.frequency);
428  return -1;
429  }
430  if (!ast_strlen_zero(args.channel)) {
431  chan_found = ast_channel_get_by_name(args.channel);
432  if (!chan_found) {
433  ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
434  return 0;
435  }
436  chan_dest = chan_found;
437  if (chan_found != chan) {
438  chan_autoservice = chan;
439  }
440  }
441  res = ast_sf_stream(chan_dest, chan_autoservice, NULL, args.digits, frequency, 0);
442  ast_channel_cleanup(chan_found);
443 
444  return chan_autoservice ? 0 : res;
445 }
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1448
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
int ast_sf_stream(struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *chan2, const char *digits, int frequency, int is_external)
Send a string of SF digits to a channel.
Definition: main/app.c:1167
Main Channel structure associated with a channel.
const char * data
const char * args

References args, AST_APP_ARG, ast_channel_cleanup, ast_channel_get_by_name(), AST_DECLARE_APP_ARGS, ast_log, ast_sf_stream(), AST_STANDARD_APP_ARGS, ast_str_to_int(), ast_strdupa, ast_strlen_zero(), ast_channel::data, LOG_WARNING, and NULL.

Referenced by load_module().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 447 of file app_sf.c.

448 {
449  int res;
450 
453 
454  return res;
455 }
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References ast_unregister_application(), readsf_name, and sendsf_name.

Variable Documentation

◆ read_app_options

const struct ast_app_option read_app_options[128] = { [ 'd' ] = { .flag = OPT_DELAY }, [ 'e' ] = { .flag = OPT_EXTRAPULSES }, [ 'm' ] = { .flag = OPT_MUTE }, [ 'q' ] = { .flag = OPT_QUELCH }, [ 'r' ] = { .flag = OPT_RELAXED }, }
static

Definition at line 1 of file app_sf.c.

Referenced by read_sf_exec().

◆ readsf_name

const char* readsf_name = "ReceiveSF"
static

Definition at line 165 of file app_sf.c.

Referenced by load_module(), and unload_module().

◆ sendsf_name

const char sendsf_name[] = "SendSF"
static

Definition at line 166 of file app_sf.c.

Referenced by load_module(), and unload_module().