c545e9a165f8d9dfa1480f24f3c0d2e1a637617c
[openwrt/svn-archive/archive.git] / net / asterisk-1.4.x / patches / 015-spandsp-app_fax.patch
1 diff -Nru asterisk-1.4.18.org/apps/app_rxfax.c asterisk-1.4.18/apps/app_rxfax.c
2 --- asterisk-1.4.18.org/apps/app_rxfax.c 1970-01-01 01:00:00.000000000 +0100
3 +++ asterisk-1.4.19.1/apps/app_rxfax.c 2008-03-02 19:35:45.000000000 +0100
4 @@ -0,0 +1,376 @@
5 +/*
6 + * Asterisk -- A telephony toolkit for Linux.
7 + *
8 + * Trivial application to receive a TIFF FAX file
9 + *
10 + * Copyright (C) 2003, Steve Underwood
11 + *
12 + * Steve Underwood <steveu@coppice.org>
13 + *
14 + * This program is free software, distributed under the terms of
15 + * the GNU General Public License
16 + */
17 +
18 +/*** MODULEINFO
19 + <depend>spandsp</depend>
20 +***/
21 +
22 +#include "asterisk.h"
23 +
24 +ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
25 +
26 +#include <string.h>
27 +#include <stdlib.h>
28 +#include <stdio.h>
29 +#include <inttypes.h>
30 +#include <pthread.h>
31 +#include <errno.h>
32 +#include <tiffio.h>
33 +
34 +#include <spandsp.h>
35 +
36 +#include "asterisk/lock.h"
37 +#include "asterisk/file.h"
38 +#include "asterisk/logger.h"
39 +#include "asterisk/channel.h"
40 +#include "asterisk/pbx.h"
41 +#include "asterisk/module.h"
42 +#include "asterisk/translate.h"
43 +#include "asterisk/dsp.h"
44 +#include "asterisk/manager.h"
45 +
46 +static char *app = "RxFAX";
47 +
48 +static char *synopsis = "Receive a FAX to a file";
49 +
50 +static char *descrip =
51 +" RxFAX(filename[|caller][|debug]): Receives a FAX from the channel into the\n"
52 +"given filename. If the file exists it will be overwritten. The file\n"
53 +"should be in TIFF/F format.\n"
54 +"The \"caller\" option makes the application behave as a calling machine,\n"
55 +"rather than the answering machine. The default behaviour is to behave as\n"
56 +"an answering machine.\n"
57 +"Uses LOCALSTATIONID to identify itself to the remote end.\n"
58 +" LOCALHEADERINFO to generate a header line on each page.\n"
59 +"Sets REMOTESTATIONID to the sender CSID.\n"
60 +" FAXPAGES to the number of pages received.\n"
61 +" FAXBITRATE to the transmition rate.\n"
62 +" FAXRESOLUTION to the resolution.\n"
63 +"Returns -1 when the user hangs up.\n"
64 +"Returns 0 otherwise.\n";
65 +
66 +#define MAX_BLOCK_SIZE 240
67 +
68 +static void span_message(int level, const char *msg)
69 +{
70 + int ast_level;
71 +
72 + if (level == SPAN_LOG_WARNING)
73 + ast_level = __LOG_WARNING;
74 + else if (level == SPAN_LOG_WARNING)
75 + ast_level = __LOG_WARNING;
76 + else
77 + ast_level = __LOG_DEBUG;
78 + ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
79 +}
80 +/*- End of function --------------------------------------------------------*/
81 +
82 +static void t30_flush(t30_state_t *s, int which)
83 +{
84 + /* TODO: */
85 +}
86 +/*- End of function --------------------------------------------------------*/
87 +
88 +static void phase_e_handler(t30_state_t *s, void *user_data, int result)
89 +{
90 + struct ast_channel *chan;
91 + t30_stats_t t;
92 + char local_ident[21];
93 + char far_ident[21];
94 + char buf[11];
95 +
96 + chan = (struct ast_channel *) user_data;
97 + if (result == T30_ERR_OK)
98 + {
99 + t30_get_transfer_statistics(s, &t);
100 + t30_get_far_ident(s, far_ident);
101 + t30_get_local_ident(s, local_ident);
102 + ast_log(LOG_DEBUG, "==============================================================================\n");
103 + ast_log(LOG_DEBUG, "Fax successfully received.\n");
104 + ast_log(LOG_DEBUG, "Remote station id: %s\n", far_ident);
105 + ast_log(LOG_DEBUG, "Local station id: %s\n", local_ident);
106 + ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
107 + ast_log(LOG_DEBUG, "Image resolution: %i x %i\n", t.x_resolution, t.y_resolution);
108 + ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate);
109 + ast_log(LOG_DEBUG, "==============================================================================\n");
110 + manager_event(EVENT_FLAG_CALL,
111 + "FaxReceived", "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n",
112 + chan->name,
113 + chan->exten,
114 + (chan->cid.cid_num) ? chan->cid.cid_num : "",
115 + far_ident,
116 + local_ident,
117 + t.pages_transferred,
118 + t.y_resolution,
119 + t.bit_rate,
120 + s->rx_file);
121 + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
122 + snprintf(buf, sizeof(buf), "%i", t.pages_transferred);
123 + pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
124 + snprintf(buf, sizeof(buf), "%i", t.y_resolution);
125 + pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf);
126 + snprintf(buf, sizeof(buf), "%i", t.bit_rate);
127 + pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf);
128 + }
129 + else
130 + {
131 + ast_log(LOG_DEBUG, "==============================================================================\n");
132 + ast_log(LOG_DEBUG, "Fax receive not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
133 + ast_log(LOG_DEBUG, "==============================================================================\n");
134 + }
135 +}
136 +/*- End of function --------------------------------------------------------*/
137 +
138 +static void phase_d_handler(t30_state_t *s, void *user_data, int result)
139 +{
140 + struct ast_channel *chan;
141 + t30_stats_t t;
142 +
143 + chan = (struct ast_channel *) user_data;
144 + if (result)
145 + {
146 + t30_get_transfer_statistics(s, &t);
147 + ast_log(LOG_DEBUG, "==============================================================================\n");
148 + ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
149 + ast_log(LOG_DEBUG, "Image size: %i x %i\n", t.width, t.length);
150 + ast_log(LOG_DEBUG, "Image resolution %i x %i\n", t.x_resolution, t.y_resolution);
151 + ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate);
152 + ast_log(LOG_DEBUG, "Bad rows %i\n", t.bad_rows);
153 + ast_log(LOG_DEBUG, "Longest bad row run %i\n", t.longest_bad_row_run);
154 + ast_log(LOG_DEBUG, "Compression type %i\n", t.encoding);
155 + ast_log(LOG_DEBUG, "Image size (bytes) %i\n", t.image_size);
156 + ast_log(LOG_DEBUG, "==============================================================================\n");
157 + }
158 +}
159 +/*- End of function --------------------------------------------------------*/
160 +
161 +static int rxfax_exec(struct ast_channel *chan, void *data)
162 +{
163 + int res = 0;
164 + char template_file[256];
165 + char target_file[256];
166 + char *s;
167 + char *t;
168 + char *v;
169 + const char *x;
170 + int option;
171 + int len;
172 + int i;
173 + fax_state_t fax;
174 + int calling_party;
175 + int verbose;
176 + int samples;
177 +
178 + struct ast_module_user *u;
179 + struct ast_frame *inf = NULL;
180 + struct ast_frame outf;
181 +
182 + int original_read_fmt;
183 + int original_write_fmt;
184 +
185 + uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
186 + uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
187 +
188 + if (chan == NULL)
189 + {
190 + ast_log(LOG_WARNING, "Fax receive channel is NULL. Giving up.\n");
191 + return -1;
192 + }
193 +
194 + span_set_message_handler(span_message);
195 +
196 + /* The next few lines of code parse out the filename and header from the input string */
197 + if (data == NULL)
198 + {
199 + /* No data implies no filename or anything is present */
200 + ast_log(LOG_WARNING, "Rxfax requires an argument (filename)\n");
201 + return -1;
202 + }
203 +
204 + calling_party = FALSE;
205 + verbose = FALSE;
206 + target_file[0] = '\0';
207 +
208 + for (option = 0, v = s = data; v; option++, s++)
209 + {
210 + t = s;
211 + v = strchr(s, '|');
212 + s = (v) ? v : s + strlen(s);
213 + strncpy((char *) buf, t, s - t);
214 + buf[s - t] = '\0';
215 + if (option == 0)
216 + {
217 + /* The first option is always the file name */
218 + len = s - t;
219 + if (len > 255)
220 + len = 255;
221 + strncpy(target_file, t, len);
222 + target_file[len] = '\0';
223 + /* Allow the use of %d in the file name for a wild card of sorts, to
224 + create a new file with the specified name scheme */
225 + if ((x = strchr(target_file, '%')) && x[1] == 'd')
226 + {
227 + strcpy(template_file, target_file);
228 + i = 0;
229 + do
230 + {
231 + snprintf(target_file, 256, template_file, 1);
232 + i++;
233 + }
234 + while (ast_fileexists(target_file, "", chan->language) != -1);
235 + }
236 + }
237 + else if (strncmp("caller", t, s - t) == 0)
238 + {
239 + calling_party = TRUE;
240 + }
241 + else if (strncmp("debug", t, s - t) == 0)
242 + {
243 + verbose = TRUE;
244 + }
245 + }
246 +
247 + /* Done parsing */
248 +
249 + u = ast_module_user_add(chan);
250 +
251 + if (chan->_state != AST_STATE_UP)
252 + {
253 + /* Shouldn't need this, but checking to see if channel is already answered
254 + * Theoretically asterisk should already have answered before running the app */
255 + res = ast_answer(chan);
256 + }
257 +
258 + if (!res)
259 + {
260 + original_read_fmt = chan->readformat;
261 + if (original_read_fmt != AST_FORMAT_SLINEAR)
262 + {
263 + res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
264 + if (res < 0)
265 + {
266 + ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
267 + return -1;
268 + }
269 + }
270 + original_write_fmt = chan->writeformat;
271 + if (original_write_fmt != AST_FORMAT_SLINEAR)
272 + {
273 + res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
274 + if (res < 0)
275 + {
276 + ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
277 + res = ast_set_read_format(chan, original_read_fmt);
278 + if (res)
279 + ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
280 + return -1;
281 + }
282 + }
283 + fax_init(&fax, calling_party);
284 + if (verbose)
285 + fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
286 + x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
287 + if (x && x[0])
288 + t30_set_local_ident(&fax.t30_state, x);
289 + x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
290 + if (x && x[0])
291 + t30_set_header_info(&fax.t30_state, x);
292 + t30_set_rx_file(&fax.t30_state, target_file, -1);
293 + //t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, chan);
294 + t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, chan);
295 + t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, chan);
296 + t30_set_ecm_capability(&fax.t30_state, TRUE);
297 + t30_set_supported_compressions(&fax.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
298 + while (ast_waitfor(chan, -1) > -1)
299 + {
300 + inf = ast_read(chan);
301 + if (inf == NULL)
302 + {
303 + res = -1;
304 + break;
305 + }
306 + if (inf->frametype == AST_FRAME_VOICE)
307 + {
308 + if (fax_rx(&fax, inf->data, inf->samples))
309 + break;
310 + samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE;
311 + len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
312 + if (len)
313 + {
314 + memset(&outf, 0, sizeof(outf));
315 + outf.frametype = AST_FRAME_VOICE;
316 + outf.subclass = AST_FORMAT_SLINEAR;
317 + outf.datalen = len*sizeof(int16_t);
318 + outf.samples = len;
319 + outf.data = &buf[AST_FRIENDLY_OFFSET];
320 + outf.offset = AST_FRIENDLY_OFFSET;
321 + outf.src = "RxFAX";
322 + if (ast_write(chan, &outf) < 0)
323 + {
324 + ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
325 + break;
326 + }
327 + }
328 + }
329 + ast_frfree(inf);
330 + }
331 + if (inf == NULL)
332 + {
333 + ast_log(LOG_DEBUG, "Got hangup\n");
334 + res = -1;
335 + }
336 + if (original_read_fmt != AST_FORMAT_SLINEAR)
337 + {
338 + res = ast_set_read_format(chan, original_read_fmt);
339 + if (res)
340 + ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
341 + }
342 + if (original_write_fmt != AST_FORMAT_SLINEAR)
343 + {
344 + res = ast_set_write_format(chan, original_write_fmt);
345 + if (res)
346 + ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
347 + }
348 + t30_terminate(&fax.t30_state);
349 + }
350 + else
351 + {
352 + ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
353 + }
354 + ast_module_user_remove(u);
355 + return res;
356 +}
357 +/*- End of function --------------------------------------------------------*/
358 +
359 +static int unload_module(void)
360 +{
361 + int res;
362 +
363 + ast_module_user_hangup_all();
364 +
365 + res = ast_unregister_application(app);
366 +
367 +
368 + return res;
369 +}
370 +/*- End of function --------------------------------------------------------*/
371 +
372 +static int load_module(void)
373 +{
374 + return ast_register_application(app, rxfax_exec, synopsis, descrip);
375 +}
376 +/*- End of function --------------------------------------------------------*/
377 +
378 +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial FAX Receive Application");
379 +
380 +/*- End of file ------------------------------------------------------------*/
381 diff -Nru asterisk-1.4.18.org/apps/app_txfax.c asterisk-1.4.18/apps/app_txfax.c
382 --- asterisk-1.4.18.org/apps/app_txfax.c 1970-01-01 01:00:00.000000000 +0100
383 +++ asterisk-1.4.19.1/apps/app_txfax.c 2008-03-02 19:35:45.000000000 +0100
384 @@ -0,0 +1,303 @@
385 +/*
386 + * Asterisk -- A telephony toolkit for Linux.
387 + *
388 + * Trivial application to send a TIFF file as a FAX
389 + *
390 + * Copyright (C) 2003, Steve Underwood
391 + *
392 + * Steve Underwood <steveu@coppice.org>
393 + *
394 + * This program is free software, distributed under the terms of
395 + * the GNU General Public License
396 + */
397 +
398 +/*** MODULEINFO
399 + <depend>spandsp</depend>
400 +***/
401 +
402 +#include "asterisk.h"
403 +
404 +ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
405 +
406 +#include <string.h>
407 +#include <stdlib.h>
408 +#include <stdio.h>
409 +#include <inttypes.h>
410 +#include <pthread.h>
411 +#include <errno.h>
412 +#include <tiffio.h>
413 +
414 +#include <spandsp.h>
415 +
416 +#include "asterisk/lock.h"
417 +#include "asterisk/file.h"
418 +#include "asterisk/logger.h"
419 +#include "asterisk/channel.h"
420 +#include "asterisk/pbx.h"
421 +#include "asterisk/module.h"
422 +#include "asterisk/translate.h"
423 +
424 +static char *app = "TxFAX";
425 +
426 +static char *synopsis = "Send a FAX file";
427 +
428 +static char *descrip =
429 +" TxFAX(filename[|caller][|debug]): Send a given TIFF file to the channel as a FAX.\n"
430 +"The \"caller\" option makes the application behave as a calling machine,\n"
431 +"rather than the answering machine. The default behaviour is to behave as\n"
432 +"an answering machine.\n"
433 +"Uses LOCALSTATIONID to identify itself to the remote end.\n"
434 +" LOCALHEADERINFO to generate a header line on each page.\n"
435 +"Sets REMOTESTATIONID to the receiver CSID.\n"
436 +"Returns -1 when the user hangs up, or if the file does not exist.\n"
437 +"Returns 0 otherwise.\n";
438 +
439 +#define MAX_BLOCK_SIZE 240
440 +
441 +static void span_message(int level, const char *msg)
442 +{
443 + int ast_level;
444 +
445 + if (level == SPAN_LOG_WARNING)
446 + ast_level = __LOG_WARNING;
447 + else if (level == SPAN_LOG_WARNING)
448 + ast_level = __LOG_WARNING;
449 + else
450 + ast_level = __LOG_DEBUG;
451 + ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
452 +}
453 +/*- End of function --------------------------------------------------------*/
454 +
455 +#if 0
456 +static void t30_flush(t30_state_t *s, int which)
457 +{
458 + /* TODO: */
459 +}
460 +/*- End of function --------------------------------------------------------*/
461 +#endif
462 +
463 +static void phase_e_handler(t30_state_t *s, void *user_data, int result)
464 +{
465 + struct ast_channel *chan;
466 + char far_ident[21];
467 +
468 + chan = (struct ast_channel *) user_data;
469 + if (result == T30_ERR_OK)
470 + {
471 + t30_get_far_ident(s, far_ident);
472 + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
473 + }
474 + else
475 + {
476 + ast_log(LOG_DEBUG, "==============================================================================\n");
477 + ast_log(LOG_DEBUG, "Fax send not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
478 + ast_log(LOG_DEBUG, "==============================================================================\n");
479 + }
480 +}
481 +/*- End of function --------------------------------------------------------*/
482 +
483 +static int txfax_exec(struct ast_channel *chan, void *data)
484 +{
485 + int res = 0;
486 + char source_file[256];
487 + char *s;
488 + char *t;
489 + char *v;
490 + const char *x;
491 + int option;
492 + int len;
493 + fax_state_t fax;
494 + int calling_party;
495 + int verbose;
496 + int samples;
497 +
498 + struct ast_module_user *u;
499 + struct ast_frame *inf = NULL;
500 + struct ast_frame outf;
501 +
502 + int original_read_fmt;
503 + int original_write_fmt;
504 +
505 + uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
506 + uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
507 +
508 + if (chan == NULL)
509 + {
510 + ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
511 + return -1;
512 + }
513 +
514 + span_set_message_handler(span_message);
515 +
516 + /* The next few lines of code parse out the filename and header from the input string */
517 + if (data == NULL)
518 + {
519 + /* No data implies no filename or anything is present */
520 + ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n");
521 + return -1;
522 + }
523 +
524 + calling_party = FALSE;
525 + verbose = FALSE;
526 + source_file[0] = '\0';
527 +
528 + for (option = 0, v = s = data; v; option++, s++)
529 + {
530 + t = s;
531 + v = strchr(s, '|');
532 + s = (v) ? v : s + strlen(s);
533 + strncpy((char *) buf, t, s - t);
534 + buf[s - t] = '\0';
535 + if (option == 0)
536 + {
537 + /* The first option is always the file name */
538 + len = s - t;
539 + if (len > 255)
540 + len = 255;
541 + strncpy(source_file, t, len);
542 + source_file[len] = '\0';
543 + }
544 + else if (strncmp("caller", t, s - t) == 0)
545 + {
546 + calling_party = TRUE;
547 + }
548 + else if (strncmp("debug", t, s - t) == 0)
549 + {
550 + verbose = TRUE;
551 + }
552 + }
553 +
554 + /* Done parsing */
555 +
556 + u = ast_module_user_add(chan);
557 +
558 + if (chan->_state != AST_STATE_UP)
559 + {
560 + /* Shouldn't need this, but checking to see if channel is already answered
561 + * Theoretically asterisk should already have answered before running the app */
562 + res = ast_answer(chan);
563 + }
564 +
565 + if (!res)
566 + {
567 + original_read_fmt = chan->readformat;
568 + if (original_read_fmt != AST_FORMAT_SLINEAR)
569 + {
570 + res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
571 + if (res < 0)
572 + {
573 + ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
574 + return -1;
575 + }
576 + }
577 + original_write_fmt = chan->writeformat;
578 + if (original_write_fmt != AST_FORMAT_SLINEAR)
579 + {
580 + res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
581 + if (res < 0)
582 + {
583 + ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
584 + res = ast_set_read_format(chan, original_read_fmt);
585 + if (res)
586 + ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
587 + return -1;
588 + }
589 + }
590 + fax_init(&fax, calling_party);
591 + if (verbose)
592 + fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
593 +
594 + x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
595 + if (x && x[0])
596 + t30_set_local_ident(&fax.t30_state, x);
597 + x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
598 + if (x && x[0])
599 + t30_set_header_info(&fax.t30_state, x);
600 + t30_set_tx_file(&fax.t30_state, source_file, -1, -1);
601 + //t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, chan);
602 + //t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, chan);
603 + t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, chan);
604 + t30_set_ecm_capability(&fax.t30_state, TRUE);
605 + t30_set_supported_compressions(&fax.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
606 + while (ast_waitfor(chan, -1) > -1)
607 + {
608 + inf = ast_read(chan);
609 + if (inf == NULL)
610 + {
611 + res = -1;
612 + break;
613 + }
614 + if (inf->frametype == AST_FRAME_VOICE)
615 + {
616 + if (fax_rx(&fax, inf->data, inf->samples))
617 + break;
618 + samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE;
619 + len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
620 + if (len)
621 + {
622 + memset(&outf, 0, sizeof(outf));
623 + outf.frametype = AST_FRAME_VOICE;
624 + outf.subclass = AST_FORMAT_SLINEAR;
625 + outf.datalen = len*sizeof(int16_t);
626 + outf.samples = len;
627 + outf.data = &buf[AST_FRIENDLY_OFFSET];
628 + outf.offset = AST_FRIENDLY_OFFSET;
629 + if (ast_write(chan, &outf) < 0)
630 + {
631 + ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
632 + break;
633 + }
634 + }
635 + }
636 + ast_frfree(inf);
637 + }
638 + if (inf == NULL)
639 + {
640 + ast_log(LOG_DEBUG, "Got hangup\n");
641 + res = -1;
642 + }
643 + if (original_read_fmt != AST_FORMAT_SLINEAR)
644 + {
645 + res = ast_set_read_format(chan, original_read_fmt);
646 + if (res)
647 + ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
648 + }
649 + if (original_write_fmt != AST_FORMAT_SLINEAR)
650 + {
651 + res = ast_set_write_format(chan, original_write_fmt);
652 + if (res)
653 + ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
654 + }
655 + t30_terminate(&fax.t30_state);
656 + }
657 + else
658 + {
659 + ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
660 + }
661 + ast_module_user_remove(u);
662 + return res;
663 +}
664 +/*- End of function --------------------------------------------------------*/
665 +
666 +static int unload_module(void)
667 +{
668 + int res;
669 +
670 + ast_module_user_hangup_all();
671 +
672 + res = ast_unregister_application(app);
673 +
674 +
675 + return res;
676 +}
677 +/*- End of function --------------------------------------------------------*/
678 +
679 +static int load_module(void)
680 +{
681 + return ast_register_application(app, txfax_exec, synopsis, descrip);
682 +}
683 +/*- End of function --------------------------------------------------------*/
684 +
685 +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial FAX Transmit Application");
686 +
687 +/*- End of file ------------------------------------------------------------*/
688 diff -Nru asterisk-1.4.18.org/build_tools/menuselect-deps.in asterisk-1.4.18/build_tools/menuselect-deps.in
689 --- asterisk-1.4.18.org/build_tools/menuselect-deps.in 2008-01-16 02:13:27.000000000 +0100
690 +++ asterisk-1.4.19.1/build_tools/menuselect-deps.in 2008-03-02 19:35:45.000000000 +0100
691 @@ -21,6 +21,7 @@
692 POPT=@PBX_POPT@
693 PRI=@PBX_PRI@
694 RADIUS=@PBX_RADIUS@
695 +SPANDSP=@PBX_SPANDSP@
696 SPEEX=@PBX_SPEEX@
697 SPEEXDSP=@PBX_SPEEXDSP@
698 SQLITE=@PBX_SQLITE@
699 diff -Nru asterisk-1.4.18.org/configure.ac asterisk-1.4.18/configure.ac
700 --- asterisk-1.4.18.org/configure.ac 2008-01-16 02:13:27.000000000 +0100
701 +++ asterisk-1.4.19.1/configure.ac 2008-03-02 19:35:45.000000000 +0100
702 @@ -198,6 +198,7 @@
703 AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib])
704 AST_EXT_LIB_SETUP([OPENH323], [OpenH323], [h323])
705 AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius])
706 +AST_EXT_LIB_SETUP([SPANDSP], [spandsp Library], [spandsp])
707 AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
708 AST_EXT_LIB_SETUP([SPEEXDSP], [Speexdsp], [speexdsp])
709 AST_EXT_LIB_SETUP([SQLITE], [SQLite], [sqlite])
710 @@ -878,6 +879,8 @@
711
712 AST_EXT_LIB_CHECK([RADIUS], [radiusclient-ng], [rc_read_config], [radiusclient-ng.h])
713
714 +AST_EXT_LIB_CHECK([SPANDSP], [spandsp], [fax_init], [spandsp.h], [-ltiff -ljpeg -lz])
715 +
716 AST_EXT_LIB_CHECK([SPEEX], [speex], [speex_encode], [speex/speex.h], [-lm])
717
718 AST_EXT_LIB_CHECK([SPEEXDSP], [speexdsp], [speex_preprocess_ctl], [speex/speex.h], [-lm])
719 diff -Nru asterisk-1.4.18.org/include/asterisk/plc.h asterisk-1.4.18/include/asterisk/plc.h
720 --- asterisk-1.4.18.org/include/asterisk/plc.h 2006-06-14 16:12:56.000000000 +0200
721 +++ asterisk-1.4.19.1/include/asterisk/plc.h 2008-03-02 19:35:45.000000000 +0100
722 @@ -1,18 +1,17 @@
723 -/*! \file
724 - * \brief SpanDSP - a series of DSP components for telephony
725 +/*
726 + * SpanDSP - a series of DSP components for telephony
727 *
728 * plc.h
729 *
730 - * \author Steve Underwood <steveu@coppice.org>
731 + * Written by Steve Underwood <steveu@coppice.org>
732 *
733 * Copyright (C) 2004 Steve Underwood
734 *
735 * All rights reserved.
736 *
737 * This program is free software; you can redistribute it and/or modify
738 - * it under the terms of the GNU General Public License as published by
739 - * the Free Software Foundation; either version 2 of the License, or
740 - * (at your option) any later version.
741 + * it under the terms of the GNU General Public License version 2, as
742 + * published by the Free Software Foundation.
743 *
744 * This program is distributed in the hope that it will be useful,
745 * but WITHOUT ANY WARRANTY; without even the implied warranty of
746 @@ -23,37 +22,36 @@
747 * along with this program; if not, write to the Free Software
748 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
749 *
750 - * This version may be optionally licenced under the GNU LGPL licence.
751 - *
752 - * A license has been granted to Digium (via disclaimer) for the use of
753 - * this code.
754 + * $Id: plc.h,v 1.15 2007/04/08 08:16:18 steveu Exp $
755 */
756
757 +/*! \file */
758
759 -#if !defined(_PLC_H_)
760 -#define _PLC_H_
761 -
762 -#ifdef SOLARIS
763 -#include <sys/int_types.h>
764 -#else
765 -#if defined(__OpenBSD__) || defined( __FreeBSD__)
766 -#include <inttypes.h>
767 -#else
768 -#include <stdint.h>
769 -#endif
770 -#endif
771 +#if !defined(_SPANDSP_PLC_H_)
772 +#define _SPANDSP_PLC_H_
773
774 /*! \page plc_page Packet loss concealment
775 \section plc_page_sec_1 What does it do?
776 -The packet loss concealment module provides a suitable synthetic fill-in signal,
777 -to minimise the audible effect of lost packets in VoIP applications. It is not
778 -tied to any particular codec, and could be used with almost any codec which does not
779 +The packet loss concealment module provides a synthetic fill-in signal, to minimise
780 +the audible effect of lost packets in VoIP applications. It is not tied to any
781 +particular codec, and could be used with almost any codec which does not
782 specify its own procedure for packet loss concealment.
783
784 -Where a codec specific concealment procedure exists, the algorithm is usually built
785 +Where a codec specific concealment procedure exists, that algorithm is usually built
786 around knowledge of the characteristics of the particular codec. It will, therefore,
787 generally give better results for that particular codec than this generic concealer will.
788
789 +The PLC code implements an algorithm similar to the one described in Appendix 1 of G.711.
790 +However, the G.711 algorithm is optimised for 10ms packets. Few people use such small
791 +packets. 20ms is a much more common value, and longer packets are also quite common. The
792 +algorithm has been adjusted with this in mind. Also, the G.711 approach causes an
793 +algorithmic delay, and requires significant buffer manipulation when there is no packet
794 +loss. The algorithm used here avoids this. It causes no delay, and achieves comparable
795 +quality with normal speech.
796 +
797 +Note that both this algorithm, and the one in G.711 are optimised for speech. For most kinds
798 +of music a much slower decay on bursts of lost packets give better results.
799 +
800 \section plc_page_sec_2 How does it work?
801 While good packets are being received, the plc_rx() routine keeps a record of the trailing
802 section of the known speech signal. If a packet is missed, plc_fillin() is called to produce
803 @@ -83,7 +81,7 @@
804 correct steadily fall. Therefore, the volume of the synthesized signal is made to decay
805 linearly, such that after 50ms of missing audio it is reduced to silence.
806
807 -- When real speech resumes, an extra 1/4 pitch period of sythetic speech is blended with the
808 +- When real speech resumes, an extra 1/4 pitch period of synthetic speech is blended with the
809 start of the real speech. If the erasure is small, this smoothes the transition. If the erasure
810 is long, and the synthetic signal has faded to zero, the blending softens the start up of the
811 real signal, avoiding a kind of "click" or "pop" effect that might occur with a sudden onset.
812 @@ -110,6 +108,9 @@
813 the pitch assessment. */
814 #define PLC_HISTORY_LEN (CORRELATION_SPAN + PLC_PITCH_MIN)
815
816 +/*!
817 + The generic packet loss concealer context.
818 +*/
819 typedef struct
820 {
821 /*! Consecutive erased samples */
822 @@ -127,12 +128,13 @@
823 } plc_state_t;
824
825
826 -#ifdef __cplusplus
827 -extern "C" {
828 +#if defined(__cplusplus)
829 +extern "C"
830 +{
831 #endif
832
833 -/*! Process a block of received audio samples.
834 - \brief Process a block of received audio samples.
835 +/*! Process a block of received audio samples for PLC.
836 + \brief Process a block of received audio samples for PLC.
837 \param s The packet loss concealer context.
838 \param amp The audio sample buffer.
839 \param len The number of samples in the buffer.
840 @@ -147,13 +149,18 @@
841 \return The number of samples synthesized. */
842 int plc_fillin(plc_state_t *s, int16_t amp[], int len);
843
844 -/*! Process a block of received V.29 modem audio samples.
845 - \brief Process a block of received V.29 modem audio samples.
846 +/*! Initialise a packet loss concealer context.
847 + \brief Initialise a PLC context.
848 \param s The packet loss concealer context.
849 - \return A pointer to the he packet loss concealer context. */
850 + \return A pointer to the the packet loss concealer context. */
851 plc_state_t *plc_init(plc_state_t *s);
852
853 -#ifdef __cplusplus
854 +/*! Free a packet loss concealer context.
855 + \param s The packet loss concealer context.
856 + \return 0 for OK. */
857 +int plc_release(plc_state_t *s);
858 +
859 +#if defined(__cplusplus)
860 }
861 #endif
862
863 diff -Nru asterisk-1.4.18.org/makeopts.in asterisk-1.4.18/makeopts.in
864 --- asterisk-1.4.18.org/makeopts.in 2008-01-16 02:13:27.000000000 +0100
865 +++ asterisk-1.4.19.1/makeopts.in 2008-03-02 19:35:45.000000000 +0100
866 @@ -137,6 +137,9 @@
867 RADIUS_INCLUDE=@RADIUS_INCLUDE@
868 RADIUS_LIB=@RADIUS_LIB@
869
870 +SPANDSP_INCLUDE=@SPANDSP_INCLUDE@
871 +SPANDSP_LIB=@SPANDSP_LIB@
872 +
873 SPEEX_INCLUDE=@SPEEX_INCLUDE@
874 SPEEX_LIB=@SPEEX_LIB@
875