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