Mon Jun 27 16:50:46 2011

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

Generated on Mon Jun 27 16:50:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7