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"); |