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