Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
res_fax_spandsp.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2009-2010, Digium, Inc.
5 *
6 * Matthew Nicholson <mnicholson@digium.com>
7 *
8 * Initial T.38-gateway code
9 * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
10 * Created by Nethemba s.r.o. http://www.nethemba.com
11 * Sponsored by IPEX a.s. http://www.ipex.cz
12 *
13 * T.38-gateway integration into asterisk app_fax and rework
14 * 2008, Gregory Hinton Nietsky <gregory@dnstelecom.co.za>
15 * dns Telecom http://www.dnstelecom.co.za
16 *
17 * Modified to make T.38-gateway compatible with Asterisk 1.6.2
18 * 2010, Anton Verevkin <mymail@verevkin.it>
19 * ViaNetTV http://www.vianettv.com
20 *
21 * Modified to make T.38-gateway work
22 * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
23 *
24 * See http://www.asterisk.org for more information about
25 * the Asterisk project. Please do not directly contact
26 * any of the maintainers of this project for assistance;
27 * the project provides a web site, mailing lists and IRC
28 * channels for your use.
29 *
30 * This program is free software, distributed under the terms of
31 * the GNU General Public License Version 2. See the LICENSE file
32 * at the top of the source tree.
33 */
34
35/*! \file
36 *
37 * \brief Spandsp T.38 and G.711 FAX Resource
38 *
39 * \author Matthew Nicholson <mnicholson@digium.com>
40 * \author Gregory H. Nietsky <gregory@distrotech.co.za>
41 *
42 * This module registers the Spandsp FAX technology with the res_fax module.
43 */
44
45/*** MODULEINFO
46 <depend>spandsp</depend>
47 <depend>res_fax</depend>
48 <support_level>extended</support_level>
49***/
50
51/* Needed for spandsp headers */
52#define ASTMM_LIBC ASTMM_IGNORE
53#include "asterisk.h"
54
55#include "asterisk/logger.h"
56#include "asterisk/module.h"
57#include "asterisk/strings.h"
58#include "asterisk/cli.h"
59#include "asterisk/utils.h"
60#include "asterisk/timing.h"
61#include "asterisk/astobj2.h"
62#include "asterisk/res_fax.h"
63#include "asterisk/channel.h"
65
66#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
67#include <spandsp.h>
68#include <spandsp/version.h>
69
70#define SPANDSP_FAX_SAMPLES 160
71#define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */
72#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
73
74static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
75static void spandsp_fax_destroy(struct ast_fax_session *s);
76static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
77static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
78static int spandsp_fax_start(struct ast_fax_session *s);
79static int spandsp_fax_cancel(struct ast_fax_session *s);
80static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
81static int spandsp_fax_gateway_start(struct ast_fax_session *s);
82static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
83static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
84static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
85static void spandsp_v21_cleanup(struct ast_fax_session *s);
86static void spandsp_v21_tone(void *data, int code, int level, int delay);
87
88static char *spandsp_fax_cli_show_capabilities(int fd);
89static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
90static void spandsp_manager_fax_session(struct mansession *s,
91 const char *id_text, struct ast_fax_session *session);
92static char *spandsp_fax_cli_show_stats(int fd);
93static char *spandsp_fax_cli_show_settings(int fd);
94
96 .type = "Spandsp",
97 .description = "Spandsp FAX Driver",
98#if SPANDSP_RELEASE_DATE >= 20090220
99 /* spandsp 0.0.6 */
100 .version = SPANDSP_RELEASE_DATETIME_STRING,
101#else
102 /* spandsp 0.0.5
103 * TODO: maybe we should determine the version better way
104 */
105 .version = "pre-20090220",
106#endif
110 .new_session = spandsp_fax_new,
111 .destroy_session = spandsp_fax_destroy,
112 .read = spandsp_fax_read,
113 .write = spandsp_fax_write,
114 .start_session = spandsp_fax_start,
115 .cancel_session = spandsp_fax_cancel,
116 .switch_to_t38 = spandsp_fax_switch_to_t38,
117 .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
118 .cli_show_session = spandsp_fax_cli_show_session,
119 .manager_fax_session = spandsp_manager_fax_session,
120 .cli_show_stats = spandsp_fax_cli_show_stats,
121 .cli_show_settings = spandsp_fax_cli_show_settings,
122};
123
126 int nofax;
138};
139
140static struct {
145
147 unsigned int ist38:1;
148 unsigned int isdone:1;
150 fax_state_t fax_state;
151 t38_terminal_state_t t38_state;
152 t30_state_t *t30_state;
153 t38_core_state_t *t38_core_state;
154
156
157 struct spandsp_fax_gw_stats *t38stats;
158 t38_gateway_state_t t38_gw_state;
159
162
164 modem_connect_tones_rx_state_t *tone_state;
165};
166
167static int spandsp_v21_new(struct spandsp_pvt *p);
168static void session_destroy(struct spandsp_pvt *p);
169static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
170static int update_stats(struct spandsp_pvt *p, int completion_code);
171static int spandsp_modems(struct ast_fax_session_details *details);
172#if SPANDSP_RELEASE_DATE >= 20120902
173/* for spandsp shaphots 3.0.0 and higher */
174static void t30_phase_e_handler(void *data, int completion_code);
175static void spandsp_log(void *user_data, int level, const char *msg);
176#else
177/* for spandsp release 0.0.6 */
178static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
179static void spandsp_log(int level, const char *msg);
180#endif
181
182static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
183static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
184static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
185static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
186
187static void session_destroy(struct spandsp_pvt *p)
188{
189 struct ast_frame *f;
190 t30_state_t *t30_to_terminate;
191
192 if (p->t30_state) {
193 t30_to_terminate = p->t30_state;
194 } else if (p->ist38) {
195#if SPANDSP_RELEASE_DATE >= 20080725
196 t30_to_terminate = &p->t38_state.t30;
197#else
198 t30_to_terminate = &p->t38_state.t30_state;
199#endif
200 } else {
201#if SPANDSP_RELEASE_DATE >= 20080725
202 t30_to_terminate = &p->fax_state.t30;
203#else
204 t30_to_terminate = &p->fax_state.t30_state;
205#endif
206 }
207
208 t30_terminate(t30_to_terminate);
209 p->isdone = 1;
210
212 p->timer = NULL;
213 fax_release(&p->fax_state);
214 t38_terminal_release(&p->t38_state);
215
216 while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
217 ast_frfree(f);
218 }
219}
220
221/*! \brief
222 *
223 */
224static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
225{
226 int res = -1;
227 struct ast_fax_session *s = data;
228 struct spandsp_pvt *p = s->tech_pvt;
229 struct ast_frame fax_frame = {
231 .subclass.integer = AST_MODEM_T38,
232 .src = "res_fax_spandsp_t38",
233 };
234
235 struct ast_frame *f = &fax_frame;
236
237
238 /* TODO: Asterisk does not provide means of resending the same packet multiple
239 times so count is ignored at the moment */
240
242
243 if (!(f = ast_frisolate(f))) {
244 return res;
245 }
246
250 res = ast_write(s->chan, f);
251 } else {
252 res = ast_queue_frame(s->chan, f);
253 }
254 ast_frfree(f);
255 } else {
256 /* no need to lock, this all runs in the same thread */
258 res = 0;
259 }
260
261 return res;
262}
263
264static int update_stats(struct spandsp_pvt *p, int completion_code)
265{
266 switch (completion_code) {
267 case T30_ERR_OK:
269 break;
270
271 /* Link problems */
272 case T30_ERR_CEDTONE: /*! The CED tone exceeded 5s */
273 case T30_ERR_T0_EXPIRED: /*! Timed out waiting for initial communication */
274 case T30_ERR_T1_EXPIRED: /*! Timed out waiting for the first message */
275 case T30_ERR_T3_EXPIRED: /*! Timed out waiting for procedural interrupt */
276 case T30_ERR_HDLC_CARRIER: /*! The HDLC carrier did not stop in a timely manner */
277 case T30_ERR_CANNOT_TRAIN: /*! Failed to train with any of the compatible modems */
279 break;
280
281 case T30_ERR_OPER_INT_FAIL: /*! Operator intervention failed */
282 case T30_ERR_INCOMPATIBLE: /*! Far end is not compatible */
283 case T30_ERR_RX_INCAPABLE: /*! Far end is not able to receive */
284 case T30_ERR_TX_INCAPABLE: /*! Far end is not able to transmit */
285 case T30_ERR_NORESSUPPORT: /*! Far end cannot receive at the resolution of the image */
286 case T30_ERR_NOSIZESUPPORT: /*! Far end cannot receive at the size of image */
288 break;
289
290 case T30_ERR_UNEXPECTED: /*! Unexpected message received */
292 break;
293
294 /* Phase E status values returned to a transmitter */
295 case T30_ERR_TX_BADDCS: /*! Received bad response to DCS or training */
296 case T30_ERR_TX_BADPG: /*! Received a DCN from remote after sending a page */
297 case T30_ERR_TX_ECMPHD: /*! Invalid ECM response received from receiver */
298 case T30_ERR_TX_GOTDCN: /*! Received a DCN while waiting for a DIS */
299 case T30_ERR_TX_INVALRSP: /*! Invalid response after sending a page */
300 case T30_ERR_TX_NODIS: /*! Received other than DIS while waiting for DIS */
301 case T30_ERR_TX_PHBDEAD: /*! Received no response to DCS, training or TCF */
302 case T30_ERR_TX_PHDDEAD: /*! No response after sending a page */
303 case T30_ERR_TX_T5EXP: /*! Timed out waiting for receiver ready (ECM mode) */
305 break;
306
307 /* Phase E status values returned to a receiver */
308 case T30_ERR_RX_ECMPHD: /*! Invalid ECM response received from transmitter */
309 case T30_ERR_RX_GOTDCS: /*! DCS received while waiting for DTC */
310 case T30_ERR_RX_INVALCMD: /*! Unexpected command after page received */
311 case T30_ERR_RX_NOCARRIER: /*! Carrier lost during fax receive */
312 case T30_ERR_RX_NOEOL: /*! Timed out while waiting for EOL (end Of line) */
314 break;
315 case T30_ERR_RX_NOFAX: /*! Timed out while waiting for first line */
317 break;
318 case T30_ERR_RX_T2EXPDCN: /*! Timer T2 expired while waiting for DCN */
319 case T30_ERR_RX_T2EXPD: /*! Timer T2 expired while waiting for phase D */
320 case T30_ERR_RX_T2EXPFAX: /*! Timer T2 expired while waiting for fax page */
321 case T30_ERR_RX_T2EXPMPS: /*! Timer T2 expired while waiting for next fax page */
322 case T30_ERR_RX_T2EXPRR: /*! Timer T2 expired while waiting for RR command */
323 case T30_ERR_RX_T2EXP: /*! Timer T2 expired while waiting for NSS, DCS or MCF */
324 case T30_ERR_RX_DCNWHY: /*! Unexpected DCN while waiting for DCS or DIS */
325 case T30_ERR_RX_DCNDATA: /*! Unexpected DCN while waiting for image data */
326 case T30_ERR_RX_DCNFAX: /*! Unexpected DCN while waiting for EOM, EOP or MPS */
327 case T30_ERR_RX_DCNPHD: /*! Unexpected DCN after EOM or MPS sequence */
328 case T30_ERR_RX_DCNRRD: /*! Unexpected DCN after RR/RNR sequence */
329 case T30_ERR_RX_DCNNORTN: /*! Unexpected DCN after requested retransmission */
331 break;
332
333 /* TIFF file problems */
334 case T30_ERR_FILEERROR: /*! TIFF/F file cannot be opened */
335 case T30_ERR_NOPAGE: /*! TIFF/F page not found */
336 case T30_ERR_BADTIFF: /*! TIFF/F format is not compatible */
337 case T30_ERR_BADPAGE: /*! TIFF/F page number tag missing */
338 case T30_ERR_BADTAG: /*! Incorrect values for TIFF/F tags */
339 case T30_ERR_BADTIFFHDR: /*! Bad TIFF/F header - incorrect values in fields */
341 break;
342 case T30_ERR_NOMEM: /*! Cannot allocate memory for more pages */
344 break;
345
346 /* General problems */
347 case T30_ERR_RETRYDCN: /*! Disconnected after permitted retries */
349 break;
350 case T30_ERR_CALLDROPPED: /*! The call dropped prematurely */
352 break;
353
354 /* Feature negotiation issues */
355 case T30_ERR_NOPOLL: /*! Poll not accepted */
356 case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
357 case T30_ERR_SUB_UNACCEPTABLE: /*! Far end's sub-address is not acceptable */
358 case T30_ERR_SEP_UNACCEPTABLE: /*! Far end's selective polling address is not acceptable */
359 case T30_ERR_PSA_UNACCEPTABLE: /*! Far end's polled sub-address is not acceptable */
360 case T30_ERR_SID_UNACCEPTABLE: /*! Far end's sender identification is not acceptable */
361 case T30_ERR_PWD_UNACCEPTABLE: /*! Far end's password is not acceptable */
362 case T30_ERR_TSA_UNACCEPTABLE: /*! Far end's transmitting subscriber internet address is not acceptable */
363 case T30_ERR_IRA_UNACCEPTABLE: /*! Far end's internet routing address is not acceptable */
364 case T30_ERR_CIA_UNACCEPTABLE: /*! Far end's calling subscriber internet address is not acceptable */
365 case T30_ERR_ISP_UNACCEPTABLE: /*! Far end's internet selective polling address is not acceptable */
366 case T30_ERR_CSA_UNACCEPTABLE: /*! Far end's called subscriber internet address is not acceptable */
368 break;
369 default:
371 ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
372 return -1;
373 }
374 return 0;
375}
376
377/*! \brief Phase E handler callback.
378 * \param t30_state the span t30 state
379 * \param data this will be the ast_fax_session
380 * \param completion_code the result of the fax session
381 *
382 * This function pulls stats from the spandsp stack and stores them for res_fax
383 * to use later.
384 */
385#if SPANDSP_RELEASE_DATE >= 20120902
386/* for spandsp shaphots 3.0.0 and higher */
387static void t30_phase_e_handler(void *data, int completion_code)
388#else
389/* for spandsp release 0.0.6 */
390static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
391#endif
392{
393 struct ast_fax_session *s = data;
394 struct spandsp_pvt *p = s->tech_pvt;
395 char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
396 const char *c;
397 t30_stats_t stats;
398#if SPANDSP_RELEASE_DATE >= 20120902
399 /* for spandsp shaphots 3.0.0 and higher */
400 t30_state_t *t30_state = p->t30_state;
401#endif
402
403 ast_debug(5, "FAX session '%u' entering phase E\n", s->id);
404
405 p->isdone = 1;
406
407 update_stats(p, completion_code);
408
409 t30_get_transfer_statistics(t30_state, &stats);
410
411 if (completion_code == T30_ERR_OK) {
412 ast_string_field_set(s->details, result, "SUCCESS");
413 } else {
414 ast_string_field_set(s->details, result, "FAILED");
415 ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
416 }
417
418 ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
419
420 ast_debug(5, "FAX session '%u' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
421
422 if ((c = t30_get_tx_ident(t30_state))) {
423 ast_string_field_set(s->details, localstationid, c);
424 }
425
426 if ((c = t30_get_rx_ident(t30_state))) {
427 ast_string_field_set(s->details, remotestationid, c);
428 }
429
430#if SPANDSP_RELEASE_DATE >= 20090220
431 s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
432#else
433 s->details->pages_transferred = stats.pages_transferred;
434#endif
435
436 ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
437
438 ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
439
440 t30_get_tx_page_header_info(t30_state, headerinfo);
441 ast_string_field_set(s->details, headerinfo, headerinfo);
442}
443
444/*! \brief Send spandsp log messages to asterisk.
445 * \param level the spandsp logging level
446 * \param msg the log message
447 *
448 * \note This function is a callback function called by spandsp.
449 */
450#if SPANDSP_RELEASE_DATE >= 20120902
451/* for spandsp shaphots 3.0.0 and higher */
452static void spandsp_log(void *user_data, int level, const char *msg)
453#else
454/* for spandsp release 0.0.6 */
455static void spandsp_log(int level, const char *msg)
456#endif
457{
458 if (level == SPAN_LOG_ERROR) {
459 ast_log(LOG_ERROR, "%s", msg);
460 } else if (level == SPAN_LOG_WARNING) {
461 ast_log(LOG_WARNING, "%s", msg);
462 } else {
464 }
465}
466
467static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
468{
469 int level = SPAN_LOG_WARNING;
470
471 if (details->option.debug) {
472 level = SPAN_LOG_DEBUG_3;
473 }
474
475#if SPANDSP_RELEASE_DATE >= 20120902
476 /* for spandsp shaphots 3.0.0 and higher */
477 span_log_set_message_handler(state, spandsp_log, NULL);
478#else
479 /* for spandsp release 0.0.6 */
480 span_log_set_message_handler(state, spandsp_log);
481#endif
482 span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
483}
484
485static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
486{
487 if (!ast_strlen_zero(details->localstationid)) {
488 t30_set_tx_ident(t30_state, details->localstationid);
489 }
490
491 if (!ast_strlen_zero(details->headerinfo)) {
492 t30_set_tx_page_header_info(t30_state, details->headerinfo);
493 }
494}
495
496static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
497{
498 if (details->caps & AST_FAX_TECH_RECEIVE) {
499 t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
500 } else {
501 /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
502 * should be safe because we ensure either RECEIVE or SEND is
503 * indicated in spandsp_fax_new() */
504 t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
505 }
506}
507
508static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
509{
510 t30_set_ecm_capability(t30_state, details->option.ecm);
511#if SPANDSP_RELEASE_DATE >= 20120902
512 /* for spandsp shaphots 3.0.0 and higher */
513 t30_set_supported_compressions(t30_state, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6);
514#else
515 /* for spandsp release 0.0.6 */
516 t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
517#endif
518}
519
520static int spandsp_v21_new(struct spandsp_pvt *p)
521{
522 /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
523 * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
524 * doesn't seem to work right all the time.
525 */
526 p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
527 if (!p->tone_state) {
528 return -1;
529 }
530
531 return 0;
532}
533
534static int spandsp_modems(struct ast_fax_session_details *details)
535{
536 int modems = 0;
537 if (AST_FAX_MODEM_V17 & details->modems) {
538 modems |= T30_SUPPORT_V17;
539 }
540 if (AST_FAX_MODEM_V27TER & details->modems) {
541 modems |= T30_SUPPORT_V27TER;
542 }
543 if (AST_FAX_MODEM_V29 & details->modems) {
544 modems |= T30_SUPPORT_V29;
545 }
546 if (AST_FAX_MODEM_V34 & details->modems) {
547#if defined(T30_SUPPORT_V34)
548 modems |= T30_SUPPORT_V34;
549#elif defined(T30_SUPPORT_V34HDX)
550 modems |= T30_SUPPORT_V34HDX;
551#else
552 ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
553#endif
554 }
555
556 return modems;
557}
558
559/*! \brief create an instance of the spandsp tech_pvt for a fax session */
560static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
561{
562 struct spandsp_pvt *p;
563 int caller_mode;
564
565 if ((!(p = ast_calloc(1, sizeof(*p))))) {
566 ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
567 goto e_return;
568 }
569
571 if (spandsp_v21_new(p)) {
572 ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
573 goto e_return;
574 }
576 return p;
577 }
578
581 return p;
582 }
583
585
587 caller_mode = 0;
588 } else if (s->details->caps & AST_FAX_TECH_SEND) {
589 caller_mode = 1;
590 } else {
591 ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
592 goto e_free;
593 }
594
595 if (!(p->timer = ast_timer_open())) {
596 ast_log(LOG_ERROR, "Channel '%s' FAX session '%u' failed to create timing source.\n", s->channame, s->id);
597 goto e_free;
598 }
599
600 s->fd = ast_timer_fd(p->timer);
601
602 p->stats = &spandsp_global_stats.g711;
603
605 if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
606 /* audio mode was not requested, start in T.38 mode */
607 p->ist38 = 1;
608 p->stats = &spandsp_global_stats.t38;
609 }
610
611 /* init t38 stuff */
612 t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
613 set_logging(&p->t38_state.logging, s->details);
614
615 /* init audio stuff */
616 fax_init(&p->fax_state, caller_mode);
617 set_logging(&p->fax_state.logging, s->details);
618 }
619
621 return p;
622
623e_free:
624 ast_free(p);
625e_return:
626 return NULL;
627}
628
630{
631 struct spandsp_pvt *p = s->tech_pvt;
632
633 modem_connect_tones_rx_free(p->tone_state);
634}
635
636/*! \brief Destroy a spandsp fax session.
637 */
639{
640 struct spandsp_pvt *p = s->tech_pvt;
641
644 } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
646 } else {
648 }
649
650 ast_free(p);
651 s->tech_pvt = NULL;
652 s->fd = -1;
653}
654
655/*! \brief Read a frame from the spandsp fax stack.
656 */
658{
659 struct spandsp_pvt *p = s->tech_pvt;
660 uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
661 int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
662 int samples;
663
664 struct ast_frame fax_frame = {
666 .src = "res_fax_spandsp_g711",
667 .subclass.format = ast_format_slin,
668 };
669 struct ast_frame *f = &fax_frame;
670
671 if (ast_timer_ack(p->timer, 1) < 0) {
672 ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%u'\n", s->id);
673 return NULL;
674 }
675
676 /* XXX do we need to lock here? */
677 if (p->isdone) {
679 ast_debug(5, "FAX session '%u' is complete.\n", s->id);
680 return NULL;
681 }
682
683 if (p->ist38) {
684 t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
686 return f;
687 }
688 } else {
689 if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
690 f->samples = samples;
692 return ast_frisolate(f);
693 }
694 }
695
696 return &ast_null_frame;
697}
698
699static void spandsp_v21_tone(void *data, int code, int level, int delay)
700{
701 struct spandsp_pvt *p = data;
702
703 if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
704 p->v21_detected = 1;
705 }
706}
707
708static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f)
709{
710 struct spandsp_pvt *p = s->tech_pvt;
711 int16_t *slndata;
712 g711_state_t *decoder;
713
714 if (p->v21_detected) {
715 return 0;
716 }
717
718 /*invalid frame*/
719 if (!f->data.ptr || !f->datalen) {
720 return -1;
721 }
722
723 ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format=%s }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, ast_format_get_name(f->subclass.format));
724
725 /* slinear frame can be passed to spandsp */
727 modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
728
729 /* alaw/ulaw frame must be converted to slinear before passing to spandsp */
732 if (!(slndata = ast_malloc(sizeof(*slndata) * f->samples))) {
733 return -1;
734 }
735 decoder = g711_init(NULL, (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL ? G711_ALAW : G711_ULAW));
736 g711_decode(decoder, slndata, f->data.ptr, f->samples);
737 ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", ast_format_get_name(f->subclass.format));
738 modem_connect_tones_rx(p->tone_state, slndata, f->samples);
739 g711_release(decoder);
740#if SPANDSP_RELEASE_DATE >= 20090220
741 g711_free(decoder);
742#endif
743 ast_free(slndata);
744
745 /* frame in other formats cannot be passed to spandsp, it could cause segfault */
746 } else {
747 ast_log(LOG_WARNING, "Frame format %s not supported, v.21 detection skipped\n", ast_format_get_name(f->subclass.format));
748 return -1;
749 }
750
751 if (p->v21_detected) {
753 ast_debug(5, "v.21 detected\n");
754 }
755
756 return 0;
757}
758
759/*! \brief Write a frame to the spandsp fax stack.
760 * \param s a fax session
761 * \param f the frame to write
762 *
763 * \note res_fax does not currently use the return value of this function.
764 * Also the fax_rx() function never fails.
765 *
766 * \retval 0 success
767 * \retval -1 failure
768 */
769static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
770{
771 struct spandsp_pvt *p = s->tech_pvt;
772
774 return spandsp_v21_detect(s, f);
775 }
776
778 return spandsp_fax_gateway_process(s, f);
779 }
780
781 /* XXX do we need to lock here? */
782 if (s->state == AST_FAX_STATE_COMPLETE) {
783 ast_log(LOG_WARNING, "FAX session '%u' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
784 return -1;
785 }
786
787 if (p->ist38) {
788 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
789 } else {
790 return fax_rx(&p->fax_state, f->data.ptr, f->samples);
791 }
792}
793
794/*! \brief generate T.30 packets sent to the T.30 leg of gateway
795 * \param chan T.30 channel
796 * \param data fax session structure
797 * \param len not used
798 * \param samples no of samples generated
799 * \return -1 on failure or 0 on sucess*/
800static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
801{
802 int res = -1;
803 struct ast_fax_session *s = data;
804 struct spandsp_pvt *p = s->tech_pvt;
805 uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
806 struct ast_frame *f;
807 struct ast_frame t30_frame = {
809 .subclass.format = ast_format_slin,
810 .src = "res_fax_spandsp_g711",
811 .samples = samples,
812 .flags = AST_FAX_FRFLAG_GATEWAY,
813 };
814
815 AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
816
817 if (!(f = ast_frisolate(&t30_frame))) {
818 return p->isdone ? -1 : res;
819 }
820
821 /* generate a T.30 packet */
822 if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
823 f->datalen = f->samples * sizeof(int16_t);
824 res = ast_write(chan, f);
825 }
826 ast_frfree(f);
827 return p->isdone ? -1 : res;
828}
829
830/*! \brief simple routine to allocate data to generator
831 * \param chan channel
832 * \param params generator data
833 * \return data to use in generator call*/
834static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params)
835{
836 ao2_ref(params, +1);
837 return params;
838}
839
840static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data)
841{
842 ao2_ref(data, -1);
843}
844
845/*! \brief activate a spandsp gateway based on the information in the given fax session
846 * \param s fax session
847 * \return -1 on error 0 on sucess*/
849{
850 struct spandsp_pvt *p = s->tech_pvt;
851 struct ast_fax_t38_parameters *t38_param;
852 int i;
853 RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
854 static struct ast_generator t30_gen = {
857 .generate = spandsp_fax_gw_t30_gen,
858 };
859
860#if SPANDSP_RELEASE_DATE >= 20081012
861 /* for spandsp shaphots 0.0.6 and higher */
862 p->t38_core_state=&p->t38_gw_state.t38x.t38;
863#else
864 /* for spandsp release 0.0.5 */
865 p->t38_core_state=&p->t38_gw_state.t38;
866#endif
867
868 if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
869 return -1;
870 }
871
872 p->ist38 = 1;
874 peer = ast_channel_bridge_peer(s->chan);
875 if (!peer) {
876 return -1;
877 }
878
879 /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
880 * gateway is started. We treat both states the same. */
883 }
884
885 ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
886
887 set_logging(&p->t38_gw_state.logging, s->details);
888 set_logging(&p->t38_core_state->logging, s->details);
889
891 t38_set_t38_version(p->t38_core_state, t38_param->version);
892 t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
893 t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
894 t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
895 t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
896 t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
897 t38_set_data_rate_management_method(p->t38_core_state,
899
900 t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
901 t38_set_sequence_number_handling(p->t38_core_state, TRUE);
902
903
904 t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details));
905
906 /* engage udptl nat on other side of T38 line
907 * (Asterisk changes media ports thus we send a few packets to reinitialize
908 * pinholes in NATs and FWs
909 */
910 for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
911#if SPANDSP_RELEASE_DATE >= 20091228
912 t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
913#elif SPANDSP_RELEASE_DATE >= 20081012
914 t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
915#else
916 t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
917#endif
918 }
919
921
922 return 0;
923}
924
925/*! \brief process a frame from the bridge
926 * \param s fax session
927 * \param f frame to process
928 * \return 1 on sucess 0 on incorrect packet*/
929static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
930{
931 struct spandsp_pvt *p = s->tech_pvt;
932
933 /*invalid frame*/
934 if (!f->data.ptr || !f->datalen) {
935 return -1;
936 }
937
938 /* Process a IFP packet */
939 if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
940 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
941 } else if ((f->frametype == AST_FRAME_VOICE) &&
943 return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
944 }
945
946 return -1;
947}
948
949/*! \brief gather data and clean up after gateway ends
950 * \param s fax session*/
952{
953 struct spandsp_pvt *p = s->tech_pvt;
954 t38_stats_t t38_stats;
955
956 t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
957
958 s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
959 s->details->pages_transferred = t38_stats.pages_transferred;
960 ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
961}
962
963/*! \brief */
965{
966 struct spandsp_pvt *p = s->tech_pvt;
967
969
972 }
973
974 if (p->ist38) {
975#if SPANDSP_RELEASE_DATE >= 20080725
976 /* for spandsp shaphots 0.0.6 and higher */
977 p->t30_state = &p->t38_state.t30;
978 p->t38_core_state = &p->t38_state.t38_fe.t38;
979#else
980 /* for spandsp releases 0.0.5 */
981 p->t30_state = &p->t38_state.t30_state;
982 p->t38_core_state = &p->t38_state.t38;
983#endif
984 } else {
985#if SPANDSP_RELEASE_DATE >= 20080725
986 /* for spandsp shaphots 0.0.6 and higher */
987 p->t30_state = &p->fax_state.t30;
988#else
989 /* for spandsp release 0.0.5 */
990 p->t30_state = &p->fax_state.t30_state;
991#endif
992 }
993
994 set_logging(&p->t30_state->logging, s->details);
995
996 /* set some parameters */
998 set_file(p->t30_state, s->details);
999 set_ecm(p->t30_state, s->details);
1000 t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
1001
1002 /* perhaps set_transmit_on_idle() should be called */
1003
1004 t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
1005
1006 /* set T.38 parameters */
1007 if (p->ist38) {
1008 set_logging(&p->t38_core_state->logging, s->details);
1009
1010 t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
1011
1013 t38_set_fill_bit_removal(p->t38_core_state, TRUE);
1014 }
1015
1017 t38_set_mmr_transcoding(p->t38_core_state, TRUE);
1018 }
1019
1021 t38_set_jbig_transcoding(p->t38_core_state, TRUE);
1022 }
1023 } else {
1024 /* have the fax stack generate silence if it has no data to send */
1025 fax_set_transmit_on_idle(&p->fax_state, 1);
1026 }
1027
1028
1029 /* start the timer */
1031 ast_log(LOG_ERROR, "FAX session '%u' error setting rate on timing source.\n", s->id);
1032 return -1;
1033 }
1034
1036
1037 return 0;
1038}
1039
1040/*! \brief */
1042{
1043 struct spandsp_pvt *p = s->tech_pvt;
1044
1045 if (s->details->caps & AST_FAX_TECH_GATEWAY) {
1046 p->isdone = 1;
1047 return 0;
1048 }
1049
1050 t30_terminate(p->t30_state);
1051 p->isdone = 1;
1052 return 0;
1053}
1054
1055/*! \brief */
1057{
1058 struct spandsp_pvt *p = s->tech_pvt;
1059
1060 /* prevent the phase E handler from running, this is not a real termination */
1061 t30_set_phase_e_handler(p->t30_state, NULL, NULL);
1062
1063 t30_terminate(p->t30_state);
1064
1067
1068 p->ist38 = 1;
1069 p->stats = &spandsp_global_stats.t38;
1071
1072 return 0;
1073}
1074
1075/*! \brief */
1077{
1078 ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
1079 return CLI_SUCCESS;
1080}
1081
1082/*! \brief */
1083static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
1084{
1085 ao2_lock(s);
1086 if (s->details->caps & AST_FAX_TECH_GATEWAY) {
1087 struct spandsp_pvt *p = s->tech_pvt;
1088
1089 ast_cli(fd, "%-22s : %u\n", "session", s->id);
1090 ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
1091 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1093 t38_stats_t stats;
1094 t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
1095 ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1096 ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1097 ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1098 }
1099 } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
1100 ast_cli(fd, "%-22s : %u\n", "session", s->id);
1101 ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
1102 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1103 } else {
1104 struct spandsp_pvt *p = s->tech_pvt;
1105
1106 ast_cli(fd, "%-22s : %u\n", "session", s->id);
1107 ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
1108 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1110 t30_stats_t stats;
1111 t30_get_transfer_statistics(p->t30_state, &stats);
1112 ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
1113 ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1114 ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1115 ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
1116#if SPANDSP_RELEASE_DATE >= 20090220
1117 ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1118#else
1119 ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1120#endif
1121 ast_cli(fd, "%-22s : %s\n", "File Name", s->details->caps & AST_FAX_TECH_RECEIVE ? p->t30_state->rx_file : p->t30_state->tx_file);
1122
1123 ast_cli(fd, "\nData Statistics:\n");
1124#if SPANDSP_RELEASE_DATE >= 20090220
1125 ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
1126 ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
1127#else
1128 ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1129 ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1130#endif
1131 ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
1132 ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
1133 }
1134 }
1135 ao2_unlock(s);
1136 ast_cli(fd, "\n\n");
1137 return CLI_SUCCESS;
1138}
1139
1141 const char *id_text, struct ast_fax_session *session)
1142{
1143 struct ast_str *message_string;
1144 struct spandsp_pvt *span_pvt = session->tech_pvt;
1145 int res;
1146
1147 message_string = ast_str_create(128);
1148
1149 if (!message_string) {
1150 return;
1151 }
1152
1154 res = ast_str_append(&message_string, 0, "SessionNumber: %u\r\n", session->id);
1155 res |= ast_str_append(&message_string, 0, "Operation: %s\r\n", ast_fax_session_operation_str(session));
1156 res |= ast_str_append(&message_string, 0, "State: %s\r\n", ast_fax_state_to_str(session->state));
1157
1158 if (session->details->caps & AST_FAX_TECH_GATEWAY) {
1159 t38_stats_t stats;
1160
1161 if (session->state == AST_FAX_STATE_UNINITIALIZED) {
1162 goto skip_cap_additions;
1163 }
1164
1165 t38_gateway_get_transfer_statistics(&span_pvt->t38_gw_state, &stats);
1166 res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
1167 stats.error_correcting_mode ? "yes" : "no");
1168 res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
1169 stats.bit_rate);
1170 res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1171 stats.pages_transferred + 1);
1172 } else if (!(session->details->caps & AST_FAX_TECH_V21_DETECT)) { /* caps is SEND/RECEIVE */
1173 t30_stats_t stats;
1174
1175 if (session->state == AST_FAX_STATE_UNINITIALIZED) {
1176 goto skip_cap_additions;
1177 }
1178
1179 t30_get_transfer_statistics(span_pvt->t30_state, &stats);
1180 res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
1181 stats.error_correcting_mode ? "Yes" : "No");
1182 res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
1183 stats.bit_rate);
1184 res |= ast_str_append(&message_string, 0, "ImageResolution: %dx%d\r\n",
1185 stats.x_resolution, stats.y_resolution);
1186#if SPANDSP_RELEASE_DATE >= 20090220
1187 res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1188 ((session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1189#else
1190 res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1191 stats.pages_transferred + 1);
1192#endif
1193 res |= ast_str_append(&message_string, 0, "FileName: %s\r\n",
1194 session->details->caps & AST_FAX_TECH_RECEIVE ? span_pvt->t30_state->rx_file :
1195 span_pvt->t30_state->tx_file);
1196#if SPANDSP_RELEASE_DATE >= 20090220
1197 res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
1198 stats.pages_tx);
1199 res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
1200 stats.pages_rx);
1201#else
1202 res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
1203 (session->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1204 res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
1205 (session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1206#endif
1207 res |= ast_str_append(&message_string, 0, "TotalBadLines: %d\r\n",
1208 stats.bad_rows);
1209 }
1210
1211skip_cap_additions:
1212
1214
1215 if (res < 0) {
1216 /* One or more of the ast_str_append attempts failed, cancel the message */
1217 ast_free(message_string);
1218 return;
1219 }
1220
1221 astman_append(s, "Event: FAXSession\r\n"
1222 "%s"
1223 "%s"
1224 "\r\n",
1225 id_text,
1226 ast_str_buffer(message_string));
1227
1228 ast_free(message_string);
1229}
1230
1231/*! \brief */
1232static char *spandsp_fax_cli_show_stats(int fd)
1233{
1235 ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
1236 ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
1237 ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
1238 ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
1239 ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
1240 ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
1241 ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
1242 ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
1243 ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
1244 ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
1245 ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
1246 ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
1247 ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
1248 ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
1249
1250 ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
1251 ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
1252 ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
1253 ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
1254 ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
1255 ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
1256 ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
1257 ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
1258 ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
1259 ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
1260 ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
1261 ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
1262 ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
1264
1265 return CLI_SUCCESS;
1266}
1267
1268/*! \brief Show res_fax_spandsp settings */
1270{
1271 /* no settings at the moment */
1272 return CLI_SUCCESS;
1273}
1274
1275/*! \brief unload res_fax_spandsp */
1276static int unload_module(void)
1277{
1281}
1282
1283/*! \brief load res_fax_spandsp */
1284static int load_module(void)
1285{
1289 ast_log(LOG_ERROR, "failed to register FAX technology\n");
1291 }
1292
1293 /* prevent logging to stderr */
1294#if SPANDSP_RELEASE_DATE >= 20120902
1295 /* for spandsp shaphots 3.0.0 and higher */
1296 span_set_message_handler(NULL, NULL);
1297#else
1298 /* for spandsp release 0.0.6 */
1299 span_set_message_handler(NULL);
1300#endif
1301
1303}
1304
1305
1306AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
1307 .support_level = AST_MODULE_SUPPORT_EXTENDED,
1308 .load = load_module,
1309 .unload = unload_module,
1310 .enhances = "res_fax",
#define TRUE
Definition: app_minivm.c:524
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static PGresult * result
Definition: cel_pgsql.c:84
General Asterisk PBX channel definitions.
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2970
static enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
Retrieves the current T38 state of a channel.
Definition: channel.h:2896
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition: channel.c:10586
ast_t38_state
Possible T38 states on channels.
Definition: channel.h:898
@ T38_STATE_NEGOTIATED
Definition: channel.h:903
@ T38_STATE_NEGOTIATING
Definition: channel.h:901
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1158
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5163
Standard Command Line Interface.
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
short int16_t
Definition: db.h:59
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition: format.h:36
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Media Format Cache API.
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define AST_MODEM_T38
#define ast_frfree(fr)
@ AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_VOICE
@ AST_FRAME_MODEM
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define LOG_ERROR
#define LOG_WARNING
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:329
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
void ast_fax_tech_unregister(struct ast_fax_tech *tech)
unregister a fax technology
Definition: res_fax.c:991
@ AST_FAX_OPTFLAG_FALSE
Definition: res_fax.h:85
@ AST_FAX_OPTFLAG_TRUE
Definition: res_fax.h:87
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert an ast_fax_state to a string
Definition: res_fax.c:1012
@ AST_FAX_TECH_T38
Definition: res_fax.h:43
@ AST_FAX_TECH_AUDIO
Definition: res_fax.h:41
@ AST_FAX_TECH_RECEIVE
Definition: res_fax.h:39
@ AST_FAX_TECH_V21_DETECT
Definition: res_fax.h:49
@ AST_FAX_TECH_SEND
Definition: res_fax.h:37
@ AST_FAX_TECH_GATEWAY
Definition: res_fax.h:47
#define AST_FAX_FRFLAG_GATEWAY
Definition: res_fax.h:232
const char * ast_fax_session_operation_str(struct ast_fax_session *s)
get string representation of a FAX session's operation
Definition: res_fax.c:4253
int ast_fax_tech_register(struct ast_fax_tech *tech)
register a fax technology
Definition: res_fax.c:973
@ AST_FAX_STATE_INITIALIZED
Definition: res_fax.h:69
@ AST_FAX_STATE_ACTIVE
Definition: res_fax.h:73
@ AST_FAX_STATE_COMPLETE
Definition: res_fax.h:75
@ AST_FAX_STATE_OPEN
Definition: res_fax.h:71
@ AST_FAX_STATE_UNINITIALIZED
Definition: res_fax.h:67
@ AST_FAX_MODEM_V17
Definition: res_fax.h:55
@ AST_FAX_MODEM_V29
Definition: res_fax.h:59
@ AST_FAX_MODEM_V27TER
Definition: res_fax.h:57
@ AST_FAX_MODEM_V34
Definition: res_fax.h:61
void ast_fax_log(int level, const char *file, const int line, const char *function, const char *msg)
Log message at FAX or recommended level.
Definition: res_fax.c:1035
static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
Phase E handler callback.
static void spandsp_log(int level, const char *msg)
Send spandsp log messages to asterisk.
static char * spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
static struct ast_fax_tech spandsp_fax_tech
#define SPANDSP_FAX_SAMPLES
static void session_destroy(struct spandsp_pvt *p)
struct spandsp_fax_stats g711
static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
static void spandsp_v21_tone(void *data, int code, int level, int delay)
static void spandsp_manager_fax_session(struct mansession *s, const char *id_text, struct ast_fax_session *session)
static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
static char * spandsp_fax_cli_show_stats(int fd)
static void * spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
create an instance of the spandsp tech_pvt for a fax session
static int spandsp_modems(struct ast_fax_session_details *details)
static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
static struct ast_frame * spandsp_fax_read(struct ast_fax_session *s)
Read a frame from the spandsp fax stack.
static void * spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params)
simple routine to allocate data to generator
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
process a frame from the bridge
static char * spandsp_fax_cli_show_capabilities(int fd)
static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
#define SPANDSP_FAX_TIMER_RATE
static int spandsp_fax_cancel(struct ast_fax_session *s)
static int load_module(void)
load res_fax_spandsp
static int spandsp_v21_new(struct spandsp_pvt *p)
#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY
static int spandsp_fax_gateway_start(struct ast_fax_session *s)
activate a spandsp gateway based on the information in the given fax session
static char * spandsp_fax_cli_show_settings(int fd)
Show res_fax_spandsp settings.
static struct @437 spandsp_global_stats
static int unload_module(void)
unload res_fax_spandsp
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
gather data and clean up after gateway ends
static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data)
static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f)
static void spandsp_v21_cleanup(struct ast_fax_session *s)
ast_mutex_t lock
static int update_stats(struct spandsp_pvt *p, int completion_code)
static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
static int spandsp_fax_start(struct ast_fax_session *s)
struct spandsp_fax_stats t38
static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
Write a frame to the spandsp fax stack.
static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
generate T.30 packets sent to the T.30 leg of gateway
static void spandsp_fax_destroy(struct ast_fax_session *s)
Destroy a spandsp fax session.
#define NULL
Definition: resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Main Channel structure associated with a channel.
The data communicated between the high level applications and the generic fax function.
Definition: res_fax.h:110
const ast_string_field localstationid
Definition: res_fax.h:142
struct ast_fax_t38_parameters their_t38_parameters
Definition: res_fax.h:177
struct ast_fax_documents documents
Definition: res_fax.h:119
const ast_string_field result
Definition: res_fax.h:142
enum ast_fax_modems modems
Definition: res_fax.h:115
const ast_string_field headerinfo
Definition: res_fax.h:142
struct ast_fax_t38_parameters our_t38_parameters
Definition: res_fax.h:175
uint32_t switch_to_t38
Definition: res_fax.h:159
union ast_fax_session_details::@251 option
const ast_string_field resultstr
Definition: res_fax.h:142
unsigned int pages_transferred
Definition: res_fax.h:144
enum ast_fax_capabilities caps
Definition: res_fax.h:113
The data required to handle a fax session.
Definition: res_fax.h:202
void * tech_pvt
Definition: res_fax.h:216
struct ast_channel * chan
Definition: res_fax.h:224
char * channame
Definition: res_fax.h:220
unsigned int id
Definition: res_fax.h:204
enum ast_fax_state state
Definition: res_fax.h:218
struct ast_fax_session_details * details
Definition: res_fax.h:208
unsigned int transcoding_jbig
Definition: res_fax.h:99
unsigned int version
Definition: res_fax.h:93
unsigned int max_ifp
Definition: res_fax.h:94
unsigned int transcoding_mmr
Definition: res_fax.h:98
enum ast_control_t38_rate_management rate_management
Definition: res_fax.h:96
unsigned int fill_bit_removal
Definition: res_fax.h:97
used to register a FAX technology module with res_fax
Definition: res_fax.h:235
struct ast_module * module
Definition: res_fax.h:245
const char *const type
Definition: res_fax.h:237
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
unsigned int flags
const char * src
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:228
struct ast_module * self
Definition: module.h:356
Structure for mutex and tracking information.
Definition: lock.h:135
Support for dynamic strings.
Definition: strings.h:623
void * data
Definition: timing.c:55
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:326
struct spandsp_fax_stats * stats
t38_core_state_t * t38_core_state
struct spandsp_pvt::frame_queue read_frames
struct spandsp_fax_gw_stats * t38stats
fax_state_t fax_state
modem_connect_tones_rx_state_t * tone_state
struct ast_timer * timer
unsigned int ist38
t38_terminal_state_t t38_state
t38_gateway_state_t t38_gw_state
t30_state_t * t30_state
enum ast_t38_state ast_t38_state
unsigned int isdone
static struct test_val c
Timing source management.
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_set_flag(p, flag)
Definition: utils.h:70