Asterisk media architecture conversion - no more format bitfields
[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  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Spandsp T.38 and G.711 FAX Resource
22  *
23  * \author Matthew Nicholson <mnicholson@digium.com>
24  *
25  * This module registers the Spandsp FAX technology with the res_fax module.
26  */
27
28 /*** MODULEINFO
29         <depend>spandsp</depend>
30         <depend>res_fax</depend>
31 ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
38 #include <spandsp.h>
39 #include <spandsp/version.h>
40
41 #include "asterisk/logger.h"
42 #include "asterisk/module.h"
43 #include "asterisk/strings.h"
44 #include "asterisk/cli.h"
45 #include "asterisk/utils.h"
46 #include "asterisk/timing.h"
47 #include "asterisk/astobj2.h"
48 #include "asterisk/res_fax.h"
49
50 #define SPANDSP_FAX_SAMPLES 160
51 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES       /* 50 ticks per second, 20ms, 160 samples per second */
52
53 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
54 static void spandsp_fax_destroy(struct ast_fax_session *s);
55 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
56 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
57 static int spandsp_fax_start(struct ast_fax_session *s);
58 static int spandsp_fax_cancel(struct ast_fax_session *s);
59 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
60
61 static char *spandsp_fax_cli_show_capabilities(int fd);
62 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
63 static char *spandsp_fax_cli_show_stats(int fd);
64 static char *spandsp_fax_cli_show_settings(int fd);
65
66 static struct ast_fax_tech spandsp_fax_tech = {
67         .type = "Spandsp",
68         .description = "Spandsp FAX Driver",
69 #if SPANDSP_RELEASE_DATE >= 20090220
70         /* spandsp 0.0.6 */
71         .version = SPANDSP_RELEASE_DATETIME_STRING,
72 #else
73         /* spandsp 0.0.5
74          * TODO: maybe we should determine the version better way
75          */
76         .version = "pre-20090220",
77 #endif
78         .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE,
79         .new_session = spandsp_fax_new,
80         .destroy_session = spandsp_fax_destroy,
81         .read = spandsp_fax_read,
82         .write = spandsp_fax_write,
83         .start_session = spandsp_fax_start,
84         .cancel_session = spandsp_fax_cancel,
85         .switch_to_t38 = spandsp_fax_switch_to_t38,
86         .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
87         .cli_show_session = spandsp_fax_cli_show_session,
88         .cli_show_stats = spandsp_fax_cli_show_stats,
89         .cli_show_settings = spandsp_fax_cli_show_settings,
90 };
91
92 struct spandsp_fax_stats {
93         int success;
94         int nofax;
95         int neg_failed;
96         int failed_to_train;
97         int rx_protocol_error;
98         int tx_protocol_error;
99         int protocol_error;
100         int retries_exceeded;
101         int file_error;
102         int mem_error;
103         int call_dropped;
104         int unknown_error;
105         int switched;
106 };
107
108 static struct {
109         ast_mutex_t lock;
110         struct spandsp_fax_stats g711;
111         struct spandsp_fax_stats t38;
112 } spandsp_global_stats;
113
114 struct spandsp_pvt {
115         unsigned int ist38:1;
116         unsigned int isdone:1;
117         fax_state_t fax_state;
118         t38_terminal_state_t t38_state;
119         t30_state_t *t30_state;
120         t38_core_state_t *t38_core_state;
121
122         struct spandsp_fax_stats *stats;
123
124         struct ast_timer *timer;
125         AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
126 };
127
128 static void session_destroy(struct spandsp_pvt *p);
129 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
130 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
131 static void spandsp_log(int level, const char *msg);
132 static int update_stats(struct spandsp_pvt *p, int completion_code);
133
134 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
135 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
136 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
137 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
138
139 static void session_destroy(struct spandsp_pvt *p)
140 {
141         struct ast_frame *f;
142
143         t30_terminate(p->t30_state);
144         p->isdone = 1;
145
146         ast_timer_close(p->timer);
147
148         fax_release(&p->fax_state);
149         t38_terminal_release(&p->t38_state);
150
151         while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
152                 ast_frfree(f);
153         }
154 }
155
156 /*! \brief
157  *
158  */
159 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
160 {
161         struct spandsp_pvt *p = data;
162         struct ast_frame fax_frame = {
163                 .frametype = AST_FRAME_MODEM,
164                 .subclass.integer = AST_MODEM_T38,
165                 .src = "res_fax_spandsp_t38",
166         };
167
168         struct ast_frame *f = &fax_frame;
169
170
171         /* TODO: Asterisk does not provide means of resending the same packet multiple
172           times so count is ignored at the moment */
173
174         AST_FRAME_SET_BUFFER(f, buf, 0, len);
175
176         if (!(f = ast_frisolate(f))) {
177                 return -1;
178         }
179
180         /* no need to lock, this all runs in the same thread */
181         AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
182
183         return 0;
184 }
185
186 static int update_stats(struct spandsp_pvt *p, int completion_code)
187 {
188         switch (completion_code) {
189         case T30_ERR_OK:
190                 ast_atomic_fetchadd_int(&p->stats->success, 1);
191                 break;
192
193         /* Link problems */
194         case T30_ERR_CEDTONE:            /*! The CED tone exceeded 5s */
195         case T30_ERR_T0_EXPIRED:         /*! Timed out waiting for initial communication */
196         case T30_ERR_T1_EXPIRED:         /*! Timed out waiting for the first message */
197         case T30_ERR_T3_EXPIRED:         /*! Timed out waiting for procedural interrupt */
198         case T30_ERR_HDLC_CARRIER:       /*! The HDLC carrier did not stop in a timely manner */
199         case T30_ERR_CANNOT_TRAIN:       /*! Failed to train with any of the compatible modems */
200                 ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
201                 break;
202
203         case T30_ERR_OPER_INT_FAIL:      /*! Operator intervention failed */
204         case T30_ERR_INCOMPATIBLE:       /*! Far end is not compatible */
205         case T30_ERR_RX_INCAPABLE:       /*! Far end is not able to receive */
206         case T30_ERR_TX_INCAPABLE:       /*! Far end is not able to transmit */
207         case T30_ERR_NORESSUPPORT:       /*! Far end cannot receive at the resolution of the image */
208         case T30_ERR_NOSIZESUPPORT:      /*! Far end cannot receive at the size of image */
209                 ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
210                 break;
211
212         case T30_ERR_UNEXPECTED:         /*! Unexpected message received */
213                 ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
214                 break;
215
216         /* Phase E status values returned to a transmitter */
217         case T30_ERR_TX_BADDCS:          /*! Received bad response to DCS or training */
218         case T30_ERR_TX_BADPG:           /*! Received a DCN from remote after sending a page */
219         case T30_ERR_TX_ECMPHD:          /*! Invalid ECM response received from receiver */
220         case T30_ERR_TX_GOTDCN:          /*! Received a DCN while waiting for a DIS */
221         case T30_ERR_TX_INVALRSP:        /*! Invalid response after sending a page */
222         case T30_ERR_TX_NODIS:           /*! Received other than DIS while waiting for DIS */
223         case T30_ERR_TX_PHBDEAD:         /*! Received no response to DCS, training or TCF */
224         case T30_ERR_TX_PHDDEAD:         /*! No response after sending a page */
225         case T30_ERR_TX_T5EXP:           /*! Timed out waiting for receiver ready (ECM mode) */
226                 ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
227                 break;
228
229         /* Phase E status values returned to a receiver */
230         case T30_ERR_RX_ECMPHD:          /*! Invalid ECM response received from transmitter */
231         case T30_ERR_RX_GOTDCS:          /*! DCS received while waiting for DTC */
232         case T30_ERR_RX_INVALCMD:        /*! Unexpected command after page received */
233         case T30_ERR_RX_NOCARRIER:       /*! Carrier lost during fax receive */
234         case T30_ERR_RX_NOEOL:           /*! Timed out while waiting for EOL (end Of line) */
235                 ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
236                 break;
237         case T30_ERR_RX_NOFAX:           /*! Timed out while waiting for first line */
238                 ast_atomic_fetchadd_int(&p->stats->nofax, 1);
239                 break;
240         case T30_ERR_RX_T2EXPDCN:        /*! Timer T2 expired while waiting for DCN */
241         case T30_ERR_RX_T2EXPD:          /*! Timer T2 expired while waiting for phase D */
242         case T30_ERR_RX_T2EXPFAX:        /*! Timer T2 expired while waiting for fax page */
243         case T30_ERR_RX_T2EXPMPS:        /*! Timer T2 expired while waiting for next fax page */
244         case T30_ERR_RX_T2EXPRR:         /*! Timer T2 expired while waiting for RR command */
245         case T30_ERR_RX_T2EXP:           /*! Timer T2 expired while waiting for NSS, DCS or MCF */
246         case T30_ERR_RX_DCNWHY:          /*! Unexpected DCN while waiting for DCS or DIS */
247         case T30_ERR_RX_DCNDATA:         /*! Unexpected DCN while waiting for image data */
248         case T30_ERR_RX_DCNFAX:          /*! Unexpected DCN while waiting for EOM, EOP or MPS */
249         case T30_ERR_RX_DCNPHD:          /*! Unexpected DCN after EOM or MPS sequence */
250         case T30_ERR_RX_DCNRRD:          /*! Unexpected DCN after RR/RNR sequence */
251         case T30_ERR_RX_DCNNORTN:        /*! Unexpected DCN after requested retransmission */
252                 ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
253                 break;
254
255         /* TIFF file problems */
256         case T30_ERR_FILEERROR:          /*! TIFF/F file cannot be opened */
257         case T30_ERR_NOPAGE:             /*! TIFF/F page not found */
258         case T30_ERR_BADTIFF:            /*! TIFF/F format is not compatible */
259         case T30_ERR_BADPAGE:            /*! TIFF/F page number tag missing */
260         case T30_ERR_BADTAG:             /*! Incorrect values for TIFF/F tags */
261         case T30_ERR_BADTIFFHDR:         /*! Bad TIFF/F header - incorrect values in fields */
262                 ast_atomic_fetchadd_int(&p->stats->file_error, 1);
263                 break;
264         case T30_ERR_NOMEM:              /*! Cannot allocate memory for more pages */
265                 ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
266                 break;
267
268         /* General problems */
269         case T30_ERR_RETRYDCN:           /*! Disconnected after permitted retries */
270                 ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
271                 break;
272         case T30_ERR_CALLDROPPED:        /*! The call dropped prematurely */
273                 ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
274                 break;
275
276         /* Feature negotiation issues */
277         case T30_ERR_NOPOLL:             /*! Poll not accepted */
278         case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
279         case T30_ERR_SUB_UNACCEPTABLE:   /*! Far end's sub-address is not acceptable */
280         case T30_ERR_SEP_UNACCEPTABLE:   /*! Far end's selective polling address is not acceptable */
281         case T30_ERR_PSA_UNACCEPTABLE:   /*! Far end's polled sub-address is not acceptable */
282         case T30_ERR_SID_UNACCEPTABLE:   /*! Far end's sender identification is not acceptable */
283         case T30_ERR_PWD_UNACCEPTABLE:   /*! Far end's password is not acceptable */
284         case T30_ERR_TSA_UNACCEPTABLE:   /*! Far end's transmitting subscriber internet address is not acceptable */
285         case T30_ERR_IRA_UNACCEPTABLE:   /*! Far end's internet routing address is not acceptable */
286         case T30_ERR_CIA_UNACCEPTABLE:   /*! Far end's calling subscriber internet address is not acceptable */
287         case T30_ERR_ISP_UNACCEPTABLE:   /*! Far end's internet selective polling address is not acceptable */
288         case T30_ERR_CSA_UNACCEPTABLE:   /*! Far end's called subscriber internet address is not acceptable */
289                 ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
290                 break;
291         default:
292                 ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
293                 ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
294                 return -1;
295         }
296         return 0;
297 }
298
299 /*! \brief Phase E handler callback.
300  * \param t30_state the span t30 state
301  * \param data this will be the ast_fax_session
302  * \param completion_code the result of the fax session
303  *
304  * This function pulls stats from the spandsp stack and stores them for res_fax
305  * to use later.
306  */
307 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
308 {
309         struct ast_fax_session *s = data;
310         struct spandsp_pvt *p = s->tech_pvt;
311         char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
312         const char *c;
313         t30_stats_t stats;
314
315         ast_debug(5, "FAX session '%d' entering phase E\n", s->id);
316
317         p->isdone = 1;
318
319         update_stats(p, completion_code);
320
321         t30_get_transfer_statistics(t30_state, &stats);
322
323         if (completion_code == T30_ERR_OK) {
324                 ast_string_field_set(s->details, result, "SUCCESS");
325         } else {
326                 ast_string_field_set(s->details, result, "FAILED");
327                 ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
328         }
329
330         ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
331
332         ast_debug(5, "FAX session '%d' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
333
334         if ((c = t30_get_tx_ident(t30_state))) {
335                 ast_string_field_set(s->details, localstationid, c);
336         }
337
338         if ((c = t30_get_rx_ident(t30_state))) {
339                 ast_string_field_set(s->details, remotestationid, c);
340         }
341
342 #if SPANDSP_RELEASE_DATE >= 20090220
343         s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
344 #else
345         s->details->pages_transferred = stats.pages_transferred;
346 #endif
347
348         ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
349
350         ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
351
352         t30_get_tx_page_header_info(t30_state, headerinfo);
353         ast_string_field_set(s->details, headerinfo, headerinfo);
354 }
355
356 /*! \brief Send spandsp log messages to asterisk.
357  * \param level the spandsp logging level
358  * \param msg the log message
359  *
360  * \note This function is a callback function called by spandsp.
361  */
362 static void spandsp_log(int level, const char *msg)
363 {
364         if (level == SPAN_LOG_ERROR) {
365                 ast_log(LOG_ERROR, "%s", msg);
366         } else if (level == SPAN_LOG_WARNING) {
367                 ast_log(LOG_WARNING, "%s", msg);
368         } else {
369                 ast_fax_log(LOG_DEBUG, msg);
370         }
371 }
372
373 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
374 {
375         int level = SPAN_LOG_WARNING;
376
377         if (details->option.debug) {
378                 level = SPAN_LOG_DEBUG_3;
379         }
380
381         span_log_set_message_handler(state, spandsp_log);
382         span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
383 }
384
385 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
386 {
387         if (!ast_strlen_zero(details->localstationid)) {
388                 t30_set_tx_ident(t30_state, details->localstationid);
389         }
390
391         if (!ast_strlen_zero(details->headerinfo)) {
392                 t30_set_tx_page_header_info(t30_state, details->headerinfo);
393         }
394 }
395
396 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
397 {
398         if (details->caps & AST_FAX_TECH_RECEIVE) {
399                 t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
400         } else {
401                 /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
402                  * should be safe because we ensure either RECEIVE or SEND is
403                  * indicated in spandsp_fax_new() */
404                 t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
405         }
406 }
407
408 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
409 {
410         t30_set_ecm_capability(t30_state, details->option.ecm);
411         t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
412 }
413
414 /*! \brief create an instance of the spandsp tech_pvt for a fax session */
415 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
416 {
417         struct spandsp_pvt *p;
418         int caller_mode;
419
420         if ((!(p = ast_calloc(1, sizeof(*p))))) {
421                 ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
422                 goto e_return;
423         }
424
425         AST_LIST_HEAD_INIT(&p->read_frames);
426
427         if (s->details->caps & AST_FAX_TECH_RECEIVE) {
428                 caller_mode = 0;
429         } else if (s->details->caps & AST_FAX_TECH_SEND) {
430                 caller_mode = 1;
431         } else {
432                 ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
433                 goto e_free;
434         }
435
436         if (!(p->timer = ast_timer_open())) {
437                 ast_log(LOG_ERROR, "Channel '%s' FAX session '%d' failed to create timing source.\n", s->channame, s->id);
438                 goto e_free;
439         }
440
441         s->fd = ast_timer_fd(p->timer);
442
443         p->stats = &spandsp_global_stats.g711;
444
445         if (s->details->caps & AST_FAX_TECH_T38) {
446                 if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
447                         /* audio mode was not requested, start in T.38 mode */
448                         p->ist38 = 1;
449                         p->stats = &spandsp_global_stats.t38;
450                 }
451
452                 /* init t38 stuff */
453                 t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, p);
454                 set_logging(&p->t38_state.logging, s->details);
455         }
456
457         if (s->details->caps & AST_FAX_TECH_AUDIO) {
458                 /* init audio stuff */
459                 fax_init(&p->fax_state, caller_mode);
460                 set_logging(&p->fax_state.logging, s->details);
461         }
462
463         s->state = AST_FAX_STATE_INITIALIZED;
464         return p;
465
466 e_free:
467         ast_free(p);
468 e_return:
469         return NULL;
470 }
471
472 /*! \brief Destroy a spandsp fax session.
473  */
474 static void spandsp_fax_destroy(struct ast_fax_session *s)
475 {
476         struct spandsp_pvt *p = s->tech_pvt;
477
478         session_destroy(p);
479         ast_free(p);
480         s->tech_pvt = NULL;
481         s->fd = -1;
482 }
483
484 /*! \brief Read a frame from the spandsp fax stack.
485  */
486 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
487 {
488         struct spandsp_pvt *p = s->tech_pvt;
489         uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
490         int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
491         int samples;
492
493         struct ast_frame fax_frame = {
494                 .frametype = AST_FRAME_VOICE,
495                 .src = "res_fax_spandsp_g711",
496         };
497         struct ast_frame *f = &fax_frame;
498         ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
499
500         ast_timer_ack(p->timer, 1);
501
502         /* XXX do we need to lock here? */
503         if (p->isdone) {
504                 s->state = AST_FAX_STATE_COMPLETE;
505                 ast_debug(5, "FAX session '%d' is complete.\n", s->id);
506                 return NULL;
507         }
508
509         if (p->ist38) {
510                 t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
511                 if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
512                         return f;
513                 }
514         } else {
515                 if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
516                         f->samples = samples;
517                         AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
518                         return ast_frisolate(f);
519                 }
520         }
521
522         return &ast_null_frame;
523 }
524
525 /*! \brief Write a frame to the spandsp fax stack.
526  * \param s a fax session
527  * \param f the frame to write
528  *
529  * \note res_fax does not currently use the return value of this function.
530  * Also the fax_rx() function never fails.
531  *
532  * \retval 0 success
533  * \retval -1 failure
534  */
535 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
536 {
537         struct spandsp_pvt *p = s->tech_pvt;
538
539         /* XXX do we need to lock here? */
540         if (s->state == AST_FAX_STATE_COMPLETE) {
541                 ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
542                 return -1;
543         }
544
545         if (p->ist38) {
546                 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
547         } else {
548                 return fax_rx(&p->fax_state, f->data.ptr, f->samples);
549         }
550 }
551
552 /*! \brief */
553 static int spandsp_fax_start(struct ast_fax_session *s)
554 {
555         struct spandsp_pvt *p = s->tech_pvt;
556
557         s->state = AST_FAX_STATE_OPEN;
558
559         if (p->ist38) {
560 #if SPANDSP_RELEASE_DATE >= 20080725
561                 /* for spandsp shaphots 0.0.6 and higher */
562                 p->t30_state = &p->t38_state.t30;
563                 p->t38_core_state = &p->t38_state.t38_fe.t38;
564 #else
565                 /* for spandsp releases 0.0.5 */
566                 p->t30_state = &p->t38_state.t30_state;
567                 p->t38_core_state = &p->t38_state.t38;
568 #endif
569         } else {
570 #if SPANDSP_RELEASE_DATE >= 20080725
571                 /* for spandsp shaphots 0.0.6 and higher */
572                 p->t30_state = &p->fax_state.t30;
573 #else
574                 /* for spandsp release 0.0.5 */
575                 p->t30_state = &p->fax_state.t30_state;
576 #endif
577         }
578
579         set_logging(&p->t30_state->logging, s->details);
580
581         /* set some parameters */
582         set_local_info(p->t30_state, s->details);
583         set_file(p->t30_state, s->details);
584         set_ecm(p->t30_state, s->details);
585
586         /* perhaps set_transmit_on_idle() should be called */
587
588         t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
589
590         /* set T.38 parameters */
591         if (p->ist38) {
592                 set_logging(&p->t38_core_state->logging, s->details);
593
594                 t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
595
596                 if (s->details->their_t38_parameters.fill_bit_removal) {
597                         t38_set_fill_bit_removal(p->t38_core_state, TRUE);
598                 }
599
600                 if (s->details->their_t38_parameters.transcoding_mmr) {
601                         t38_set_mmr_transcoding(p->t38_core_state, TRUE);
602                 }
603
604                 if (s->details->their_t38_parameters.transcoding_jbig) {
605                         t38_set_jbig_transcoding(p->t38_core_state, TRUE);
606                 }
607         } else {
608                 /* have the fax stack generate silence if it has no data to send */
609                 fax_set_transmit_on_idle(&p->fax_state, 1);
610         }
611
612
613         /* start the timer */
614         if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
615                 ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
616                 return -1;
617         }
618
619         s->state = AST_FAX_STATE_ACTIVE;
620
621         return 0;
622 }
623
624 /*! \brief */
625 static int spandsp_fax_cancel(struct ast_fax_session *s)
626 {
627         struct spandsp_pvt *p = s->tech_pvt;
628         t30_terminate(p->t30_state);
629         p->isdone = 1;
630         return 0;
631 }
632
633 /*! \brief */
634 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
635 {
636         struct spandsp_pvt *p = s->tech_pvt;
637
638         /* prevent the phase E handler from running, this is not a real termination */
639         t30_set_phase_e_handler(p->t30_state, NULL, NULL);
640
641         t30_terminate(p->t30_state);
642
643         s->details->option.switch_to_t38 = 1;
644         ast_atomic_fetchadd_int(&p->stats->switched, 1);
645
646         p->ist38 = 1;
647         p->stats = &spandsp_global_stats.t38;
648         spandsp_fax_start(s);
649
650         return 0;
651 }
652
653 /*! \brief */
654 static char *spandsp_fax_cli_show_capabilities(int fd)
655 {
656         ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
657         return  CLI_SUCCESS;
658 }
659
660 /*! \brief */
661 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
662 {
663         struct spandsp_pvt *p = s->tech_pvt;
664         t30_stats_t stats;
665
666         ao2_lock(s);
667         ast_cli(fd, "%-22s : %d\n", "session", s->id);
668         ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
669         ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
670         if (s->state != AST_FAX_STATE_UNINITIALIZED) {
671                 t30_get_transfer_statistics(p->t30_state, &stats);
672                 ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
673                 ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
674                 ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
675                 ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
676 #if SPANDSP_RELEASE_DATE >= 20090220
677                 ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
678 #else
679                 ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
680 #endif
681                 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);
682
683                 ast_cli(fd, "\nData Statistics:\n");
684 #if SPANDSP_RELEASE_DATE >= 20090220
685                 ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
686                 ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
687 #else
688                 ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
689                 ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
690 #endif
691                 ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
692                 ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
693         }
694         ao2_unlock(s);
695         ast_cli(fd, "\n\n");
696         return CLI_SUCCESS;
697 }
698
699 /*! \brief */
700 static char *spandsp_fax_cli_show_stats(int fd)
701 {
702         ast_mutex_lock(&spandsp_global_stats.lock);
703         ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
704         ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
705         ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
706         ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
707         ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
708         ast_cli(fd, "%-20.20s : %d\n", "Negotation Failed", spandsp_global_stats.g711.neg_failed);
709         ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
710         ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
711         ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
712         ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
713         ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
714         ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
715         ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
716         ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
717
718         ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
719         ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
720         ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
721         ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
722         ast_cli(fd, "%-20.20s : %d\n", "Negotation Failed", spandsp_global_stats.t38.neg_failed);
723         ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
724         ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
725         ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
726         ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
727         ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
728         ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
729         ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
730         ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
731         ast_mutex_unlock(&spandsp_global_stats.lock);
732
733         return CLI_SUCCESS;
734 }
735
736 /*! \brief Show res_fax_spandsp settings */
737 static char *spandsp_fax_cli_show_settings(int fd)
738 {
739         /* no settings at the moment */
740         return CLI_SUCCESS;
741 }
742
743 /*! \brief unload res_fax_spandsp */
744 static int unload_module(void)
745 {
746         ast_fax_tech_unregister(&spandsp_fax_tech);
747         ast_mutex_destroy(&spandsp_global_stats.lock);
748         return AST_MODULE_LOAD_SUCCESS;
749 }
750
751 /*! \brief load res_fax_spandsp */
752 static int load_module(void)
753 {
754         ast_mutex_init(&spandsp_global_stats.lock);
755         spandsp_fax_tech.module = ast_module_info->self;
756         if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
757                 ast_log(LOG_ERROR, "failed to register FAX technology\n");
758                 return AST_MODULE_LOAD_DECLINE;
759         }
760
761         /* prevent logging to stderr */
762         span_set_message_handler(NULL);
763
764         return AST_MODULE_LOAD_SUCCESS;
765 }
766
767
768 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
769                 .load = load_module,
770                 .unload = unload_module,
771                );