Tue Aug 20 16:34:21 2013

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

Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1