Mon Jun 27 16:51:19 2011

Asterisk developer's documentation


res_fax_spandsp.c File Reference

Spandsp T.38 and G.711 FAX Resource. More...

#include "asterisk.h"
#include <spandsp.h>
#include <spandsp/version.h>
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/strings.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/timing.h"
#include "asterisk/astobj2.h"
#include "asterisk/res_fax.h"

Go to the source code of this file.

Data Structures

struct  spandsp_fax_stats
struct  spandsp_pvt
struct  spandsp_pvt::frame_queue

Defines

#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
#define SPANDSP_FAX_SAMPLES   160
#define SPANDSP_FAX_TIMER_RATE   8000 / SPANDSP_FAX_SAMPLES

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int load_module (void)
 load res_fax_spandsp
static void session_destroy (struct spandsp_pvt *p)
static void set_ecm (t30_state_t *t30_state, struct ast_fax_session_details *details)
static void set_file (t30_state_t *t30_state, struct ast_fax_session_details *details)
static void set_local_info (t30_state_t *t30_state, struct ast_fax_session_details *details)
static void set_logging (logging_state_t *state, struct ast_fax_session_details *details)
static int spandsp_fax_cancel (struct ast_fax_session *s)
static char * spandsp_fax_cli_show_capabilities (int fd)
static char * spandsp_fax_cli_show_session (struct ast_fax_session *s, int fd)
static char * spandsp_fax_cli_show_settings (int fd)
 Show res_fax_spandsp settings.
static char * spandsp_fax_cli_show_stats (int fd)
static void spandsp_fax_destroy (struct ast_fax_session *s)
 Destroy a spandsp fax session.
static void * spandsp_fax_new (struct ast_fax_session *s, struct ast_fax_tech_token *token)
 create an instance of the spandsp tech_pvt for a fax session
static struct ast_framespandsp_fax_read (struct ast_fax_session *s)
 Read a frame from the spandsp fax stack.
static int spandsp_fax_start (struct ast_fax_session *s)
static int spandsp_fax_switch_to_t38 (struct ast_fax_session *s)
static int spandsp_fax_write (struct ast_fax_session *s, const struct ast_frame *f)
 Write a frame to the spandsp fax stack.
static void spandsp_log (int level, const char *msg)
 Send spandsp log messages to asterisk.
static void t30_phase_e_handler (t30_state_t *t30_state, void *data, int completion_code)
 Phase E handler callback.
static int t38_tx_packet_handler (t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
static int unload_module (void)
 unload res_fax_spandsp
static int update_stats (struct spandsp_pvt *p, int completion_code)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Spandsp G.711 and T.38 FAX Technologies" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_fax_tech spandsp_fax_tech
struct {
   spandsp_fax_stats   g711
   ast_mutex_t   lock
   spandsp_fax_stats   t38
spandsp_global_stats


Detailed Description

Spandsp T.38 and G.711 FAX Resource.

Author:
Matthew Nicholson <mnicholson@digium.com>
This module registers the Spandsp FAX technology with the res_fax module.

Definition in file res_fax_spandsp.c.


Define Documentation

#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES

Definition at line 37 of file res_fax_spandsp.c.

#define SPANDSP_FAX_SAMPLES   160

Definition at line 50 of file res_fax_spandsp.c.

Referenced by spandsp_fax_read().

#define SPANDSP_FAX_TIMER_RATE   8000 / SPANDSP_FAX_SAMPLES

Definition at line 51 of file res_fax_spandsp.c.

Referenced by spandsp_fax_start().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 772 of file res_fax_spandsp.c.

static void __unreg_module ( void   )  [static]

Definition at line 772 of file res_fax_spandsp.c.

static int load_module ( void   )  [static]

load res_fax_spandsp

Definition at line 753 of file res_fax_spandsp.c.

References ast_fax_tech_register(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init, LOG_ERROR, ast_fax_tech::module, and spandsp_fax_tech.

00754 {
00755    ast_mutex_init(&spandsp_global_stats.lock);
00756    spandsp_fax_tech.module = ast_module_info->self;
00757    if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
00758       ast_log(LOG_ERROR, "failed to register FAX technology\n");
00759       return AST_MODULE_LOAD_DECLINE;
00760    }
00761 
00762    /* prevent logging to stderr */
00763    span_set_message_handler(NULL);
00764 
00765    return AST_MODULE_LOAD_SUCCESS;
00766 }

static void session_destroy ( struct spandsp_pvt p  )  [static]

Definition at line 139 of file res_fax_spandsp.c.

References ast_frfree, AST_LIST_REMOVE_HEAD, ast_timer_close(), and f.

00140 {
00141    struct ast_frame *f;
00142 
00143    t30_terminate(p->t30_state);
00144    p->isdone = 1;
00145 
00146    ast_timer_close(p->timer);
00147 
00148    fax_release(&p->fax_state);
00149    t38_terminal_release(&p->t38_state);
00150 
00151    while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00152       ast_frfree(f);
00153    }
00154 }

static void set_ecm ( t30_state_t *  t30_state,
struct ast_fax_session_details details 
) [static]

Definition at line 408 of file res_fax_spandsp.c.

References ast_fax_session_details::ecm, and ast_fax_session_details::option.

00409 {
00410    t30_set_ecm_capability(t30_state, details->option.ecm);
00411    t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
00412 }

static void set_file ( t30_state_t *  t30_state,
struct ast_fax_session_details details 
) [static]

Definition at line 396 of file res_fax_spandsp.c.

References AST_FAX_TECH_RECEIVE, AST_LIST_FIRST, ast_fax_session_details::caps, and ast_fax_session_details::documents.

00397 {
00398    if (details->caps & AST_FAX_TECH_RECEIVE) {
00399       t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
00400    } else {
00401       /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
00402        * should be safe because we ensure either RECEIVE or SEND is
00403        * indicated in spandsp_fax_new() */
00404       t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
00405    }
00406 }

static void set_local_info ( t30_state_t *  t30_state,
struct ast_fax_session_details details 
) [static]

Definition at line 385 of file res_fax_spandsp.c.

References ast_strlen_zero(), ast_fax_session_details::headerinfo, and ast_fax_session_details::localstationid.

00386 {
00387    if (!ast_strlen_zero(details->localstationid)) {
00388       t30_set_tx_ident(t30_state, details->localstationid);
00389    }
00390 
00391    if (!ast_strlen_zero(details->headerinfo)) {
00392       t30_set_tx_page_header_info(t30_state, details->headerinfo);
00393    }
00394 }

static void set_logging ( logging_state_t *  state,
struct ast_fax_session_details details 
) [static]

Definition at line 373 of file res_fax_spandsp.c.

References ast_fax_session_details::debug, ast_fax_session_details::option, and spandsp_log().

00374 {
00375    int level = SPAN_LOG_WARNING;
00376 
00377         if (details->option.debug) {
00378       level = SPAN_LOG_DEBUG_3;
00379    }
00380 
00381    span_log_set_message_handler(state, spandsp_log);
00382    span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
00383 }

static int spandsp_fax_cancel ( struct ast_fax_session s  )  [static]

Definition at line 626 of file res_fax_spandsp.c.

References spandsp_pvt::isdone, spandsp_pvt::t30_state, and ast_fax_session::tech_pvt.

00627 {
00628    struct spandsp_pvt *p = s->tech_pvt;
00629    t30_terminate(p->t30_state);
00630    p->isdone = 1;
00631    return 0;
00632 }

static char * spandsp_fax_cli_show_capabilities ( int  fd  )  [static]

Definition at line 655 of file res_fax_spandsp.c.

References ast_cli(), and CLI_SUCCESS.

00656 {
00657    ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
00658    return  CLI_SUCCESS;
00659 }

static char * spandsp_fax_cli_show_session ( struct ast_fax_session s,
int  fd 
) [static]

Definition at line 662 of file res_fax_spandsp.c.

References ao2_lock, ao2_unlock, ast_cli(), ast_fax_state_to_str(), AST_FAX_STATE_UNINITIALIZED, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_SEND, ast_fax_session_details::caps, CLI_SUCCESS, ast_fax_session::details, ast_fax_session::id, ast_fax_session::state, spandsp_pvt::stats, spandsp_pvt::t30_state, and ast_fax_session::tech_pvt.

00663 {
00664    struct spandsp_pvt *p = s->tech_pvt;
00665    t30_stats_t stats;
00666 
00667    ao2_lock(s);
00668    ast_cli(fd, "%-22s : %d\n", "session", s->id);
00669    ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
00670    ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
00671    if (s->state != AST_FAX_STATE_UNINITIALIZED) {
00672       t30_get_transfer_statistics(p->t30_state, &stats);
00673       ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
00674       ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
00675       ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
00676       ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
00677 #if SPANDSP_RELEASE_DATE >= 20090220
00678       ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
00679 #else
00680       ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
00681 #endif
00682       ast_cli(fd, "%-22s : %s\n", "File Name", s->details->caps & AST_FAX_TECH_RECEIVE ? p->t30_state->rx_file : p->t30_state->tx_file);
00683 
00684       ast_cli(fd, "\nData Statistics:\n");
00685 #if SPANDSP_RELEASE_DATE >= 20090220
00686       ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
00687       ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
00688 #else
00689       ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
00690       ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
00691 #endif
00692       ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
00693       ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
00694    }
00695    ao2_unlock(s);
00696    ast_cli(fd, "\n\n");
00697    return CLI_SUCCESS;
00698 }

static char * spandsp_fax_cli_show_settings ( int  fd  )  [static]

Show res_fax_spandsp settings.

Definition at line 738 of file res_fax_spandsp.c.

References CLI_SUCCESS.

00739 {
00740    /* no settings at the moment */
00741    return CLI_SUCCESS;
00742 }

static char * spandsp_fax_cli_show_stats ( int  fd  )  [static]

Definition at line 701 of file res_fax_spandsp.c.

References ast_cli(), ast_mutex_lock, ast_mutex_unlock, and CLI_SUCCESS.

00702 {
00703    ast_mutex_lock(&spandsp_global_stats.lock);
00704    ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
00705    ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
00706    ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
00707    ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
00708    ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
00709    ast_cli(fd, "%-20.20s : %d\n", "Negotation Failed", spandsp_global_stats.g711.neg_failed);
00710    ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
00711    ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
00712    ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
00713    ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
00714    ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
00715    ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
00716    ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
00717    ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
00718 
00719    ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
00720    ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
00721    ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
00722    ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
00723    ast_cli(fd, "%-20.20s : %d\n", "Negotation Failed", spandsp_global_stats.t38.neg_failed);
00724    ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
00725    ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
00726    ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
00727    ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
00728    ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
00729    ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
00730    ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
00731    ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
00732    ast_mutex_unlock(&spandsp_global_stats.lock);
00733 
00734    return CLI_SUCCESS;
00735 }

static void spandsp_fax_destroy ( struct ast_fax_session s  )  [static]

Destroy a spandsp fax session.

Definition at line 474 of file res_fax_spandsp.c.

References ast_free, ast_fax_session::fd, session_destroy(), and ast_fax_session::tech_pvt.

00475 {
00476    struct spandsp_pvt *p = s->tech_pvt;
00477 
00478    session_destroy(p);
00479    ast_free(p);
00480    s->tech_pvt = NULL;
00481    s->fd = -1;
00482 }

static void * spandsp_fax_new ( struct ast_fax_session s,
struct ast_fax_tech_token *  token 
) [static]

create an instance of the spandsp tech_pvt for a fax session

Definition at line 415 of file res_fax_spandsp.c.

References ast_calloc, AST_FAX_STATE_INITIALIZED, AST_FAX_TECH_AUDIO, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_SEND, AST_FAX_TECH_T38, ast_free, AST_LIST_HEAD_INIT, ast_log(), ast_timer_fd(), ast_timer_open(), ast_fax_session_details::caps, ast_fax_session::channame, ast_fax_session::details, ast_fax_session::fd, ast_fax_session::id, LOG_ERROR, set_logging(), ast_fax_session::state, and t38_tx_packet_handler().

00416 {
00417    struct spandsp_pvt *p;
00418    int caller_mode;
00419 
00420    if ((!(p = ast_calloc(1, sizeof(*p))))) {
00421       ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
00422       goto e_return;
00423    }
00424 
00425    AST_LIST_HEAD_INIT(&p->read_frames);
00426 
00427    if (s->details->caps & AST_FAX_TECH_RECEIVE) {
00428       caller_mode = 0;
00429    } else if (s->details->caps & AST_FAX_TECH_SEND) {
00430       caller_mode = 1;
00431    } else {
00432       ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
00433       goto e_free;
00434    }
00435 
00436    if (!(p->timer = ast_timer_open())) {
00437       ast_log(LOG_ERROR, "Channel '%s' FAX session '%d' failed to create timing source.\n", s->channame, s->id);
00438       goto e_free;
00439    }
00440 
00441    s->fd = ast_timer_fd(p->timer);
00442 
00443    p->stats = &spandsp_global_stats.g711;
00444 
00445    if (s->details->caps & AST_FAX_TECH_T38) {
00446       if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
00447          /* audio mode was not requested, start in T.38 mode */
00448          p->ist38 = 1;
00449          p->stats = &spandsp_global_stats.t38;
00450       }
00451 
00452       /* init t38 stuff */
00453       t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, p);
00454       set_logging(&p->t38_state.logging, s->details);
00455    }
00456 
00457    if (s->details->caps & AST_FAX_TECH_AUDIO) {
00458       /* init audio stuff */
00459       fax_init(&p->fax_state, caller_mode);
00460       set_logging(&p->fax_state.logging, s->details);
00461    }
00462 
00463    s->state = AST_FAX_STATE_INITIALIZED;
00464    return p;
00465 
00466 e_free:
00467    ast_free(p);
00468 e_return:
00469    return NULL;
00470 }

static struct ast_frame * spandsp_fax_read ( struct ast_fax_session s  )  [static]

Read a frame from the spandsp fax stack.

Definition at line 486 of file res_fax_spandsp.c.

References ast_debug, AST_FAX_STATE_COMPLETE, AST_FORMAT_SLINEAR, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_frisolate(), AST_LIST_REMOVE_HEAD, ast_null_frame, ast_timer_ack(), f, spandsp_pvt::fax_state, ast_frame::frametype, ast_fax_session::id, spandsp_pvt::isdone, spandsp_pvt::ist38, spandsp_pvt::read_frames, SPANDSP_FAX_SAMPLES, ast_fax_session::state, spandsp_pvt::t38_state, ast_fax_session::tech_pvt, and spandsp_pvt::timer.

00487 {
00488    struct spandsp_pvt *p = s->tech_pvt;
00489    uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
00490    int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
00491    int samples;
00492 
00493    struct ast_frame fax_frame = {
00494       .frametype = AST_FRAME_VOICE,
00495       .subclass.codec = AST_FORMAT_SLINEAR,
00496       .src = "res_fax_spandsp_g711",
00497    };
00498 
00499    struct ast_frame *f = &fax_frame;
00500 
00501    ast_timer_ack(p->timer, 1);
00502 
00503    /* XXX do we need to lock here? */
00504    if (p->isdone) {
00505       s->state = AST_FAX_STATE_COMPLETE;
00506       ast_debug(5, "FAX session '%d' is complete.\n", s->id);
00507       return NULL;
00508    }
00509 
00510    if (p->ist38) {
00511       t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
00512       if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00513          return f;
00514       }
00515    } else {
00516       if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
00517          f->samples = samples;
00518          AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
00519          return ast_frisolate(f);
00520       }
00521    }
00522 
00523    return &ast_null_frame;
00524 }

static int spandsp_fax_start ( struct ast_fax_session s  )  [static]

Definition at line 554 of file res_fax_spandsp.c.

References AST_FAX_STATE_ACTIVE, AST_FAX_STATE_OPEN, ast_log(), ast_timer_set_rate(), ast_fax_session::details, spandsp_pvt::fax_state, ast_fax_t38_parameters::fill_bit_removal, ast_fax_session::id, spandsp_pvt::ist38, LOG_ERROR, ast_fax_t38_parameters::max_ifp, set_ecm(), set_file(), set_local_info(), set_logging(), SPANDSP_FAX_TIMER_RATE, ast_fax_session::state, t30_phase_e_handler(), spandsp_pvt::t30_state, spandsp_pvt::t38_core_state, spandsp_pvt::t38_state, ast_fax_session::tech_pvt, ast_fax_session_details::their_t38_parameters, spandsp_pvt::timer, ast_fax_t38_parameters::transcoding_jbig, ast_fax_t38_parameters::transcoding_mmr, and TRUE.

Referenced by spandsp_fax_switch_to_t38().

00555 {
00556    struct spandsp_pvt *p = s->tech_pvt;
00557 
00558    s->state = AST_FAX_STATE_OPEN;
00559 
00560    if (p->ist38) {
00561 #if SPANDSP_RELEASE_DATE >= 20080725
00562       /* for spandsp shaphots 0.0.6 and higher */
00563       p->t30_state = &p->t38_state.t30;
00564       p->t38_core_state = &p->t38_state.t38_fe.t38;
00565 #else
00566       /* for spandsp releases 0.0.5 */
00567       p->t30_state = &p->t38_state.t30_state;
00568       p->t38_core_state = &p->t38_state.t38;
00569 #endif
00570    } else {
00571 #if SPANDSP_RELEASE_DATE >= 20080725
00572       /* for spandsp shaphots 0.0.6 and higher */
00573       p->t30_state = &p->fax_state.t30;
00574 #else
00575       /* for spandsp release 0.0.5 */
00576       p->t30_state = &p->fax_state.t30_state;
00577 #endif
00578    }
00579 
00580    set_logging(&p->t30_state->logging, s->details);
00581 
00582    /* set some parameters */
00583    set_local_info(p->t30_state, s->details);
00584    set_file(p->t30_state, s->details);
00585    set_ecm(p->t30_state, s->details);
00586 
00587    /* perhaps set_transmit_on_idle() should be called */
00588 
00589    t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
00590 
00591    /* set T.38 parameters */
00592    if (p->ist38) {
00593       set_logging(&p->t38_core_state->logging, s->details);
00594 
00595       t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
00596 
00597       if (s->details->their_t38_parameters.fill_bit_removal) {
00598          t38_set_fill_bit_removal(p->t38_core_state, TRUE);
00599       }
00600 
00601       if (s->details->their_t38_parameters.transcoding_mmr) {
00602          t38_set_mmr_transcoding(p->t38_core_state, TRUE);
00603       }
00604 
00605       if (s->details->their_t38_parameters.transcoding_jbig) {
00606          t38_set_jbig_transcoding(p->t38_core_state, TRUE);
00607       }
00608    } else {
00609       /* have the fax stack generate silence if it has no data to send */
00610       fax_set_transmit_on_idle(&p->fax_state, 1);
00611    }
00612 
00613 
00614    /* start the timer */
00615    if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
00616       ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
00617       return -1;
00618    }
00619 
00620    s->state = AST_FAX_STATE_ACTIVE;
00621 
00622    return 0;
00623 }

static int spandsp_fax_switch_to_t38 ( struct ast_fax_session s  )  [static]

Definition at line 635 of file res_fax_spandsp.c.

References ast_atomic_fetchadd_int(), ast_fax_session::details, spandsp_pvt::ist38, ast_fax_session_details::option, spandsp_fax_start(), spandsp_pvt::stats, ast_fax_session_details::switch_to_t38, spandsp_fax_stats::switched, spandsp_pvt::t30_state, and ast_fax_session::tech_pvt.

00636 {
00637    struct spandsp_pvt *p = s->tech_pvt;
00638 
00639    /* prevent the phase E handler from running, this is not a real termination */
00640    t30_set_phase_e_handler(p->t30_state, NULL, NULL);
00641 
00642    t30_terminate(p->t30_state);
00643 
00644    s->details->option.switch_to_t38 = 1;
00645    ast_atomic_fetchadd_int(&p->stats->switched, 1);
00646 
00647    p->ist38 = 1;
00648    p->stats = &spandsp_global_stats.t38;
00649    spandsp_fax_start(s);
00650 
00651    return 0;
00652 }

static int spandsp_fax_write ( struct ast_fax_session s,
const struct ast_frame f 
) [static]

Write a frame to the spandsp fax stack.

Parameters:
s a fax session
f the frame to write
Note:
res_fax does not currently use the return value of this function. Also the fax_rx() function never fails.
Return values:
0 success
-1 failure

Definition at line 536 of file res_fax_spandsp.c.

References AST_FAX_STATE_COMPLETE, ast_fax_state_to_str(), ast_log(), f, spandsp_pvt::fax_state, ast_fax_session::id, spandsp_pvt::ist38, LOG_WARNING, ast_fax_session::state, spandsp_pvt::t38_core_state, and ast_fax_session::tech_pvt.

00537 {
00538    struct spandsp_pvt *p = s->tech_pvt;
00539 
00540    /* XXX do we need to lock here? */
00541    if (s->state == AST_FAX_STATE_COMPLETE) {
00542       ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
00543       return -1;
00544    }
00545 
00546    if (p->ist38) {
00547       return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
00548    } else {
00549       return fax_rx(&p->fax_state, f->data.ptr, f->samples);
00550    }
00551 }

static void spandsp_log ( int  level,
const char *  msg 
) [static]

Send spandsp log messages to asterisk.

Parameters:
level the spandsp logging level
msg the log message
Note:
This function is a callback function called by spandsp.

Definition at line 362 of file res_fax_spandsp.c.

References ast_fax_log(), ast_log(), LOG_DEBUG, LOG_ERROR, and LOG_WARNING.

Referenced by set_logging().

00363 {
00364    if (level == SPAN_LOG_ERROR) {
00365       ast_log(LOG_ERROR, "%s", msg);
00366    } else if (level == SPAN_LOG_WARNING) {
00367       ast_log(LOG_WARNING, "%s", msg);
00368    } else {
00369       ast_fax_log(LOG_DEBUG, msg);
00370    }
00371 }

static void t30_phase_e_handler ( t30_state_t *  t30_state,
void *  data,
int  completion_code 
) [static]

Phase E handler callback.

Parameters:
t30_state the span t30 state
data this will be the ast_fax_session
completion_code the result of the fax session
This function pulls stats from the spandsp stack and stores them for res_fax to use later.

Definition at line 307 of file res_fax_spandsp.c.

References ast_debug, AST_FAX_TECH_RECEIVE, ast_string_field_build, ast_string_field_set, ast_fax_session_details::caps, ast_fax_session::details, ast_fax_session::id, spandsp_pvt::isdone, ast_fax_session_details::pages_transferred, ast_fax_session_details::result, ast_fax_session_details::resultstr, spandsp_pvt::stats, ast_fax_session::tech_pvt, and update_stats().

Referenced by spandsp_fax_start().

00308 {
00309    struct ast_fax_session *s = data;
00310    struct spandsp_pvt *p = s->tech_pvt;
00311    char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
00312    const char *c;
00313    t30_stats_t stats;
00314 
00315    ast_debug(5, "FAX session '%d' entering phase E\n", s->id);
00316 
00317    p->isdone = 1;
00318 
00319    update_stats(p, completion_code);
00320 
00321    t30_get_transfer_statistics(t30_state, &stats);
00322 
00323    if (completion_code == T30_ERR_OK) {
00324       ast_string_field_set(s->details, result, "SUCCESS");
00325    } else {
00326       ast_string_field_set(s->details, result, "FAILED");
00327       ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
00328    }
00329 
00330    ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
00331 
00332    ast_debug(5, "FAX session '%d' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
00333 
00334    if ((c = t30_get_tx_ident(t30_state))) {
00335       ast_string_field_set(s->details, localstationid, c);
00336    }
00337 
00338    if ((c = t30_get_rx_ident(t30_state))) {
00339       ast_string_field_set(s->details, remotestationid, c);
00340    }
00341 
00342 #if SPANDSP_RELEASE_DATE >= 20090220
00343    s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
00344 #else
00345    s->details->pages_transferred = stats.pages_transferred;
00346 #endif
00347 
00348    ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
00349 
00350    ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
00351 
00352    t30_get_tx_page_header_info(t30_state, headerinfo);
00353    ast_string_field_set(s->details, headerinfo, headerinfo);
00354 }

static int t38_tx_packet_handler ( t38_core_state_t *  t38_core_state,
void *  data,
const uint8_t *  buf,
int  len,
int  count 
) [static]

Definition at line 159 of file res_fax_spandsp.c.

References AST_FRAME_MODEM, AST_FRAME_SET_BUFFER, ast_frisolate(), AST_LIST_INSERT_TAIL, AST_MODEM_T38, f, ast_frame::frametype, and spandsp_pvt::read_frames.

00160 {
00161    struct spandsp_pvt *p = data;
00162    struct ast_frame fax_frame = {
00163       .frametype = AST_FRAME_MODEM,
00164       .subclass.integer = AST_MODEM_T38,
00165       .src = "res_fax_spandsp_t38",
00166    };
00167 
00168    struct ast_frame *f = &fax_frame;
00169 
00170 
00171    /* TODO: Asterisk does not provide means of resending the same packet multiple
00172      times so count is ignored at the moment */
00173 
00174    AST_FRAME_SET_BUFFER(f, buf, 0, len);
00175 
00176    if (!(f = ast_frisolate(f))) {
00177       return -1;
00178    }
00179 
00180    /* no need to lock, this all runs in the same thread */
00181    AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
00182 
00183    return 0;
00184 }

static int unload_module ( void   )  [static]

unload res_fax_spandsp

Definition at line 745 of file res_fax_spandsp.c.

References ast_fax_tech_unregister(), AST_MODULE_LOAD_SUCCESS, ast_mutex_destroy, and spandsp_fax_tech.

static int update_stats ( struct spandsp_pvt p,
int  completion_code 
) [static]

Definition at line 186 of file res_fax_spandsp.c.

References ast_atomic_fetchadd_int(), ast_log(), spandsp_fax_stats::call_dropped, spandsp_fax_stats::failed_to_train, spandsp_fax_stats::file_error, LOG_WARNING, spandsp_fax_stats::mem_error, spandsp_fax_stats::neg_failed, spandsp_fax_stats::nofax, spandsp_fax_stats::protocol_error, spandsp_fax_stats::retries_exceeded, spandsp_fax_stats::rx_protocol_error, spandsp_pvt::stats, spandsp_fax_stats::success, spandsp_fax_stats::tx_protocol_error, and spandsp_fax_stats::unknown_error.

Referenced by t30_phase_e_handler().

00187 {
00188    switch (completion_code) {
00189    case T30_ERR_OK:
00190       ast_atomic_fetchadd_int(&p->stats->success, 1);
00191       break;
00192 
00193    /* Link problems */
00194    case T30_ERR_CEDTONE:            /*! The CED tone exceeded 5s */
00195    case T30_ERR_T0_EXPIRED:         /*! Timed out waiting for initial communication */
00196    case T30_ERR_T1_EXPIRED:         /*! Timed out waiting for the first message */
00197    case T30_ERR_T3_EXPIRED:         /*! Timed out waiting for procedural interrupt */
00198    case T30_ERR_HDLC_CARRIER:       /*! The HDLC carrier did not stop in a timely manner */
00199    case T30_ERR_CANNOT_TRAIN:       /*! Failed to train with any of the compatible modems */
00200       ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
00201       break;
00202 
00203    case T30_ERR_OPER_INT_FAIL:      /*! Operator intervention failed */
00204    case T30_ERR_INCOMPATIBLE:       /*! Far end is not compatible */
00205    case T30_ERR_RX_INCAPABLE:       /*! Far end is not able to receive */
00206    case T30_ERR_TX_INCAPABLE:       /*! Far end is not able to transmit */
00207    case T30_ERR_NORESSUPPORT:       /*! Far end cannot receive at the resolution of the image */
00208    case T30_ERR_NOSIZESUPPORT:      /*! Far end cannot receive at the size of image */
00209       ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
00210       break;
00211 
00212    case T30_ERR_UNEXPECTED:         /*! Unexpected message received */
00213       ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
00214       break;
00215 
00216    /* Phase E status values returned to a transmitter */
00217    case T30_ERR_TX_BADDCS:          /*! Received bad response to DCS or training */
00218    case T30_ERR_TX_BADPG:           /*! Received a DCN from remote after sending a page */
00219    case T30_ERR_TX_ECMPHD:          /*! Invalid ECM response received from receiver */
00220    case T30_ERR_TX_GOTDCN:          /*! Received a DCN while waiting for a DIS */
00221    case T30_ERR_TX_INVALRSP:        /*! Invalid response after sending a page */
00222    case T30_ERR_TX_NODIS:           /*! Received other than DIS while waiting for DIS */
00223    case T30_ERR_TX_PHBDEAD:         /*! Received no response to DCS, training or TCF */
00224    case T30_ERR_TX_PHDDEAD:         /*! No response after sending a page */
00225    case T30_ERR_TX_T5EXP:           /*! Timed out waiting for receiver ready (ECM mode) */
00226       ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
00227       break;
00228 
00229    /* Phase E status values returned to a receiver */
00230    case T30_ERR_RX_ECMPHD:          /*! Invalid ECM response received from transmitter */
00231    case T30_ERR_RX_GOTDCS:          /*! DCS received while waiting for DTC */
00232    case T30_ERR_RX_INVALCMD:        /*! Unexpected command after page received */
00233    case T30_ERR_RX_NOCARRIER:       /*! Carrier lost during fax receive */
00234    case T30_ERR_RX_NOEOL:           /*! Timed out while waiting for EOL (end Of line) */
00235       ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
00236       break;
00237    case T30_ERR_RX_NOFAX:           /*! Timed out while waiting for first line */
00238       ast_atomic_fetchadd_int(&p->stats->nofax, 1);
00239       break;
00240    case T30_ERR_RX_T2EXPDCN:        /*! Timer T2 expired while waiting for DCN */
00241    case T30_ERR_RX_T2EXPD:          /*! Timer T2 expired while waiting for phase D */
00242    case T30_ERR_RX_T2EXPFAX:        /*! Timer T2 expired while waiting for fax page */
00243    case T30_ERR_RX_T2EXPMPS:        /*! Timer T2 expired while waiting for next fax page */
00244    case T30_ERR_RX_T2EXPRR:         /*! Timer T2 expired while waiting for RR command */
00245    case T30_ERR_RX_T2EXP:           /*! Timer T2 expired while waiting for NSS, DCS or MCF */
00246    case T30_ERR_RX_DCNWHY:          /*! Unexpected DCN while waiting for DCS or DIS */
00247    case T30_ERR_RX_DCNDATA:         /*! Unexpected DCN while waiting for image data */
00248    case T30_ERR_RX_DCNFAX:          /*! Unexpected DCN while waiting for EOM, EOP or MPS */
00249    case T30_ERR_RX_DCNPHD:          /*! Unexpected DCN after EOM or MPS sequence */
00250    case T30_ERR_RX_DCNRRD:          /*! Unexpected DCN after RR/RNR sequence */
00251    case T30_ERR_RX_DCNNORTN:        /*! Unexpected DCN after requested retransmission */
00252       ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
00253       break;
00254 
00255    /* TIFF file problems */
00256    case T30_ERR_FILEERROR:          /*! TIFF/F file cannot be opened */
00257    case T30_ERR_NOPAGE:             /*! TIFF/F page not found */
00258    case T30_ERR_BADTIFF:            /*! TIFF/F format is not compatible */
00259    case T30_ERR_BADPAGE:            /*! TIFF/F page number tag missing */
00260    case T30_ERR_BADTAG:             /*! Incorrect values for TIFF/F tags */
00261    case T30_ERR_BADTIFFHDR:         /*! Bad TIFF/F header - incorrect values in fields */
00262       ast_atomic_fetchadd_int(&p->stats->file_error, 1);
00263       break;
00264    case T30_ERR_NOMEM:              /*! Cannot allocate memory for more pages */
00265       ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
00266       break;
00267 
00268    /* General problems */
00269    case T30_ERR_RETRYDCN:           /*! Disconnected after permitted retries */
00270       ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
00271       break;
00272    case T30_ERR_CALLDROPPED:        /*! The call dropped prematurely */
00273       ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
00274       break;
00275 
00276    /* Feature negotiation issues */
00277    case T30_ERR_NOPOLL:             /*! Poll not accepted */
00278    case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
00279    case T30_ERR_SUB_UNACCEPTABLE:   /*! Far end's sub-address is not acceptable */
00280    case T30_ERR_SEP_UNACCEPTABLE:   /*! Far end's selective polling address is not acceptable */
00281    case T30_ERR_PSA_UNACCEPTABLE:   /*! Far end's polled sub-address is not acceptable */
00282    case T30_ERR_SID_UNACCEPTABLE:   /*! Far end's sender identification is not acceptable */
00283    case T30_ERR_PWD_UNACCEPTABLE:   /*! Far end's password is not acceptable */
00284    case T30_ERR_TSA_UNACCEPTABLE:   /*! Far end's transmitting subscriber internet address is not acceptable */
00285    case T30_ERR_IRA_UNACCEPTABLE:   /*! Far end's internet routing address is not acceptable */
00286    case T30_ERR_CIA_UNACCEPTABLE:   /*! Far end's calling subscriber internet address is not acceptable */
00287    case T30_ERR_ISP_UNACCEPTABLE:   /*! Far end's internet selective polling address is not acceptable */
00288    case T30_ERR_CSA_UNACCEPTABLE:   /*! Far end's called subscriber internet address is not acceptable */
00289       ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
00290       break;
00291    default:
00292       ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
00293       ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
00294       return -1;
00295    }
00296    return 0;
00297 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Spandsp G.711 and T.38 FAX Technologies" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, } [static]

Definition at line 772 of file res_fax_spandsp.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 772 of file res_fax_spandsp.c.

struct spandsp_fax_stats g711

Definition at line 110 of file res_fax_spandsp.c.

ast_mutex_t lock

Definition at line 109 of file res_fax_spandsp.c.

struct ast_fax_tech spandsp_fax_tech [static]

Definition at line 66 of file res_fax_spandsp.c.

Referenced by load_module(), and unload_module().

struct { ... } spandsp_global_stats [static]

struct spandsp_fax_stats t38

Definition at line 111 of file res_fax_spandsp.c.

Referenced by transmit_t38().


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