Sat Apr 26 2014 22:01:40

Asterisk developer's documentation


res_fax_spandsp.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2009-2010, Digium, Inc.
00005  *
00006  * Matthew Nicholson <mnicholson@digium.com>
00007  *
00008  * Initial T.38-gateway code
00009  * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
00010  * Created by Nethemba s.r.o. http://www.nethemba.com
00011  * Sponsored by IPEX a.s. http://www.ipex.cz
00012  *
00013  * T.38-gateway integration into asterisk app_fax and rework
00014  * 2008, Gregory Hinton Nietsky <gregory@dnstelecom.co.za>
00015  * dns Telecom http://www.dnstelecom.co.za
00016  *
00017  * Modified to make T.38-gateway compatible with Asterisk 1.6.2
00018  * 2010, Anton Verevkin <mymail@verevkin.it>
00019  * ViaNetTV http://www.vianettv.com
00020  *
00021  * Modified to make T.38-gateway work
00022  * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
00023  *
00024  * See http://www.asterisk.org for more information about
00025  * the Asterisk project. Please do not directly contact
00026  * any of the maintainers of this project for assistance;
00027  * the project provides a web site, mailing lists and IRC
00028  * channels for your use.
00029  *
00030  * This program is free software, distributed under the terms of
00031  * the GNU General Public License Version 2. See the LICENSE file
00032  * at the top of the source tree.
00033  */
00034 
00035 /*! \file
00036  *
00037  * \brief Spandsp T.38 and G.711 FAX Resource
00038  *
00039  * \author Matthew Nicholson <mnicholson@digium.com>
00040  * \author Gregory H. Nietsky <gregory@distrotech.co.za>
00041  *
00042  * This module registers the Spandsp FAX technology with the res_fax module.
00043  */
00044 
00045 /*** MODULEINFO
00046    <depend>spandsp</depend>
00047    <depend>res_fax</depend>
00048    <support_level>extended</support_level>
00049 ***/
00050 
00051 #include "asterisk.h"
00052 
00053 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 410829 $")
00054 
00055 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
00056 #include <spandsp.h>
00057 #include <spandsp/version.h>
00058 
00059 #include "asterisk/logger.h"
00060 #include "asterisk/module.h"
00061 #include "asterisk/strings.h"
00062 #include "asterisk/cli.h"
00063 #include "asterisk/utils.h"
00064 #include "asterisk/timing.h"
00065 #include "asterisk/astobj2.h"
00066 #include "asterisk/res_fax.h"
00067 #include "asterisk/channel.h"
00068 
00069 #define SPANDSP_FAX_SAMPLES 160
00070 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES   /* 50 ticks per second, 20ms, 160 samples per second */
00071 #define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
00072 
00073 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
00074 static void spandsp_fax_destroy(struct ast_fax_session *s);
00075 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
00076 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
00077 static int spandsp_fax_start(struct ast_fax_session *s);
00078 static int spandsp_fax_cancel(struct ast_fax_session *s);
00079 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
00080 static int spandsp_fax_gateway_start(struct ast_fax_session *s);
00081 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
00082 static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
00083 static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
00084 static void spandsp_v21_cleanup(struct ast_fax_session *s);
00085 static void spandsp_v21_tone(void *data, int code, int level, int delay);
00086 
00087 static char *spandsp_fax_cli_show_capabilities(int fd);
00088 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
00089 static char *spandsp_fax_cli_show_stats(int fd);
00090 static char *spandsp_fax_cli_show_settings(int fd);
00091 
00092 static struct ast_fax_tech spandsp_fax_tech = {
00093    .type = "Spandsp",
00094    .description = "Spandsp FAX Driver",
00095 #if SPANDSP_RELEASE_DATE >= 20090220
00096    /* spandsp 0.0.6 */
00097    .version = SPANDSP_RELEASE_DATETIME_STRING,
00098 #else
00099    /* spandsp 0.0.5
00100     * TODO: maybe we should determine the version better way
00101     */
00102    .version = "pre-20090220",
00103 #endif
00104    .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND
00105       | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY
00106       | AST_FAX_TECH_V21_DETECT,
00107    .new_session = spandsp_fax_new,
00108    .destroy_session = spandsp_fax_destroy,
00109    .read = spandsp_fax_read,
00110    .write = spandsp_fax_write,
00111    .start_session = spandsp_fax_start,
00112    .cancel_session = spandsp_fax_cancel,
00113    .switch_to_t38 = spandsp_fax_switch_to_t38,
00114    .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
00115    .cli_show_session = spandsp_fax_cli_show_session,
00116    .cli_show_stats = spandsp_fax_cli_show_stats,
00117    .cli_show_settings = spandsp_fax_cli_show_settings,
00118 };
00119 
00120 struct spandsp_fax_stats {
00121    int success;
00122    int nofax;
00123    int neg_failed;
00124    int failed_to_train;
00125    int rx_protocol_error;
00126    int tx_protocol_error;
00127    int protocol_error;
00128    int retries_exceeded;
00129    int file_error;
00130    int mem_error;
00131    int call_dropped;
00132    int unknown_error;
00133    int switched;
00134 };
00135 
00136 static struct {
00137    ast_mutex_t lock;
00138    struct spandsp_fax_stats g711;
00139    struct spandsp_fax_stats t38;
00140 } spandsp_global_stats;
00141 
00142 struct spandsp_pvt {
00143    unsigned int ist38:1;
00144    unsigned int isdone:1;
00145    enum ast_t38_state ast_t38_state;
00146    fax_state_t fax_state;
00147    t38_terminal_state_t t38_state;
00148    t30_state_t *t30_state;
00149    t38_core_state_t *t38_core_state;
00150 
00151    struct spandsp_fax_stats *stats;
00152 
00153    struct spandsp_fax_gw_stats *t38stats;
00154    t38_gateway_state_t t38_gw_state;
00155 
00156    struct ast_timer *timer;
00157    AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
00158 
00159    int v21_detected;
00160    modem_connect_tones_rx_state_t *tone_state;
00161 };
00162 
00163 static int spandsp_v21_new(struct spandsp_pvt *p);
00164 static void session_destroy(struct spandsp_pvt *p);
00165 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
00166 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
00167 static void spandsp_log(int level, const char *msg);
00168 static int update_stats(struct spandsp_pvt *p, int completion_code);
00169 static int spandsp_modems(struct ast_fax_session_details *details);
00170 
00171 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
00172 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
00173 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
00174 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
00175 
00176 static void session_destroy(struct spandsp_pvt *p)
00177 {
00178    struct ast_frame *f;
00179 
00180    t30_terminate(p->t30_state);
00181    p->isdone = 1;
00182 
00183    ast_timer_close(p->timer);
00184    p->timer = NULL;
00185    fax_release(&p->fax_state);
00186    t38_terminal_release(&p->t38_state);
00187 
00188    while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00189       ast_frfree(f);
00190    }
00191 }
00192 
00193 /*! \brief
00194  *
00195  */
00196 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
00197 {
00198    int res = -1;
00199    struct ast_fax_session *s = data;
00200    struct spandsp_pvt *p = s->tech_pvt;
00201    struct ast_frame fax_frame = {
00202       .frametype = AST_FRAME_MODEM,
00203       .subclass.integer = AST_MODEM_T38,
00204       .src = "res_fax_spandsp_t38",
00205    };
00206 
00207    struct ast_frame *f = &fax_frame;
00208 
00209 
00210    /* TODO: Asterisk does not provide means of resending the same packet multiple
00211      times so count is ignored at the moment */
00212 
00213    AST_FRAME_SET_BUFFER(f, buf, 0, len);
00214 
00215    if (!(f = ast_frisolate(f))) {
00216       return res;
00217    }
00218 
00219    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
00220       ast_set_flag(f, AST_FAX_FRFLAG_GATEWAY);
00221       if (p->ast_t38_state == T38_STATE_NEGOTIATED) {
00222          res = ast_write(s->chan, f);
00223       } else {
00224          res = ast_queue_frame(s->chan, f);
00225       }
00226       ast_frfree(f);
00227    } else {
00228       /* no need to lock, this all runs in the same thread */
00229       AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
00230       res = 0;
00231    }
00232 
00233    return res;
00234 }
00235 
00236 static int update_stats(struct spandsp_pvt *p, int completion_code)
00237 {
00238    switch (completion_code) {
00239    case T30_ERR_OK:
00240       ast_atomic_fetchadd_int(&p->stats->success, 1);
00241       break;
00242 
00243    /* Link problems */
00244    case T30_ERR_CEDTONE:            /*! The CED tone exceeded 5s */
00245    case T30_ERR_T0_EXPIRED:         /*! Timed out waiting for initial communication */
00246    case T30_ERR_T1_EXPIRED:         /*! Timed out waiting for the first message */
00247    case T30_ERR_T3_EXPIRED:         /*! Timed out waiting for procedural interrupt */
00248    case T30_ERR_HDLC_CARRIER:       /*! The HDLC carrier did not stop in a timely manner */
00249    case T30_ERR_CANNOT_TRAIN:       /*! Failed to train with any of the compatible modems */
00250       ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
00251       break;
00252 
00253    case T30_ERR_OPER_INT_FAIL:      /*! Operator intervention failed */
00254    case T30_ERR_INCOMPATIBLE:       /*! Far end is not compatible */
00255    case T30_ERR_RX_INCAPABLE:       /*! Far end is not able to receive */
00256    case T30_ERR_TX_INCAPABLE:       /*! Far end is not able to transmit */
00257    case T30_ERR_NORESSUPPORT:       /*! Far end cannot receive at the resolution of the image */
00258    case T30_ERR_NOSIZESUPPORT:      /*! Far end cannot receive at the size of image */
00259       ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
00260       break;
00261 
00262    case T30_ERR_UNEXPECTED:         /*! Unexpected message received */
00263       ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
00264       break;
00265 
00266    /* Phase E status values returned to a transmitter */
00267    case T30_ERR_TX_BADDCS:          /*! Received bad response to DCS or training */
00268    case T30_ERR_TX_BADPG:           /*! Received a DCN from remote after sending a page */
00269    case T30_ERR_TX_ECMPHD:          /*! Invalid ECM response received from receiver */
00270    case T30_ERR_TX_GOTDCN:          /*! Received a DCN while waiting for a DIS */
00271    case T30_ERR_TX_INVALRSP:        /*! Invalid response after sending a page */
00272    case T30_ERR_TX_NODIS:           /*! Received other than DIS while waiting for DIS */
00273    case T30_ERR_TX_PHBDEAD:         /*! Received no response to DCS, training or TCF */
00274    case T30_ERR_TX_PHDDEAD:         /*! No response after sending a page */
00275    case T30_ERR_TX_T5EXP:           /*! Timed out waiting for receiver ready (ECM mode) */
00276       ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
00277       break;
00278 
00279    /* Phase E status values returned to a receiver */
00280    case T30_ERR_RX_ECMPHD:          /*! Invalid ECM response received from transmitter */
00281    case T30_ERR_RX_GOTDCS:          /*! DCS received while waiting for DTC */
00282    case T30_ERR_RX_INVALCMD:        /*! Unexpected command after page received */
00283    case T30_ERR_RX_NOCARRIER:       /*! Carrier lost during fax receive */
00284    case T30_ERR_RX_NOEOL:           /*! Timed out while waiting for EOL (end Of line) */
00285       ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
00286       break;
00287    case T30_ERR_RX_NOFAX:           /*! Timed out while waiting for first line */
00288       ast_atomic_fetchadd_int(&p->stats->nofax, 1);
00289       break;
00290    case T30_ERR_RX_T2EXPDCN:        /*! Timer T2 expired while waiting for DCN */
00291    case T30_ERR_RX_T2EXPD:          /*! Timer T2 expired while waiting for phase D */
00292    case T30_ERR_RX_T2EXPFAX:        /*! Timer T2 expired while waiting for fax page */
00293    case T30_ERR_RX_T2EXPMPS:        /*! Timer T2 expired while waiting for next fax page */
00294    case T30_ERR_RX_T2EXPRR:         /*! Timer T2 expired while waiting for RR command */
00295    case T30_ERR_RX_T2EXP:           /*! Timer T2 expired while waiting for NSS, DCS or MCF */
00296    case T30_ERR_RX_DCNWHY:          /*! Unexpected DCN while waiting for DCS or DIS */
00297    case T30_ERR_RX_DCNDATA:         /*! Unexpected DCN while waiting for image data */
00298    case T30_ERR_RX_DCNFAX:          /*! Unexpected DCN while waiting for EOM, EOP or MPS */
00299    case T30_ERR_RX_DCNPHD:          /*! Unexpected DCN after EOM or MPS sequence */
00300    case T30_ERR_RX_DCNRRD:          /*! Unexpected DCN after RR/RNR sequence */
00301    case T30_ERR_RX_DCNNORTN:        /*! Unexpected DCN after requested retransmission */
00302       ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
00303       break;
00304 
00305    /* TIFF file problems */
00306    case T30_ERR_FILEERROR:          /*! TIFF/F file cannot be opened */
00307    case T30_ERR_NOPAGE:             /*! TIFF/F page not found */
00308    case T30_ERR_BADTIFF:            /*! TIFF/F format is not compatible */
00309    case T30_ERR_BADPAGE:            /*! TIFF/F page number tag missing */
00310    case T30_ERR_BADTAG:             /*! Incorrect values for TIFF/F tags */
00311    case T30_ERR_BADTIFFHDR:         /*! Bad TIFF/F header - incorrect values in fields */
00312       ast_atomic_fetchadd_int(&p->stats->file_error, 1);
00313       break;
00314    case T30_ERR_NOMEM:              /*! Cannot allocate memory for more pages */
00315       ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
00316       break;
00317 
00318    /* General problems */
00319    case T30_ERR_RETRYDCN:           /*! Disconnected after permitted retries */
00320       ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
00321       break;
00322    case T30_ERR_CALLDROPPED:        /*! The call dropped prematurely */
00323       ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
00324       break;
00325 
00326    /* Feature negotiation issues */
00327    case T30_ERR_NOPOLL:             /*! Poll not accepted */
00328    case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
00329    case T30_ERR_SUB_UNACCEPTABLE:   /*! Far end's sub-address is not acceptable */
00330    case T30_ERR_SEP_UNACCEPTABLE:   /*! Far end's selective polling address is not acceptable */
00331    case T30_ERR_PSA_UNACCEPTABLE:   /*! Far end's polled sub-address is not acceptable */
00332    case T30_ERR_SID_UNACCEPTABLE:   /*! Far end's sender identification is not acceptable */
00333    case T30_ERR_PWD_UNACCEPTABLE:   /*! Far end's password is not acceptable */
00334    case T30_ERR_TSA_UNACCEPTABLE:   /*! Far end's transmitting subscriber internet address is not acceptable */
00335    case T30_ERR_IRA_UNACCEPTABLE:   /*! Far end's internet routing address is not acceptable */
00336    case T30_ERR_CIA_UNACCEPTABLE:   /*! Far end's calling subscriber internet address is not acceptable */
00337    case T30_ERR_ISP_UNACCEPTABLE:   /*! Far end's internet selective polling address is not acceptable */
00338    case T30_ERR_CSA_UNACCEPTABLE:   /*! Far end's called subscriber internet address is not acceptable */
00339       ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
00340       break;
00341    default:
00342       ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
00343       ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
00344       return -1;
00345    }
00346    return 0;
00347 }
00348 
00349 /*! \brief Phase E handler callback.
00350  * \param t30_state the span t30 state
00351  * \param data this will be the ast_fax_session
00352  * \param completion_code the result of the fax session
00353  *
00354  * This function pulls stats from the spandsp stack and stores them for res_fax
00355  * to use later.
00356  */
00357 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
00358 {
00359    struct ast_fax_session *s = data;
00360    struct spandsp_pvt *p = s->tech_pvt;
00361    char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
00362    const char *c;
00363    t30_stats_t stats;
00364 
00365    ast_debug(5, "FAX session '%d' entering phase E\n", s->id);
00366 
00367    p->isdone = 1;
00368 
00369    update_stats(p, completion_code);
00370 
00371    t30_get_transfer_statistics(t30_state, &stats);
00372 
00373    if (completion_code == T30_ERR_OK) {
00374       ast_string_field_set(s->details, result, "SUCCESS");
00375    } else {
00376       ast_string_field_set(s->details, result, "FAILED");
00377       ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
00378    }
00379 
00380    ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
00381 
00382    ast_debug(5, "FAX session '%d' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
00383 
00384    if ((c = t30_get_tx_ident(t30_state))) {
00385       ast_string_field_set(s->details, localstationid, c);
00386    }
00387 
00388    if ((c = t30_get_rx_ident(t30_state))) {
00389       ast_string_field_set(s->details, remotestationid, c);
00390    }
00391 
00392 #if SPANDSP_RELEASE_DATE >= 20090220
00393    s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
00394 #else
00395    s->details->pages_transferred = stats.pages_transferred;
00396 #endif
00397 
00398    ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
00399 
00400    ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
00401 
00402    t30_get_tx_page_header_info(t30_state, headerinfo);
00403    ast_string_field_set(s->details, headerinfo, headerinfo);
00404 }
00405 
00406 /*! \brief Send spandsp log messages to asterisk.
00407  * \param level the spandsp logging level
00408  * \param msg the log message
00409  *
00410  * \note This function is a callback function called by spandsp.
00411  */
00412 static void spandsp_log(int level, const char *msg)
00413 {
00414    if (level == SPAN_LOG_ERROR) {
00415       ast_log(LOG_ERROR, "%s", msg);
00416    } else if (level == SPAN_LOG_WARNING) {
00417       ast_log(LOG_WARNING, "%s", msg);
00418    } else {
00419       ast_fax_log(LOG_DEBUG, msg);
00420    }
00421 }
00422 
00423 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
00424 {
00425    int level = SPAN_LOG_WARNING;
00426 
00427         if (details->option.debug) {
00428       level = SPAN_LOG_DEBUG_3;
00429    }
00430 
00431    span_log_set_message_handler(state, spandsp_log);
00432    span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
00433 }
00434 
00435 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
00436 {
00437    if (!ast_strlen_zero(details->localstationid)) {
00438       t30_set_tx_ident(t30_state, details->localstationid);
00439    }
00440 
00441    if (!ast_strlen_zero(details->headerinfo)) {
00442       t30_set_tx_page_header_info(t30_state, details->headerinfo);
00443    }
00444 }
00445 
00446 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
00447 {
00448    if (details->caps & AST_FAX_TECH_RECEIVE) {
00449       t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
00450    } else {
00451       /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
00452        * should be safe because we ensure either RECEIVE or SEND is
00453        * indicated in spandsp_fax_new() */
00454       t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
00455    }
00456 }
00457 
00458 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
00459 {
00460    t30_set_ecm_capability(t30_state, details->option.ecm);
00461    t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
00462 }
00463 
00464 static int spandsp_v21_new(struct spandsp_pvt *p)
00465 {
00466    /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
00467     * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
00468     * doesn't seem to work right all the time.
00469     */
00470    p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
00471    if (!p->tone_state) {
00472       return -1;
00473    }
00474 
00475    return 0;
00476 }
00477 
00478 static int spandsp_modems(struct ast_fax_session_details *details)
00479 {
00480    int modems = 0;
00481    if (AST_FAX_MODEM_V17 & details->modems) {
00482       modems |= T30_SUPPORT_V17;
00483    }
00484    if (AST_FAX_MODEM_V27 & details->modems) {
00485       modems |= T30_SUPPORT_V27TER;
00486    }
00487    if (AST_FAX_MODEM_V29 & details->modems) {
00488       modems |= T30_SUPPORT_V29;
00489    }
00490    if (AST_FAX_MODEM_V34 & details->modems) {
00491 #if defined(T30_SUPPORT_V34)
00492       modems |= T30_SUPPORT_V34;
00493 #elif defined(T30_SUPPORT_V34HDX)
00494       modems |= T30_SUPPORT_V34HDX;
00495 #else
00496       ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
00497 #endif
00498    }
00499 
00500    return modems;
00501 }
00502 
00503 /*! \brief create an instance of the spandsp tech_pvt for a fax session */
00504 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
00505 {
00506    struct spandsp_pvt *p;
00507    int caller_mode;
00508 
00509    if ((!(p = ast_calloc(1, sizeof(*p))))) {
00510       ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
00511       goto e_return;
00512    }
00513 
00514    if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
00515       if (spandsp_v21_new(p)) {
00516          ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
00517          goto e_return;
00518       }
00519       s->state = AST_FAX_STATE_ACTIVE;
00520       return p;
00521    }
00522 
00523    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
00524       s->state = AST_FAX_STATE_INITIALIZED;
00525       return p;
00526    }
00527 
00528    AST_LIST_HEAD_INIT(&p->read_frames);
00529 
00530    if (s->details->caps & AST_FAX_TECH_RECEIVE) {
00531       caller_mode = 0;
00532    } else if (s->details->caps & AST_FAX_TECH_SEND) {
00533       caller_mode = 1;
00534    } else {
00535       ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
00536       goto e_free;
00537    }
00538 
00539    if (!(p->timer = ast_timer_open())) {
00540       ast_log(LOG_ERROR, "Channel '%s' FAX session '%d' failed to create timing source.\n", s->channame, s->id);
00541       goto e_free;
00542    }
00543 
00544    s->fd = ast_timer_fd(p->timer);
00545 
00546    p->stats = &spandsp_global_stats.g711;
00547 
00548    if (s->details->caps & (AST_FAX_TECH_T38 | AST_FAX_TECH_AUDIO)) {
00549       if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
00550          /* audio mode was not requested, start in T.38 mode */
00551          p->ist38 = 1;
00552          p->stats = &spandsp_global_stats.t38;
00553       }
00554 
00555       /* init t38 stuff */
00556       t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
00557       set_logging(&p->t38_state.logging, s->details);
00558 
00559       /* init audio stuff */
00560       fax_init(&p->fax_state, caller_mode);
00561       set_logging(&p->fax_state.logging, s->details);
00562    }
00563 
00564    s->state = AST_FAX_STATE_INITIALIZED;
00565    return p;
00566 
00567 e_free:
00568    ast_free(p);
00569 e_return:
00570    return NULL;
00571 }
00572 
00573 static void spandsp_v21_cleanup(struct ast_fax_session *s) {
00574    struct spandsp_pvt *p = s->tech_pvt;
00575    modem_connect_tones_rx_free(p->tone_state);
00576 }
00577 
00578 /*! \brief Destroy a spandsp fax session.
00579  */
00580 static void spandsp_fax_destroy(struct ast_fax_session *s)
00581 {
00582    struct spandsp_pvt *p = s->tech_pvt;
00583 
00584    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
00585       spandsp_fax_gateway_cleanup(s);
00586    } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
00587       spandsp_v21_cleanup(s);
00588    } else {
00589       session_destroy(p);
00590    }
00591 
00592    ast_free(p);
00593    s->tech_pvt = NULL;
00594    s->fd = -1;
00595 }
00596 
00597 /*! \brief Read a frame from the spandsp fax stack.
00598  */
00599 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
00600 {
00601    struct spandsp_pvt *p = s->tech_pvt;
00602    uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
00603    int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
00604    int samples;
00605 
00606    struct ast_frame fax_frame = {
00607       .frametype = AST_FRAME_VOICE,
00608       .src = "res_fax_spandsp_g711",
00609    };
00610    struct ast_frame *f = &fax_frame;
00611    ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
00612 
00613    if (ast_timer_ack(p->timer, 1) < 0) {
00614       ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%d'\n", s->id);
00615       return NULL;
00616    }
00617 
00618    /* XXX do we need to lock here? */
00619    if (p->isdone) {
00620       s->state = AST_FAX_STATE_COMPLETE;
00621       ast_debug(5, "FAX session '%d' is complete.\n", s->id);
00622       return NULL;
00623    }
00624 
00625    if (p->ist38) {
00626       t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
00627       if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00628          return f;
00629       }
00630    } else {
00631       if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
00632          f->samples = samples;
00633          AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
00634          return ast_frisolate(f);
00635       }
00636    }
00637 
00638    return &ast_null_frame;
00639 }
00640 
00641 static void spandsp_v21_tone(void *data, int code, int level, int delay)
00642 {
00643    struct spandsp_pvt *p = data;
00644 
00645    if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
00646       p->v21_detected = 1;
00647    }
00648 }
00649 
00650 static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f) {
00651    struct spandsp_pvt *p = s->tech_pvt;
00652    int16_t *slndata;
00653    g711_state_t *decoder;
00654 
00655    if (p->v21_detected) {
00656       return 0;
00657    }
00658 
00659    /*invalid frame*/
00660    if (!f->data.ptr || !f->datalen) {
00661       return -1;
00662    }
00663 
00664    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);
00665 
00666    /* slinear frame can be passed to spandsp */
00667    if (f->subclass.format.id == AST_FORMAT_SLINEAR) {
00668       modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
00669 
00670    /* alaw/ulaw frame must be converted to slinear before passing to spandsp */
00671    } else if (f->subclass.format.id == AST_FORMAT_ALAW || f->subclass.format.id == AST_FORMAT_ULAW) {
00672       if (!(slndata = ast_malloc(sizeof(*slndata) * f->samples))) {
00673          return -1;
00674       }
00675       decoder = g711_init(NULL, (f->subclass.format.id == AST_FORMAT_ALAW ? G711_ALAW : G711_ULAW));
00676       g711_decode(decoder, slndata, f->data.ptr, f->samples);
00677       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"));
00678       modem_connect_tones_rx(p->tone_state, slndata, f->samples);
00679       g711_release(decoder);
00680 #if SPANDSP_RELEASE_DATE >= 20090220
00681       g711_free(decoder);
00682 #endif
00683       ast_free(slndata);
00684 
00685    /* frame in other formats cannot be passed to spandsp, it could cause segfault */
00686    } else {
00687       ast_log(LOG_WARNING, "Unknown frame format %d, v.21 detection skipped\n", f->subclass.format.id);
00688       return -1;
00689    }
00690 
00691    if (p->v21_detected) {
00692       s->details->option.v21_detected = 1;
00693       ast_debug(5, "v.21 detected\n");
00694    }
00695 
00696    return 0;
00697 }
00698 
00699 /*! \brief Write a frame to the spandsp fax stack.
00700  * \param s a fax session
00701  * \param f the frame to write
00702  *
00703  * \note res_fax does not currently use the return value of this function.
00704  * Also the fax_rx() function never fails.
00705  *
00706  * \retval 0 success
00707  * \retval -1 failure
00708  */
00709 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
00710 {
00711    struct spandsp_pvt *p = s->tech_pvt;
00712 
00713    if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
00714       return spandsp_v21_detect(s, f);
00715    }
00716 
00717    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
00718       return spandsp_fax_gateway_process(s, f);
00719    }
00720 
00721    /* XXX do we need to lock here? */
00722    if (s->state == AST_FAX_STATE_COMPLETE) {
00723       ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
00724       return -1;
00725    }
00726 
00727    if (p->ist38) {
00728       return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
00729    } else {
00730       return fax_rx(&p->fax_state, f->data.ptr, f->samples);
00731    }
00732 }
00733 
00734 /*! \brief generate T.30 packets sent to the T.30 leg of gateway
00735  * \param chan T.30 channel
00736  * \param data fax session structure
00737  * \param len not used
00738  * \param samples no of samples generated
00739  * \return -1 on failure or 0 on sucess*/
00740 static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
00741 {
00742    int res = -1;
00743    struct ast_fax_session *s = data;
00744    struct spandsp_pvt *p = s->tech_pvt;
00745    uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
00746    struct ast_frame *f;
00747    struct ast_frame t30_frame = {
00748       .frametype = AST_FRAME_VOICE,
00749       .src = "res_fax_spandsp_g711",
00750       .samples = samples,
00751       .flags = AST_FAX_FRFLAG_GATEWAY,
00752    };
00753 
00754    AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
00755 
00756    ast_format_set(&t30_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
00757    if (!(f = ast_frisolate(&t30_frame))) {
00758       return p->isdone ? -1 : res;
00759    }
00760 
00761    /* generate a T.30 packet */
00762    if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
00763       f->datalen = f->samples * sizeof(int16_t);
00764       res = ast_write(chan, f);
00765    }
00766    ast_frfree(f);
00767    return p->isdone ? -1 : res;
00768 }
00769 
00770 /*! \brief simple routine to allocate data to generator
00771  * \param chan channel
00772  * \param params generator data
00773  * \return data to use in generator call*/
00774 static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params) {
00775    ao2_ref(params, +1);
00776    return params;
00777 }
00778 
00779 static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data) {
00780    ao2_ref(data, -1);
00781 }
00782 
00783 /*! \brief activate a spandsp gateway based on the information in the given fax session
00784  * \param s fax session
00785  * \return -1 on error 0 on sucess*/
00786 static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
00787    struct spandsp_pvt *p = s->tech_pvt;
00788    struct ast_fax_t38_parameters *t38_param;
00789    int i;
00790    struct ast_channel *peer;
00791    static struct ast_generator t30_gen = {
00792       .alloc = spandsp_fax_gw_gen_alloc,
00793       .release = spandsp_fax_gw_gen_release,
00794       .generate = spandsp_fax_gw_t30_gen,
00795    };
00796 
00797 #if SPANDSP_RELEASE_DATE >= 20081012
00798    /* for spandsp shaphots 0.0.6 and higher */
00799    p->t38_core_state=&p->t38_gw_state.t38x.t38;
00800 #else
00801    /* for spandsp release 0.0.5 */
00802    p->t38_core_state=&p->t38_gw_state.t38;
00803 #endif
00804 
00805    if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
00806       return -1;
00807    }
00808 
00809    p->ist38 = 1;
00810    p->ast_t38_state = ast_channel_get_t38_state(s->chan);
00811    if (!(peer = ast_bridged_channel(s->chan))) {
00812       ast_channel_unlock(s->chan);
00813       return -1;
00814    }
00815 
00816    /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
00817     * gateway is started. We treat both states the same. */
00818    if (p->ast_t38_state == T38_STATE_NEGOTIATING) {
00819       p->ast_t38_state = T38_STATE_NEGOTIATED;
00820    }
00821 
00822    ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
00823 
00824    set_logging(&p->t38_gw_state.logging, s->details);
00825    set_logging(&p->t38_core_state->logging, s->details);
00826 
00827    t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
00828    t38_set_t38_version(p->t38_core_state, t38_param->version);
00829    t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
00830    t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
00831    t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
00832    t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
00833    t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
00834    t38_set_data_rate_management_method(p->t38_core_state, 
00835          (t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
00836 
00837    t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
00838    t38_set_sequence_number_handling(p->t38_core_state, TRUE);
00839 
00840 
00841    t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details));
00842 
00843    /* engage udptl nat on other side of T38 line 
00844     * (Asterisk changes media ports thus we send a few packets to reinitialize
00845     * pinholes in NATs and FWs
00846     */
00847    for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
00848 #if SPANDSP_RELEASE_DATE >= 20091228
00849       t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
00850 #elif SPANDSP_RELEASE_DATE >= 20081012
00851       t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
00852 #else
00853       t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
00854 #endif
00855    }
00856 
00857    s->state = AST_FAX_STATE_ACTIVE;
00858 
00859    return 0;
00860 }
00861 
00862 /*! \brief process a frame from the bridge
00863  * \param s fax session
00864  * \param f frame to process
00865  * \return 1 on sucess 0 on incorect packet*/
00866 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
00867 {
00868    struct spandsp_pvt *p = s->tech_pvt;
00869 
00870    /*invalid frame*/
00871    if (!f->data.ptr || !f->datalen) {
00872       return -1;
00873    }
00874 
00875    /* Process a IFP packet */
00876    if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
00877       return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
00878    } else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
00879       return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
00880    }
00881 
00882    return -1;
00883 }
00884 
00885 /*! \brief gather data and clean up after gateway ends
00886  * \param s fax session*/
00887 static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
00888 {
00889    struct spandsp_pvt *p = s->tech_pvt;
00890    t38_stats_t t38_stats;
00891 
00892    t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
00893 
00894    s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
00895    s->details->pages_transferred = t38_stats.pages_transferred;
00896    ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
00897 }
00898 
00899 /*! \brief */
00900 static int spandsp_fax_start(struct ast_fax_session *s)
00901 {
00902    struct spandsp_pvt *p = s->tech_pvt;
00903 
00904    s->state = AST_FAX_STATE_OPEN;
00905 
00906    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
00907       return spandsp_fax_gateway_start(s);
00908    }
00909 
00910    if (p->ist38) {
00911 #if SPANDSP_RELEASE_DATE >= 20080725
00912       /* for spandsp shaphots 0.0.6 and higher */
00913       p->t30_state = &p->t38_state.t30;
00914       p->t38_core_state = &p->t38_state.t38_fe.t38;
00915 #else
00916       /* for spandsp releases 0.0.5 */
00917       p->t30_state = &p->t38_state.t30_state;
00918       p->t38_core_state = &p->t38_state.t38;
00919 #endif
00920    } else {
00921 #if SPANDSP_RELEASE_DATE >= 20080725
00922       /* for spandsp shaphots 0.0.6 and higher */
00923       p->t30_state = &p->fax_state.t30;
00924 #else
00925       /* for spandsp release 0.0.5 */
00926       p->t30_state = &p->fax_state.t30_state;
00927 #endif
00928    }
00929 
00930    set_logging(&p->t30_state->logging, s->details);
00931 
00932    /* set some parameters */
00933    set_local_info(p->t30_state, s->details);
00934    set_file(p->t30_state, s->details);
00935    set_ecm(p->t30_state, s->details);
00936    t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
00937 
00938    /* perhaps set_transmit_on_idle() should be called */
00939 
00940    t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
00941 
00942    /* set T.38 parameters */
00943    if (p->ist38) {
00944       set_logging(&p->t38_core_state->logging, s->details);
00945 
00946       t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
00947 
00948       if (s->details->their_t38_parameters.fill_bit_removal) {
00949          t38_set_fill_bit_removal(p->t38_core_state, TRUE);
00950       }
00951 
00952       if (s->details->their_t38_parameters.transcoding_mmr) {
00953          t38_set_mmr_transcoding(p->t38_core_state, TRUE);
00954       }
00955 
00956       if (s->details->their_t38_parameters.transcoding_jbig) {
00957          t38_set_jbig_transcoding(p->t38_core_state, TRUE);
00958       }
00959    } else {
00960       /* have the fax stack generate silence if it has no data to send */
00961       fax_set_transmit_on_idle(&p->fax_state, 1);
00962    }
00963 
00964 
00965    /* start the timer */
00966    if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
00967       ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
00968       return -1;
00969    }
00970 
00971    s->state = AST_FAX_STATE_ACTIVE;
00972 
00973    return 0;
00974 }
00975 
00976 /*! \brief */
00977 static int spandsp_fax_cancel(struct ast_fax_session *s)
00978 {
00979    struct spandsp_pvt *p = s->tech_pvt;
00980 
00981    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
00982       p->isdone = 1;
00983       return 0;
00984    }
00985 
00986    t30_terminate(p->t30_state);
00987    p->isdone = 1;
00988    return 0;
00989 }
00990 
00991 /*! \brief */
00992 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
00993 {
00994    struct spandsp_pvt *p = s->tech_pvt;
00995 
00996    /* prevent the phase E handler from running, this is not a real termination */
00997    t30_set_phase_e_handler(p->t30_state, NULL, NULL);
00998 
00999    t30_terminate(p->t30_state);
01000 
01001    s->details->option.switch_to_t38 = 1;
01002    ast_atomic_fetchadd_int(&p->stats->switched, 1);
01003 
01004    p->ist38 = 1;
01005    p->stats = &spandsp_global_stats.t38;
01006    spandsp_fax_start(s);
01007 
01008    return 0;
01009 }
01010 
01011 /*! \brief */
01012 static char *spandsp_fax_cli_show_capabilities(int fd)
01013 {
01014    ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
01015    return  CLI_SUCCESS;
01016 }
01017 
01018 /*! \brief */
01019 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
01020 {
01021    ao2_lock(s);
01022    if (s->details->caps & AST_FAX_TECH_GATEWAY) {
01023       struct spandsp_pvt *p = s->tech_pvt;
01024 
01025       ast_cli(fd, "%-22s : %d\n", "session", s->id);
01026       ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
01027       ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
01028       if (s->state != AST_FAX_STATE_UNINITIALIZED) {
01029          t38_stats_t stats;
01030          t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
01031          ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
01032          ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
01033          ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
01034       }
01035    } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
01036       ast_cli(fd, "%-22s : %d\n", "session", s->id);
01037       ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
01038       ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
01039    } else {
01040       struct spandsp_pvt *p = s->tech_pvt;
01041 
01042       ast_cli(fd, "%-22s : %d\n", "session", s->id);
01043       ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
01044       ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
01045       if (s->state != AST_FAX_STATE_UNINITIALIZED) {
01046          t30_stats_t stats;
01047          t30_get_transfer_statistics(p->t30_state, &stats);
01048          ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
01049          ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
01050          ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
01051          ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
01052 #if SPANDSP_RELEASE_DATE >= 20090220
01053          ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
01054 #else
01055          ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
01056 #endif
01057          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);
01058 
01059          ast_cli(fd, "\nData Statistics:\n");
01060 #if SPANDSP_RELEASE_DATE >= 20090220
01061          ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
01062          ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
01063 #else
01064          ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
01065          ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
01066 #endif
01067          ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
01068          ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
01069       }
01070    }
01071    ao2_unlock(s);
01072    ast_cli(fd, "\n\n");
01073    return CLI_SUCCESS;
01074 }
01075 
01076 /*! \brief */
01077 static char *spandsp_fax_cli_show_stats(int fd)
01078 {
01079    ast_mutex_lock(&spandsp_global_stats.lock);
01080    ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
01081    ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
01082    ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
01083    ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
01084    ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
01085    ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
01086    ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
01087    ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
01088    ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
01089    ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
01090    ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
01091    ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
01092    ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
01093    ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
01094 
01095    ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
01096    ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
01097    ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
01098    ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
01099    ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
01100    ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
01101    ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
01102    ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
01103    ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
01104    ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
01105    ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
01106    ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
01107    ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
01108    ast_mutex_unlock(&spandsp_global_stats.lock);
01109 
01110    return CLI_SUCCESS;
01111 }
01112 
01113 /*! \brief Show res_fax_spandsp settings */
01114 static char *spandsp_fax_cli_show_settings(int fd)
01115 {
01116    /* no settings at the moment */
01117    return CLI_SUCCESS;
01118 }
01119 
01120 /*! \brief unload res_fax_spandsp */
01121 static int unload_module(void)
01122 {
01123    ast_fax_tech_unregister(&spandsp_fax_tech);
01124    ast_mutex_destroy(&spandsp_global_stats.lock);
01125    return AST_MODULE_LOAD_SUCCESS;
01126 }
01127 
01128 /*! \brief load res_fax_spandsp */
01129 static int load_module(void)
01130 {
01131    ast_mutex_init(&spandsp_global_stats.lock);
01132    spandsp_fax_tech.module = ast_module_info->self;
01133    if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
01134       ast_log(LOG_ERROR, "failed to register FAX technology\n");
01135       return AST_MODULE_LOAD_DECLINE;
01136    }
01137 
01138    /* prevent logging to stderr */
01139    span_set_message_handler(NULL);
01140 
01141    return AST_MODULE_LOAD_SUCCESS;
01142 }
01143 
01144 
01145 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
01146       .load = load_module,
01147       .unload = unload_module,
01148           );