app_fax.c

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

Generated on Thu Apr 16 06:27:09 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6