Tue Mar 2 17:31:42 2010

Asterisk developer's documentation


app_fax.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Simple fax applications
00005  * 
00006  * 2007-2008, Dmitry Andrianov <asterisk@dima.spb.ru>
00007  *
00008  * Code based on original implementation by Steve Underwood <steveu@coppice.org>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  *
00013  */
00014 
00015 /*** MODULEINFO
00016     <depend>spandsp</depend>
00017 ***/
00018  
00019 #include "asterisk.h"
00020 
00021 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 235012 $")
00022 
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <inttypes.h>
00027 #include <pthread.h>
00028 #include <errno.h>
00029 #include <tiffio.h>
00030 
00031 #include <spandsp.h>
00032 #ifdef HAVE_SPANDSP_EXPOSE_H
00033 #include <spandsp/expose.h>
00034 #endif
00035 #include <spandsp/version.h>
00036 
00037 #include "asterisk/lock.h"
00038 #include "asterisk/file.h"
00039 #include "asterisk/logger.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/dsp.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/manager.h"
00046 
00047 static char *app_sndfax_name = "SendFAX";
00048 static char *app_sndfax_synopsis = "Send a FAX";
00049 static char *app_sndfax_desc = 
00050 "  SendFAX(filename[|options]):\n"
00051 "Send a given TIFF file to the channel as a FAX.\n"
00052 "The option string may contain zero or more of the following characters:\n"
00053 "     'a' - makes the application behave as an answering machine\n"
00054 "           The default behaviour is to behave as a calling machine.\n"
00055 "\n"
00056 "This application uses following variables:\n"
00057 "     LOCALSTATIONID to identify itself to the remote end.\n"
00058 "     LOCALHEADERINFO to generate a header line on each page.\n"
00059 "\n"
00060 "This application sets the following channel variables upon completion:\n"
00061 "     FAXSTATUS       - status of operation:\n"
00062 "                           SUCCESS | FAILED\n"
00063 "     FAXERROR        - Error when FAILED\n"
00064 "     FAXMODE         - Mode used:\n"
00065 "                           audio | T38\n"
00066 "     REMOTESTATIONID - CSID of the remote side.\n"
00067 "     FAXPAGES        - number of pages sent.\n"
00068 "     FAXBITRATE      - transmition rate.\n"
00069 "     FAXRESOLUTION   - resolution.\n"
00070 "\n"
00071 "Returns -1 in case of user hang up or any channel error.\n"
00072 "Returns 0 on success.\n";
00073 
00074 static char *app_rcvfax_name = "ReceiveFAX";
00075 static char *app_rcvfax_synopsis = "Receive a FAX";
00076 static char *app_rcvfax_desc = 
00077 "  ReceiveFAX(filename[|options]):\n"
00078 "Receives a fax from the channel into the given filename overwriting\n"
00079 "the file if it already exists. File created will have TIFF format.\n"
00080 "The option string may contain zero or more of the following characters:\n"
00081 "     'c' -- makes the application behave as a calling machine\n"
00082 "            The default behaviour is to behave as an answering machine.\n"
00083 "\n"
00084 "This application uses following variables:\n"
00085 "     LOCALSTATIONID to identify itself to the remote end.\n"
00086 "     LOCALHEADERINFO to generate a header line on each page.\n"
00087 "\n"
00088 "This application sets the following channel variables upon completion:\n"
00089 "     FAXSTATUS       - status of operation:\n"
00090 "                           SUCCESS | FAILED\n"
00091 "     FAXERROR        - Error when FAILED\n"
00092 "     FAXMODE         - Mode used:\n"
00093 "                           audio | T38\n"
00094 "     REMOTESTATIONID - CSID of the remote side.\n"
00095 "     FAXPAGES        - number of pages sent.\n"
00096 "     FAXBITRATE      - transmition rate.\n"
00097 "     FAXRESOLUTION   - resolution.\n"
00098 "\n"
00099 "Returns -1 in case of user hang up or any channel error.\n"
00100 "Returns 0 on success.\n";
00101 
00102 #define MAX_SAMPLES 240
00103 
00104 /* Watchdog. I have seen situations when remote fax disconnects (because of poor line
00105    quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
00106    To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
00107    We also terminate application when more than 30 minutes passed regardless of
00108    state changes. This is just a precaution measure - no fax should take that long */
00109 
00110 #define WATCHDOG_TOTAL_TIMEOUT   30 * 60
00111 #define WATCHDOG_STATE_TIMEOUT   5 * 60
00112 
00113 typedef struct {
00114    struct ast_channel *chan;
00115    enum ast_t38_state t38state;  /* T38 state of the channel */
00116    int direction;       /* Fax direction: 0 - receiving, 1 - sending */
00117    int caller_mode;
00118    char *file_name;
00119    struct ast_control_t38_parameters t38parameters;
00120    volatile int finished;
00121 } fax_session;
00122 
00123 static void span_message(int level, const char *msg)
00124 {
00125    if (level == SPAN_LOG_ERROR) {
00126       ast_log(LOG_ERROR, "%s", msg);
00127    } else if (level == SPAN_LOG_WARNING) {
00128       ast_log(LOG_WARNING, "%s", msg);
00129    } else {
00130       ast_log(LOG_DEBUG, "%s", msg);
00131    }
00132 }
00133 
00134 static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
00135 {
00136    struct ast_channel *chan = (struct ast_channel *) user_data;
00137 
00138    struct ast_frame outf = {
00139       .frametype = AST_FRAME_MODEM,
00140       .subclass = AST_MODEM_T38,
00141       .src = __FUNCTION__,
00142    };
00143 
00144    /* TODO: Asterisk does not provide means of resending the same packet multiple
00145      times so count is ignored at the moment */
00146 
00147    AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
00148 
00149    if (ast_write(chan, &outf) < 0) {
00150       ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
00151       return -1;
00152    }
00153 
00154    return 0;
00155 }
00156 
00157 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
00158 {
00159    const char *local_ident;
00160    const char *far_ident;
00161    char buf[20];
00162    fax_session *s = (fax_session *) user_data;
00163    t30_stats_t stat;
00164    int pages_transferred;
00165 
00166    ast_debug(1, "Fax phase E handler. result=%d\n", result);
00167 
00168    t30_get_transfer_statistics(f, &stat);
00169 
00170    s = (fax_session *) user_data;
00171 
00172    if (result != T30_ERR_OK) {
00173       s->finished = -1;
00174 
00175       /* FAXSTATUS is already set to FAILED */
00176       pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
00177 
00178       ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
00179 
00180       return;
00181    }
00182    
00183    s->finished = 1; 
00184    
00185    local_ident = t30_get_tx_ident(f);
00186    far_ident = t30_get_rx_ident(f);
00187    pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); 
00188    pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); 
00189    pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
00190 #if SPANDSP_RELEASE_DATE >= 20090220
00191    pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
00192 #else
00193    pages_transferred = stat.pages_transferred;
00194 #endif
00195    snprintf(buf, sizeof(buf), "%d", pages_transferred);
00196    pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
00197    snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
00198    pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
00199    snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
00200    pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); 
00201    
00202    ast_debug(1, "Fax transmitted successfully.\n");
00203    ast_debug(1, "  Remote station ID: %s\n", far_ident);
00204    ast_debug(1, "  Pages transferred: %d\n", pages_transferred);
00205    ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
00206    ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);
00207    
00208    manager_event(EVENT_FLAG_CALL,
00209             s->direction ? "FaxSent" : "FaxReceived", 
00210             "Channel: %s\r\n"
00211             "Exten: %s\r\n"
00212             "CallerID: %s\r\n"
00213             "RemoteStationID: %s\r\n"
00214             "LocalStationID: %s\r\n"
00215             "PagesTransferred: %d\r\n"
00216             "Resolution: %d\r\n"
00217             "TransferRate: %d\r\n"
00218             "FileName: %s\r\n",
00219             s->chan->name,
00220             s->chan->exten,
00221             S_OR(s->chan->cid.cid_num, ""),
00222             far_ident,
00223             local_ident,
00224             pages_transferred,
00225             stat.y_resolution,
00226             stat.bit_rate,
00227             s->file_name);
00228 }
00229 
00230 /* === Helper functions to configure fax === */
00231 
00232 /* Setup SPAN logging according to Asterisk debug level */
00233 static int set_logging(logging_state_t *state)
00234 {
00235    int level = SPAN_LOG_WARNING + option_debug;
00236 
00237    span_log_set_message_handler(state, span_message);
00238    span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 
00239 
00240    return 0;
00241 }
00242 
00243 static void set_local_info(t30_state_t *state, fax_session *s)
00244 {
00245    const char *x;
00246 
00247    x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
00248    if (!ast_strlen_zero(x))
00249       t30_set_tx_ident(state, x);
00250 
00251    x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
00252    if (!ast_strlen_zero(x))
00253       t30_set_tx_page_header_info(state, x);
00254 }
00255 
00256 static void set_file(t30_state_t *state, fax_session *s)
00257 {
00258    if (s->direction)
00259       t30_set_tx_file(state, s->file_name, -1, -1);
00260    else
00261       t30_set_rx_file(state, s->file_name, -1);
00262 }
00263 
00264 static void set_ecm(t30_state_t *state, int ecm)
00265 {
00266    t30_set_ecm_capability(state, ecm);
00267    t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
00268 }
00269 
00270 /* === Generator === */
00271 
00272 /* This function is only needed to return passed params so
00273    generator_activate will save it to channel's generatordata */
00274 static void *fax_generator_alloc(struct ast_channel *chan, void *params)
00275 {
00276    return params;
00277 }
00278 
00279 static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
00280 {
00281    fax_state_t *fax = (fax_state_t*) data;
00282    uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
00283    int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
00284     
00285    struct ast_frame outf = {
00286       .frametype = AST_FRAME_VOICE,
00287       .subclass = AST_FORMAT_SLINEAR,
00288       .src = __FUNCTION__,
00289    };
00290 
00291    if (samples > MAX_SAMPLES) {
00292       ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
00293       samples = MAX_SAMPLES;
00294    }
00295    
00296    if ((len = fax_tx(fax, buf, samples)) > 0) {
00297       outf.samples = len;
00298       AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
00299 
00300       if (ast_write(chan, &outf) < 0) {
00301          ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00302          return -1;
00303       }
00304    }
00305 
00306    return 0;
00307 }
00308 
00309 struct ast_generator generator = {
00310    alloc:      fax_generator_alloc,
00311    generate:   fax_generator_generate,
00312 };
00313 
00314 
00315 /* === Transmission === */
00316 
00317 static int transmit_audio(fax_session *s)
00318 {
00319    int res = -1;
00320    int original_read_fmt = AST_FORMAT_SLINEAR;
00321    int original_write_fmt = AST_FORMAT_SLINEAR;
00322    fax_state_t fax;
00323    t30_state_t *t30state;
00324    struct ast_frame *inf = NULL;
00325    int last_state = 0;
00326    struct timeval now, start, state_change;
00327    enum ast_t38_state t38_state;
00328    struct ast_control_t38_parameters t38_parameters = { .version = 0,
00329                           .max_ifp = 800,
00330                           .rate = AST_T38_RATE_14400,
00331                           .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
00332                           .fill_bit_removal = 1,
00333                           .transcoding_mmr = 1,
00334                           .transcoding_jbig = 1,
00335    };
00336 
00337    /* if in called party mode, try to use T.38 */
00338    if (s->caller_mode == FALSE) {
00339       /* check if we are already in T.38 mode (unlikely), or if we can request
00340        * a switch... if so, request it now and wait for the result, rather
00341        * than starting an audio FAX session that will have to be cancelled
00342        */
00343       if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
00344          return 1;
00345       } else if ((t38_state != T38_STATE_UNAVAILABLE) &&
00346             (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE,
00347              (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
00348          /* wait up to five seconds for negotiation to complete */
00349          unsigned int timeout = 5000;
00350          int ms;
00351          
00352          ast_debug(1, "Negotiating T.38 for receive on %s\n", s->chan->name);
00353          while (timeout > 0) {
00354             ms = ast_waitfor(s->chan, 1000);
00355             if (ms < 0) {
00356                ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name);
00357                return -1;
00358             }
00359             if (!ms) {
00360                /* nothing happened */
00361                if (timeout > 0) {
00362                   timeout -= 1000;
00363                   continue;
00364                } else {
00365                   ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", s->chan->name);
00366                   break;
00367                }
00368             }
00369             if (!(inf = ast_read(s->chan))) {
00370                return -1;
00371             }
00372             if ((inf->frametype == AST_FRAME_CONTROL) &&
00373                 (inf->subclass == AST_CONTROL_T38_PARAMETERS) &&
00374                 (inf->datalen == sizeof(t38_parameters))) {
00375                struct ast_control_t38_parameters *parameters = inf->data.ptr;
00376                
00377                switch (parameters->request_response) {
00378                case AST_T38_NEGOTIATED:
00379                   ast_debug(1, "Negotiated T.38 for receive on %s\n", s->chan->name);
00380                   res = 1;
00381                   break;
00382                case AST_T38_REFUSED:
00383                   ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", s->chan->name);
00384                   break;
00385                default:
00386                   ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", s->chan->name);
00387                   break;
00388                }
00389                ast_frfree(inf);
00390                if (res == 1) {
00391                   return 1;
00392                } else {
00393                   break;
00394                }
00395             }
00396             ast_frfree(inf);
00397          }
00398       }
00399    }
00400 
00401 #if SPANDSP_RELEASE_DATE >= 20080725
00402         /* for spandsp shaphots 0.0.6 and higher */
00403         t30state = &fax.t30;
00404 #else
00405         /* for spandsp release 0.0.5 */
00406         t30state = &fax.t30_state;
00407 #endif
00408 
00409    original_read_fmt = s->chan->readformat;
00410    if (original_read_fmt != AST_FORMAT_SLINEAR) {
00411       res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
00412       if (res < 0) {
00413          ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
00414          goto done;
00415       }
00416    }
00417 
00418    original_write_fmt = s->chan->writeformat;
00419    if (original_write_fmt != AST_FORMAT_SLINEAR) {
00420       res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
00421       if (res < 0) {
00422          ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
00423          goto done;
00424       }
00425    }
00426 
00427    /* Initialize T30 terminal */
00428    fax_init(&fax, s->caller_mode);
00429 
00430    /* Setup logging */
00431    set_logging(&fax.logging);
00432    set_logging(&t30state->logging);
00433 
00434    /* Configure terminal */
00435    set_local_info(t30state, s);
00436    set_file(t30state, s);
00437    set_ecm(t30state, TRUE);
00438 
00439    fax_set_transmit_on_idle(&fax, TRUE);
00440 
00441    t30_set_phase_e_handler(t30state, phase_e_handler, s);
00442 
00443    start = state_change = ast_tvnow();
00444 
00445    ast_activate_generator(s->chan, &generator, &fax);
00446 
00447    while (!s->finished) {
00448       inf = NULL;
00449 
00450       if ((res = ast_waitfor(s->chan, 25)) < 0) {
00451          ast_debug(1, "Error waiting for a frame\n");
00452          break;
00453       }
00454 
00455       /* Watchdog */
00456       now = ast_tvnow();
00457       if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
00458          ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
00459          res = -1;
00460          break;
00461       }
00462 
00463       if (!res) {
00464          /* There was timeout waiting for a frame. Loop around and wait again */
00465          continue;
00466       }
00467 
00468       /* There is a frame available. Get it */
00469       res = 0;
00470 
00471       if (!(inf = ast_read(s->chan))) {
00472          ast_debug(1, "Channel hangup\n");
00473          res = -1;
00474          break;
00475       }
00476 
00477       ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
00478 
00479       /* Check the frame type. Format also must be checked because there is a chance
00480          that a frame in old format was already queued before we set channel format
00481          to slinear so it will still be received by ast_read */
00482       if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
00483          if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
00484             /* I know fax_rx never returns errors. The check here is for good style only */
00485             ast_log(LOG_WARNING, "fax_rx returned error\n");
00486             res = -1;
00487             break;
00488          }
00489          if (last_state != t30state->state) {
00490             state_change = ast_tvnow();
00491             last_state = t30state->state;
00492          }
00493       } else if ((inf->frametype == AST_FRAME_CONTROL) &&
00494             (inf->subclass == AST_CONTROL_T38_PARAMETERS)) {
00495          struct ast_control_t38_parameters *parameters = inf->data.ptr;
00496 
00497          if (parameters->request_response == AST_T38_NEGOTIATED) {
00498             /* T38 switchover completed */
00499             s->t38parameters = *parameters;
00500             ast_debug(1, "T38 negotiated, finishing audio loop\n");
00501             res = 1;
00502             break;
00503          } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
00504             t38_parameters.request_response = AST_T38_NEGOTIATED;
00505             ast_debug(1, "T38 request received, accepting\n");
00506             /* Complete T38 switchover */
00507             ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
00508             /* Do not break audio loop, wait until channel driver finally acks switchover
00509              * with AST_T38_NEGOTIATED
00510              */
00511          }
00512       }
00513 
00514       ast_frfree(inf);
00515    }
00516 
00517    ast_debug(1, "Loop finished, res=%d\n", res);
00518 
00519    if (inf)
00520       ast_frfree(inf);
00521 
00522    ast_deactivate_generator(s->chan);
00523 
00524    /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
00525       by t30_terminate, display diagnostics and set status variables although no transmittion
00526       has taken place yet. */
00527    if (res > 0) {
00528       t30_set_phase_e_handler(t30state, NULL, NULL);
00529    }
00530 
00531    t30_terminate(t30state);
00532    fax_release(&fax);
00533 
00534 done:
00535    if (original_write_fmt != AST_FORMAT_SLINEAR) {
00536       if (ast_set_write_format(s->chan, original_write_fmt) < 0)
00537          ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
00538    }
00539 
00540    if (original_read_fmt != AST_FORMAT_SLINEAR) {
00541       if (ast_set_read_format(s->chan, original_read_fmt) < 0)
00542          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
00543    }
00544 
00545    return res;
00546 
00547 }
00548 
00549 static int transmit_t38(fax_session *s)
00550 {
00551    int res = 0;
00552    t38_terminal_state_t t38;
00553    struct ast_frame *inf = NULL;
00554    int last_state = 0;
00555    struct timeval now, start, state_change, last_frame;
00556    t30_state_t *t30state;
00557    t38_core_state_t *t38state;
00558 
00559 #if SPANDSP_RELEASE_DATE >= 20080725
00560    /* for spandsp shaphots 0.0.6 and higher */
00561    t30state = &t38.t30;
00562    t38state = &t38.t38_fe.t38;
00563 #else
00564    /* for spandsp releases 0.0.5 */
00565    t30state = &t38.t30_state;
00566    t38state = &t38.t38;
00567 #endif
00568 
00569    /* Initialize terminal */
00570    memset(&t38, 0, sizeof(t38));
00571    if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
00572       ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
00573       res = -1;
00574       goto disable_t38;
00575    }
00576 
00577    t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
00578 
00579    if (s->t38parameters.fill_bit_removal) {
00580       t38_set_fill_bit_removal(t38state, TRUE);
00581    }
00582    if (s->t38parameters.transcoding_mmr) {
00583       t38_set_mmr_transcoding(t38state, TRUE);
00584    }
00585    if (s->t38parameters.transcoding_jbig) {
00586       t38_set_jbig_transcoding(t38state, TRUE);
00587    }
00588 
00589    /* Setup logging */
00590    set_logging(&t38.logging);
00591    set_logging(&t30state->logging);
00592    set_logging(&t38state->logging);
00593 
00594    /* Configure terminal */
00595    set_local_info(t30state, s);
00596    set_file(t30state, s);
00597    set_ecm(t30state, TRUE);
00598 
00599    t30_set_phase_e_handler(t30state, phase_e_handler, s);
00600 
00601    now = start = state_change = ast_tvnow();
00602 
00603    while (!s->finished) {
00604 
00605       res = ast_waitfor(s->chan, 20);
00606       if (res < 0)
00607          break;
00608       else if (res > 0)
00609          res = 0;
00610 
00611       last_frame = now;
00612       now = ast_tvnow();
00613       t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
00614 
00615       inf = ast_read(s->chan);
00616       if (inf == NULL) {
00617          ast_debug(1, "Channel hangup\n");
00618          res = -1;
00619          break;
00620       }
00621 
00622       ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
00623 
00624       if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
00625          t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
00626 
00627          /* Watchdog */
00628          if (last_state != t30state->state) {
00629             state_change = ast_tvnow();
00630             last_state = t30state->state;
00631          }
00632       } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38_PARAMETERS) {
00633          struct ast_control_t38_parameters *parameters = inf->data.ptr;
00634          if (parameters->request_response == AST_T38_TERMINATED) {
00635             ast_debug(1, "T38 down, finishing\n");
00636             break;
00637          }
00638       }
00639 
00640       ast_frfree(inf);
00641       inf = NULL;
00642 
00643       /* Watchdog */
00644       if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
00645          ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
00646          res = -1;
00647          break;
00648       }
00649    }
00650 
00651    ast_debug(1, "Loop finished, res=%d\n", res);
00652 
00653    if (inf)
00654       ast_frfree(inf);
00655 
00656    t30_terminate(t30state);
00657    t38_terminal_release(&t38);
00658 
00659 disable_t38:
00660    /* if we are not the caller, it's our job to shut down the T.38
00661     * session when the FAX transmisson is complete.
00662     */
00663    if ((s->caller_mode == FALSE) &&
00664        (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) {
00665       struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
00666 
00667       if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
00668          /* wait up to five seconds for negotiation to complete */
00669          unsigned int timeout = 5000;
00670          int ms;
00671          
00672          ast_debug(1, "Shutting down T.38 on %s\n", s->chan->name);
00673          while (timeout > 0) {
00674             ms = ast_waitfor(s->chan, 1000);
00675             if (ms < 0) {
00676                ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name);
00677                return -1;
00678             }
00679             if (!ms) {
00680                /* nothing happened */
00681                if (timeout > 0) {
00682                   timeout -= 1000;
00683                   continue;
00684                } else {
00685                   ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", s->chan->name);
00686                   break;
00687                }
00688             }
00689             if (!(inf = ast_read(s->chan))) {
00690                return -1;
00691             }
00692             if ((inf->frametype == AST_FRAME_CONTROL) &&
00693                 (inf->subclass == AST_CONTROL_T38_PARAMETERS) &&
00694                 (inf->datalen == sizeof(t38_parameters))) {
00695                struct ast_control_t38_parameters *parameters = inf->data.ptr;
00696                
00697                switch (parameters->request_response) {
00698                case AST_T38_TERMINATED:
00699                   ast_debug(1, "Shut down T.38 on %s\n", s->chan->name);
00700                   break;
00701                case AST_T38_REFUSED:
00702                   ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", s->chan->name);
00703                   break;
00704                default:
00705                   ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", s->chan->name);
00706                   break;
00707                }
00708                ast_frfree(inf);
00709                break;
00710             }
00711             ast_frfree(inf);
00712          }
00713       }
00714    }
00715 
00716    return res;
00717 }
00718 
00719 static int transmit(fax_session *s)
00720 {
00721    int res = 0;
00722 
00723    /* Clear all channel variables which to be set by the application.
00724       Pre-set status to error so in case of any problems we can just leave */
00725    pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
00726    pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
00727 
00728    pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
00729    pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
00730    pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
00731    pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
00732    pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
00733 
00734    if (s->chan->_state != AST_STATE_UP) {
00735       /* Shouldn't need this, but checking to see if channel is already answered
00736        * Theoretically asterisk should already have answered before running the app */
00737       res = ast_answer(s->chan);
00738       if (res) {
00739          ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
00740          return res;
00741       }
00742    }
00743 
00744    s->t38state = ast_channel_get_t38_state(s->chan);
00745    if (s->t38state != T38_STATE_NEGOTIATED) {
00746       /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */   
00747       pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
00748       res = transmit_audio(s);
00749       if (res > 0) {
00750          /* transmit_audio reports switchover to T38. Update t38state */
00751          s->t38state = ast_channel_get_t38_state(s->chan);
00752          if (s->t38state != T38_STATE_NEGOTIATED) {
00753             ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
00754          }
00755       }
00756    }
00757 
00758    if (s->t38state == T38_STATE_NEGOTIATED) {
00759       pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
00760       res = transmit_t38(s);
00761    }
00762 
00763    if (res) {
00764       ast_log(LOG_WARNING, "Transmission error\n");
00765       res = -1;
00766    } else if (s->finished < 0) {
00767       ast_log(LOG_WARNING, "Transmission failed\n");
00768    } else if (s->finished > 0) {
00769       ast_debug(1, "Transmission finished Ok\n");
00770    }
00771 
00772    return res;
00773 }
00774 
00775 /* === Application functions === */
00776 
00777 static int sndfax_exec(struct ast_channel *chan, void *data)
00778 {
00779    int res = 0;
00780    char *parse;
00781    fax_session session = { 0, };
00782 
00783    AST_DECLARE_APP_ARGS(args,
00784       AST_APP_ARG(file_name);
00785       AST_APP_ARG(options);
00786    );
00787 
00788    if (chan == NULL) {
00789       ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
00790       return -1;
00791    }
00792 
00793    /* The next few lines of code parse out the filename and header from the input string */
00794    if (ast_strlen_zero(data)) {
00795       /* No data implies no filename or anything is present */
00796       ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
00797       return -1;
00798    }
00799 
00800    parse = ast_strdupa(data);
00801    AST_STANDARD_APP_ARGS(args, parse);
00802    
00803    session.caller_mode = TRUE;
00804 
00805    if (args.options) {
00806       if (strchr(args.options, 'a'))
00807          session.caller_mode = FALSE;
00808    }
00809 
00810    /* Done parsing */
00811    session.direction = 1;
00812    session.file_name = args.file_name;
00813    session.chan = chan;
00814    session.finished = 0;
00815 
00816    res = transmit(&session);
00817 
00818    return res;
00819 }
00820 
00821 static int rcvfax_exec(struct ast_channel *chan, void *data)
00822 {
00823    int res = 0;
00824    char *parse;
00825    fax_session session;
00826 
00827    AST_DECLARE_APP_ARGS(args,
00828       AST_APP_ARG(file_name);
00829       AST_APP_ARG(options);
00830    );
00831 
00832    if (chan == NULL) {
00833       ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
00834       return -1;
00835    }
00836 
00837    /* The next few lines of code parse out the filename and header from the input string */
00838    if (ast_strlen_zero(data)) {
00839       /* No data implies no filename or anything is present */
00840       ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
00841       return -1;
00842    }
00843 
00844    parse = ast_strdupa(data);
00845    AST_STANDARD_APP_ARGS(args, parse);
00846    
00847    session.caller_mode = FALSE;
00848 
00849    if (args.options) {
00850       if (strchr(args.options, 'c'))
00851          session.caller_mode = TRUE;
00852    }
00853 
00854    /* Done parsing */
00855    session.direction = 0;
00856    session.file_name = args.file_name;
00857    session.chan = chan;
00858    session.finished = 0;
00859 
00860    res = transmit(&session);
00861 
00862    return res;
00863 }
00864 
00865 static int unload_module(void)
00866 {
00867    int res;
00868 
00869    res = ast_unregister_application(app_sndfax_name); 
00870    res |= ast_unregister_application(app_rcvfax_name);   
00871 
00872    return res;
00873 }
00874 
00875 static int load_module(void)
00876 {
00877    int res ;
00878 
00879    res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
00880    res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
00881 
00882    /* The default SPAN message handler prints to stderr. It is something we do not want */
00883    span_set_message_handler(NULL);
00884 
00885    return res;
00886 }
00887 
00888 
00889 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
00890       .load = load_module,
00891       .unload = unload_module,
00892       );
00893 
00894 

Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1