Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Functions | Variables
res_fax_spandsp.c File Reference

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

#include "asterisk.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"
#include "asterisk/channel.h"
#include "asterisk/format_cache.h"
#include <spandsp.h>
#include <spandsp/version.h>

Go to the source code of this file.

Data Structures

struct  spandsp_pvt::frame_queue
 
struct  spandsp_fax_stats
 
struct  spandsp_pvt
 

Macros

#define ASTMM_LIBC   ASTMM_IGNORE
 
#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY   3
 
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
 
#define SPANDSP_FAX_SAMPLES   160
 
#define SPANDSP_FAX_TIMER_RATE   8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (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_gateway_cleanup (struct ast_fax_session *s)
 gather data and clean up after gateway ends More...
 
static int spandsp_fax_gateway_process (struct ast_fax_session *s, const struct ast_frame *f)
 process a frame from the bridge More...
 
static int spandsp_fax_gateway_start (struct ast_fax_session *s)
 activate a spandsp gateway based on the information in the given fax session More...
 
static void * spandsp_fax_gw_gen_alloc (struct ast_channel *chan, void *params)
 simple routine to allocate data to generator More...
 
static void spandsp_fax_gw_gen_release (struct ast_channel *chan, void *data)
 
static int spandsp_fax_gw_t30_gen (struct ast_channel *chan, void *data, int len, int samples)
 generate T.30 packets sent to the T.30 leg of gateway More...
 
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. More...
 
static void spandsp_log (int level, const char *msg)
 Send spandsp log messages to asterisk. More...
 
static void spandsp_manager_fax_session (struct mansession *s, const char *id_text, struct ast_fax_session *session)
 
static int spandsp_modems (struct ast_fax_session_details *details)
 
static void spandsp_v21_cleanup (struct ast_fax_session *s)
 
static int spandsp_v21_detect (struct ast_fax_session *s, const struct ast_frame *f)
 
static int spandsp_v21_new (struct spandsp_pvt *p)
 
static void spandsp_v21_tone (void *data, int code, int level, int delay)
 
static void t30_phase_e_handler (t30_state_t *t30_state, void *data, int completion_code)
 Phase E handler callback. More...
 
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 = "da6642af068ee5e6490c5b1d2cc1d238" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .enhances = "res_fax", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_fax_tech spandsp_fax_tech
 
struct {
   struct spandsp_fax_stats   g711
 
   ast_mutex_t   lock
 
   struct spandsp_fax_stats   t38
 
spandsp_global_stats
 

Detailed Description

Spandsp T.38 and G.711 FAX Resource.

Author
Matthew Nicholson mnich.nosp@m.olso.nosp@m.n@dig.nosp@m.ium..nosp@m.com
Gregory H. Nietsky grego.nosp@m.ry@d.nosp@m.istro.nosp@m.tech.nosp@m..co.z.nosp@m.a

This module registers the Spandsp FAX technology with the res_fax module.

Definition in file res_fax_spandsp.c.

Function Documentation

static void spandsp_fax_gateway_cleanup ( struct ast_fax_session s)
static

gather data and clean up after gateway ends

Parameters
sfax session

Definition at line 951 of file res_fax_spandsp.c.

References ast_string_field_build, ast_fax_session::details, ast_fax_session_details::ecm, ast_fax_session_details::option, ast_fax_session_details::pages_transferred, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_destroy().

952 {
953  struct spandsp_pvt *p = s->tech_pvt;
954  t38_stats_t t38_stats;
955 
956  t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
957 
958  s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
959  s->details->pages_transferred = t38_stats.pages_transferred;
960  ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
961 }
struct ast_fax_session_details * details
Definition: res_fax.h:208
unsigned int pages_transferred
Definition: res_fax.h:144
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
union ast_fax_session_details::@249 option
void * tech_pvt
Definition: res_fax.h:216
static int spandsp_fax_gateway_process ( struct ast_fax_session s,
const struct ast_frame f 
)
static

process a frame from the bridge

Parameters
sfax session
fframe to process
Returns
1 on sucess 0 on incorrect packet

Definition at line 929 of file res_fax_spandsp.c.

References ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_slin, AST_FRAME_MODEM, AST_FRAME_VOICE, AST_MODEM_T38, ast_frame::data, ast_frame::datalen, ast_frame_subclass::format, ast_frame::frametype, ast_frame_subclass::integer, ast_frame::samples, ast_frame::seqno, ast_frame::subclass, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_write().

930 {
931  struct spandsp_pvt *p = s->tech_pvt;
932 
933  /*invalid frame*/
934  if (!f->data.ptr || !f->datalen) {
935  return -1;
936  }
937 
938  /* Process a IFP packet */
939  if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
940  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
941  } else if ((f->frametype == AST_FRAME_VOICE) &&
943  return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
944  }
945 
946  return -1;
947 }
struct ast_frame_subclass subclass
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
union ast_frame::@224 data
#define AST_MODEM_T38
void * tech_pvt
Definition: res_fax.h:216
enum ast_frame_type frametype
struct ast_format * format
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
static int spandsp_fax_gateway_start ( struct ast_fax_session s)
static

activate a spandsp gateway based on the information in the given fax session

Parameters
sfax session
Returns
-1 on error 0 on sucess

Definition at line 848 of file res_fax_spandsp.c.

References ast_activate_generator(), ast_channel_bridge_peer(), ast_channel_get_t38_state(), ast_fax_session::chan, ast_fax_session::details, ast_fax_session_details::ecm, ast_fax_t38_parameters::fill_bit_removal, ast_fax_t38_parameters::max_ifp, ast_fax_session_details::option, ast_fax_session_details::our_t38_parameters, RAII_VAR, ast_fax_t38_parameters::rate_management, spandsp_fax_gw_gen_alloc(), spandsp_fax_gw_t30_gen(), ast_fax_session::state, T38_STATE_NEGOTIATED, T38_STATE_NEGOTIATING, ast_fax_session::tech_pvt, ast_fax_session_details::their_t38_parameters, ast_fax_t38_parameters::transcoding_jbig, ast_fax_t38_parameters::transcoding_mmr, and ast_fax_t38_parameters::version.

849 {
850  struct spandsp_pvt *p = s->tech_pvt;
851  struct ast_fax_t38_parameters *t38_param;
852  int i;
853  RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
854  static struct ast_generator t30_gen = {
855  .alloc = spandsp_fax_gw_gen_alloc,
856  .release = spandsp_fax_gw_gen_release,
857  .generate = spandsp_fax_gw_t30_gen,
858  };
859 
860 #if SPANDSP_RELEASE_DATE >= 20081012
861  /* for spandsp shaphots 0.0.6 and higher */
862  p->t38_core_state=&p->t38_gw_state.t38x.t38;
863 #else
864  /* for spandsp release 0.0.5 */
865  p->t38_core_state=&p->t38_gw_state.t38;
866 #endif
867 
868  if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
869  return -1;
870  }
871 
872  p->ist38 = 1;
873  p->ast_t38_state = ast_channel_get_t38_state(s->chan);
874  peer = ast_channel_bridge_peer(s->chan);
875  if (!peer) {
876  return -1;
877  }
878 
879  /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
880  * gateway is started. We treat both states the same. */
881  if (p->ast_t38_state == T38_STATE_NEGOTIATING) {
882  p->ast_t38_state = T38_STATE_NEGOTIATED;
883  }
884 
885  ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
886 
887  set_logging(&p->t38_gw_state.logging, s->details);
888  set_logging(&p->t38_core_state->logging, s->details);
889 
890  t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
891  t38_set_t38_version(p->t38_core_state, t38_param->version);
892  t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
893  t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
894  t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
895  t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
896  t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
897  t38_set_data_rate_management_method(p->t38_core_state,
898  (t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
899 
900  t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
901  t38_set_sequence_number_handling(p->t38_core_state, TRUE);
902 
903 
904  t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details));
905 
906  /* engage udptl nat on other side of T38 line
907  * (Asterisk changes media ports thus we send a few packets to reinitialize
908  * pinholes in NATs and FWs
909  */
910  for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
911 #if SPANDSP_RELEASE_DATE >= 20091228
912  t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
913 #elif SPANDSP_RELEASE_DATE >= 20081012
914  t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
915 #else
916  t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
917 #endif
918  }
919 
920  s->state = AST_FAX_STATE_ACTIVE;
921 
922  return 0;
923 }
static enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
Retrieves the current T38 state of a channel.
Definition: channel.h:2850
Main Channel structure associated with a channel.
static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
generate T.30 packets sent to the T.30 leg of gateway
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2951
struct ast_channel * chan
Definition: res_fax.h:224
struct ast_fax_t38_parameters our_t38_parameters
Definition: res_fax.h:175
struct ast_fax_session_details * details
Definition: res_fax.h:208
unsigned int transcoding_mmr
Definition: res_fax.h:98
unsigned int transcoding_jbig
Definition: res_fax.h:99
unsigned int max_ifp
Definition: res_fax.h:94
enum ast_fax_state state
Definition: res_fax.h:218
unsigned int version
Definition: res_fax.h:93
union ast_fax_session_details::@249 option
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition: channel.c:10564
enum ast_control_t38_rate_management rate_management
Definition: res_fax.h:96
void * tech_pvt
Definition: res_fax.h:216
unsigned int fill_bit_removal
Definition: res_fax.h:97
struct ast_fax_t38_parameters their_t38_parameters
Definition: res_fax.h:177
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
static void * spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params)
simple routine to allocate data to generator
static void* spandsp_fax_gw_gen_alloc ( struct ast_channel chan,
void *  params 
)
static

simple routine to allocate data to generator

Parameters
chanchannel
paramsgenerator data
Returns
data to use in generator call

Definition at line 834 of file res_fax_spandsp.c.

References ao2_ref.

Referenced by spandsp_fax_gateway_start().

835 {
836  ao2_ref(params, +1);
837  return params;
838 }
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static int spandsp_fax_gw_t30_gen ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

generate T.30 packets sent to the T.30 leg of gateway

Parameters
chanT.30 channel
datafax session structure
lennot used
samplesno of samples generated
Returns
-1 on failure or 0 on sucess

Definition at line 800 of file res_fax_spandsp.c.

References ast_format_slin, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_frisolate, ast_write(), ast_frame::data, ast_frame::datalen, ast_frame::frametype, ast_frame::samples, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_gateway_start().

801 {
802  int res = -1;
803  struct ast_fax_session *s = data;
804  struct spandsp_pvt *p = s->tech_pvt;
805  uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
806  struct ast_frame *f;
807  struct ast_frame t30_frame = {
809  .subclass.format = ast_format_slin,
810  .src = "res_fax_spandsp_g711",
811  .samples = samples,
812  .flags = AST_FAX_FRFLAG_GATEWAY,
813  };
814 
815  AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
816 
817  if (!(f = ast_frisolate(&t30_frame))) {
818  return p->isdone ? -1 : res;
819  }
820 
821  /* generate a T.30 packet */
822  if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
823  f->datalen = f->samples * sizeof(int16_t);
824  res = ast_write(chan, f);
825  }
826  ast_frfree(f);
827  return p->isdone ? -1 : res;
828 }
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
union ast_frame::@224 data
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5144
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
The data required to handle a fax session.
Definition: res_fax.h:202
Data structure associated with a single frame of data.
void * tech_pvt
Definition: res_fax.h:216
enum ast_frame_type frametype
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
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
sa fax session
fthe 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
0success
-1failure

Definition at line 769 of file res_fax_spandsp.c.

References ast_fax_state_to_str(), ast_fax_session_details::caps, ast_frame::data, ast_frame::datalen, ast_fax_session::details, ast_fax_session::id, ast_frame::samples, ast_frame::seqno, spandsp_fax_gateway_process(), ast_fax_session::state, and ast_fax_session::tech_pvt.

770 {
771  struct spandsp_pvt *p = s->tech_pvt;
772 
773  if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
774  return spandsp_v21_detect(s, f);
775  }
776 
777  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
778  return spandsp_fax_gateway_process(s, f);
779  }
780 
781  /* XXX do we need to lock here? */
782  if (s->state == AST_FAX_STATE_COMPLETE) {
783  ast_log(LOG_WARNING, "FAX session '%u' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
784  return -1;
785  }
786 
787  if (p->ist38) {
788  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
789  } else {
790  return fax_rx(&p->fax_state, f->data.ptr, f->samples);
791  }
792 }
unsigned int id
Definition: res_fax.h:204
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
process a frame from the bridge
struct ast_fax_session_details * details
Definition: res_fax.h:208
union ast_frame::@224 data
enum ast_fax_state state
Definition: res_fax.h:218
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert a ast_fax_state to a string
Definition: res_fax.c:1012
static void spandsp_log ( int  level,
const char *  msg 
)
static

Send spandsp log messages to asterisk.

Parameters
levelthe spandsp logging level
msgthe log message
Note
This function is a callback function called by spandsp.

Definition at line 455 of file res_fax_spandsp.c.

References ast_fax_log().

457 {
458  if (level == SPAN_LOG_ERROR) {
459  ast_log(LOG_ERROR, "%s", msg);
460  } else if (level == SPAN_LOG_WARNING) {
461  ast_log(LOG_WARNING, "%s", msg);
462  } else {
463  ast_fax_log(LOG_DEBUG, msg);
464  }
465 }
void ast_fax_log(int level, const char *file, const int line, const char *function, const char *msg)
Log message at FAX or recommended level.
Definition: res_fax.c:1035
static void t30_phase_e_handler ( t30_state_t *  t30_state,
void *  data,
int  completion_code 
)
static

Phase E handler callback.

Parameters
t30_statethe span t30 state
datathis will be the ast_fax_session
completion_codethe 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 390 of file res_fax_spandsp.c.

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

392 {
393  struct ast_fax_session *s = data;
394  struct spandsp_pvt *p = s->tech_pvt;
395  char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
396  const char *c;
397  t30_stats_t stats;
398 #if SPANDSP_RELEASE_DATE >= 20120902
399  /* for spandsp shaphots 3.0.0 and higher */
400  t30_state_t *t30_state = p->t30_state;
401 #endif
402 
403  ast_debug(5, "FAX session '%u' entering phase E\n", s->id);
404 
405  p->isdone = 1;
406 
407  update_stats(p, completion_code);
408 
409  t30_get_transfer_statistics(t30_state, &stats);
410 
411  if (completion_code == T30_ERR_OK) {
412  ast_string_field_set(s->details, result, "SUCCESS");
413  } else {
414  ast_string_field_set(s->details, result, "FAILED");
415  ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
416  }
417 
418  ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
419 
420  ast_debug(5, "FAX session '%u' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
421 
422  if ((c = t30_get_tx_ident(t30_state))) {
423  ast_string_field_set(s->details, localstationid, c);
424  }
425 
426  if ((c = t30_get_rx_ident(t30_state))) {
427  ast_string_field_set(s->details, remotestationid, c);
428  }
429 
430 #if SPANDSP_RELEASE_DATE >= 20090220
431  s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
432 #else
433  s->details->pages_transferred = stats.pages_transferred;
434 #endif
435 
436  ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
437 
438  ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
439 
440  t30_get_tx_page_header_info(t30_state, headerinfo);
441  ast_string_field_set(s->details, headerinfo, headerinfo);
442 }
const ast_string_field result
Definition: res_fax.h:142
unsigned int id
Definition: res_fax.h:204
struct ast_fax_session_details * details
Definition: res_fax.h:208
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int pages_transferred
Definition: res_fax.h:144
static int update_stats(struct spandsp_pvt *p, int completion_code)
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
The data required to handle a fax session.
Definition: res_fax.h:202
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216
const ast_string_field resultstr
Definition: res_fax.h:142
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
static int update_stats ( struct spandsp_pvt p,
int  completion_code 
)
static

The CED tone exceeded 5s

Timed out waiting for initial communication

Timed out waiting for the first message

Timed out waiting for procedural interrupt

The HDLC carrier did not stop in a timely manner

Failed to train with any of the compatible modems

Operator intervention failed

Far end is not compatible

Far end is not able to receive

Far end is not able to transmit

Far end cannot receive at the resolution of the image

Far end cannot receive at the size of image

Unexpected message received

Received bad response to DCS or training

Received a DCN from remote after sending a page

Invalid ECM response received from receiver

Received a DCN while waiting for a DIS

Invalid response after sending a page

Received other than DIS while waiting for DIS

Received no response to DCS, training or TCF

No response after sending a page

Timed out waiting for receiver ready (ECM mode)

Invalid ECM response received from transmitter

DCS received while waiting for DTC

Unexpected command after page received

Carrier lost during fax receive

Timed out while waiting for EOL (end Of line)

Timed out while waiting for first line

Timer T2 expired while waiting for DCN

Timer T2 expired while waiting for phase D

Timer T2 expired while waiting for fax page

Timer T2 expired while waiting for next fax page

Timer T2 expired while waiting for RR command

Timer T2 expired while waiting for NSS, DCS or MCF

Unexpected DCN while waiting for DCS or DIS

Unexpected DCN while waiting for image data

Unexpected DCN while waiting for EOM, EOP or MPS

Unexpected DCN after EOM or MPS sequence

Unexpected DCN after RR/RNR sequence

Unexpected DCN after requested retransmission

TIFF/F file cannot be opened

TIFF/F page not found

TIFF/F format is not compatible

TIFF/F page number tag missing

Incorrect values for TIFF/F tags

Bad TIFF/F header - incorrect values in fields

Cannot allocate memory for more pages

Disconnected after permitted retries

The call dropped prematurely

Poll not accepted

Far end's ident is not acceptable

Far end's sub-address is not acceptable

Far end's selective polling address is not acceptable

Far end's polled sub-address is not acceptable

Far end's sender identification is not acceptable

Far end's password is not acceptable

Far end's transmitting subscriber internet address is not acceptable

Far end's internet routing address is not acceptable

Far end's calling subscriber internet address is not acceptable

Far end's internet selective polling address is not acceptable

Far end's called subscriber internet address is not acceptable

Definition at line 264 of file res_fax_spandsp.c.

References ast_atomic_fetchadd_int().

Referenced by t30_phase_e_handler().

265 {
266  switch (completion_code) {
267  case T30_ERR_OK:
268  ast_atomic_fetchadd_int(&p->stats->success, 1);
269  break;
270 
271  /* Link problems */
272  case T30_ERR_CEDTONE: /*! The CED tone exceeded 5s */
273  case T30_ERR_T0_EXPIRED: /*! Timed out waiting for initial communication */
274  case T30_ERR_T1_EXPIRED: /*! Timed out waiting for the first message */
275  case T30_ERR_T3_EXPIRED: /*! Timed out waiting for procedural interrupt */
276  case T30_ERR_HDLC_CARRIER: /*! The HDLC carrier did not stop in a timely manner */
277  case T30_ERR_CANNOT_TRAIN: /*! Failed to train with any of the compatible modems */
278  ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
279  break;
280 
281  case T30_ERR_OPER_INT_FAIL: /*! Operator intervention failed */
282  case T30_ERR_INCOMPATIBLE: /*! Far end is not compatible */
283  case T30_ERR_RX_INCAPABLE: /*! Far end is not able to receive */
284  case T30_ERR_TX_INCAPABLE: /*! Far end is not able to transmit */
285  case T30_ERR_NORESSUPPORT: /*! Far end cannot receive at the resolution of the image */
286  case T30_ERR_NOSIZESUPPORT: /*! Far end cannot receive at the size of image */
287  ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
288  break;
289 
290  case T30_ERR_UNEXPECTED: /*! Unexpected message received */
291  ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
292  break;
293 
294  /* Phase E status values returned to a transmitter */
295  case T30_ERR_TX_BADDCS: /*! Received bad response to DCS or training */
296  case T30_ERR_TX_BADPG: /*! Received a DCN from remote after sending a page */
297  case T30_ERR_TX_ECMPHD: /*! Invalid ECM response received from receiver */
298  case T30_ERR_TX_GOTDCN: /*! Received a DCN while waiting for a DIS */
299  case T30_ERR_TX_INVALRSP: /*! Invalid response after sending a page */
300  case T30_ERR_TX_NODIS: /*! Received other than DIS while waiting for DIS */
301  case T30_ERR_TX_PHBDEAD: /*! Received no response to DCS, training or TCF */
302  case T30_ERR_TX_PHDDEAD: /*! No response after sending a page */
303  case T30_ERR_TX_T5EXP: /*! Timed out waiting for receiver ready (ECM mode) */
304  ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
305  break;
306 
307  /* Phase E status values returned to a receiver */
308  case T30_ERR_RX_ECMPHD: /*! Invalid ECM response received from transmitter */
309  case T30_ERR_RX_GOTDCS: /*! DCS received while waiting for DTC */
310  case T30_ERR_RX_INVALCMD: /*! Unexpected command after page received */
311  case T30_ERR_RX_NOCARRIER: /*! Carrier lost during fax receive */
312  case T30_ERR_RX_NOEOL: /*! Timed out while waiting for EOL (end Of line) */
313  ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
314  break;
315  case T30_ERR_RX_NOFAX: /*! Timed out while waiting for first line */
316  ast_atomic_fetchadd_int(&p->stats->nofax, 1);
317  break;
318  case T30_ERR_RX_T2EXPDCN: /*! Timer T2 expired while waiting for DCN */
319  case T30_ERR_RX_T2EXPD: /*! Timer T2 expired while waiting for phase D */
320  case T30_ERR_RX_T2EXPFAX: /*! Timer T2 expired while waiting for fax page */
321  case T30_ERR_RX_T2EXPMPS: /*! Timer T2 expired while waiting for next fax page */
322  case T30_ERR_RX_T2EXPRR: /*! Timer T2 expired while waiting for RR command */
323  case T30_ERR_RX_T2EXP: /*! Timer T2 expired while waiting for NSS, DCS or MCF */
324  case T30_ERR_RX_DCNWHY: /*! Unexpected DCN while waiting for DCS or DIS */
325  case T30_ERR_RX_DCNDATA: /*! Unexpected DCN while waiting for image data */
326  case T30_ERR_RX_DCNFAX: /*! Unexpected DCN while waiting for EOM, EOP or MPS */
327  case T30_ERR_RX_DCNPHD: /*! Unexpected DCN after EOM or MPS sequence */
328  case T30_ERR_RX_DCNRRD: /*! Unexpected DCN after RR/RNR sequence */
329  case T30_ERR_RX_DCNNORTN: /*! Unexpected DCN after requested retransmission */
330  ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
331  break;
332 
333  /* TIFF file problems */
334  case T30_ERR_FILEERROR: /*! TIFF/F file cannot be opened */
335  case T30_ERR_NOPAGE: /*! TIFF/F page not found */
336  case T30_ERR_BADTIFF: /*! TIFF/F format is not compatible */
337  case T30_ERR_BADPAGE: /*! TIFF/F page number tag missing */
338  case T30_ERR_BADTAG: /*! Incorrect values for TIFF/F tags */
339  case T30_ERR_BADTIFFHDR: /*! Bad TIFF/F header - incorrect values in fields */
340  ast_atomic_fetchadd_int(&p->stats->file_error, 1);
341  break;
342  case T30_ERR_NOMEM: /*! Cannot allocate memory for more pages */
343  ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
344  break;
345 
346  /* General problems */
347  case T30_ERR_RETRYDCN: /*! Disconnected after permitted retries */
348  ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
349  break;
350  case T30_ERR_CALLDROPPED: /*! The call dropped prematurely */
351  ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
352  break;
353 
354  /* Feature negotiation issues */
355  case T30_ERR_NOPOLL: /*! Poll not accepted */
356  case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
357  case T30_ERR_SUB_UNACCEPTABLE: /*! Far end's sub-address is not acceptable */
358  case T30_ERR_SEP_UNACCEPTABLE: /*! Far end's selective polling address is not acceptable */
359  case T30_ERR_PSA_UNACCEPTABLE: /*! Far end's polled sub-address is not acceptable */
360  case T30_ERR_SID_UNACCEPTABLE: /*! Far end's sender identification is not acceptable */
361  case T30_ERR_PWD_UNACCEPTABLE: /*! Far end's password is not acceptable */
362  case T30_ERR_TSA_UNACCEPTABLE: /*! Far end's transmitting subscriber internet address is not acceptable */
363  case T30_ERR_IRA_UNACCEPTABLE: /*! Far end's internet routing address is not acceptable */
364  case T30_ERR_CIA_UNACCEPTABLE: /*! Far end's calling subscriber internet address is not acceptable */
365  case T30_ERR_ISP_UNACCEPTABLE: /*! Far end's internet selective polling address is not acceptable */
366  case T30_ERR_CSA_UNACCEPTABLE: /*! Far end's called subscriber internet address is not acceptable */
367  ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
368  break;
369  default:
370  ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
371  ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
372  return -1;
373  }
374  return 0;
375 }
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757