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