Asterisk - The Open Source Telephony Project GIT-master-f36a736
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_KEEP_TERMINATOR = (1 << 4) , OPT_ANSWER = (1 << 0) ,
  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_KEEP_TERMINATOR 
OPT_ANSWER 
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:640

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
const char * ast_channel_name(const struct ast_channel *chan)
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3181
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
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:1499
#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:1872
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
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: utils.c:2281
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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)) {
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
375 features |= DSP_DIGITMODE_MUTEMAX;
376 }
377
379 features |= DSP_DIGITMODE_MUTECONF;
380 }
381
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:3066
#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}
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3015
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
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:1097
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 163 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().