Improve T.38 gateway V.21 preamble detection.
[asterisk/asterisk.git] / res / res_fax_spandsp.c
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 #include "asterisk.h"
52
53 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
54
55 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
56 #include <spandsp.h>
57 #include <spandsp/version.h>
58
59 #include "asterisk/logger.h"
60 #include "asterisk/module.h"
61 #include "asterisk/strings.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/timing.h"
65 #include "asterisk/astobj2.h"
66 #include "asterisk/res_fax.h"
67 #include "asterisk/channel.h"
68
69 #define SPANDSP_FAX_SAMPLES 160
70 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES       /* 50 ticks per second, 20ms, 160 samples per second */
71 #define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
72
73 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
74 static void spandsp_fax_destroy(struct ast_fax_session *s);
75 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
76 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
77 static int spandsp_fax_start(struct ast_fax_session *s);
78 static int spandsp_fax_cancel(struct ast_fax_session *s);
79 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
80 static int spandsp_fax_gateway_start(struct ast_fax_session *s);
81 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
82 static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
83 static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
84 static void spandsp_v21_cleanup(struct ast_fax_session *s);
85 static void spandsp_v21_tone(void *data, int code, int level, int delay);
86
87 static char *spandsp_fax_cli_show_capabilities(int fd);
88 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
89 static char *spandsp_fax_cli_show_stats(int fd);
90 static char *spandsp_fax_cli_show_settings(int fd);
91
92 static struct ast_fax_tech spandsp_fax_tech = {
93         .type = "Spandsp",
94         .description = "Spandsp FAX Driver",
95 #if SPANDSP_RELEASE_DATE >= 20090220
96         /* spandsp 0.0.6 */
97         .version = SPANDSP_RELEASE_DATETIME_STRING,
98 #else
99         /* spandsp 0.0.5
100          * TODO: maybe we should determine the version better way
101          */
102         .version = "pre-20090220",
103 #endif
104         .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND
105                 | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY
106                 | AST_FAX_TECH_V21_DETECT,
107         .new_session = spandsp_fax_new,
108         .destroy_session = spandsp_fax_destroy,
109         .read = spandsp_fax_read,
110         .write = spandsp_fax_write,
111         .start_session = spandsp_fax_start,
112         .cancel_session = spandsp_fax_cancel,
113         .switch_to_t38 = spandsp_fax_switch_to_t38,
114         .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
115         .cli_show_session = spandsp_fax_cli_show_session,
116         .cli_show_stats = spandsp_fax_cli_show_stats,
117         .cli_show_settings = spandsp_fax_cli_show_settings,
118 };
119
120 struct spandsp_fax_stats {
121         int success;
122         int nofax;
123         int neg_failed;
124         int failed_to_train;
125         int rx_protocol_error;
126         int tx_protocol_error;
127         int protocol_error;
128         int retries_exceeded;
129         int file_error;
130         int mem_error;
131         int call_dropped;
132         int unknown_error;
133         int switched;
134 };
135
136 static struct {
137         ast_mutex_t lock;
138         struct spandsp_fax_stats g711;
139         struct spandsp_fax_stats t38;
140 } spandsp_global_stats;
141
142 struct spandsp_pvt {
143         unsigned int ist38:1;
144         unsigned int isdone:1;
145         enum ast_t38_state ast_t38_state;
146         fax_state_t fax_state;
147         t38_terminal_state_t t38_state;
148         t30_state_t *t30_state;
149         t38_core_state_t *t38_core_state;
150
151         struct spandsp_fax_stats *stats;
152
153         struct spandsp_fax_gw_stats *t38stats;
154         t38_gateway_state_t t38_gw_state;
155
156         struct ast_timer *timer;
157         AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
158
159         int v21_detected;
160         modem_connect_tones_rx_state_t *tone_state;
161 };
162
163 static int spandsp_v21_new(struct spandsp_pvt *p);
164 static void session_destroy(struct spandsp_pvt *p);
165 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
166 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
167 static void spandsp_log(int level, const char *msg);
168 static int update_stats(struct spandsp_pvt *p, int completion_code);
169
170 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
171 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
172 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
173 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
174
175 static void session_destroy(struct spandsp_pvt *p)
176 {
177         struct ast_frame *f;
178
179         t30_terminate(p->t30_state);
180         p->isdone = 1;
181
182         ast_timer_close(p->timer);
183
184         fax_release(&p->fax_state);
185         t38_terminal_release(&p->t38_state);
186
187         while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
188                 ast_frfree(f);
189         }
190 }
191
192 /*! \brief
193  *
194  */
195 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
196 {
197         int res = -1;
198         struct ast_fax_session *s = data;
199         struct spandsp_pvt *p = s->tech_pvt;
200         struct ast_frame fax_frame = {
201                 .frametype = AST_FRAME_MODEM,
202                 .subclass.integer = AST_MODEM_T38,
203                 .src = "res_fax_spandsp_t38",
204         };
205
206         struct ast_frame *f = &fax_frame;
207
208
209         /* TODO: Asterisk does not provide means of resending the same packet multiple
210           times so count is ignored at the moment */
211
212         AST_FRAME_SET_BUFFER(f, buf, 0, len);
213
214         if (!(f = ast_frisolate(f))) {
215                 return res;
216         }
217
218         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
219                 ast_set_flag(f, AST_FAX_FRFLAG_GATEWAY);
220                 if (p->ast_t38_state == T38_STATE_NEGOTIATED) {
221                         res = ast_write(s->chan, f);
222                 } else {
223                         res = ast_queue_frame(s->chan, f);
224                 }
225                 ast_frfree(f);
226         } else {
227                 /* no need to lock, this all runs in the same thread */
228                 AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
229         }
230
231         return res;
232 }
233
234 static int update_stats(struct spandsp_pvt *p, int completion_code)
235 {
236         switch (completion_code) {
237         case T30_ERR_OK:
238                 ast_atomic_fetchadd_int(&p->stats->success, 1);
239                 break;
240
241         /* Link problems */
242         case T30_ERR_CEDTONE:            /*! The CED tone exceeded 5s */
243         case T30_ERR_T0_EXPIRED:         /*! Timed out waiting for initial communication */
244         case T30_ERR_T1_EXPIRED:         /*! Timed out waiting for the first message */
245         case T30_ERR_T3_EXPIRED:         /*! Timed out waiting for procedural interrupt */
246         case T30_ERR_HDLC_CARRIER:       /*! The HDLC carrier did not stop in a timely manner */
247         case T30_ERR_CANNOT_TRAIN:       /*! Failed to train with any of the compatible modems */
248                 ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
249                 break;
250
251         case T30_ERR_OPER_INT_FAIL:      /*! Operator intervention failed */
252         case T30_ERR_INCOMPATIBLE:       /*! Far end is not compatible */
253         case T30_ERR_RX_INCAPABLE:       /*! Far end is not able to receive */
254         case T30_ERR_TX_INCAPABLE:       /*! Far end is not able to transmit */
255         case T30_ERR_NORESSUPPORT:       /*! Far end cannot receive at the resolution of the image */
256         case T30_ERR_NOSIZESUPPORT:      /*! Far end cannot receive at the size of image */
257                 ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
258                 break;
259
260         case T30_ERR_UNEXPECTED:         /*! Unexpected message received */
261                 ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
262                 break;
263
264         /* Phase E status values returned to a transmitter */
265         case T30_ERR_TX_BADDCS:          /*! Received bad response to DCS or training */
266         case T30_ERR_TX_BADPG:           /*! Received a DCN from remote after sending a page */
267         case T30_ERR_TX_ECMPHD:          /*! Invalid ECM response received from receiver */
268         case T30_ERR_TX_GOTDCN:          /*! Received a DCN while waiting for a DIS */
269         case T30_ERR_TX_INVALRSP:        /*! Invalid response after sending a page */
270         case T30_ERR_TX_NODIS:           /*! Received other than DIS while waiting for DIS */
271         case T30_ERR_TX_PHBDEAD:         /*! Received no response to DCS, training or TCF */
272         case T30_ERR_TX_PHDDEAD:         /*! No response after sending a page */
273         case T30_ERR_TX_T5EXP:           /*! Timed out waiting for receiver ready (ECM mode) */
274                 ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
275                 break;
276
277         /* Phase E status values returned to a receiver */
278         case T30_ERR_RX_ECMPHD:          /*! Invalid ECM response received from transmitter */
279         case T30_ERR_RX_GOTDCS:          /*! DCS received while waiting for DTC */
280         case T30_ERR_RX_INVALCMD:        /*! Unexpected command after page received */
281         case T30_ERR_RX_NOCARRIER:       /*! Carrier lost during fax receive */
282         case T30_ERR_RX_NOEOL:           /*! Timed out while waiting for EOL (end Of line) */
283                 ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
284                 break;
285         case T30_ERR_RX_NOFAX:           /*! Timed out while waiting for first line */
286                 ast_atomic_fetchadd_int(&p->stats->nofax, 1);
287                 break;
288         case T30_ERR_RX_T2EXPDCN:        /*! Timer T2 expired while waiting for DCN */
289         case T30_ERR_RX_T2EXPD:          /*! Timer T2 expired while waiting for phase D */
290         case T30_ERR_RX_T2EXPFAX:        /*! Timer T2 expired while waiting for fax page */
291         case T30_ERR_RX_T2EXPMPS:        /*! Timer T2 expired while waiting for next fax page */
292         case T30_ERR_RX_T2EXPRR:         /*! Timer T2 expired while waiting for RR command */
293         case T30_ERR_RX_T2EXP:           /*! Timer T2 expired while waiting for NSS, DCS or MCF */
294         case T30_ERR_RX_DCNWHY:          /*! Unexpected DCN while waiting for DCS or DIS */
295         case T30_ERR_RX_DCNDATA:         /*! Unexpected DCN while waiting for image data */
296         case T30_ERR_RX_DCNFAX:          /*! Unexpected DCN while waiting for EOM, EOP or MPS */
297         case T30_ERR_RX_DCNPHD:          /*! Unexpected DCN after EOM or MPS sequence */
298         case T30_ERR_RX_DCNRRD:          /*! Unexpected DCN after RR/RNR sequence */
299         case T30_ERR_RX_DCNNORTN:        /*! Unexpected DCN after requested retransmission */
300                 ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
301                 break;
302
303         /* TIFF file problems */
304         case T30_ERR_FILEERROR:          /*! TIFF/F file cannot be opened */
305         case T30_ERR_NOPAGE:             /*! TIFF/F page not found */
306         case T30_ERR_BADTIFF:            /*! TIFF/F format is not compatible */
307         case T30_ERR_BADPAGE:            /*! TIFF/F page number tag missing */
308         case T30_ERR_BADTAG:             /*! Incorrect values for TIFF/F tags */
309         case T30_ERR_BADTIFFHDR:         /*! Bad TIFF/F header - incorrect values in fields */
310                 ast_atomic_fetchadd_int(&p->stats->file_error, 1);
311                 break;
312         case T30_ERR_NOMEM:              /*! Cannot allocate memory for more pages */
313                 ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
314                 break;
315
316         /* General problems */
317         case T30_ERR_RETRYDCN:           /*! Disconnected after permitted retries */
318                 ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
319                 break;
320         case T30_ERR_CALLDROPPED:        /*! The call dropped prematurely */
321                 ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
322                 break;
323
324         /* Feature negotiation issues */
325         case T30_ERR_NOPOLL:             /*! Poll not accepted */
326         case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
327         case T30_ERR_SUB_UNACCEPTABLE:   /*! Far end's sub-address is not acceptable */
328         case T30_ERR_SEP_UNACCEPTABLE:   /*! Far end's selective polling address is not acceptable */
329         case T30_ERR_PSA_UNACCEPTABLE:   /*! Far end's polled sub-address is not acceptable */
330         case T30_ERR_SID_UNACCEPTABLE:   /*! Far end's sender identification is not acceptable */
331         case T30_ERR_PWD_UNACCEPTABLE:   /*! Far end's password is not acceptable */
332         case T30_ERR_TSA_UNACCEPTABLE:   /*! Far end's transmitting subscriber internet address is not acceptable */
333         case T30_ERR_IRA_UNACCEPTABLE:   /*! Far end's internet routing address is not acceptable */
334         case T30_ERR_CIA_UNACCEPTABLE:   /*! Far end's calling subscriber internet address is not acceptable */
335         case T30_ERR_ISP_UNACCEPTABLE:   /*! Far end's internet selective polling address is not acceptable */
336         case T30_ERR_CSA_UNACCEPTABLE:   /*! Far end's called subscriber internet address is not acceptable */
337                 ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
338                 break;
339         default:
340                 ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
341                 ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
342                 return -1;
343         }
344         return 0;
345 }
346
347 /*! \brief Phase E handler callback.
348  * \param t30_state the span t30 state
349  * \param data this will be the ast_fax_session
350  * \param completion_code the result of the fax session
351  *
352  * This function pulls stats from the spandsp stack and stores them for res_fax
353  * to use later.
354  */
355 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
356 {
357         struct ast_fax_session *s = data;
358         struct spandsp_pvt *p = s->tech_pvt;
359         char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
360         const char *c;
361         t30_stats_t stats;
362
363         ast_debug(5, "FAX session '%d' entering phase E\n", s->id);
364
365         p->isdone = 1;
366
367         update_stats(p, completion_code);
368
369         t30_get_transfer_statistics(t30_state, &stats);
370
371         if (completion_code == T30_ERR_OK) {
372                 ast_string_field_set(s->details, result, "SUCCESS");
373         } else {
374                 ast_string_field_set(s->details, result, "FAILED");
375                 ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
376         }
377
378         ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
379
380         ast_debug(5, "FAX session '%d' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
381
382         if ((c = t30_get_tx_ident(t30_state))) {
383                 ast_string_field_set(s->details, localstationid, c);
384         }
385
386         if ((c = t30_get_rx_ident(t30_state))) {
387                 ast_string_field_set(s->details, remotestationid, c);
388         }
389
390 #if SPANDSP_RELEASE_DATE >= 20090220
391         s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
392 #else
393         s->details->pages_transferred = stats.pages_transferred;
394 #endif
395
396         ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
397
398         ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
399
400         t30_get_tx_page_header_info(t30_state, headerinfo);
401         ast_string_field_set(s->details, headerinfo, headerinfo);
402 }
403
404 /*! \brief Send spandsp log messages to asterisk.
405  * \param level the spandsp logging level
406  * \param msg the log message
407  *
408  * \note This function is a callback function called by spandsp.
409  */
410 static void spandsp_log(int level, const char *msg)
411 {
412         if (level == SPAN_LOG_ERROR) {
413                 ast_log(LOG_ERROR, "%s", msg);
414         } else if (level == SPAN_LOG_WARNING) {
415                 ast_log(LOG_WARNING, "%s", msg);
416         } else {
417                 ast_fax_log(LOG_DEBUG, msg);
418         }
419 }
420
421 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
422 {
423         int level = SPAN_LOG_WARNING;
424
425         if (details->option.debug) {
426                 level = SPAN_LOG_DEBUG_3;
427         }
428
429         span_log_set_message_handler(state, spandsp_log);
430         span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
431 }
432
433 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
434 {
435         if (!ast_strlen_zero(details->localstationid)) {
436                 t30_set_tx_ident(t30_state, details->localstationid);
437         }
438
439         if (!ast_strlen_zero(details->headerinfo)) {
440                 t30_set_tx_page_header_info(t30_state, details->headerinfo);
441         }
442 }
443
444 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
445 {
446         if (details->caps & AST_FAX_TECH_RECEIVE) {
447                 t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
448         } else {
449                 /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
450                  * should be safe because we ensure either RECEIVE or SEND is
451                  * indicated in spandsp_fax_new() */
452                 t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
453         }
454 }
455
456 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
457 {
458         t30_set_ecm_capability(t30_state, details->option.ecm);
459         t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
460 }
461
462 static int spandsp_v21_new(struct spandsp_pvt *p)
463 {
464         /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
465          * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
466          * doesn't seem to work right all the time.
467          */
468         p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
469         if (!p->tone_state) {
470                 return -1;
471         }
472
473         return 0;
474 }
475
476 /*! \brief create an instance of the spandsp tech_pvt for a fax session */
477 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
478 {
479         struct spandsp_pvt *p;
480         int caller_mode;
481
482         if ((!(p = ast_calloc(1, sizeof(*p))))) {
483                 ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
484                 goto e_return;
485         }
486
487         if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
488                 if (spandsp_v21_new(p)) {
489                         ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
490                         goto e_return;
491                 }
492                 s->state = AST_FAX_STATE_ACTIVE;
493                 return p;
494         }
495
496         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
497                 s->state = AST_FAX_STATE_INITIALIZED;
498                 return p;
499         }
500
501         AST_LIST_HEAD_INIT(&p->read_frames);
502
503         if (s->details->caps & AST_FAX_TECH_RECEIVE) {
504                 caller_mode = 0;
505         } else if (s->details->caps & AST_FAX_TECH_SEND) {
506                 caller_mode = 1;
507         } else {
508                 ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
509                 goto e_free;
510         }
511
512         if (!(p->timer = ast_timer_open())) {
513                 ast_log(LOG_ERROR, "Channel '%s' FAX session '%d' failed to create timing source.\n", s->channame, s->id);
514                 goto e_free;
515         }
516
517         s->fd = ast_timer_fd(p->timer);
518
519         p->stats = &spandsp_global_stats.g711;
520
521         if (s->details->caps & AST_FAX_TECH_T38) {
522                 if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
523                         /* audio mode was not requested, start in T.38 mode */
524                         p->ist38 = 1;
525                         p->stats = &spandsp_global_stats.t38;
526                 }
527
528                 /* init t38 stuff */
529                 t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
530                 set_logging(&p->t38_state.logging, s->details);
531         }
532
533         if (s->details->caps & AST_FAX_TECH_AUDIO) {
534                 /* init audio stuff */
535                 fax_init(&p->fax_state, caller_mode);
536                 set_logging(&p->fax_state.logging, s->details);
537         }
538
539         s->state = AST_FAX_STATE_INITIALIZED;
540         return p;
541
542 e_free:
543         ast_free(p);
544 e_return:
545         return NULL;
546 }
547
548 static void spandsp_v21_cleanup(struct ast_fax_session *s) {
549         struct spandsp_pvt *p = s->tech_pvt;
550         modem_connect_tones_rx_free(p->tone_state);
551 }
552
553 /*! \brief Destroy a spandsp fax session.
554  */
555 static void spandsp_fax_destroy(struct ast_fax_session *s)
556 {
557         struct spandsp_pvt *p = s->tech_pvt;
558
559         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
560                 spandsp_fax_gateway_cleanup(s);
561         } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
562                 spandsp_v21_cleanup(s);
563         } else {
564                 session_destroy(p);
565         }
566
567         ast_free(p);
568         s->tech_pvt = NULL;
569         s->fd = -1;
570 }
571
572 /*! \brief Read a frame from the spandsp fax stack.
573  */
574 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
575 {
576         struct spandsp_pvt *p = s->tech_pvt;
577         uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
578         int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
579         int samples;
580
581         struct ast_frame fax_frame = {
582                 .frametype = AST_FRAME_VOICE,
583                 .src = "res_fax_spandsp_g711",
584         };
585         struct ast_frame *f = &fax_frame;
586         ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
587
588         ast_timer_ack(p->timer, 1);
589
590         /* XXX do we need to lock here? */
591         if (p->isdone) {
592                 s->state = AST_FAX_STATE_COMPLETE;
593                 ast_debug(5, "FAX session '%d' is complete.\n", s->id);
594                 return NULL;
595         }
596
597         if (p->ist38) {
598                 t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
599                 if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
600                         return f;
601                 }
602         } else {
603                 if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
604                         f->samples = samples;
605                         AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
606                         return ast_frisolate(f);
607                 }
608         }
609
610         return &ast_null_frame;
611 }
612
613 static void spandsp_v21_tone(void *data, int code, int level, int delay)
614 {
615         struct spandsp_pvt *p = data;
616
617         if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
618                 p->v21_detected = 1;
619         }
620 }
621
622 static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f) {
623         struct spandsp_pvt *p = s->tech_pvt;
624
625         if (p->v21_detected) {
626                 return 0;
627         }
628
629         /*invalid frame*/
630         if (!f->data.ptr || !f->datalen) {
631                 return -1;
632         }
633
634         modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
635
636         if (p->v21_detected) {
637                 s->details->option.v21_detected = 1;
638         }
639
640         return 0;
641 }
642
643 /*! \brief Write a frame to the spandsp fax stack.
644  * \param s a fax session
645  * \param f the frame to write
646  *
647  * \note res_fax does not currently use the return value of this function.
648  * Also the fax_rx() function never fails.
649  *
650  * \retval 0 success
651  * \retval -1 failure
652  */
653 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
654 {
655         struct spandsp_pvt *p = s->tech_pvt;
656
657         if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
658                 return spandsp_v21_detect(s, f);
659         }
660
661         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
662                 return spandsp_fax_gateway_process(s, f);
663         }
664
665         /* XXX do we need to lock here? */
666         if (s->state == AST_FAX_STATE_COMPLETE) {
667                 ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
668                 return -1;
669         }
670
671         if (p->ist38) {
672                 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
673         } else {
674                 return fax_rx(&p->fax_state, f->data.ptr, f->samples);
675         }
676 }
677
678 /*! \brief generate T.30 packets sent to the T.30 leg of gateway
679  * \param chan T.30 channel
680  * \param data fax session structure
681  * \param len not used
682  * \param samples no of samples generated
683  * \return -1 on failure or 0 on sucess*/
684 static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
685 {
686         int res = -1;
687         struct ast_fax_session *s = data;
688         struct spandsp_pvt *p = s->tech_pvt;
689         uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
690         struct ast_frame *f;
691         struct ast_frame t30_frame = {
692                 .frametype = AST_FRAME_VOICE,
693                 .src = "res_fax_spandsp_g711",
694                 .samples = samples,
695                 .flags = AST_FAX_FRFLAG_GATEWAY,
696         };
697
698         AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
699
700         ast_format_set(&t30_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
701         if (!(f = ast_frisolate(&t30_frame))) {
702                 return p->isdone ? -1 : res;
703         }
704
705         /* generate a T.30 packet */
706         if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
707                 f->datalen = f->samples * sizeof(int16_t);
708                 res = ast_write(chan, f);
709         }
710         ast_frfree(f);
711         return p->isdone ? -1 : res;
712 }
713
714 /*! \brief simple routine to allocate data to generator
715  * \param chan channel
716  * \param params generator data
717  * \return data to use in generator call*/
718 static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params) {
719         ao2_ref(params, +1);
720         return params;
721 }
722
723 static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data) {
724         ao2_ref(data, -1);
725 }
726
727 /*! \brief activate a spandsp gateway based on the information in the given fax session
728  * \param s fax session
729  * \return -1 on error 0 on sucess*/
730 static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
731         struct spandsp_pvt *p = s->tech_pvt;
732         struct ast_fax_t38_parameters *t38_param;
733         int i, modems = 0;
734         struct ast_channel *peer;
735         static struct ast_generator t30_gen = {
736                 alloc: spandsp_fax_gw_gen_alloc,
737                 release: spandsp_fax_gw_gen_release,
738                 generate: spandsp_fax_gw_t30_gen,
739         };
740
741 #if SPANDSP_RELEASE_DATE >= 20081012
742         /* for spandsp shaphots 0.0.6 and higher */
743         p->t38_core_state=&p->t38_gw_state.t38x.t38;
744 #else
745         /* for spandsp release 0.0.5 */
746         p->t38_core_state=&p->t38_gw_state.t38;
747 #endif
748
749         if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
750                 return -1;
751         }
752
753         p->ist38 = 1;
754         p->ast_t38_state = ast_channel_get_t38_state(s->chan);
755         if (!(peer = ast_bridged_channel(s->chan))) {
756                 ast_channel_unlock(s->chan);
757                 return -1;
758         }
759
760         /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
761          * gateway is started. We treat both states the same. */
762         if (p->ast_t38_state == T38_STATE_NEGOTIATING) {
763                 p->ast_t38_state = T38_STATE_NEGOTIATED;
764         }
765
766         ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
767
768         set_logging(&p->t38_gw_state.logging, s->details);
769         set_logging(&p->t38_core_state->logging, s->details);
770
771         t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
772         t38_set_t38_version(p->t38_core_state, t38_param->version);
773         t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
774         t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
775         t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
776         t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
777         t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
778         t38_set_data_rate_management_method(p->t38_core_state, 
779                         (t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
780
781         t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
782         t38_set_sequence_number_handling(p->t38_core_state, TRUE);
783
784         if (AST_FAX_MODEM_V17 & s->details->modems) {
785                 modems |= T30_SUPPORT_V17;
786         }
787         if (AST_FAX_MODEM_V27 & s->details->modems) {
788                 modems |= T30_SUPPORT_V27TER;
789         }
790         if (AST_FAX_MODEM_V29 & s->details->modems) {
791                 modems |= T30_SUPPORT_V29;
792         }
793         if (AST_FAX_MODEM_V34 & s->details->modems) {
794 #if defined(T30_SUPPORT_V34)
795                 modems |= T30_SUPPORT_V34;
796 #elif defined(T30_SUPPORT_V34HDX)
797                 modems |= T30_SUPPORT_V34HDX;
798 #else
799                 ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
800 #endif
801         }
802
803         t38_gateway_set_supported_modems(&p->t38_gw_state, modems);
804
805         /* engage udptl nat on other side of T38 line 
806          * (Asterisk changes media ports thus we send a few packets to reinitialize
807          * pinholes in NATs and FWs
808          */
809         for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
810 #if SPANDSP_RELEASE_DATE >= 20091228
811                 t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
812 #elif SPANDSP_RELEASE_DATE >= 20081012
813                 t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
814 #else
815                 t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
816 #endif
817         }
818
819         s->state = AST_FAX_STATE_ACTIVE;
820
821         return 0;
822 }
823
824 /*! \brief process a frame from the bridge
825  * \param s fax session
826  * \param f frame to process
827  * \return 1 on sucess 0 on incorect packet*/
828 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
829 {
830         struct spandsp_pvt *p = s->tech_pvt;
831
832         /*invalid frame*/
833         if (!f->data.ptr || !f->datalen) {
834                 return -1;
835         }
836
837         /* Process a IFP packet */
838         if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
839                 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
840         } else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
841                 return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
842         }
843
844         return -1;
845 }
846
847 /*! \brief gather data and clean up after gateway ends
848  * \param s fax session*/
849 static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
850 {
851         struct spandsp_pvt *p = s->tech_pvt;
852         t38_stats_t t38_stats;
853
854         t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
855
856         s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
857         s->details->pages_transferred = t38_stats.pages_transferred;
858         ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
859 }
860
861 /*! \brief */
862 static int spandsp_fax_start(struct ast_fax_session *s)
863 {
864         struct spandsp_pvt *p = s->tech_pvt;
865
866         s->state = AST_FAX_STATE_OPEN;
867
868         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
869                 return spandsp_fax_gateway_start(s);
870         }
871
872         if (p->ist38) {
873 #if SPANDSP_RELEASE_DATE >= 20080725
874                 /* for spandsp shaphots 0.0.6 and higher */
875                 p->t30_state = &p->t38_state.t30;
876                 p->t38_core_state = &p->t38_state.t38_fe.t38;
877 #else
878                 /* for spandsp releases 0.0.5 */
879                 p->t30_state = &p->t38_state.t30_state;
880                 p->t38_core_state = &p->t38_state.t38;
881 #endif
882         } else {
883 #if SPANDSP_RELEASE_DATE >= 20080725
884                 /* for spandsp shaphots 0.0.6 and higher */
885                 p->t30_state = &p->fax_state.t30;
886 #else
887                 /* for spandsp release 0.0.5 */
888                 p->t30_state = &p->fax_state.t30_state;
889 #endif
890         }
891
892         set_logging(&p->t30_state->logging, s->details);
893
894         /* set some parameters */
895         set_local_info(p->t30_state, s->details);
896         set_file(p->t30_state, s->details);
897         set_ecm(p->t30_state, s->details);
898
899         /* perhaps set_transmit_on_idle() should be called */
900
901         t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
902
903         /* set T.38 parameters */
904         if (p->ist38) {
905                 set_logging(&p->t38_core_state->logging, s->details);
906
907                 t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
908
909                 if (s->details->their_t38_parameters.fill_bit_removal) {
910                         t38_set_fill_bit_removal(p->t38_core_state, TRUE);
911                 }
912
913                 if (s->details->their_t38_parameters.transcoding_mmr) {
914                         t38_set_mmr_transcoding(p->t38_core_state, TRUE);
915                 }
916
917                 if (s->details->their_t38_parameters.transcoding_jbig) {
918                         t38_set_jbig_transcoding(p->t38_core_state, TRUE);
919                 }
920         } else {
921                 /* have the fax stack generate silence if it has no data to send */
922                 fax_set_transmit_on_idle(&p->fax_state, 1);
923         }
924
925
926         /* start the timer */
927         if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
928                 ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
929                 return -1;
930         }
931
932         s->state = AST_FAX_STATE_ACTIVE;
933
934         return 0;
935 }
936
937 /*! \brief */
938 static int spandsp_fax_cancel(struct ast_fax_session *s)
939 {
940         struct spandsp_pvt *p = s->tech_pvt;
941
942         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
943                 p->isdone = 1;
944                 return 0;
945         }
946
947         t30_terminate(p->t30_state);
948         p->isdone = 1;
949         return 0;
950 }
951
952 /*! \brief */
953 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
954 {
955         struct spandsp_pvt *p = s->tech_pvt;
956
957         /* prevent the phase E handler from running, this is not a real termination */
958         t30_set_phase_e_handler(p->t30_state, NULL, NULL);
959
960         t30_terminate(p->t30_state);
961
962         s->details->option.switch_to_t38 = 1;
963         ast_atomic_fetchadd_int(&p->stats->switched, 1);
964
965         p->ist38 = 1;
966         p->stats = &spandsp_global_stats.t38;
967         spandsp_fax_start(s);
968
969         return 0;
970 }
971
972 /*! \brief */
973 static char *spandsp_fax_cli_show_capabilities(int fd)
974 {
975         ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
976         return  CLI_SUCCESS;
977 }
978
979 /*! \brief */
980 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
981 {
982         ao2_lock(s);
983         if (s->details->caps & AST_FAX_TECH_GATEWAY) {
984                 struct spandsp_pvt *p = s->tech_pvt;
985
986                 ast_cli(fd, "%-22s : %d\n", "session", s->id);
987                 ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
988                 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
989                 if (s->state != AST_FAX_STATE_UNINITIALIZED) {
990                         t38_stats_t stats;
991                         t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
992                         ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
993                         ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
994                         ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
995                 }
996         } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
997                 ast_cli(fd, "%-22s : %d\n", "session", s->id);
998                 ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
999                 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1000         } else {
1001                 struct spandsp_pvt *p = s->tech_pvt;
1002
1003                 ast_cli(fd, "%-22s : %d\n", "session", s->id);
1004                 ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
1005                 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1006                 if (s->state != AST_FAX_STATE_UNINITIALIZED) {
1007                         t30_stats_t stats;
1008                         t30_get_transfer_statistics(p->t30_state, &stats);
1009                         ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
1010                         ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1011                         ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1012                         ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
1013 #if SPANDSP_RELEASE_DATE >= 20090220
1014                         ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1015 #else
1016                         ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1017 #endif
1018                         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);
1019
1020                         ast_cli(fd, "\nData Statistics:\n");
1021 #if SPANDSP_RELEASE_DATE >= 20090220
1022                         ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
1023                         ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
1024 #else
1025                         ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1026                         ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1027 #endif
1028                         ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
1029                         ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
1030                 }
1031         }
1032         ao2_unlock(s);
1033         ast_cli(fd, "\n\n");
1034         return CLI_SUCCESS;
1035 }
1036
1037 /*! \brief */
1038 static char *spandsp_fax_cli_show_stats(int fd)
1039 {
1040         ast_mutex_lock(&spandsp_global_stats.lock);
1041         ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
1042         ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
1043         ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
1044         ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
1045         ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
1046         ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
1047         ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
1048         ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
1049         ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
1050         ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
1051         ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
1052         ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
1053         ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
1054         ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
1055
1056         ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
1057         ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
1058         ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
1059         ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
1060         ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
1061         ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
1062         ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
1063         ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
1064         ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
1065         ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
1066         ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
1067         ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
1068         ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
1069         ast_mutex_unlock(&spandsp_global_stats.lock);
1070
1071         return CLI_SUCCESS;
1072 }
1073
1074 /*! \brief Show res_fax_spandsp settings */
1075 static char *spandsp_fax_cli_show_settings(int fd)
1076 {
1077         /* no settings at the moment */
1078         return CLI_SUCCESS;
1079 }
1080
1081 /*! \brief unload res_fax_spandsp */
1082 static int unload_module(void)
1083 {
1084         ast_fax_tech_unregister(&spandsp_fax_tech);
1085         ast_mutex_destroy(&spandsp_global_stats.lock);
1086         return AST_MODULE_LOAD_SUCCESS;
1087 }
1088
1089 /*! \brief load res_fax_spandsp */
1090 static int load_module(void)
1091 {
1092         ast_mutex_init(&spandsp_global_stats.lock);
1093         spandsp_fax_tech.module = ast_module_info->self;
1094         if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
1095                 ast_log(LOG_ERROR, "failed to register FAX technology\n");
1096                 return AST_MODULE_LOAD_DECLINE;
1097         }
1098
1099         /* prevent logging to stderr */
1100         span_set_message_handler(NULL);
1101
1102         return AST_MODULE_LOAD_SUCCESS;
1103 }
1104
1105
1106 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
1107                 .load = load_module,
1108                 .unload = unload_module,
1109                );