Wed Aug 18 22:33:41 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: 245731 $")
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 /*
00334  * spandsp has API calls to support MMR and JBIG transcoding, but they aren't
00335  * implemented quite yet... so don't offer them to the remote endpoint
00336  *                        .transcoding_mmr = 1,
00337  *                        .transcoding_jbig = 1,
00338 */
00339    };
00340 
00341    /* if in called party mode, try to use T.38 */
00342    if (s->caller_mode == FALSE) {
00343       /* check if we are already in T.38 mode (unlikely), or if we can request
00344        * a switch... if so, request it now and wait for the result, rather
00345        * than starting an audio FAX session that will have to be cancelled
00346        */
00347       if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
00348          return 1;
00349       } else if ((t38_state != T38_STATE_UNAVAILABLE) &&
00350             (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE,
00351              (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
00352          /* wait up to five seconds for negotiation to complete */
00353          unsigned int timeout = 5000;
00354          int ms;
00355          
00356          ast_debug(1, "Negotiating T.38 for receive on %s\n", s->chan->name);
00357          while (timeout > 0) {
00358             ms = ast_waitfor(s->chan, 1000);
00359             if (ms < 0) {
00360                ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name);
00361                return -1;
00362             }
00363             if (!ms) {
00364                /* nothing happened */
00365                if (timeout > 0) {
00366                   timeout -= 1000;
00367                   continue;
00368                } else {
00369                   ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", s->chan->name);
00370                   break;
00371                }
00372             }
00373             if (!(inf = ast_read(s->chan))) {
00374                return -1;
00375             }
00376             if ((inf->frametype == AST_FRAME_CONTROL) &&
00377                 (inf->subclass == AST_CONTROL_T38_PARAMETERS) &&
00378                 (inf->datalen == sizeof(t38_parameters))) {
00379                struct ast_control_t38_parameters *parameters = inf->data.ptr;
00380                
00381                switch (parameters->request_response) {
00382                case AST_T38_NEGOTIATED:
00383                   ast_debug(1, "Negotiated T.38 for receive on %s\n", s->chan->name);
00384                   res = 1;
00385                   break;
00386                case AST_T38_REFUSED:
00387                   ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", s->chan->name);
00388                   break;
00389                default:
00390                   ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", s->chan->name);
00391                   break;
00392                }
00393                ast_frfree(inf);
00394                if (res == 1) {
00395                   return 1;
00396                } else {
00397                   break;
00398                }
00399             }
00400             ast_frfree(inf);
00401          }
00402       }
00403    }
00404 
00405 #if SPANDSP_RELEASE_DATE >= 20080725
00406         /* for spandsp shaphots 0.0.6 and higher */
00407         t30state = &fax.t30;
00408 #else
00409         /* for spandsp release 0.0.5 */
00410         t30state = &fax.t30_state;
00411 #endif
00412 
00413    original_read_fmt = s->chan->readformat;
00414    if (original_read_fmt != AST_FORMAT_SLINEAR) {
00415       res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
00416       if (res < 0) {
00417          ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
00418          goto done;
00419       }
00420    }
00421 
00422    original_write_fmt = s->chan->writeformat;
00423    if (original_write_fmt != AST_FORMAT_SLINEAR) {
00424       res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
00425       if (res < 0) {
00426          ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
00427          goto done;
00428       }
00429    }
00430 
00431    /* Initialize T30 terminal */
00432    fax_init(&fax, s->caller_mode);
00433 
00434    /* Setup logging */
00435    set_logging(&fax.logging);
00436    set_logging(&t30state->logging);
00437 
00438    /* Configure terminal */
00439    set_local_info(t30state, s);
00440    set_file(t30state, s);
00441    set_ecm(t30state, TRUE);
00442 
00443    fax_set_transmit_on_idle(&fax, TRUE);
00444 
00445    t30_set_phase_e_handler(t30state, phase_e_handler, s);
00446 
00447    start = state_change = ast_tvnow();
00448 
00449    ast_activate_generator(s->chan, &generator, &fax);
00450 
00451    while (!s->finished) {
00452       inf = NULL;
00453 
00454       if ((res = ast_waitfor(s->chan, 25)) < 0) {
00455          ast_debug(1, "Error waiting for a frame\n");
00456          break;
00457       }
00458 
00459       /* Watchdog */
00460       now = ast_tvnow();
00461       if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
00462          ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
00463          res = -1;
00464          break;
00465       }
00466 
00467       if (!res) {
00468          /* There was timeout waiting for a frame. Loop around and wait again */
00469          continue;
00470       }
00471 
00472       /* There is a frame available. Get it */
00473       res = 0;
00474 
00475       if (!(inf = ast_read(s->chan))) {
00476          ast_debug(1, "Channel hangup\n");
00477          res = -1;
00478          break;
00479       }
00480 
00481       ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
00482 
00483       /* Check the frame type. Format also must be checked because there is a chance
00484          that a frame in old format was already queued before we set channel format
00485          to slinear so it will still be received by ast_read */
00486       if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
00487          if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
00488             /* I know fax_rx never returns errors. The check here is for good style only */
00489             ast_log(LOG_WARNING, "fax_rx returned error\n");
00490             res = -1;
00491             break;
00492          }
00493          if (last_state != t30state->state) {
00494             state_change = ast_tvnow();
00495             last_state = t30state->state;
00496          }
00497       } else if ((inf->frametype == AST_FRAME_CONTROL) &&
00498             (inf->subclass == AST_CONTROL_T38_PARAMETERS)) {
00499          struct ast_control_t38_parameters *parameters = inf->data.ptr;
00500 
00501          if (parameters->request_response == AST_T38_NEGOTIATED) {
00502             /* T38 switchover completed */
00503             s->t38parameters = *parameters;
00504             ast_debug(1, "T38 negotiated, finishing audio loop\n");
00505             res = 1;
00506             break;
00507          } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
00508             t38_parameters.request_response = AST_T38_NEGOTIATED;
00509             ast_debug(1, "T38 request received, accepting\n");
00510             /* Complete T38 switchover */
00511             ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
00512             /* Do not break audio loop, wait until channel driver finally acks switchover
00513              * with AST_T38_NEGOTIATED
00514              */
00515          }
00516       }
00517 
00518       ast_frfree(inf);
00519       inf = NULL;
00520    }
00521 
00522    ast_debug(1, "Loop finished, res=%d\n", res);
00523 
00524    if (inf)
00525       ast_frfree(inf);
00526 
00527    ast_deactivate_generator(s->chan);
00528 
00529    /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
00530       by t30_terminate, display diagnostics and set status variables although no transmittion
00531       has taken place yet. */
00532    if (res > 0) {
00533       t30_set_phase_e_handler(t30state, NULL, NULL);
00534    }
00535 
00536    t30_terminate(t30state);
00537    fax_release(&fax);
00538 
00539 done:
00540    if (original_write_fmt != AST_FORMAT_SLINEAR) {
00541       if (ast_set_write_format(s->chan, original_write_fmt) < 0)
00542          ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
00543    }
00544 
00545    if (original_read_fmt != AST_FORMAT_SLINEAR) {
00546       if (ast_set_read_format(s->chan, original_read_fmt) < 0)
00547          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
00548    }
00549 
00550    return res;
00551 
00552 }
00553 
00554 static int transmit_t38(fax_session *s)
00555 {
00556    int res = 0;
00557    t38_terminal_state_t t38;
00558    struct ast_frame *inf = NULL;
00559    int last_state = 0;
00560    struct timeval now, start, state_change, last_frame;
00561    t30_state_t *t30state;
00562    t38_core_state_t *t38state;
00563 
00564 #if SPANDSP_RELEASE_DATE >= 20080725
00565    /* for spandsp shaphots 0.0.6 and higher */
00566    t30state = &t38.t30;
00567    t38state = &t38.t38_fe.t38;
00568 #else
00569    /* for spandsp releases 0.0.5 */
00570    t30state = &t38.t30_state;
00571    t38state = &t38.t38;
00572 #endif
00573 
00574    /* Initialize terminal */
00575    memset(&t38, 0, sizeof(t38));
00576    if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
00577       ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
00578       res = -1;
00579       goto disable_t38;
00580    }
00581 
00582    t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
00583 
00584    if (s->t38parameters.fill_bit_removal) {
00585       t38_set_fill_bit_removal(t38state, TRUE);
00586    }
00587    if (s->t38parameters.transcoding_mmr) {
00588       t38_set_mmr_transcoding(t38state, TRUE);
00589    }
00590    if (s->t38parameters.transcoding_jbig) {
00591       t38_set_jbig_transcoding(t38state, TRUE);
00592    }
00593 
00594    /* Setup logging */
00595    set_logging(&t38.logging);
00596    set_logging(&t30state->logging);
00597    set_logging(&t38state->logging);
00598 
00599    /* Configure terminal */
00600    set_local_info(t30state, s);
00601    set_file(t30state, s);
00602    set_ecm(t30state, TRUE);
00603 
00604    t30_set_phase_e_handler(t30state, phase_e_handler, s);
00605 
00606    now = start = state_change = ast_tvnow();
00607 
00608    while (!s->finished) {
00609 
00610       res = ast_waitfor(s->chan, 20);
00611       if (res < 0)
00612          break;
00613       else if (res > 0)
00614          res = 0;
00615 
00616       last_frame = now;
00617       now = ast_tvnow();
00618       t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
00619 
00620       inf = ast_read(s->chan);
00621       if (inf == NULL) {
00622          ast_debug(1, "Channel hangup\n");
00623          res = -1;
00624          break;
00625       }
00626 
00627       ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
00628 
00629       if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
00630          t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
00631 
00632          /* Watchdog */
00633          if (last_state != t30state->state) {
00634             state_change = ast_tvnow();
00635             last_state = t30state->state;
00636          }
00637       } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38_PARAMETERS) {
00638          struct ast_control_t38_parameters *parameters = inf->data.ptr;
00639          if (parameters->request_response == AST_T38_TERMINATED) {
00640             ast_debug(1, "T38 down, finishing\n");
00641             break;
00642          }
00643       }
00644 
00645       ast_frfree(inf);
00646       inf = NULL;
00647 
00648       /* Watchdog */
00649       if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
00650          ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
00651          res = -1;
00652          break;
00653       }
00654    }
00655 
00656    ast_debug(1, "Loop finished, res=%d\n", res);
00657 
00658    if (inf)
00659       ast_frfree(inf);
00660 
00661    t30_terminate(t30state);
00662    t38_terminal_release(&t38);
00663 
00664 disable_t38:
00665    /* if we are not the caller, it's our job to shut down the T.38
00666     * session when the FAX transmisson is complete.
00667     */
00668    if ((s->caller_mode == FALSE) &&
00669        (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) {
00670       struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
00671 
00672       if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
00673          /* wait up to five seconds for negotiation to complete */
00674          unsigned int timeout = 5000;
00675          int ms;
00676          
00677          ast_debug(1, "Shutting down T.38 on %s\n", s->chan->name);
00678          while (timeout > 0) {
00679             ms = ast_waitfor(s->chan, 1000);
00680             if (ms < 0) {
00681                ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name);
00682                return -1;
00683             }
00684             if (!ms) {
00685                /* nothing happened */
00686                if (timeout > 0) {
00687                   timeout -= 1000;
00688                   continue;
00689                } else {
00690                   ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", s->chan->name);
00691                   break;
00692                }
00693             }
00694             if (!(inf = ast_read(s->chan))) {
00695                return -1;
00696             }
00697             if ((inf->frametype == AST_FRAME_CONTROL) &&
00698                 (inf->subclass == AST_CONTROL_T38_PARAMETERS) &&
00699                 (inf->datalen == sizeof(t38_parameters))) {
00700                struct ast_control_t38_parameters *parameters = inf->data.ptr;
00701                
00702                switch (parameters->request_response) {
00703                case AST_T38_TERMINATED:
00704                   ast_debug(1, "Shut down T.38 on %s\n", s->chan->name);
00705                   break;
00706                case AST_T38_REFUSED:
00707                   ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", s->chan->name);
00708                   break;
00709                default:
00710                   ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", s->chan->name);
00711                   break;
00712                }
00713                ast_frfree(inf);
00714                break;
00715             }
00716             ast_frfree(inf);
00717          }
00718       }
00719    }
00720 
00721    return res;
00722 }
00723 
00724 static int transmit(fax_session *s)
00725 {
00726    int res = 0;
00727 
00728    /* Clear all channel variables which to be set by the application.
00729       Pre-set status to error so in case of any problems we can just leave */
00730    pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
00731    pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
00732 
00733    pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
00734    pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
00735    pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
00736    pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
00737    pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
00738 
00739    if (s->chan->_state != AST_STATE_UP) {
00740       /* Shouldn't need this, but checking to see if channel is already answered
00741        * Theoretically asterisk should already have answered before running the app */
00742       res = ast_answer(s->chan);
00743       if (res) {
00744          ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
00745          return res;
00746       }
00747    }
00748 
00749    s->t38state = ast_channel_get_t38_state(s->chan);
00750    if (s->t38state != T38_STATE_NEGOTIATED) {
00751       /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */   
00752       pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
00753       res = transmit_audio(s);
00754       if (res > 0) {
00755          /* transmit_audio reports switchover to T38. Update t38state */
00756          s->t38state = ast_channel_get_t38_state(s->chan);
00757          if (s->t38state != T38_STATE_NEGOTIATED) {
00758             ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
00759          }
00760       }
00761    }
00762 
00763    if (s->t38state == T38_STATE_NEGOTIATED) {
00764       pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
00765       res = transmit_t38(s);
00766    }
00767 
00768    if (res) {
00769       ast_log(LOG_WARNING, "Transmission error\n");
00770       res = -1;
00771    } else if (s->finished < 0) {
00772       ast_log(LOG_WARNING, "Transmission failed\n");
00773    } else if (s->finished > 0) {
00774       ast_debug(1, "Transmission finished Ok\n");
00775    }
00776 
00777    return res;
00778 }
00779 
00780 /* === Application functions === */
00781 
00782 static int sndfax_exec(struct ast_channel *chan, void *data)
00783 {
00784    int res = 0;
00785    char *parse;
00786    fax_session session = { 0, };
00787 
00788    AST_DECLARE_APP_ARGS(args,
00789       AST_APP_ARG(file_name);
00790       AST_APP_ARG(options);
00791    );
00792 
00793    if (chan == NULL) {
00794       ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
00795       return -1;
00796    }
00797 
00798    /* The next few lines of code parse out the filename and header from the input string */
00799    if (ast_strlen_zero(data)) {
00800       /* No data implies no filename or anything is present */
00801       ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
00802       return -1;
00803    }
00804 
00805    parse = ast_strdupa(data);
00806    AST_STANDARD_APP_ARGS(args, parse);
00807    
00808    session.caller_mode = TRUE;
00809 
00810    if (args.options) {
00811       if (strchr(args.options, 'a'))
00812          session.caller_mode = FALSE;
00813    }
00814 
00815    /* Done parsing */
00816    session.direction = 1;
00817    session.file_name = args.file_name;
00818    session.chan = chan;
00819    session.finished = 0;
00820 
00821    res = transmit(&session);
00822 
00823    return res;
00824 }
00825 
00826 static int rcvfax_exec(struct ast_channel *chan, void *data)
00827 {
00828    int res = 0;
00829    char *parse;
00830    fax_session session;
00831 
00832    AST_DECLARE_APP_ARGS(args,
00833       AST_APP_ARG(file_name);
00834       AST_APP_ARG(options);
00835    );
00836 
00837    if (chan == NULL) {
00838       ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
00839       return -1;
00840    }
00841 
00842    /* The next few lines of code parse out the filename and header from the input string */
00843    if (ast_strlen_zero(data)) {
00844       /* No data implies no filename or anything is present */
00845       ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
00846       return -1;
00847    }
00848 
00849    parse = ast_strdupa(data);
00850    AST_STANDARD_APP_ARGS(args, parse);
00851    
00852    session.caller_mode = FALSE;
00853 
00854    if (args.options) {
00855       if (strchr(args.options, 'c'))
00856          session.caller_mode = TRUE;
00857    }
00858 
00859    /* Done parsing */
00860    session.direction = 0;
00861    session.file_name = args.file_name;
00862    session.chan = chan;
00863    session.finished = 0;
00864 
00865    res = transmit(&session);
00866 
00867    return res;
00868 }
00869 
00870 static int unload_module(void)
00871 {
00872    int res;
00873 
00874    res = ast_unregister_application(app_sndfax_name); 
00875    res |= ast_unregister_application(app_rcvfax_name);   
00876 
00877    return res;
00878 }
00879 
00880 static int load_module(void)
00881 {
00882    int res ;
00883 
00884    res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
00885    res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
00886 
00887    /* The default SPAN message handler prints to stderr. It is something we do not want */
00888    span_set_message_handler(NULL);
00889 
00890    return res;
00891 }
00892 
00893 
00894 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
00895       .load = load_module,
00896       .unload = unload_module,
00897       );
00898 
00899 

Generated on Wed Aug 18 22:33:41 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7