Asterisk - The Open Source Telephony Project  18.5.0
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>
Include dependency graph for res_fax_spandsp.c:

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 More...
 
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. More...
 
static char * spandsp_fax_cli_show_stats (int fd)
 
static void spandsp_fax_destroy (struct ast_fax_session *s)
 Destroy a spandsp fax session. More...
 
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 More...
 
static struct ast_framespandsp_fax_read (struct ast_fax_session *s)
 Read a frame from the spandsp fax stack. More...
 
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 More...
 
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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.

Macro Definition Documentation

◆ ASTMM_LIBC

#define ASTMM_LIBC   ASTMM_IGNORE

Definition at line 52 of file res_fax_spandsp.c.

◆ SPANDSP_ENGAGE_UDPTL_NAT_RETRY

#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY   3

Definition at line 72 of file res_fax_spandsp.c.

Referenced by spandsp_fax_gateway_start().

◆ SPANDSP_EXPOSE_INTERNAL_STRUCTURES

#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES

Definition at line 66 of file res_fax_spandsp.c.

◆ SPANDSP_FAX_SAMPLES

#define SPANDSP_FAX_SAMPLES   160

Definition at line 70 of file res_fax_spandsp.c.

Referenced by spandsp_fax_read().

◆ SPANDSP_FAX_TIMER_RATE

#define SPANDSP_FAX_TIMER_RATE   8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */

Definition at line 71 of file res_fax_spandsp.c.

Referenced by spandsp_fax_start().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1270 of file res_fax_spandsp.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1270 of file res_fax_spandsp.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1270 of file res_fax_spandsp.c.

◆ load_module()

static int load_module ( void  )
static

load res_fax_spandsp

Definition at line 1249 of file res_fax_spandsp.c.

References ast_fax_tech_register(), ast_log, AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_EXTENDED, ast_mutex_init, ASTERISK_GPL_KEY, LOG_ERROR, ast_fax_tech::module, NULL, ast_module_info::self, spandsp_global_stats, and unload_module().

1250 {
1254  ast_log(LOG_ERROR, "failed to register FAX technology\n");
1255  return AST_MODULE_LOAD_DECLINE;
1256  }
1257 
1258  /* prevent logging to stderr */
1259  span_set_message_handler(NULL);
1260 
1261  return AST_MODULE_LOAD_SUCCESS;
1262 }
static struct @462 spandsp_global_stats
static struct ast_fax_tech spandsp_fax_tech
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
struct ast_module * module
Definition: res_fax.h:245
#define LOG_ERROR
Definition: logger.h:285
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_mutex_init(pmutex)
Definition: lock.h:184
int ast_fax_tech_register(struct ast_fax_tech *tech)
register a fax technology
Definition: res_fax.c:974

◆ session_destroy()

static void session_destroy ( struct spandsp_pvt p)
static

Definition at line 180 of file res_fax_spandsp.c.

References ast_frfree, AST_LIST_REMOVE_HEAD, ast_timer_close(), spandsp_pvt::fax_state, spandsp_pvt::isdone, spandsp_pvt::ist38, NULL, spandsp_pvt::read_frames, spandsp_pvt::t30_state, spandsp_pvt::t38_state, and spandsp_pvt::timer.

Referenced by spandsp_fax_destroy().

181 {
182  struct ast_frame *f;
183  t30_state_t *t30_to_terminate;
184 
185  if (p->t30_state) {
186  t30_to_terminate = p->t30_state;
187  } else if (p->ist38) {
188 #if SPANDSP_RELEASE_DATE >= 20080725
189  t30_to_terminate = &p->t38_state.t30;
190 #else
191  t30_to_terminate = &p->t38_state.t30_state;
192 #endif
193  } else {
194 #if SPANDSP_RELEASE_DATE >= 20080725
195  t30_to_terminate = &p->fax_state.t30;
196 #else
197  t30_to_terminate = &p->fax_state.t30_state;
198 #endif
199  }
200 
201  t30_terminate(t30_to_terminate);
202  p->isdone = 1;
203 
205  p->timer = NULL;
206  fax_release(&p->fax_state);
207  t38_terminal_release(&p->t38_state);
208 
209  while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
210  ast_frfree(f);
211  }
212 }
t38_terminal_state_t t38_state
struct ast_timer * timer
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
unsigned int ist38
#define NULL
Definition: resample.c:96
struct spandsp_pvt::frame_queue read_frames
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
unsigned int isdone
t30_state_t * t30_state
#define ast_frfree(fr)
Data structure associated with a single frame of data.
fax_state_t fax_state

◆ set_ecm()

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

Definition at line 479 of file res_fax_spandsp.c.

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

Referenced by spandsp_fax_start().

480 {
481  t30_set_ecm_capability(t30_state, details->option.ecm);
482  t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
483 }
union ast_fax_session_details::@290 option

◆ set_file()

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

Definition at line 467 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.

Referenced by spandsp_fax_start().

468 {
469  if (details->caps & AST_FAX_TECH_RECEIVE) {
470  t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
471  } else {
472  /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
473  * should be safe because we ensure either RECEIVE or SEND is
474  * indicated in spandsp_fax_new() */
475  t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
476  }
477 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
struct ast_fax_documents documents
Definition: res_fax.h:119
enum ast_fax_capabilities caps
Definition: res_fax.h:113

◆ set_local_info()

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

Definition at line 456 of file res_fax_spandsp.c.

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

Referenced by spandsp_fax_start().

457 {
458  if (!ast_strlen_zero(details->localstationid)) {
459  t30_set_tx_ident(t30_state, details->localstationid);
460  }
461 
462  if (!ast_strlen_zero(details->headerinfo)) {
463  t30_set_tx_page_header_info(t30_state, details->headerinfo);
464  }
465 }
const ast_string_field headerinfo
Definition: res_fax.h:142
#define ast_strlen_zero(foo)
Definition: strings.h:52
const ast_string_field localstationid
Definition: res_fax.h:142

◆ set_logging()

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

Definition at line 444 of file res_fax_spandsp.c.

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

Referenced by spandsp_fax_gateway_start(), spandsp_fax_new(), and spandsp_fax_start().

445 {
446  int level = SPAN_LOG_WARNING;
447 
448  if (details->option.debug) {
449  level = SPAN_LOG_DEBUG_3;
450  }
451 
452  span_log_set_message_handler(state, spandsp_log);
453  span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
454 }
union ast_fax_session_details::@290 option
static void spandsp_log(int level, const char *msg)
Send spandsp log messages to asterisk.

◆ spandsp_fax_cancel()

static int spandsp_fax_cancel ( struct ast_fax_session s)
static

Definition at line 1006 of file res_fax_spandsp.c.

References AST_FAX_TECH_GATEWAY, ast_fax_session_details::caps, ast_fax_session::details, spandsp_pvt::isdone, spandsp_pvt::t30_state, and ast_fax_session::tech_pvt.

1007 {
1008  struct spandsp_pvt *p = s->tech_pvt;
1009 
1010  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
1011  p->isdone = 1;
1012  return 0;
1013  }
1014 
1015  t30_terminate(p->t30_state);
1016  p->isdone = 1;
1017  return 0;
1018 }
struct ast_fax_session_details * details
Definition: res_fax.h:208
unsigned int isdone
t30_state_t * t30_state
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216

◆ spandsp_fax_cli_show_capabilities()

static char * spandsp_fax_cli_show_capabilities ( int  fd)
static

Definition at line 1041 of file res_fax_spandsp.c.

References ast_cli(), and CLI_SUCCESS.

1042 {
1043  ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
1044  return CLI_SUCCESS;
1045 }
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define CLI_SUCCESS
Definition: cli.h:44

◆ spandsp_fax_cli_show_session()

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

Definition at line 1048 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_GATEWAY, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_SEND, AST_FAX_TECH_V21_DETECT, 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, spandsp_pvt::t38_gw_state, and ast_fax_session::tech_pvt.

1049 {
1050  ao2_lock(s);
1051  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
1052  struct spandsp_pvt *p = s->tech_pvt;
1053 
1054  ast_cli(fd, "%-22s : %u\n", "session", s->id);
1055  ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
1056  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1057  if (s->state != AST_FAX_STATE_UNINITIALIZED) {
1058  t38_stats_t stats;
1059  t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
1060  ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1061  ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1062  ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1063  }
1064  } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
1065  ast_cli(fd, "%-22s : %u\n", "session", s->id);
1066  ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
1067  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1068  } else {
1069  struct spandsp_pvt *p = s->tech_pvt;
1070 
1071  ast_cli(fd, "%-22s : %u\n", "session", s->id);
1072  ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
1073  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1074  if (s->state != AST_FAX_STATE_UNINITIALIZED) {
1075  t30_stats_t stats;
1076  t30_get_transfer_statistics(p->t30_state, &stats);
1077  ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
1078  ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1079  ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1080  ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
1081 #if SPANDSP_RELEASE_DATE >= 20090220
1082  ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1083 #else
1084  ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1085 #endif
1086  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);
1087 
1088  ast_cli(fd, "\nData Statistics:\n");
1089 #if SPANDSP_RELEASE_DATE >= 20090220
1090  ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
1091  ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
1092 #else
1093  ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1094  ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1095 #endif
1096  ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
1097  ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
1098  }
1099  }
1100  ao2_unlock(s);
1101  ast_cli(fd, "\n\n");
1102  return CLI_SUCCESS;
1103 }
unsigned int id
Definition: res_fax.h:204
#define ao2_unlock(a)
Definition: astobj2.h:730
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
struct ast_fax_session_details * details
Definition: res_fax.h:208
#define ao2_lock(a)
Definition: astobj2.h:718
t38_gateway_state_t t38_gw_state
struct spandsp_fax_stats * stats
t30_state_t * t30_state
enum ast_fax_state state
Definition: res_fax.h:218
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert an ast_fax_state to a string
Definition: res_fax.c:1013
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216

◆ spandsp_fax_cli_show_settings()

static char * spandsp_fax_cli_show_settings ( int  fd)
static

Show res_fax_spandsp settings.

Definition at line 1234 of file res_fax_spandsp.c.

References CLI_SUCCESS.

1235 {
1236  /* no settings at the moment */
1237  return CLI_SUCCESS;
1238 }
#define CLI_SUCCESS
Definition: cli.h:44

◆ spandsp_fax_cli_show_stats()

static char * spandsp_fax_cli_show_stats ( int  fd)
static

Definition at line 1197 of file res_fax_spandsp.c.

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

1198 {
1200  ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
1201  ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
1202  ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
1203  ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
1204  ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
1205  ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
1206  ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
1207  ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
1208  ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
1209  ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
1210  ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
1211  ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
1212  ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
1213  ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
1214 
1215  ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
1216  ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
1217  ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
1218  ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
1219  ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
1220  ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
1221  ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
1222  ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
1223  ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
1224  ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
1225  ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
1226  ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
1227  ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
1229 
1230  return CLI_SUCCESS;
1231 }
static struct @462 spandsp_global_stats
#define ast_mutex_lock(a)
Definition: lock.h:187
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define CLI_SUCCESS
Definition: cli.h:44
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ spandsp_fax_destroy()

static void spandsp_fax_destroy ( struct ast_fax_session s)
static

Destroy a spandsp fax session.

Definition at line 603 of file res_fax_spandsp.c.

References AST_FAX_TECH_GATEWAY, AST_FAX_TECH_V21_DETECT, ast_free, ast_fax_session_details::caps, ast_fax_session::details, ast_fax_session::fd, NULL, session_destroy(), spandsp_fax_gateway_cleanup(), spandsp_v21_cleanup(), and ast_fax_session::tech_pvt.

604 {
605  struct spandsp_pvt *p = s->tech_pvt;
606 
607  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
609  } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
611  } else {
612  session_destroy(p);
613  }
614 
615  ast_free(p);
616  s->tech_pvt = NULL;
617  s->fd = -1;
618 }
static void session_destroy(struct spandsp_pvt *p)
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
gather data and clean up after gateway ends
#define NULL
Definition: resample.c:96
static void spandsp_v21_cleanup(struct ast_fax_session *s)
struct ast_fax_session_details * details
Definition: res_fax.h:208
#define ast_free(a)
Definition: astmm.h:182
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216

◆ spandsp_fax_gateway_cleanup()

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 916 of file res_fax_spandsp.c.

References AST_FAX_OPTFLAG_FALSE, AST_FAX_OPTFLAG_TRUE, ast_string_field_build, ast_fax_session::details, ast_fax_session_details::ecm, ast_fax_session_details::option, ast_fax_session_details::pages_transferred, spandsp_pvt::t38_gw_state, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_destroy().

917 {
918  struct spandsp_pvt *p = s->tech_pvt;
919  t38_stats_t t38_stats;
920 
921  t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
922 
923  s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
924  s->details->pages_transferred = t38_stats.pages_transferred;
925  ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
926 }
union ast_fax_session_details::@290 option
struct ast_fax_session_details * details
Definition: res_fax.h:208
t38_gateway_state_t t38_gw_state
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:550
void * tech_pvt
Definition: res_fax.h:216

◆ spandsp_fax_gateway_process()

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 incorect packet

Definition at line 894 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::ptr, ast_frame::samples, ast_frame::seqno, ast_frame::subclass, spandsp_pvt::t38_core_state, spandsp_pvt::t38_gw_state, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_write().

895 {
896  struct spandsp_pvt *p = s->tech_pvt;
897 
898  /*invalid frame*/
899  if (!f->data.ptr || !f->datalen) {
900  return -1;
901  }
902 
903  /* Process a IFP packet */
904  if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
905  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
906  } else if ((f->frametype == AST_FRAME_VOICE) &&
908  return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
909  }
910 
911  return -1;
912 }
struct ast_frame_subclass subclass
t38_core_state_t * t38_core_state
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
t38_gateway_state_t t38_gw_state
#define AST_MODEM_T38
void * tech_pvt
Definition: res_fax.h:216
union ast_frame::@263 data
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

◆ spandsp_fax_gateway_start()

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 813 of file res_fax_spandsp.c.

References ast_generator::alloc, ao2_cleanup, ast_activate_generator(), ast_channel_bridge_peer(), ast_channel_get_t38_state(), AST_FAX_STATE_ACTIVE, AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, spandsp_pvt::ast_t38_state, ast_fax_session::chan, ast_fax_session::details, ast_fax_session_details::ecm, ast_fax_t38_parameters::fill_bit_removal, spandsp_pvt::ist38, ast_fax_t38_parameters::max_ifp, NULL, ast_fax_session_details::option, ast_fax_session_details::our_t38_parameters, RAII_VAR, ast_fax_t38_parameters::rate_management, set_logging(), SPANDSP_ENGAGE_UDPTL_NAT_RETRY, spandsp_fax_gw_gen_alloc(), spandsp_fax_gw_gen_release(), spandsp_fax_gw_t30_gen(), spandsp_modems(), ast_fax_session::state, spandsp_pvt::t38_core_state, spandsp_pvt::t38_gw_state, T38_STATE_NEGOTIATED, T38_STATE_NEGOTIATING, t38_tx_packet_handler(), ast_fax_session::tech_pvt, ast_fax_session_details::their_t38_parameters, ast_fax_t38_parameters::transcoding_jbig, ast_fax_t38_parameters::transcoding_mmr, TRUE, and ast_fax_t38_parameters::version.

Referenced by spandsp_fax_start().

814 {
815  struct spandsp_pvt *p = s->tech_pvt;
816  struct ast_fax_t38_parameters *t38_param;
817  int i;
818  RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
819  static struct ast_generator t30_gen = {
821  .release = spandsp_fax_gw_gen_release,
822  .generate = spandsp_fax_gw_t30_gen,
823  };
824 
825 #if SPANDSP_RELEASE_DATE >= 20081012
826  /* for spandsp shaphots 0.0.6 and higher */
827  p->t38_core_state=&p->t38_gw_state.t38x.t38;
828 #else
829  /* for spandsp release 0.0.5 */
830  p->t38_core_state=&p->t38_gw_state.t38;
831 #endif
832 
833  if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
834  return -1;
835  }
836 
837  p->ist38 = 1;
839  peer = ast_channel_bridge_peer(s->chan);
840  if (!peer) {
841  return -1;
842  }
843 
844  /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
845  * gateway is started. We treat both states the same. */
848  }
849 
850  ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
851 
852  set_logging(&p->t38_gw_state.logging, s->details);
853  set_logging(&p->t38_core_state->logging, s->details);
854 
856  t38_set_t38_version(p->t38_core_state, t38_param->version);
857  t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
858  t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
859  t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
860  t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
861  t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
862  t38_set_data_rate_management_method(p->t38_core_state,
864 
865  t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
866  t38_set_sequence_number_handling(p->t38_core_state, TRUE);
867 
868 
869  t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details));
870 
871  /* engage udptl nat on other side of T38 line
872  * (Asterisk changes media ports thus we send a few packets to reinitialize
873  * pinholes in NATs and FWs
874  */
875  for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
876 #if SPANDSP_RELEASE_DATE >= 20091228
877  t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
878 #elif SPANDSP_RELEASE_DATE >= 20081012
879  t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
880 #else
881  t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
882 #endif
883  }
884 
886 
887  return 0;
888 }
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:2873
Main Channel structure associated with a channel.
static int spandsp_modems(struct ast_fax_session_details *details)
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
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:227
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2960
static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data)
unsigned int ist38
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
#define NULL
Definition: resample.c:96
struct ast_channel * chan
Definition: res_fax.h:224
t38_core_state_t * t38_core_state
union ast_fax_session_details::@290 option
struct ast_fax_t38_parameters our_t38_parameters
Definition: res_fax.h:175
#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:911
struct ast_fax_session_details * details
Definition: res_fax.h:208
t38_gateway_state_t t38_gw_state
static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
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_t38_state ast_t38_state
enum ast_fax_state state
Definition: res_fax.h:218
unsigned int version
Definition: res_fax.h:93
#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel&#39;s bridge peer only if the bridge is two-party.
Definition: channel.c:10765
#define TRUE
Definition: app_minivm.c:518
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
static void * spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params)
simple routine to allocate data to generator

◆ spandsp_fax_gw_gen_alloc()

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 799 of file res_fax_spandsp.c.

References ao2_ref.

Referenced by spandsp_fax_gateway_start().

800 {
801  ao2_ref(params, +1);
802  return params;
803 }
#define ao2_ref(o, delta)
Definition: astobj2.h:464

◆ spandsp_fax_gw_gen_release()

static void spandsp_fax_gw_gen_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 805 of file res_fax_spandsp.c.

References ao2_ref.

Referenced by spandsp_fax_gateway_start().

806 {
807  ao2_ref(data, -1);
808 }
#define ao2_ref(o, delta)
Definition: astobj2.h:464

◆ spandsp_fax_gw_t30_gen()

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 765 of file res_fax_spandsp.c.

References AST_FAX_FRFLAG_GATEWAY, ast_format_slin, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_frisolate, ast_write(), ast_frame::data, ast_frame::datalen, ast_frame::frametype, spandsp_pvt::isdone, ast_frame::ptr, ast_frame::samples, spandsp_pvt::t38_gw_state, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_gateway_start().

766 {
767  int res = -1;
768  struct ast_fax_session *s = data;
769  struct spandsp_pvt *p = s->tech_pvt;
770  uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
771  struct ast_frame *f;
772  struct ast_frame t30_frame = {
774  .subclass.format = ast_format_slin,
775  .src = "res_fax_spandsp_g711",
776  .samples = samples,
777  .flags = AST_FAX_FRFLAG_GATEWAY,
778  };
779 
780  AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
781 
782  if (!(f = ast_frisolate(&t30_frame))) {
783  return p->isdone ? -1 : res;
784  }
785 
786  /* generate a T.30 packet */
787  if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
788  f->datalen = f->samples * sizeof(int16_t);
789  res = ast_write(chan, f);
790  }
791  ast_frfree(f);
792  return p->isdone ? -1 : res;
793 }
#define AST_FAX_FRFLAG_GATEWAY
Definition: res_fax.h:232
short int16_t
Definition: db.h:59
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
t38_gateway_state_t t38_gw_state
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
unsigned int isdone
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:5189
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define ast_frfree(fr)
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
union ast_frame::@263 data
enum ast_frame_type frametype
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ spandsp_fax_new()

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 525 of file res_fax_spandsp.c.

References ast_calloc, AST_FAX_STATE_ACTIVE, AST_FAX_STATE_INITIALIZED, AST_FAX_TECH_AUDIO, AST_FAX_TECH_GATEWAY, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_SEND, AST_FAX_TECH_T38, AST_FAX_TECH_V21_DETECT, 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, spandsp_pvt::fax_state, ast_fax_session::fd, ast_fax_session::id, spandsp_pvt::ist38, LOG_ERROR, NULL, spandsp_pvt::read_frames, set_logging(), spandsp_global_stats, spandsp_v21_new(), ast_fax_session::state, spandsp_pvt::stats, spandsp_pvt::t38_state, t38_tx_packet_handler(), and spandsp_pvt::timer.

526 {
527  struct spandsp_pvt *p;
528  int caller_mode;
529 
530  if ((!(p = ast_calloc(1, sizeof(*p))))) {
531  ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
532  goto e_return;
533  }
534 
536  if (spandsp_v21_new(p)) {
537  ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
538  goto e_return;
539  }
541  return p;
542  }
543 
544  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
546  return p;
547  }
548 
550 
551  if (s->details->caps & AST_FAX_TECH_RECEIVE) {
552  caller_mode = 0;
553  } else if (s->details->caps & AST_FAX_TECH_SEND) {
554  caller_mode = 1;
555  } else {
556  ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
557  goto e_free;
558  }
559 
560  if (!(p->timer = ast_timer_open())) {
561  ast_log(LOG_ERROR, "Channel '%s' FAX session '%u' failed to create timing source.\n", s->channame, s->id);
562  goto e_free;
563  }
564 
565  s->fd = ast_timer_fd(p->timer);
566 
567  p->stats = &spandsp_global_stats.g711;
568 
570  if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
571  /* audio mode was not requested, start in T.38 mode */
572  p->ist38 = 1;
573  p->stats = &spandsp_global_stats.t38;
574  }
575 
576  /* init t38 stuff */
577  t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
578  set_logging(&p->t38_state.logging, s->details);
579 
580  /* init audio stuff */
581  fax_init(&p->fax_state, caller_mode);
582  set_logging(&p->fax_state.logging, s->details);
583  }
584 
586  return p;
587 
588 e_free:
589  ast_free(p);
590 e_return:
591  return NULL;
592 }
t38_terminal_state_t t38_state
unsigned int id
Definition: res_fax.h:204
static struct @462 spandsp_global_stats
struct ast_timer * timer
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
unsigned int ist38
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
#define NULL
Definition: resample.c:96
struct spandsp_pvt::frame_queue read_frames
#define ast_log
Definition: astobj2.c:42
struct ast_fax_session_details * details
Definition: res_fax.h:208
char * channame
Definition: res_fax.h:220
static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
#define LOG_ERROR
Definition: logger.h:285
struct spandsp_fax_stats * stats
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
enum ast_fax_state state
Definition: res_fax.h:218
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
enum ast_fax_capabilities caps
Definition: res_fax.h:113
static int spandsp_v21_new(struct spandsp_pvt *p)
fax_state_t fax_state

◆ spandsp_fax_read()

static struct ast_frame * spandsp_fax_read ( struct ast_fax_session s)
static

Read a frame from the spandsp fax stack.

Definition at line 622 of file res_fax_spandsp.c.

References ast_debug, AST_FAX_STATE_COMPLETE, ast_format_slin, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_frisolate, AST_LIST_REMOVE_HEAD, ast_log, ast_null_frame, ast_timer_ack(), buf, spandsp_pvt::fax_state, ast_frame::frametype, ast_fax_session::id, spandsp_pvt::isdone, spandsp_pvt::ist38, LOG_ERROR, NULL, spandsp_pvt::read_frames, ast_frame::samples, SPANDSP_FAX_SAMPLES, ast_fax_session::state, spandsp_pvt::t38_state, ast_fax_session::tech_pvt, and spandsp_pvt::timer.

623 {
624  struct spandsp_pvt *p = s->tech_pvt;
625  uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
626  int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
627  int samples;
628 
629  struct ast_frame fax_frame = {
631  .src = "res_fax_spandsp_g711",
632  .subclass.format = ast_format_slin,
633  };
634  struct ast_frame *f = &fax_frame;
635 
636  if (ast_timer_ack(p->timer, 1) < 0) {
637  ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%u'\n", s->id);
638  return NULL;
639  }
640 
641  /* XXX do we need to lock here? */
642  if (p->isdone) {
644  ast_debug(5, "FAX session '%u' is complete.\n", s->id);
645  return NULL;
646  }
647 
648  if (p->ist38) {
649  t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
650  if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
651  return f;
652  }
653  } else {
654  if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
655  f->samples = samples;
656  AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
657  return ast_frisolate(f);
658  }
659  }
660 
661  return &ast_null_frame;
662 }
t38_terminal_state_t t38_state
short int16_t
Definition: db.h:59
unsigned int id
Definition: res_fax.h:204
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
struct ast_timer * timer
unsigned int ist38
#define NULL
Definition: resample.c:96
struct spandsp_pvt::frame_queue read_frames
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
#define LOG_ERROR
Definition: logger.h:285
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
unsigned int isdone
enum ast_fax_state state
Definition: res_fax.h:218
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define SPANDSP_FAX_SAMPLES
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
fax_state_t fax_state

◆ spandsp_fax_start()

static int spandsp_fax_start ( struct ast_fax_session s)
static

Definition at line 929 of file res_fax_spandsp.c.

References AST_FAX_STATE_ACTIVE, AST_FAX_STATE_OPEN, AST_FAX_TECH_GATEWAY, ast_log, ast_timer_set_rate(), ast_fax_session_details::caps, 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_gateway_start(), SPANDSP_FAX_TIMER_RATE, spandsp_modems(), 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().

930 {
931  struct spandsp_pvt *p = s->tech_pvt;
932 
934 
935  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
936  return spandsp_fax_gateway_start(s);
937  }
938 
939  if (p->ist38) {
940 #if SPANDSP_RELEASE_DATE >= 20080725
941  /* for spandsp shaphots 0.0.6 and higher */
942  p->t30_state = &p->t38_state.t30;
943  p->t38_core_state = &p->t38_state.t38_fe.t38;
944 #else
945  /* for spandsp releases 0.0.5 */
946  p->t30_state = &p->t38_state.t30_state;
947  p->t38_core_state = &p->t38_state.t38;
948 #endif
949  } else {
950 #if SPANDSP_RELEASE_DATE >= 20080725
951  /* for spandsp shaphots 0.0.6 and higher */
952  p->t30_state = &p->fax_state.t30;
953 #else
954  /* for spandsp release 0.0.5 */
955  p->t30_state = &p->fax_state.t30_state;
956 #endif
957  }
958 
959  set_logging(&p->t30_state->logging, s->details);
960 
961  /* set some parameters */
963  set_file(p->t30_state, s->details);
964  set_ecm(p->t30_state, s->details);
965  t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
966 
967  /* perhaps set_transmit_on_idle() should be called */
968 
969  t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
970 
971  /* set T.38 parameters */
972  if (p->ist38) {
973  set_logging(&p->t38_core_state->logging, s->details);
974 
975  t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
976 
978  t38_set_fill_bit_removal(p->t38_core_state, TRUE);
979  }
980 
982  t38_set_mmr_transcoding(p->t38_core_state, TRUE);
983  }
984 
986  t38_set_jbig_transcoding(p->t38_core_state, TRUE);
987  }
988  } else {
989  /* have the fax stack generate silence if it has no data to send */
990  fax_set_transmit_on_idle(&p->fax_state, 1);
991  }
992 
993 
994  /* start the timer */
996  ast_log(LOG_ERROR, "FAX session '%u' error setting rate on timing source.\n", s->id);
997  return -1;
998  }
999 
1001 
1002  return 0;
1003 }
static int spandsp_modems(struct ast_fax_session_details *details)
t38_terminal_state_t t38_state
unsigned int id
Definition: res_fax.h:204
static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
struct ast_timer * timer
unsigned int ist38
static int spandsp_fax_gateway_start(struct ast_fax_session *s)
activate a spandsp gateway based on the information in the given fax session
t38_core_state_t * t38_core_state
#define ast_log
Definition: astobj2.c:42
struct ast_fax_session_details * details
Definition: res_fax.h:208
static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
Phase E handler callback.
static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
unsigned int transcoding_mmr
Definition: res_fax.h:98
unsigned int transcoding_jbig
Definition: res_fax.h:99
#define LOG_ERROR
Definition: logger.h:285
unsigned int max_ifp
Definition: res_fax.h:94
static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
t30_state_t * t30_state
enum ast_fax_state state
Definition: res_fax.h:218
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
#define SPANDSP_FAX_TIMER_RATE
#define TRUE
Definition: app_minivm.c:518
enum ast_fax_capabilities caps
Definition: res_fax.h:113
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
fax_state_t fax_state

◆ spandsp_fax_switch_to_t38()

static int spandsp_fax_switch_to_t38 ( struct ast_fax_session s)
static

Definition at line 1021 of file res_fax_spandsp.c.

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

1022 {
1023  struct spandsp_pvt *p = s->tech_pvt;
1024 
1025  /* prevent the phase E handler from running, this is not a real termination */
1026  t30_set_phase_e_handler(p->t30_state, NULL, NULL);
1027 
1028  t30_terminate(p->t30_state);
1029 
1030  s->details->option.switch_to_t38 = 1;
1032 
1033  p->ist38 = 1;
1034  p->stats = &spandsp_global_stats.t38;
1035  spandsp_fax_start(s);
1036 
1037  return 0;
1038 }
static struct @462 spandsp_global_stats
static int spandsp_fax_start(struct ast_fax_session *s)
uint32_t switch_to_t38
Definition: res_fax.h:159
unsigned int ist38
#define NULL
Definition: resample.c:96
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:755
union ast_fax_session_details::@290 option
struct ast_fax_session_details * details
Definition: res_fax.h:208
struct spandsp_fax_stats * stats
t30_state_t * t30_state
void * tech_pvt
Definition: res_fax.h:216

◆ spandsp_fax_write()

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 734 of file res_fax_spandsp.c.

References AST_FAX_STATE_COMPLETE, ast_fax_state_to_str(), AST_FAX_TECH_GATEWAY, AST_FAX_TECH_V21_DETECT, ast_log, ast_fax_session_details::caps, ast_frame::data, ast_frame::datalen, ast_fax_session::details, spandsp_pvt::fax_state, ast_fax_session::id, spandsp_pvt::ist38, LOG_WARNING, ast_frame::ptr, ast_frame::samples, ast_frame::seqno, spandsp_fax_gateway_process(), spandsp_v21_detect(), ast_fax_session::state, spandsp_pvt::t38_core_state, and ast_fax_session::tech_pvt.

735 {
736  struct spandsp_pvt *p = s->tech_pvt;
737 
739  return spandsp_v21_detect(s, f);
740  }
741 
742  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
743  return spandsp_fax_gateway_process(s, f);
744  }
745 
746  /* XXX do we need to lock here? */
747  if (s->state == AST_FAX_STATE_COMPLETE) {
748  ast_log(LOG_WARNING, "FAX session '%u' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
749  return -1;
750  }
751 
752  if (p->ist38) {
753  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
754  } else {
755  return fax_rx(&p->fax_state, f->data.ptr, f->samples);
756  }
757 }
static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f)
unsigned int id
Definition: res_fax.h:204
#define LOG_WARNING
Definition: logger.h:274
unsigned int ist38
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
process a frame from the bridge
t38_core_state_t * t38_core_state
#define ast_log
Definition: astobj2.c:42
struct ast_fax_session_details * details
Definition: res_fax.h:208
enum ast_fax_state state
Definition: res_fax.h:218
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert an ast_fax_state to a string
Definition: res_fax.c:1013
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216
union ast_frame::@263 data
fax_state_t fax_state

◆ spandsp_log()

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 433 of file res_fax_spandsp.c.

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

Referenced by set_logging().

434 {
435  if (level == SPAN_LOG_ERROR) {
436  ast_log(LOG_ERROR, "%s", msg);
437  } else if (level == SPAN_LOG_WARNING) {
438  ast_log(LOG_WARNING, "%s", msg);
439  } else {
440  ast_fax_log(LOG_DEBUG, msg);
441  }
442 }
#define LOG_WARNING
Definition: logger.h:274
#define LOG_DEBUG
Definition: logger.h:241
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
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:1036

◆ spandsp_manager_fax_session()

static void spandsp_manager_fax_session ( struct mansession s,
const char *  id_text,
struct ast_fax_session session 
)
static

Definition at line 1105 of file res_fax_spandsp.c.

References ao2_lock, ao2_unlock, ast_fax_session_operation_str(), ast_fax_state_to_str(), AST_FAX_STATE_UNINITIALIZED, AST_FAX_TECH_GATEWAY, AST_FAX_TECH_RECEIVE, AST_FAX_TECH_SEND, AST_FAX_TECH_V21_DETECT, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, astman_append(), ast_fax_session_details::caps, ast_fax_session::details, ast_fax_session::id, ast_fax_session::state, spandsp_pvt::stats, spandsp_pvt::t30_state, spandsp_pvt::t38_gw_state, and ast_fax_session::tech_pvt.

1107 {
1108  struct ast_str *message_string;
1109  struct spandsp_pvt *span_pvt = session->tech_pvt;
1110  int res;
1111 
1112  message_string = ast_str_create(128);
1113 
1114  if (!message_string) {
1115  return;
1116  }
1117 
1118  ao2_lock(session);
1119  res = ast_str_append(&message_string, 0, "SessionNumber: %u\r\n", session->id);
1120  res |= ast_str_append(&message_string, 0, "Operation: %s\r\n", ast_fax_session_operation_str(session));
1121  res |= ast_str_append(&message_string, 0, "State: %s\r\n", ast_fax_state_to_str(session->state));
1122 
1123  if (session->details->caps & AST_FAX_TECH_GATEWAY) {
1124  t38_stats_t stats;
1125 
1126  if (session->state == AST_FAX_STATE_UNINITIALIZED) {
1127  goto skip_cap_additions;
1128  }
1129 
1130  t38_gateway_get_transfer_statistics(&span_pvt->t38_gw_state, &stats);
1131  res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
1132  stats.error_correcting_mode ? "yes" : "no");
1133  res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
1134  stats.bit_rate);
1135  res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1136  stats.pages_transferred + 1);
1137  } else if (!(session->details->caps & AST_FAX_TECH_V21_DETECT)) { /* caps is SEND/RECEIVE */
1138  t30_stats_t stats;
1139 
1140  if (session->state == AST_FAX_STATE_UNINITIALIZED) {
1141  goto skip_cap_additions;
1142  }
1143 
1144  t30_get_transfer_statistics(span_pvt->t30_state, &stats);
1145  res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
1146  stats.error_correcting_mode ? "Yes" : "No");
1147  res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
1148  stats.bit_rate);
1149  res |= ast_str_append(&message_string, 0, "ImageResolution: %dx%d\r\n",
1150  stats.x_resolution, stats.y_resolution);
1151 #if SPANDSP_RELEASE_DATE >= 20090220
1152  res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1153  ((session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1154 #else
1155  res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1156  stats.pages_transferred + 1);
1157 #endif
1158  res |= ast_str_append(&message_string, 0, "FileName: %s\r\n",
1159  session->details->caps & AST_FAX_TECH_RECEIVE ? span_pvt->t30_state->rx_file :
1160  span_pvt->t30_state->tx_file);
1161 #if SPANDSP_RELEASE_DATE >= 20090220
1162  res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
1163  stats.pages_tx);
1164  res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
1165  stats.pages_rx);
1166 #else
1167  res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
1168  (session->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1169  res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
1170  (session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1171 #endif
1172  res |= ast_str_append(&message_string, 0, "TotalBadLines: %d\r\n",
1173  stats.bad_rows);
1174  }
1175 
1176 skip_cap_additions:
1177 
1178  ao2_unlock(session);
1179 
1180  if (res < 0) {
1181  /* One or more of the ast_str_append attempts failed, cancel the message */
1182  ast_free(message_string);
1183  return;
1184  }
1185 
1186  astman_append(s, "Event: FAXSession\r\n"
1187  "%s"
1188  "%s"
1189  "\r\n",
1190  id_text,
1191  ast_str_buffer(message_string));
1192 
1193  ast_free(message_string);
1194 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
unsigned int id
Definition: res_fax.h:204
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * ast_fax_session_operation_str(struct ast_fax_session *s)
get string representation of a FAX session&#39;s operation
Definition: res_fax.c:4254
struct ast_fax_session_details * details
Definition: res_fax.h:208
#define ao2_lock(a)
Definition: astobj2.h:718
t38_gateway_state_t t38_gw_state
struct spandsp_fax_stats * stats
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
t30_state_t * t30_state
enum ast_fax_state state
Definition: res_fax.h:218
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert an ast_fax_state to a string
Definition: res_fax.c:1013
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ spandsp_modems()

static int spandsp_modems ( struct ast_fax_session_details details)
static

Definition at line 499 of file res_fax_spandsp.c.

References AST_FAX_MODEM_V17, AST_FAX_MODEM_V27TER, AST_FAX_MODEM_V29, AST_FAX_MODEM_V34, ast_log, LOG_WARNING, and ast_fax_session_details::modems.

Referenced by spandsp_fax_gateway_start(), and spandsp_fax_start().

500 {
501  int modems = 0;
502  if (AST_FAX_MODEM_V17 & details->modems) {
503  modems |= T30_SUPPORT_V17;
504  }
505  if (AST_FAX_MODEM_V27TER & details->modems) {
506  modems |= T30_SUPPORT_V27TER;
507  }
508  if (AST_FAX_MODEM_V29 & details->modems) {
509  modems |= T30_SUPPORT_V29;
510  }
511  if (AST_FAX_MODEM_V34 & details->modems) {
512 #if defined(T30_SUPPORT_V34)
513  modems |= T30_SUPPORT_V34;
514 #elif defined(T30_SUPPORT_V34HDX)
515  modems |= T30_SUPPORT_V34HDX;
516 #else
517  ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
518 #endif
519  }
520 
521  return modems;
522 }
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
enum ast_fax_modems modems
Definition: res_fax.h:115

◆ spandsp_v21_cleanup()

static void spandsp_v21_cleanup ( struct ast_fax_session s)
static

Definition at line 594 of file res_fax_spandsp.c.

References ast_fax_session::tech_pvt, and spandsp_pvt::tone_state.

Referenced by spandsp_fax_destroy().

595 {
596  struct spandsp_pvt *p = s->tech_pvt;
597 
598  modem_connect_tones_rx_free(p->tone_state);
599 }
modem_connect_tones_rx_state_t * tone_state
void * tech_pvt
Definition: res_fax.h:216

◆ spandsp_v21_detect()

static int spandsp_v21_detect ( struct ast_fax_session s,
const struct ast_frame f 
)
static

Definition at line 673 of file res_fax_spandsp.c.

References ast_debug, ast_format_alaw, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_get_name(), ast_format_slin, ast_format_ulaw, ast_free, ast_log, ast_malloc, ast_frame::data, ast_frame::datalen, ast_fax_session::details, ast_frame::flags, ast_frame_subclass::format, ast_frame::len, LOG_WARNING, ast_frame::mallocd, NULL, ast_fax_session_details::option, ast_frame::ptr, ast_frame::samples, ast_frame::seqno, ast_frame::src, ast_frame::subclass, ast_fax_session::tech_pvt, spandsp_pvt::tone_state, ast_frame::ts, spandsp_pvt::v21_detected, and ast_fax_session_details::v21_detected.

Referenced by spandsp_fax_write().

674 {
675  struct spandsp_pvt *p = s->tech_pvt;
676  int16_t *slndata;
677  g711_state_t *decoder;
678 
679  if (p->v21_detected) {
680  return 0;
681  }
682 
683  /*invalid frame*/
684  if (!f->data.ptr || !f->datalen) {
685  return -1;
686  }
687 
688  ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format=%s }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, ast_format_get_name(f->subclass.format));
689 
690  /* slinear frame can be passed to spandsp */
692  modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
693 
694  /* alaw/ulaw frame must be converted to slinear before passing to spandsp */
697  if (!(slndata = ast_malloc(sizeof(*slndata) * f->samples))) {
698  return -1;
699  }
700  decoder = g711_init(NULL, (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL ? G711_ALAW : G711_ULAW));
701  g711_decode(decoder, slndata, f->data.ptr, f->samples);
702  ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", ast_format_get_name(f->subclass.format));
703  modem_connect_tones_rx(p->tone_state, slndata, f->samples);
704  g711_release(decoder);
705 #if SPANDSP_RELEASE_DATE >= 20090220
706  g711_free(decoder);
707 #endif
708  ast_free(slndata);
709 
710  /* frame in other formats cannot be passed to spandsp, it could cause segfault */
711  } else {
712  ast_log(LOG_WARNING, "Frame format %s not supported, v.21 detection skipped\n", ast_format_get_name(f->subclass.format));
713  return -1;
714  }
715 
716  if (p->v21_detected) {
717  s->details->option.v21_detected = 1;
718  ast_debug(5, "v.21 detected\n");
719  }
720 
721  return 0;
722 }
short int16_t
Definition: db.h:59
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
#define LOG_WARNING
Definition: logger.h:274
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define NULL
Definition: resample.c:96
struct ast_frame_subclass subclass
union ast_fax_session_details::@290 option
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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
const char * src
struct ast_fax_session_details * details
Definition: res_fax.h:208
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
modem_connect_tones_rx_state_t * tone_state
#define ast_free(a)
Definition: astmm.h:182
unsigned int flags
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
void * tech_pvt
Definition: res_fax.h:216
union ast_frame::@263 data
struct ast_format * format
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ spandsp_v21_new()

static int spandsp_v21_new ( struct spandsp_pvt p)
static

Definition at line 485 of file res_fax_spandsp.c.

References NULL, spandsp_v21_tone(), and spandsp_pvt::tone_state.

Referenced by spandsp_fax_new().

486 {
487  /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
488  * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
489  * doesn't seem to work right all the time.
490  */
491  p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
492  if (!p->tone_state) {
493  return -1;
494  }
495 
496  return 0;
497 }
static void spandsp_v21_tone(void *data, int code, int level, int delay)
#define NULL
Definition: resample.c:96
modem_connect_tones_rx_state_t * tone_state

◆ spandsp_v21_tone()

static void spandsp_v21_tone ( void *  data,
int  code,
int  level,
int  delay 
)
static

Definition at line 664 of file res_fax_spandsp.c.

References spandsp_pvt::v21_detected.

Referenced by spandsp_v21_new().

665 {
666  struct spandsp_pvt *p = data;
667 
668  if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
669  p->v21_detected = 1;
670  }
671 }

◆ t30_phase_e_handler()

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 378 of file res_fax_spandsp.c.

References ast_debug, AST_FAX_TECH_RECEIVE, ast_string_field_build, ast_string_field_set, c, ast_fax_session_details::caps, ast_fax_session::details, error(), ast_fax_session::id, spandsp_pvt::isdone, ast_fax_session_details::pages_transferred, result, 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().

379 {
380  struct ast_fax_session *s = data;
381  struct spandsp_pvt *p = s->tech_pvt;
382  char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
383  const char *c;
384  t30_stats_t stats;
385 
386  ast_debug(5, "FAX session '%u' entering phase E\n", s->id);
387 
388  p->isdone = 1;
389 
390  update_stats(p, completion_code);
391 
392  t30_get_transfer_statistics(t30_state, &stats);
393 
394  if (completion_code == T30_ERR_OK) {
395  ast_string_field_set(s->details, result, "SUCCESS");
396  } else {
397  ast_string_field_set(s->details, result, "FAILED");
398  ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
399  }
400 
401  ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
402 
403  ast_debug(5, "FAX session '%u' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
404 
405  if ((c = t30_get_tx_ident(t30_state))) {
406  ast_string_field_set(s->details, localstationid, c);
407  }
408 
409  if ((c = t30_get_rx_ident(t30_state))) {
410  ast_string_field_set(s->details, remotestationid, c);
411  }
412 
413 #if SPANDSP_RELEASE_DATE >= 20090220
414  s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
415 #else
416  s->details->pages_transferred = stats.pages_transferred;
417 #endif
418 
419  ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
420 
421  ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
422 
423  t30_get_tx_page_header_info(t30_state, headerinfo);
424  ast_string_field_set(s->details, headerinfo, headerinfo);
425 }
const ast_string_field result
Definition: res_fax.h:142
unsigned int id
Definition: res_fax.h:204
static struct test_val c
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_fax_session_details * details
Definition: res_fax.h:208
struct spandsp_fax_stats * stats
unsigned int pages_transferred
Definition: res_fax.h:144
static int update_stats(struct spandsp_pvt *p, int completion_code)
unsigned int isdone
t30_state_t * t30_state
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
static PGresult * result
Definition: cel_pgsql.c:88
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
int error(const char *format,...)
Definition: utils/frame.c:999
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:514

◆ t38_tx_packet_handler()

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 217 of file res_fax_spandsp.c.

References AST_FAX_FRFLAG_GATEWAY, AST_FAX_TECH_GATEWAY, AST_FRAME_MODEM, AST_FRAME_SET_BUFFER, ast_frfree, ast_frisolate, AST_LIST_INSERT_TAIL, AST_MODEM_T38, ast_queue_frame(), ast_set_flag, spandsp_pvt::ast_t38_state, ast_write(), ast_fax_session_details::caps, ast_fax_session::chan, ast_fax_session::details, ast_frame::frametype, spandsp_pvt::read_frames, T38_STATE_NEGOTIATED, and ast_fax_session::tech_pvt.

Referenced by spandsp_fax_gateway_start(), and spandsp_fax_new().

218 {
219  int res = -1;
220  struct ast_fax_session *s = data;
221  struct spandsp_pvt *p = s->tech_pvt;
222  struct ast_frame fax_frame = {
224  .subclass.integer = AST_MODEM_T38,
225  .src = "res_fax_spandsp_t38",
226  };
227 
228  struct ast_frame *f = &fax_frame;
229 
230 
231  /* TODO: Asterisk does not provide means of resending the same packet multiple
232  times so count is ignored at the moment */
233 
234  AST_FRAME_SET_BUFFER(f, buf, 0, len);
235 
236  if (!(f = ast_frisolate(f))) {
237  return res;
238  }
239 
240  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
243  res = ast_write(s->chan, f);
244  } else {
245  res = ast_queue_frame(s->chan, f);
246  }
247  ast_frfree(f);
248  } else {
249  /* no need to lock, this all runs in the same thread */
251  res = 0;
252  }
253 
254  return res;
255 }
#define AST_FAX_FRFLAG_GATEWAY
Definition: res_fax.h:232
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_set_flag(p, flag)
Definition: utils.h:70
struct ast_channel * chan
Definition: res_fax.h:224
struct spandsp_pvt::frame_queue read_frames
struct ast_fax_session_details * details
Definition: res_fax.h:208
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1139
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_t38_state ast_t38_state
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:5189
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define ast_frfree(fr)
The data required to handle a fax session.
Definition: res_fax.h:202
#define AST_MODEM_T38
Data structure associated with a single frame of data.
enum ast_fax_capabilities caps
Definition: res_fax.h:113
void * tech_pvt
Definition: res_fax.h:216
enum ast_frame_type frametype

◆ unload_module()

static int unload_module ( void  )
static

unload res_fax_spandsp

Definition at line 1241 of file res_fax_spandsp.c.

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

Referenced by load_module().

1242 {
1245  return AST_MODULE_LOAD_SUCCESS;
1246 }
void ast_fax_tech_unregister(struct ast_fax_tech *tech)
unregister a fax technology
Definition: res_fax.c:992
static struct @462 spandsp_global_stats
static struct ast_fax_tech spandsp_fax_tech
#define ast_mutex_destroy(a)
Definition: lock.h:186

◆ update_stats()

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 257 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().

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

Variable Documentation

◆ __mod_info

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .enhances = "res_fax", }
static

Definition at line 1270 of file res_fax_spandsp.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1270 of file res_fax_spandsp.c.

◆ g711

struct spandsp_fax_stats g711

Definition at line 142 of file res_fax_spandsp.c.

◆ lock

Definition at line 141 of file res_fax_spandsp.c.

◆ spandsp_fax_tech

struct ast_fax_tech spandsp_fax_tech
static

Definition at line 95 of file res_fax_spandsp.c.

◆ spandsp_global_stats

struct { ... } spandsp_global_stats

◆ t38

struct spandsp_fax_stats t38

Definition at line 143 of file res_fax_spandsp.c.

Referenced by transmit_t38().