Gentoo Archives: gentoo-commits

From: "Tony Vroon (chainsaw)" <chainsaw@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in net-misc/asterisk/files/1.6.2: asterisk-1.6.2.2-graceful-restart-segfault.patch asterisk-1.6.2.2-parallel-make.patch asterisk-1.6.2.2-nv-faxdetect.patch
Date: Wed, 10 Feb 2010 22:25:36
Message-Id: E1NfKzz-0003hh-Uu@stork.gentoo.org
1 chainsaw 10/02/10 22:25:31
2
3 Added: asterisk-1.6.2.2-graceful-restart-segfault.patch
4 asterisk-1.6.2.2-parallel-make.patch
5 asterisk-1.6.2.2-nv-faxdetect.patch
6 Log:
7 Add nv_faxdetect as scavenged by Cory Coager in bug #298328. Trim unnecessary parts from parallel make patch, upstream bug #16489. Stop segfaulting on a graceful restart, upstream bugs #16062 & #16470.
8 (Portage version: 2.2_rc62/cvs/Linux x86_64)
9
10 Revision Changes Path
11 1.1 net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-graceful-restart-segfault.patch
12
13 file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-graceful-restart-segfault.patch?rev=1.1&view=markup
14 plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-graceful-restart-segfault.patch?rev=1.1&content-type=text/plain
15
16 Index: asterisk-1.6.2.2-graceful-restart-segfault.patch
17 ===================================================================
18 diff -uNr asterisk-1.6.2.2.ORIG/main/event.c asterisk-1.6.2.2/main/event.c
19 --- asterisk-1.6.2.2.ORIG/main/event.c 2010-02-10 21:05:55.278139356 +0000
20 +++ asterisk-1.6.2.2/main/event.c 2010-02-10 21:06:58.008198202 +0000
21 @@ -841,6 +841,11 @@
22 struct ast_event_iterator iterator;
23 int res = 0;
24
25 + /* Event has no IEs allocated */
26 + if (event->event_len < sizeof(*event) + sizeof(ie_type)) {
27 + return NULL;
28 + }
29 +
30 for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
31 if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
32 return ast_event_iterator_get_ie_raw(&iterator);
33 diff -uNr asterisk-1.6.2.2.ORIG/main/loader.c asterisk-1.6.2.2/main/loader.c
34 --- asterisk-1.6.2.2.ORIG/main/loader.c 2010-02-10 21:05:55.273223462 +0000
35 +++ asterisk-1.6.2.2/main/loader.c 2010-02-10 21:06:58.006203410 +0000
36 @@ -444,26 +444,39 @@
37 void ast_module_shutdown(void)
38 {
39 struct ast_module *mod;
40 - AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
41 -
42 - /* We have to call the unload() callbacks in reverse order that the modules
43 - * exist in the module list so it is the reverse order of how they were
44 - * loaded. */
45 + int somethingchanged = 1, final = 0;
46
47 AST_LIST_LOCK(&module_list);
48 - while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
49 - AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
50 - AST_LIST_UNLOCK(&module_list);
51
52 - while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
53 - if (mod->info->unload)
54 - mod->info->unload();
55 - /* Since this should only be called when shutting down "gracefully",
56 - * all channels should be down before we get to this point, meaning
57 - * there will be no module users left. */
58 - AST_LIST_HEAD_DESTROY(&mod->users);
59 - free(mod);
60 - }
61 + /*!\note Some resources, like timers, are started up dynamically, and thus
62 + * may be still in use, even if all channels are dead. We must therefore
63 + * check the usecount before asking modules to unload. */
64 + do {
65 + if (!somethingchanged) {
66 + /*!\note If we go through the entire list without changing
67 + * anything, ignore the usecounts and unload, then exit. */
68 + final = 1;
69 + }
70 +
71 + /* Reset flag before traversing the list */
72 + somethingchanged = 0;
73 +
74 + AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
75 + if (!final && mod->usecount) {
76 + continue;
77 + }
78 + AST_LIST_REMOVE_CURRENT(entry);
79 + if (mod->info->unload) {
80 + mod->info->unload();
81 + }
82 + AST_LIST_HEAD_DESTROY(&mod->users);
83 + free(mod);
84 + somethingchanged = 1;
85 + }
86 + AST_LIST_TRAVERSE_SAFE_END;
87 + } while (somethingchanged && !final);
88 +
89 + AST_LIST_UNLOCK(&module_list);
90 }
91
92 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
93
94
95
96 1.1 net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-parallel-make.patch
97
98 file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-parallel-make.patch?rev=1.1&view=markup
99 plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-parallel-make.patch?rev=1.1&content-type=text/plain
100
101 Index: asterisk-1.6.2.2-parallel-make.patch
102 ===================================================================
103 diff -uNr asterisk-1.6.2.1.ORIG/Makefile asterisk-1.6.2.1/Makefile
104 --- asterisk-1.6.2.1.ORIG/Makefile 2010-01-19 17:06:47.000000000 +0000
105 +++ asterisk-1.6.2.1/Makefile 2010-01-19 17:08:15.000000000 +0000
106 @@ -590,7 +590,7 @@
107 fi
108
109 $(SUBDIRS_INSTALL):
110 - @DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" $(SUBMAKE) -C $(@:-install=) install
111 + +@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" $(SUBMAKE) -C $(@:-install=) install
112
113 NEWMODS:=$(foreach d,$(MOD_SUBDIRS),$(notdir $(wildcard $(d)/*.so)))
114 OLDMODS=$(filter-out $(NEWMODS),$(notdir $(wildcard $(DESTDIR)$(MODULES_DIR)/*.so)))
115 @@ -852,7 +852,7 @@
116 @cmp -s .cleancount .lastclean || $(MAKE) clean
117
118 $(SUBDIRS_UNINSTALL):
119 - @$(SUBMAKE) -C $(@:-uninstall=) uninstall
120 + +@$(SUBMAKE) -C $(@:-uninstall=) uninstall
121
122 _uninstall: $(SUBDIRS_UNINSTALL)
123 rm -f $(DESTDIR)$(MODULES_DIR)/*
124
125
126
127 1.1 net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-nv-faxdetect.patch
128
129 file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-nv-faxdetect.patch?rev=1.1&view=markup
130 plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/asterisk/files/1.6.2/asterisk-1.6.2.2-nv-faxdetect.patch?rev=1.1&content-type=text/plain
131
132 Index: asterisk-1.6.2.2-nv-faxdetect.patch
133 ===================================================================
134 diff -uNr apps/app_nv_backgrounddetect.c apps/app_nv_backgrounddetect.c
135 --- apps/app_nv_backgrounddetect.c 1970-01-01 01:00:00.000000000 +0100
136 +++ apps/app_nv_backgrounddetect.c 2010-02-10 22:09:40.118390386 +0000
137 @@ -0,0 +1,325 @@
138 +/*
139 + * Asterisk -- A telephony toolkit for Linux.
140 + *
141 + * Playback a file with audio detect
142 + *
143 + * Copyright (C) 2004-2005, Newman Telecom, Inc. and Newman Ventures, Inc.
144 + *
145 + * Justin Newman <jnewman@×××××××××××××.com>
146 + *
147 + * We would like to thank Newman Ventures, Inc. for funding this
148 + * Asterisk project.
149 + *
150 + * Newman Ventures <info@××××××××××××××.com>
151 + *
152 + * Portions Copyright:
153 + * Copyright (C) 2001, Linux Support Services, Inc.
154 + * Copyright (C) 2004, Digium, Inc.
155 + *
156 + * Matthew Fredrickson <creslin@×××××××××××××.net>
157 + * Mark Spencer <markster@××××××.com>
158 + *
159 + * This program is free software, distributed under the terms of
160 + * the GNU General Public License
161 + */
162 +
163 +#include "asterisk.h"
164 +
165 +#include <asterisk/lock.h>
166 +#include <asterisk/file.h>
167 +#include <asterisk/logger.h>
168 +#include <asterisk/channel.h>
169 +#include <asterisk/pbx.h>
170 +#include <asterisk/module.h>
171 +#include <asterisk/translate.h>
172 +#include <asterisk/utils.h>
173 +#include <asterisk/dsp.h>
174 +
175 +static char *app = "NVBackgroundDetect";
176 +
177 +static char *synopsis = "Background a file with talk and fax detect (IAX and SIP too)";
178 +
179 +static char *descrip =
180 +" NVBackgroundDetect(filename[|options[|sildur[|mindur|[maxdur]]]]):\n"
181 +"Plays filename, waiting for interruption from fax tones (on IAX and SIP too),\n"
182 +"a digit, or non-silence. Audio is monitored in the receive direction. If\n"
183 +"digits interrupt, they must be the start of a valid extension unless the\n"
184 +"option is included to ignore. If fax is detected, it will jump to the\n"
185 +"'fax' extension. If a period of non-silence is greater than 'mindur' ms,\n"
186 +"yet less than 'maxdur' ms is followed by silence at least 'sildur' ms\n"
187 +"then the app is aborted and processing jumps to the 'talk' extension.\n"
188 +"If all undetected, control will continue at the next priority.\n"
189 +" options:\n"
190 +" 'n': Attempt on-hook if unanswered (default=no)\n"
191 +" 'x': DTMF digits terminate without extension (default=no)\n"
192 +" 'd': Ignore DTMF digit detection (default=no)\n"
193 +" 'f': Ignore fax detection (default=no)\n"
194 +" 't': Ignore talk detection (default=no)\n"
195 +" sildur: Silence ms after mindur/maxdur before aborting (default=1000)\n"
196 +" mindur: Minimum non-silence ms needed (default=100)\n"
197 +" maxdur: Maximum non-silence ms allowed (default=0/forever)\n"
198 +"Returns -1 on hangup, and 0 on successful completion with no exit conditions.\n\n"
199 +"For questions or comments, please e-mail support@×××××××××××××.com.\n";
200 +
201 +// Use the second one for recent Asterisk releases
202 +#define CALLERID_FIELD cid.cid_num
203 +//#define CALLERID_FIELD callerid
204 +
205 +static int nv_background_detect_exec(struct ast_channel *chan, void *data)
206 +{
207 + int res = 0;
208 + char tmp[256] = "\0";
209 + char *p = NULL;
210 + char *filename = NULL;
211 + char *options = NULL;
212 + char *silstr = NULL;
213 + char *minstr = NULL;
214 + char *maxstr = NULL;
215 + struct ast_frame *fr = NULL;
216 + struct ast_frame *fr2 = NULL;
217 + int notsilent = 0;
218 + struct timeval start = {0, 0}, end = {0, 0};
219 + int sildur = 1000;
220 + int mindur = 100;
221 + int maxdur = -1;
222 + int skipanswer = 0;
223 + int noextneeded = 0;
224 + int ignoredtmf = 0;
225 + int ignorefax = 0;
226 + int ignoretalk = 0;
227 + int x = 0;
228 + int origrformat = 0;
229 + int features = 0;
230 + struct ast_dsp *dsp = NULL;
231 +
232 + pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
233 + pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
234 + pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
235 + pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
236 +
237 + if (!data || ast_strlen_zero((char *)data)) {
238 + ast_log(LOG_WARNING, "NVBackgroundDetect requires an argument (filename)\n");
239 + return -1;
240 + }
241 +
242 + strncpy(tmp, (char *)data, sizeof(tmp)-1);
243 + p = tmp;
244 +
245 + filename = strsep(&p, "|");
246 + options = strsep(&p, "|");
247 + silstr = strsep(&p, "|");
248 + minstr = strsep(&p, "|");
249 + maxstr = strsep(&p, "|");
250 +
251 + if (options) {
252 + if (strchr(options, 'n'))
253 + skipanswer = 1;
254 + if (strchr(options, 'x'))
255 + noextneeded = 1;
256 + if (strchr(options, 'd'))
257 + ignoredtmf = 1;
258 + if (strchr(options, 'f'))
259 + ignorefax = 1;
260 + if (strchr(options, 't'))
261 + ignoretalk = 1;
262 + }
263 +
264 + if (silstr) {
265 + if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
266 + sildur = x;
267 + }
268 +
269 + if (minstr) {
270 + if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
271 + mindur = x;
272 + }
273 +
274 + if (maxstr) {
275 + if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
276 + maxdur = x;
277 + }
278 +
279 + ast_log(LOG_DEBUG, "Preparing detect of '%s' (sildur=%dms, mindur=%dms, maxdur=%dms)\n",
280 + tmp, sildur, mindur, maxdur);
281 +
282 + // LOCAL_USER_ADD(u);
283 + if (chan->_state != AST_STATE_UP && !skipanswer) {
284 + /* Otherwise answer unless we're supposed to send this while on-hook */
285 + res = ast_answer(chan);
286 + }
287 + if (!res) {
288 + origrformat = chan->readformat;
289 + if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
290 + ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
291 + }
292 + if (!(dsp = ast_dsp_new())) {
293 + ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
294 + res = -1;
295 + }
296 +
297 + if (dsp) {
298 + if (!ignoretalk)
299 + ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */
300 + if (!ignorefax)
301 + features |= DSP_FEATURE_FAX_DETECT;
302 + //if (!ignoredtmf)
303 + features |= DSP_FEATURE_DIGIT_DETECT;
304 +
305 + ast_dsp_set_threshold(dsp, 256);
306 + ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
307 + ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF);
308 + }
309 +
310 + if (!res) {
311 + ast_stopstream(chan);
312 + res = ast_streamfile(chan, tmp, chan->language);
313 + if (!res) {
314 + while(chan->stream) {
315 + res = ast_sched_wait(chan->sched);
316 + if ((res < 0) && !chan->timingfunc) {
317 + res = 0;
318 + break;
319 + }
320 + if (res < 0)
321 + res = 1000;
322 + res = ast_waitfor(chan, res);
323 + if (res < 0) {
324 + ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
325 + break;
326 + } else if (res > 0) {
327 + fr = ast_read(chan);
328 + if (!fr) {
329 + ast_log(LOG_DEBUG, "Got hangup\n");
330 + res = -1;
331 + break;
332 + }
333 +
334 + fr2 = ast_dsp_process(chan, dsp, fr);
335 + if (!fr2) {
336 + ast_log(LOG_WARNING, "Bad DSP received (what happened!!)\n");
337 + fr2 = fr;
338 + }
339 +
340 + if (fr2->frametype == AST_FRAME_DTMF) {
341 + if (fr2->subclass == 'f' && !ignorefax) {
342 + /* Fax tone -- Handle and return NULL */
343 + ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name);
344 + if (strcmp(chan->exten, "fax")) {
345 + ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", chan->name);
346 + pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
347 + pbx_builtin_setvar_helper(chan,"FAXEXTEN",chan->exten);
348 + if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) {
349 + /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
350 + strncpy(chan->exten, "fax", sizeof(chan->exten)-1);
351 + chan->priority = 0;
352 + } else
353 + ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
354 + } else
355 + ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");
356 +
357 + res = 0;
358 + ast_frfree(fr);
359 + break;
360 + } else if (!ignoredtmf) {
361 + ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name);
362 + char t[2];
363 + t[0] = fr2->subclass;
364 + t[1] = '\0';
365 + if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) {
366 + pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
367 + /* They entered a valid extension, or might be anyhow */
368 + if (noextneeded) {
369 + ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
370 + res = 0;
371 + } else {
372 + ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
373 + res = fr2->subclass;
374 + }
375 + ast_frfree(fr);
376 + break;
377 + } else
378 + ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
379 + }
380 + } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
381 + int totalsilence;
382 + int ms;
383 + res = ast_dsp_silence(dsp, fr, &totalsilence);
384 + if (res && (totalsilence > sildur)) {
385 + /* We've been quiet a little while */
386 + if (notsilent) {
387 + /* We had heard some talking */
388 + gettimeofday(&end, NULL);
389 + ms = (end.tv_sec - start.tv_sec) * 1000;
390 + ms += (end.tv_usec - start.tv_usec) / 1000;
391 + ms -= sildur;
392 + if (ms < 0)
393 + ms = 0;
394 + if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
395 + char ms_str[10];
396 + ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
397 + ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name);
398 +
399 + /* Save detected talk time (in milliseconds) */
400 + sprintf(ms_str, "%d", ms);
401 + pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
402 +
403 + if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) {
404 + strncpy(chan->exten, "talk", sizeof(chan->exten) - 1);
405 + chan->priority = 0;
406 + } else
407 + ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
408 + res = 0;
409 + ast_frfree(fr);
410 + break;
411 + } else
412 + ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
413 + notsilent = 0;
414 + }
415 + } else {
416 + if (!notsilent) {
417 + /* Heard some audio, mark the begining of the token */
418 + gettimeofday(&start, NULL);
419 + ast_log(LOG_DEBUG, "Start of voice token!\n");
420 + notsilent = 1;
421 + }
422 + }
423 + }
424 + ast_frfree(fr);
425 + }
426 + ast_sched_runq(chan->sched);
427 + }
428 + ast_stopstream(chan);
429 + } else {
430 + ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
431 + res = 0;
432 + }
433 + } else
434 + ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
435 +
436 + if (res > -1) {
437 + if (origrformat && ast_set_read_format(chan, origrformat)) {
438 + ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
439 + chan->name, ast_getformatname(origrformat));
440 + }
441 + }
442 +
443 + if (dsp)
444 + ast_dsp_free(dsp);
445 +
446 + // LOCAL_USER_REMOVE(u);
447 +
448 + return res;
449 +}
450 +
451 +static int unload_module(void)
452 +{
453 + // STANDARD_HANGUP_LOCALUSERS;
454 + return ast_unregister_application(app);
455 +}
456 +
457 +static int load_module(void)
458 +{
459 + return ast_register_application(app, nv_background_detect_exec, synopsis, descrip);
460 +}
461 +
462 +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fax playing Background Music Detection Application");
463 diff -uNr apps/app_nv_faxdetect.c apps/app_nv_faxdetect.c
464 --- apps/app_nv_faxdetect.c 1970-01-01 01:00:00.000000000 +0100
465 +++ apps/app_nv_faxdetect.c 2010-02-10 22:09:40.119390638 +0000
466 @@ -0,0 +1,317 @@
467 +/*
468 + * Asterisk -- A telephony toolkit for Linux.
469 + *
470 + * Fax detection application for all channel types.
471 + *
472 + * Copyright (C) 2004-2005, Newman Telecom, Inc. and Newman Ventures, Inc.
473 + *
474 + * Justin Newman <jnewman@×××××××××××××.com>
475 + *
476 + * We would like to thank Newman Ventures, Inc. for funding this
477 + * Asterisk project.
478 + *
479 + * Newman Ventures <info@××××××××××××××.com>
480 + *
481 + * Portions Copyright:
482 + * Copyright (C) 2001, Linux Support Services, Inc.
483 + * Copyright (C) 2004, Digium, Inc.
484 + *
485 + * Matthew Fredrickson <creslin@×××××××××××××.net>
486 + * Mark Spencer <markster@××××××.com>
487 + *
488 + * This program is free software, distributed under the terms of
489 + * the GNU General Public License
490 + */
491 +
492 +#include "asterisk.h"
493 +
494 +#include <asterisk/lock.h>
495 +#include <asterisk/file.h>
496 +#include <asterisk/logger.h>
497 +#include <asterisk/channel.h>
498 +#include <asterisk/pbx.h>
499 +#include <asterisk/module.h>
500 +#include <asterisk/translate.h>
501 +#include <asterisk/dsp.h>
502 +#include <asterisk/utils.h>
503 +
504 +static char *app = "NVFaxDetect";
505 +
506 +static char *synopsis = "Detects fax sounds on all channel types (IAX and SIP too)";
507 +
508 +static char *descrip =
509 +" NVFaxDetect([waitdur[|options[|sildur[|mindur[|maxdur]]]]]):\n"
510 +"This application listens for fax tones (on IAX and SIP channels too)\n"
511 +"for waitdur seconds of time. In addition, it can be interrupted by digits,\n"
512 +"or non-silence. Audio is only monitored in the receive direction. If\n"
513 +"digits interrupt, they must be the start of a valid extension unless the\n"
514 +"option is included to ignore. If fax is detected, it will jump to the\n"
515 +"'fax' extension. If a period of non-silence greater than 'mindur' ms,\n"
516 +"yet less than 'maxdur' ms is followed by silence at least 'sildur' ms\n"
517 +"then the app is aborted and processing jumps to the 'talk' extension.\n"
518 +"If all undetected, control will continue at the next priority.\n"
519 +" waitdur: Maximum number of seconds to wait (default=4)\n"
520 +" options:\n"
521 +" 'n': Attempt on-hook if unanswered (default=no)\n"
522 +" 'x': DTMF digits terminate without extension (default=no)\n"
523 +" 'd': Ignore DTMF digit detection (default=no)\n"
524 +" 'f': Ignore fax detection (default=no)\n"
525 +" 't': Ignore talk detection (default=no)\n"
526 +" sildur: Silence ms after mindur/maxdur before aborting (default=1000)\n"
527 +" mindur: Minimum non-silence ms needed (default=100)\n"
528 +" maxdur: Maximum non-silence ms allowed (default=0/forever)\n"
529 +"Returns -1 on hangup, and 0 on successful completion with no exit conditions.\n\n"
530 +"For questions or comments, please e-mail support@×××××××××××××.com.\n";
531 +
532 +// Use the second one for recent Asterisk releases
533 +#define CALLERID_FIELD cid.cid_num
534 +//#define CALLERID_FIELD callerid
535 +
536 +static int nv_detectfax_exec(struct ast_channel *chan, void *data)
537 +{
538 + int res = 0;
539 + char tmp[256] = "\0";
540 + char *p = NULL;
541 + char *waitstr = NULL;
542 + char *options = NULL;
543 + char *silstr = NULL;
544 + char *minstr = NULL;
545 + char *maxstr = NULL;
546 + struct ast_frame *fr = NULL;
547 + struct ast_frame *fr2 = NULL;
548 + int notsilent = 0;
549 + struct timeval start = {0, 0}, end = {0, 0};
550 + int waitdur = 4;
551 + int sildur = 1000;
552 + int mindur = 100;
553 + int maxdur = -1;
554 + int skipanswer = 0;
555 + int noextneeded = 0;
556 + int ignoredtmf = 0;
557 + int ignorefax = 0;
558 + int ignoretalk = 0;
559 + int x = 0;
560 + int origrformat = 0;
561 + int features = 0;
562 + time_t timeout = 0;
563 + struct ast_dsp *dsp = NULL;
564 +
565 + pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
566 + pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
567 + pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
568 + pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
569 +
570 + if (data || !ast_strlen_zero((char *)data)) {
571 + strncpy(tmp, (char *)data, sizeof(tmp)-1);
572 + }
573 +
574 + p = tmp;
575 +
576 + waitstr = strsep(&p, "|");
577 + options = strsep(&p, "|");
578 + silstr = strsep(&p, "|");
579 + minstr = strsep(&p, "|");
580 + maxstr = strsep(&p, "|");
581 +
582 + if (waitstr) {
583 + if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0))
584 + waitdur = x;
585 + }
586 +
587 + if (options) {
588 + if (strchr(options, 'n'))
589 + skipanswer = 1;
590 + if (strchr(options, 'x'))
591 + noextneeded = 1;
592 + if (strchr(options, 'd'))
593 + ignoredtmf = 1;
594 + if (strchr(options, 'f'))
595 + ignorefax = 1;
596 + if (strchr(options, 't'))
597 + ignoretalk = 1;
598 + }
599 +
600 + if (silstr) {
601 + if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
602 + sildur = x;
603 + }
604 +
605 + if (minstr) {
606 + if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
607 + mindur = x;
608 + }
609 +
610 + if (maxstr) {
611 + if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
612 + maxdur = x;
613 + }
614 +
615 + ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n",
616 + waitdur, sildur, mindur, maxdur);
617 +
618 + // LOCAL_USER_ADD(u);
619 + if (chan->_state != AST_STATE_UP && !skipanswer) {
620 + /* Otherwise answer unless we're supposed to send this while on-hook */
621 + res = ast_answer(chan);
622 + }
623 + if (!res) {
624 + origrformat = chan->readformat;
625 + if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
626 + ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
627 + }
628 + if (!(dsp = ast_dsp_new())) {
629 + ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
630 + res = -1;
631 + }
632 +
633 + if (dsp) {
634 + if (!ignoretalk)
635 + ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */
636 + if (!ignorefax)
637 + features |= DSP_FEATURE_FAX_DETECT;
638 + //if (!ignoredtmf)
639 + features |= DSP_FEATURE_DIGIT_DETECT;
640 +
641 + ast_dsp_set_threshold(dsp, 256);
642 + ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
643 + ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF);
644 + }
645 +
646 + if (!res) {
647 + if (waitdur > 0)
648 + timeout = time(NULL) + (time_t)waitdur;
649 +
650 + while(ast_waitfor(chan, -1) > -1) {
651 + if (waitdur > 0 && time(NULL) > timeout) {
652 + res = 0;
653 + break;
654 + }
655 +
656 + fr = ast_read(chan);
657 + if (!fr) {
658 + ast_log(LOG_DEBUG, "Got hangup\n");
659 + res = -1;
660 + break;
661 + }
662 +
663 + fr2 = ast_dsp_process(chan, dsp, fr);
664 + if (!fr2) {
665 + ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n");
666 + fr2 = fr;
667 + }
668 +
669 + if (fr2->frametype == AST_FRAME_DTMF) {
670 + if (fr2->subclass == 'f' && !ignorefax) {
671 + /* Fax tone -- Handle and return NULL */
672 + ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name);
673 + if (strcmp(chan->exten, "fax")) {
674 + ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", chan->name);
675 + pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
676 + pbx_builtin_setvar_helper(chan,"FAXEXTEN",chan->exten);
677 + if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) {
678 + /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
679 + strncpy(chan->exten, "fax", sizeof(chan->exten)-1);
680 + chan->priority = 0;
681 + } else
682 + ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
683 + } else
684 + ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");
685 +
686 + res = 0;
687 + ast_frfree(fr);
688 + break;
689 + } else if (!ignoredtmf) {
690 + ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name);
691 + char t[2];
692 + t[0] = fr2->subclass;
693 + t[1] = '\0';
694 + if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) {
695 + pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
696 + /* They entered a valid extension, or might be anyhow */
697 + if (noextneeded) {
698 + ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
699 + res = 0;
700 + } else {
701 + ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
702 + res = fr2->subclass;
703 + }
704 + ast_frfree(fr);
705 + break;
706 + } else
707 + ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
708 + }
709 + } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
710 + int totalsilence;
711 + int ms;
712 + res = ast_dsp_silence(dsp, fr, &totalsilence);
713 + if (res && (totalsilence > sildur)) {
714 + /* We've been quiet a little while */
715 + if (notsilent) {
716 + /* We had heard some talking */
717 + gettimeofday(&end, NULL);
718 + ms = (end.tv_sec - start.tv_sec) * 1000;
719 + ms += (end.tv_usec - start.tv_usec) / 1000;
720 + ms -= sildur;
721 + if (ms < 0)
722 + ms = 0;
723 + if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
724 + char ms_str[10];
725 + ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
726 + ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name);
727 +
728 + /* Save detected talk time (in milliseconds) */
729 + sprintf(ms_str, "%d", ms);
730 + pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
731 +
732 + if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) {
733 + strncpy(chan->exten, "talk", sizeof(chan->exten) - 1);
734 + chan->priority = 0;
735 + } else
736 + ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
737 + res = 0;
738 + ast_frfree(fr);
739 + break;
740 + } else
741 + ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
742 + notsilent = 0;
743 + }
744 + } else {
745 + if (!notsilent) {
746 + /* Heard some audio, mark the begining of the token */
747 + gettimeofday(&start, NULL);
748 + ast_log(LOG_DEBUG, "Start of voice token!\n");
749 + notsilent = 1;
750 + }
751 + }
752 + }
753 + ast_frfree(fr);
754 + }
755 + } else
756 + ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
757 +
758 + if (res > -1) {
759 + if (origrformat && ast_set_read_format(chan, origrformat)) {
760 + ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
761 + chan->name, ast_getformatname(origrformat));
762 + }
763 + }
764 +
765 + if (dsp)
766 + ast_dsp_free(dsp);
767 +
768 + // LOCAL_USER_REMOVE(u);
769 +
770 + return res;
771 +}
772 +
773 +static int unload_module(void)
774 +{
775 + return ast_unregister_application(app);
776 +}
777 +
778 +static int load_module(void)
779 +{
780 + return ast_register_application(app, nv_detectfax_exec, synopsis, descrip);
781 +}
782 +
783 +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fax Detection Application");