Asterisk - The Open Source Telephony Project GIT-master-a63eec2
Loading...
Searching...
No Matches
app_sf.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2021, Naveen Albert
5 *
6 * Naveen Albert <asterisk@phreaknet.org>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief SF sender and receiver applications
22 *
23 * \author Naveen Albert <asterisk@phreaknet.org>
24 *
25 * \ingroup applications
26 */
27
28/*** MODULEINFO
29 <support_level>extended</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/file.h"
35#include "asterisk/pbx.h"
36#include "asterisk/channel.h"
37#include "asterisk/dsp.h"
38#include "asterisk/app.h"
39#include "asterisk/module.h"
42
43/*** DOCUMENTATION
44 <application name="ReceiveSF" language="en_US">
45 <since>
46 <version>16.24.0</version>
47 <version>18.10.0</version>
48 <version>19.2.0</version>
49 </since>
50 <synopsis>
51 Detects SF digits on a channel and saves them to a variable.
52 </synopsis>
53 <syntax>
54 <parameter name="variable" required="true">
55 <para>The input digits will be stored in the given
56 <replaceable>variable</replaceable> name.</para>
57 </parameter>
58 <parameter name="digits" required="false">
59 <para>Maximum number of digits to read. Default is unlimited.</para>
60 </parameter>
61 <parameter name="timeout">
62 <para>The number of seconds to wait for all digits, if greater
63 than <literal>0</literal>. Can be floating point. Default
64 is no timeout.</para>
65 </parameter>
66 <parameter name="frequency">
67 <para>The frequency for which to detect pulsed digits.
68 Default is 2600 Hz.</para>
69 </parameter>
70 <parameter name="options">
71 <optionlist>
72 <option name="d">
73 <para>Delay audio by a frame to try to extra quelch.</para>
74 </option>
75 <option name="e">
76 <para>Allow receiving extra pulses 11 through 16.</para>
77 </option>
78 <option name="m">
79 <para>Mute conference.</para>
80 </option>
81 <option name="t">
82 <para>Post-digit timeout, in seconds. If more than this amount of time
83 elapses after a digit, the number will be deemed finalized and
84 the application will return This is useful when reading a variable
85 number of digits that is unknown in advance.</para>
86 <para>This can be almost any positive decimal number of seconds, but must
87 be no less than 0.6 seconds, since this is the SF inter-digit timeout.
88 The default is 0.8, which should be compatible with <literal>SendSF</literal>.
89 Values lower than 0.75 will generally produce unreliable results.</para>
90 <para>Note this timer only kicks in after at least one digit has been received,
91 to account for sender/receiver synchronization.</para>
92 <para>Note that <literal>RECEIVESFSTATUS</literal> will still be
93 set to <literal>TIMEOUT</literal> if the post-digit timer expires.</para>
94 </option>
95 <option name="q">
96 <para>Quelch SF from in-band.</para>
97 </option>
98 <option name="r">
99 <para>"Radio" mode (relaxed SF).</para>
100 </option>
101 </optionlist>
102 </parameter>
103 </syntax>
104 <description>
105 <para>Reads SF digits from the user in to the given
106 <replaceable>variable</replaceable>.</para>
107 <para>This application does not automatically answer the channel and
108 should be preceded with <literal>Answer</literal> or
109 <literal>Progress</literal> as needed.</para>
110 <variablelist>
111 <variable name="RECEIVESFSTATUS">
112 <para>This is the status of the read operation.</para>
113 <value name="START" />
114 <value name="ERROR" />
115 <value name="HANGUP" />
116 <value name="MAXDIGITS" />
117 <value name="TIMEOUT" />
118 </variable>
119 </variablelist>
120 </description>
121 <see-also>
122 <ref type="application">ReceiveMF</ref>
123 <ref type="application">SendMF</ref>
124 <ref type="application">SendSF</ref>
125 <ref type="application">Read</ref>
126 </see-also>
127 </application>
128 <application name="SendSF" language="en_US">
129 <since>
130 <version>16.24.0</version>
131 <version>18.10.0</version>
132 <version>19.2.0</version>
133 </since>
134 <synopsis>
135 Sends arbitrary SF digits on the current or specified channel.
136 </synopsis>
137 <syntax>
138 <parameter name="digits" required="true">
139 <para>List of digits 0-9 to send; w for a half-second pause,
140 also f or F for a flash-hook if the channel supports flash-hook,
141 h or H for 250 ms of 2600 Hz, and W for a wink if the channel
142 supports wink.</para>
143 </parameter>
144 <parameter name="frequency" required="false">
145 <para>Frequency to use. (defaults to 2600 Hz).</para>
146 </parameter>
147 <parameter name="channel" required="false">
148 <para>Channel where digits will be played</para>
149 </parameter>
150 </syntax>
151 <description>
152 <para>It will send all digits or terminate if it encounters an error.</para>
153 </description>
154 <see-also>
155 <ref type="application">SendDTMF</ref>
156 <ref type="application">SendMF</ref>
157 <ref type="application">ReceiveMF</ref>
158 <ref type="application">ReceiveSF</ref>
159 </see-also>
160 </application>
161 ***/
162
163/* Default post-digit timer */
164#define DEFAULT_POST_DIGIT_TIMER 0.8
165
166/* Bell System Technical Journal 39 (Nov. 1960) */
167#define SF_MIN_OFF 25
168#define SF_ON 67
169#define SF_BETWEEN 600
170#define SF_MIN_DETECT 50
171
173 OPT_DELAY = (1 << 0),
174 OPT_MUTE = (1 << 1),
175 OPT_QUELCH = (1 << 2),
176 OPT_RELAXED = (1 << 3),
177 OPT_EXTRAPULSES = (1 << 4),
179};
180
181enum {
183 /* note: this entry _MUST_ be the last one in the enum */
185};
186
194});
195
196static const char *readsf_name = "ReceiveSF";
197static const char sendsf_name[] = "SendSF";
198
199/*!
200 * \brief Detects SF digits on channel using DSP
201 *
202 * \param chan channel on which to read digits
203 * \param buf Buffer in which to store digits
204 * \param buflen Size of buffer
205 * \param timeout ms to wait for all digits before giving up
206 * \param digit_timeout ms to wait for the next digit before giving up
207 * \param maxdigits Maximum number of digits
208 * \param freq Frequency to use
209 * \param features DSP features
210 * \param extrapulses Whether to recognize extra pulses
211 *
212 * \retval 0 if successful
213 * \retval -1 if unsuccessful (including hangup).
214 */
215static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int digit_timeout, int maxdigits, int freq, int features, int extrapulses)
216{
217 struct ast_dsp *dsp = NULL;
218 struct ast_frame *frame = NULL;
219 struct timeval start, pulsetimer, digittimer;
220 int remaining_time = timeout;
221 char *str = buf;
222 int hits = 0, digits_read = 0;
223 unsigned short int sf_on = 0;
224 int res = 0;
225
226 if (!(dsp = ast_dsp_new())) {
227 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
228 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "ERROR");
229 return -1;
230 }
232 /* tolerance is 46 to 76% make break at 8 to 12 pps */
233 ast_dsp_set_freqmode(dsp, freq, SF_MIN_DETECT, 16, 0);
234
235 start = ast_tvnow();
236 *str = 0; /* start with empty output buffer */
237
238 while (timeout == 0 || remaining_time > 0) {
239 if (timeout > 0) {
240 remaining_time = ast_remaining_ms(start, timeout);
241 if (remaining_time <= 0) {
242 ast_debug(1, "SF all-digit timer expired\n");
243 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "TIMEOUT");
244 break;
245 }
246 }
247 /* If we haven't received a digit yet, don't apply the post-digit timer just yet,
248 * since the sender may not have started sending any digits.
249 *
250 * Note that we use the digit timer, which is reset for each SF pulse,
251 * as opposed to simply an entire digit being received.
252 * This is done because we only want to expire the timer if there has been no activity
253 * since the last digit. If we're in the middle of receiving a digit (e.g. 0)
254 * we may not have a full digit yet but that should not cause an expiration. */
255 if (digits_read > 0 && digit_timeout > 0) {
256 int remaining_time_for_next_digit = ast_remaining_ms(digittimer, digit_timeout);
257 if (remaining_time_for_next_digit <= 0) {
258 ast_debug(1, "SF post-digit timer expired (>= %d ms since last SF pulse)\n", digit_timeout);
259 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "TIMEOUT");
260 break;
261 }
262 }
263 if (digits_read >= (buflen - 1)) { /* we don't have room to store any more digits (very unlikely to happen for a legitimate reason) */
264 /* This result will probably not be usable, so status should not be START */
265 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "MAXDIGITS");
266 break;
267 }
268 if (ast_waitfor(chan, 1000) > 0) {
269 frame = ast_read(chan);
270 if (!frame) {
271 ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
272 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "HANGUP");
273 break;
274 } else if (frame->frametype == AST_FRAME_VOICE) {
275 frame = ast_dsp_process(chan, dsp, frame);
276 if (frame->frametype == AST_FRAME_DTMF) {
277 char result = frame->subclass.integer;
278 if (result == 'q') {
279 sf_on = 1;
280 pulsetimer = ast_tvnow(); /* reset the pulse timer */
281 /* now, we need at least a 33ms pause to register the pulse */
282 }
283 } else {
284 if (sf_on) {
285 int timeleft = ast_remaining_ms(pulsetimer, SF_MIN_OFF);
286 if (timeleft <= 0) {
287 sf_on = 0;
288 /* The pulse needs to end no more than 30ms after we detected it */
289 if (timeleft > -30) {
290 hits++;
291 digittimer = ast_tvnow(); /* reset the digit timer */
292 ast_debug(5, "Detected SF pulse (pulse #%d)\n", hits);
293 ast_dsp_free(dsp);
294 if (!(dsp = ast_dsp_new())) {
295 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
296 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "ERROR");
297 ast_frfree(frame);
298 return -1;
299 }
301 ast_dsp_set_freqmode(dsp, freq, SF_MIN_DETECT, 16, 0);
302 } else {
303 ast_debug(5, "SF noise, ignoring, time elapsed was %d ms\n", timeleft);
304 }
305 }
306 } else if (hits > 0 && ast_remaining_ms(digittimer, SF_BETWEEN) <= 0) {
307 /* has the digit finished? */
308 ast_debug(2, "Received SF digit: %d\n", hits == 10 ? 0 : hits); /* Edge case for 10, since this is the digit '0' */
309 digits_read++;
310 if (hits > 10) {
311 if (extrapulses) {
312 /* dahdi-base.c translates 11 to * and 12 to # */
313 if (hits == 11) {
314 hits = '*';
315 } else if (hits == 12) {
316 hits = '#';
317 } else if (hits == 13) {
318 hits = 'D';
319 } else if (hits == 14) {
320 hits = 'C';
321 } else if (hits == 15) {
322 hits = 'B';
323 } else if (hits == 16) {
324 hits = 'A';
325 } else {
326 ast_debug(3, "Got %d SF pulses, is someone playing with the phone?\n", hits);
327 hits = 'A';
328 }
329 *str++ = hits;
330 } else {
331 ast_debug(2, "Got more than 10 pulses, truncating to 10\n");
332 hits = 0; /* 10 dial pulses = digit 0 */
333 *str++ = hits + '0';
334 }
335 } else {
336 if (hits == 10) {
337 hits = 0; /* 10 dial pulses = digit 0 */
338 }
339 *str++ = hits + '0';
340 }
341 *str = 0;
342 hits = 0;
343 if (maxdigits > 0 && digits_read >= maxdigits) {
344 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "START");
345 ast_frfree(frame);
346 break;
347 }
348 }
349 }
350 }
351 ast_frfree(frame);
352 } else {
353 pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "HANGUP");
354 res = -1;
355 }
356 }
357 if (dsp) {
358 ast_dsp_free(dsp);
359 }
360 ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
361 return res;
362}
363
364static int read_sf_exec(struct ast_channel *chan, const char *data)
365{
366#define BUFFER_SIZE 256
367 char tmp[BUFFER_SIZE] = "";
368 double tosec, digitsec;
369 struct ast_flags flags = {0};
370 char *opt_args[OPT_ARG_ARRAY_SIZE];
371 char *argcopy = NULL;
372 int res, features = 0, digits = 0, to = 0, digit_timeout = 0, freq = 2600;
373
374 AST_DECLARE_APP_ARGS(arglist,
375 AST_APP_ARG(variable);
376 AST_APP_ARG(digits);
377 AST_APP_ARG(timeout);
378 AST_APP_ARG(freq);
380 );
381
382 if (ast_strlen_zero(data)) {
383 ast_log(LOG_WARNING, "ReceiveSF requires an argument (variable)\n");
384 return -1;
385 }
386
387 argcopy = ast_strdupa(data);
388
389 AST_STANDARD_APP_ARGS(arglist, argcopy);
390
391 if (!ast_strlen_zero(arglist.options)) {
392 ast_app_parse_options(read_app_options, &flags, opt_args, arglist.options);
393 }
394
395 if (!ast_strlen_zero(arglist.timeout)) {
396 tosec = atof(arglist.timeout);
397 if (tosec <= 0) {
398 to = 0;
399 } else {
400 to = tosec * 1000.0;
401 }
402 }
404 digitsec = (!ast_strlen_zero(opt_args[OPT_ARG_DIGIT_TIMEOUT]) ? atof(opt_args[OPT_ARG_DIGIT_TIMEOUT]) : DEFAULT_POST_DIGIT_TIMER);
405 if (digitsec <= 0) {
406 digit_timeout = 0;
407 } else {
408 digit_timeout = digitsec * 1000.0;
409 if (digit_timeout < SF_BETWEEN) {
410 ast_log(LOG_WARNING, "SF post-digit timer (%d) cannot be less than the SF inter-digit timeout (%d ms)\n", digit_timeout, SF_BETWEEN);
411 digit_timeout = SF_BETWEEN; /* If we have a shorter timeout, it won't work at all */
412 }
413 }
414 }
415
416 if (!ast_strlen_zero(arglist.digits) && (ast_str_to_int(arglist.digits, &digits) || digits <= 0)) {
417 ast_log(LOG_WARNING, "Invalid number of digits: %s\n", arglist.digits);
418 return -1;
419 }
420
421 if (!ast_strlen_zero(arglist.freq) && (ast_str_to_int(arglist.freq, &freq) || freq <= 0)) {
422 ast_log(LOG_WARNING, "Invalid freq: %s\n", arglist.freq);
423 return -1;
424 }
425
426 if (ast_strlen_zero(arglist.variable)) {
427 ast_log(LOG_WARNING, "Invalid! Usage: ReceiveSF(variable[,timeout][,option])\n");
428 return -1;
429 }
430
432 features |= DSP_DIGITMODE_MUTEMAX;
433 }
434
436 features |= DSP_DIGITMODE_MUTECONF;
437 }
438
440 features |= DSP_DIGITMODE_NOQUELCH;
441 }
442
444 features |= DSP_DIGITMODE_RELAXDTMF;
445 }
446
447 res = read_sf_digits(chan, tmp, BUFFER_SIZE, to, digit_timeout, digits, freq, features, ast_test_flag(&flags, OPT_EXTRAPULSES));
448 pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
449 if (!ast_strlen_zero(tmp)) {
450 ast_verb(3, "SF digits received: '%s'\n", tmp);
451 } else if (!res) { /* if channel hung up, don't print anything out */
452 ast_verb(3, "No SF digits received.\n");
453 }
454 return res;
455}
456
457static int sendsf_exec(struct ast_channel *chan, const char *vdata)
458{
459 int res;
460 char *data;
461 int frequency = 2600;
462 struct ast_channel *chan_found = NULL;
463 struct ast_channel *chan_dest = chan;
464 struct ast_channel *chan_autoservice = NULL;
466 AST_APP_ARG(digits);
467 AST_APP_ARG(frequency);
468 AST_APP_ARG(channel);
469 );
470
471 if (ast_strlen_zero(vdata)) {
472 ast_log(LOG_WARNING, "SendSF requires an argument\n");
473 return 0;
474 }
475
476 data = ast_strdupa(vdata);
478
479 if (ast_strlen_zero(args.digits)) {
480 ast_log(LOG_WARNING, "The digits argument is required (0-9,wf)\n");
481 return 0;
482 }
483 if (!ast_strlen_zero(args.frequency) && (ast_str_to_int(args.frequency, &frequency) || frequency < 1)) {
484 ast_log(LOG_WARNING, "Invalid duration: %s\n", args.frequency);
485 return -1;
486 }
487 if (!ast_strlen_zero(args.channel)) {
488 chan_found = ast_channel_get_by_name(args.channel);
489 if (!chan_found) {
490 ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
491 return 0;
492 }
493 chan_dest = chan_found;
494 if (chan_found != chan) {
495 chan_autoservice = chan;
496 }
497 }
498 res = ast_sf_stream(chan_dest, chan_autoservice, NULL, args.digits, frequency, 0);
499 ast_channel_cleanup(chan_found);
500
501 return chan_autoservice ? 0 : res;
502}
503
504static int unload_module(void)
505{
506 int res;
507
510
511 return res;
512}
513
514static int load_module(void)
515{
516 int res;
517
520
521 return res;
522}
523
524AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "SF Sender and Receiver Applications");
const char * str
Definition app_jack.c:150
read_option_flags
Definition app_mf.c:188
#define SF_MIN_OFF
Definition app_sf.c:167
static const char sendsf_name[]
Definition app_sf.c:197
static const char * readsf_name
Definition app_sf.c:196
@ OPT_ARG_DIGIT_TIMEOUT
Definition app_sf.c:182
@ OPT_ARG_ARRAY_SIZE
Definition app_sf.c:184
#define SF_BETWEEN
Definition app_sf.c:169
#define BUFFER_SIZE
static int read_sf_exec(struct ast_channel *chan, const char *data)
Definition app_sf.c:364
static int sendsf_exec(struct ast_channel *chan, const char *vdata)
Definition app_sf.c:457
#define SF_MIN_DETECT
Definition app_sf.c:170
static int load_module(void)
Definition app_sf.c:514
static int unload_module(void)
Definition app_sf.c:504
@ OPT_EXTRAPULSES
Definition app_sf.c:177
@ OPT_MUTE
Definition app_sf.c:174
@ OPT_RELAXED
Definition app_sf.c:176
@ OPT_QUELCH
Definition app_sf.c:175
@ OPT_DELAY
Definition app_sf.c:173
@ OPT_DIGIT_TIMEOUT
Definition app_sf.c:178
static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int digit_timeout, int maxdigits, int freq, int features, int extrapulses)
Detects SF digits on channel using DSP.
Definition app_sf.c:215
#define DEFAULT_POST_DIGIT_TIMER
Definition app_sf.c:164
static const struct ast_app_option read_app_options[128]
Definition app_sf.c:194
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
static PGresult * result
Definition cel_pgsql.c:84
General Asterisk PBX channel definitions.
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:3132
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4223
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1398
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3019
Conversion utility functions.
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition conversions.c:44
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1787
#define DSP_DIGITMODE_NOQUELCH
Definition dsp.h:34
#define DSP_DIGITMODE_MUTEMAX
Definition dsp.h:36
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:1503
#define DSP_DIGITMODE_MUTECONF
Definition dsp.h:35
#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:1876
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition dsp.c:1772
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1762
#define DSP_DIGITMODE_RELAXDTMF
Definition dsp.h:37
char buf[BUFSIZE]
Definition eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
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
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an 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_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
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_FRAME_DTMF
#define ast_frfree(fr)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
#define LOG_WARNING
Tone Indication Support.
Asterisk module definitions.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392
#define AST_MODULE_INFO_STANDARD_EXTENDED(keystr, desc)
Definition module.h:589
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
Core PBX routines and definitions.
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.
static struct @519 args
#define NULL
Definition resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Main Channel structure associated with a channel.
const char * data
Definition dsp.c:407
Structure used to handle boolean flags.
Definition utils.h:217
unsigned int flags
Definition utils.h:218
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
static struct test_options options
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2317
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define ast_test_flag(p, flag)
Definition utils.h:63