Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Functions | Variables
app_fax.c File Reference
#include "asterisk.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <pthread.h>
#include <errno.h>
#include <tiffio.h>
#include <spandsp.h>
#include <spandsp/version.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/module.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/format_cache.h"
Include dependency graph for app_fax.c:

Go to the source code of this file.

Data Structures

struct  fax_session
 

Macros

#define ASTMM_LIBC   ASTMM_IGNORE
 
#define MAX_SAMPLES   240
 
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
 
#define WATCHDOG_STATE_TIMEOUT   5 * 60
 
#define WATCHDOG_TOTAL_TIMEOUT   30 * 60
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void * fax_generator_alloc (struct ast_channel *chan, void *params)
 
static int fax_generator_generate (struct ast_channel *chan, void *data, int len, int samples)
 
static int load_module (void)
 
static void phase_e_handler (t30_state_t *f, void *user_data, int result)
 
static int rcvfax_exec (struct ast_channel *chan, const char *data)
 
static void set_ecm (t30_state_t *state, int ecm)
 
static void set_file (t30_state_t *state, fax_session *s)
 
static void set_local_info (t30_state_t *state, fax_session *s)
 
static int set_logging (logging_state_t *state)
 
static int sndfax_exec (struct ast_channel *chan, const char *data)
 
static void span_message (int level, const char *msg)
 
static int t38_tx_packet_handler (t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
 
static int transmit (fax_session *s)
 
static int transmit_audio (fax_session *s)
 
static int transmit_t38 (fax_session *s)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Simple FAX Application" , .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_DEPRECATED, .load = load_module, .unload = unload_module, }
 
static const char app_rcvfax_name [] = "ReceiveFAX"
 
static const char app_sndfax_name [] = "SendFAX"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_generator generator
 

Macro Definition Documentation

◆ ASTMM_LIBC

#define ASTMM_LIBC   ASTMM_IGNORE

Definition at line 24 of file app_fax.c.

◆ MAX_SAMPLES

#define MAX_SAMPLES   240

Definition at line 151 of file app_fax.c.

Referenced by fax_generator_generate().

◆ SPANDSP_EXPOSE_INTERNAL_STRUCTURES

#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES

Definition at line 35 of file app_fax.c.

◆ WATCHDOG_STATE_TIMEOUT

#define WATCHDOG_STATE_TIMEOUT   5 * 60

Definition at line 160 of file app_fax.c.

Referenced by transmit_audio(), and transmit_t38().

◆ WATCHDOG_TOTAL_TIMEOUT

#define WATCHDOG_TOTAL_TIMEOUT   30 * 60

Definition at line 159 of file app_fax.c.

Referenced by transmit_audio(), and transmit_t38().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1003 of file app_fax.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1003 of file app_fax.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1003 of file app_fax.c.

◆ fax_generator_alloc()

static void* fax_generator_alloc ( struct ast_channel chan,
void *  params 
)
static

Definition at line 324 of file app_fax.c.

325 {
326  return params;
327 }

◆ fax_generator_generate()

static int fax_generator_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

Definition at line 329 of file app_fax.c.

References ast_channel_name(), ast_format_slin, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log, ast_write(), buf, errno, ast_frame::frametype, len(), LOG_WARNING, MAX_SAMPLES, and ast_frame::samples.

330 {
331  fax_state_t *fax = (fax_state_t*) data;
332  uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
333  int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
334 
335  struct ast_frame outf = {
337  .subclass.format = ast_format_slin,
338  .src = __FUNCTION__,
339  };
340 
341  if (samples > MAX_SAMPLES) {
342  ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
344  }
345 
346  if ((len = fax_tx(fax, buf, samples)) > 0) {
347  outf.samples = len;
348  AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
349 
350  if (ast_write(chan, &outf) < 0) {
351  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
352  return -1;
353  }
354  }
355 
356  return 0;
357 }
short int16_t
Definition: db.h:59
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
#define MAX_SAMPLES
Definition: app_fax.c:151
#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)
int errno
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
const char * ast_channel_name(const struct ast_channel *chan)
Data structure associated with a single frame of data.
enum ast_frame_type frametype
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ load_module()

static int load_module ( void  )
static

Definition at line 985 of file app_fax.c.

References app_rcvfax_name, app_sndfax_name, AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_SUPPORT_DEPRECATED, ast_register_application_xml, ASTERISK_GPL_KEY, NULL, rcvfax_exec(), sndfax_exec(), and unload_module().

986 {
987  int res ;
988 
991 
992  /* The default SPAN message handler prints to stderr. It is something we do not want */
993  span_set_message_handler(NULL);
994 
995  return res;
996 }
static const char app_sndfax_name[]
Definition: app_fax.c:148
static const char app_rcvfax_name[]
Definition: app_fax.c:149
#define NULL
Definition: resample.c:96
static int rcvfax_exec(struct ast_channel *chan, const char *data)
Definition: app_fax.c:906
static int sndfax_exec(struct ast_channel *chan, const char *data)
Definition: app_fax.c:837
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ phase_e_handler()

static void phase_e_handler ( t30_state_t *  f,
void *  user_data,
int  result 
)
static

Definition at line 206 of file app_fax.c.

References ao2_cleanup, ast_channel_blob_create_from_cache(), ast_channel_fax_type(), ast_channel_topic(), ast_channel_uniqueid(), ast_debug, ast_json_pack(), ast_json_ref(), ast_json_unref(), AST_JSON_UTF8_VALIDATE, ast_log, buf, fax_session::chan, fax_session::direction, fax_session::file_name, fax_session::finished, LOG_WARNING, NULL, pbx_builtin_setvar_helper(), RAII_VAR, S_OR, and stasis_publish().

Referenced by transmit_audio(), and transmit_t38().

207 {
208  RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
209  RAII_VAR(struct ast_json *, json_filenames, NULL, ast_json_unref);
211  const char *local_ident;
212  const char *far_ident;
213  char buf[20];
214  fax_session *s = (fax_session *) user_data;
215  t30_stats_t stat;
216  int pages_transferred;
217 
218  ast_debug(1, "Fax phase E handler. result=%d\n", result);
219 
220  t30_get_transfer_statistics(f, &stat);
221 
222  s = (fax_session *) user_data;
223 
224  if (result != T30_ERR_OK) {
225  s->finished = -1;
226 
227  /* FAXSTATUS is already set to FAILED */
228  pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
229 
230  ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
231 
232  return;
233  }
234 
235  s->finished = 1;
236 
237  local_ident = S_OR(t30_get_tx_ident(f), "");
238  far_ident = S_OR(t30_get_rx_ident(f), "");
239  pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
240  pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
241  pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
242 #if SPANDSP_RELEASE_DATE >= 20090220
243  pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
244 #else
245  pages_transferred = stat.pages_transferred;
246 #endif
247  snprintf(buf, sizeof(buf), "%d", pages_transferred);
248  pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
249  snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
250  pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
251  snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
252  pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);
253 
254  ast_debug(1, "Fax transmitted successfully.\n");
255  ast_debug(1, " Remote station ID: %s\n", far_ident);
256  ast_debug(1, " Pages transferred: %d\n", pages_transferred);
257  ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
258  ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
259 
260  json_filenames = ast_json_pack("[s]", s->file_name);
261  if (!json_filenames) {
262  return;
263  }
264  ast_json_ref(json_filenames);
265  json_object = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: i, s: o}",
266  "type", s->direction ? "send" : "receive",
267  "remote_station_id", AST_JSON_UTF8_VALIDATE(far_ident),
268  "local_station_id", AST_JSON_UTF8_VALIDATE(local_ident),
269  "fax_pages", pages_transferred,
270  "fax_resolution", stat.y_resolution,
271  "fax_bitrate", stat.bit_rate,
272  "filenames", json_filenames);
274  if (!message) {
275  return;
276  }
278 }
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
char * file_name
Definition: app_fax.c:167
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
struct ast_channel * chan
Definition: app_fax.c:163
int direction
Definition: app_fax.c:165
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#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
volatile int finished
Definition: app_fax.c:169
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static PGresult * result
Definition: cel_pgsql.c:88
Abstract JSON element (object, array, string, int, ...).
struct stasis_message_type * ast_channel_fax_type(void)
Message type for a fax operation.
#define AST_JSON_UTF8_VALIDATE(str)
Check str for UTF-8 and replace with an empty string if fails the check.
Definition: json.h:224

◆ rcvfax_exec()

static int rcvfax_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 906 of file app_fax.c.

References args, AST_APP_ARG, ast_channel_queryoption(), ast_channel_setoption(), AST_DECLARE_APP_ARGS, ast_log, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, fax_session::caller_mode, fax_session::chan, fax_session::direction, dummy(), FALSE, fax_session::file_name, fax_session::finished, LOG_ERROR, NULL, options, parse(), session, transmit(), and TRUE.

Referenced by load_module().

907 {
908  int res = 0;
909  char *parse;
911  char restore_digit_detect = 0;
912 
914  AST_APP_ARG(file_name);
916  );
917 
918  if (chan == NULL) {
919  ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
920  return -1;
921  }
922 
923  /* The next few lines of code parse out the filename and header from the input string */
924  if (ast_strlen_zero(data)) {
925  /* No data implies no filename or anything is present */
926  ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
927  return -1;
928  }
929 
930  parse = ast_strdupa(data);
931  AST_STANDARD_APP_ARGS(args, parse);
932 
933  session.caller_mode = FALSE;
934 
935  if (args.options) {
936  if (strchr(args.options, 'c'))
937  session.caller_mode = TRUE;
938  }
939 
940  /* Done parsing */
941  session.direction = 0;
942  session.file_name = args.file_name;
943  session.chan = chan;
944  session.finished = 0;
945 
946  /* get current digit detection mode, then disable digit detection if enabled */
947  {
948  int dummy = sizeof(restore_digit_detect);
949 
950  ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
951  }
952 
953  if (restore_digit_detect) {
954  char new_digit_detect = 0;
955 
956  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
957  }
958 
959  /* disable FAX tone detection if enabled */
960  {
961  char new_fax_detect = 0;
962 
963  ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
964  }
965 
966  res = transmit(&session);
967 
968  if (restore_digit_detect) {
969  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
970  }
971 
972  return res;
973 }
#define FALSE
Definition: app_minivm.c:521
char * file_name
Definition: app_fax.c:167
int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block)
Checks the value of an option.
Definition: channel.c:7542
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
int caller_mode
Definition: app_fax.c:166
const char * args
#define NULL
Definition: resample.c:96
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7522
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_channel * chan
Definition: app_fax.c:163
int direction
Definition: app_fax.c:165
#define ast_log
Definition: astobj2.c:42
static struct ast_mansession session
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
volatile int finished
Definition: app_fax.c:169
#define AST_OPTION_DIGIT_DETECT
#define LOG_ERROR
Definition: logger.h:285
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define AST_OPTION_FAX_DETECT
#define TRUE
Definition: app_minivm.c:518
static int transmit(fax_session *s)
Definition: app_fax.c:779
union ast_frame::@263 data
static struct test_options options
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ set_ecm()

static void set_ecm ( t30_state_t *  state,
int  ecm 
)
static

Definition at line 314 of file app_fax.c.

Referenced by transmit_audio(), and transmit_t38().

315 {
316  t30_set_ecm_capability(state, ecm);
317  t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
318 }

◆ set_file()

static void set_file ( t30_state_t *  state,
fax_session s 
)
static

Definition at line 306 of file app_fax.c.

References fax_session::direction, and fax_session::file_name.

Referenced by transmit_audio(), and transmit_t38().

307 {
308  if (s->direction)
309  t30_set_tx_file(state, s->file_name, -1, -1);
310  else
311  t30_set_rx_file(state, s->file_name, -1);
312 }
char * file_name
Definition: app_fax.c:167
int direction
Definition: app_fax.c:165

◆ set_local_info()

static void set_local_info ( t30_state_t *  state,
fax_session s 
)
static

Definition at line 293 of file app_fax.c.

References ast_strlen_zero, fax_session::chan, and pbx_builtin_getvar_helper().

Referenced by transmit_audio(), and transmit_t38().

294 {
295  const char *x;
296 
297  x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
298  if (!ast_strlen_zero(x))
299  t30_set_tx_ident(state, x);
300 
301  x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
302  if (!ast_strlen_zero(x))
303  t30_set_tx_page_header_info(state, x);
304 }
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_channel * chan
Definition: app_fax.c:163

◆ set_logging()

static int set_logging ( logging_state_t *  state)
static

Definition at line 283 of file app_fax.c.

References option_debug, and span_message().

Referenced by transmit_audio(), and transmit_t38().

284 {
285  int level = SPAN_LOG_WARNING + option_debug;
286 
287  span_log_set_message_handler(state, span_message);
288  span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
289 
290  return 0;
291 }
int option_debug
Definition: options.c:69
static void span_message(int level, const char *msg)
Definition: app_fax.c:172

◆ sndfax_exec()

static int sndfax_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 837 of file app_fax.c.

References args, AST_APP_ARG, ast_channel_queryoption(), ast_channel_setoption(), AST_DECLARE_APP_ARGS, ast_log, AST_OPTION_DIGIT_DETECT, AST_OPTION_FAX_DETECT, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, fax_session::caller_mode, fax_session::chan, fax_session::direction, dummy(), FALSE, fax_session::file_name, fax_session::finished, LOG_ERROR, NULL, options, parse(), session, transmit(), and TRUE.

Referenced by load_module().

838 {
839  int res = 0;
840  char *parse;
841  fax_session session = { 0, };
842  char restore_digit_detect = 0;
843 
845  AST_APP_ARG(file_name);
847  );
848 
849  if (chan == NULL) {
850  ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
851  return -1;
852  }
853 
854  /* The next few lines of code parse out the filename and header from the input string */
855  if (ast_strlen_zero(data)) {
856  /* No data implies no filename or anything is present */
857  ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
858  return -1;
859  }
860 
861  parse = ast_strdupa(data);
862  AST_STANDARD_APP_ARGS(args, parse);
863 
864  session.caller_mode = TRUE;
865 
866  if (args.options) {
867  if (strchr(args.options, 'a'))
868  session.caller_mode = FALSE;
869  }
870 
871  /* Done parsing */
872  session.direction = 1;
873  session.file_name = args.file_name;
874  session.chan = chan;
875  session.finished = 0;
876 
877  /* get current digit detection mode, then disable digit detection if enabled */
878  {
879  int dummy = sizeof(restore_digit_detect);
880 
881  ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
882  }
883 
884  if (restore_digit_detect) {
885  char new_digit_detect = 0;
886 
887  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
888  }
889 
890  /* disable FAX tone detection if enabled */
891  {
892  char new_fax_detect = 0;
893 
894  ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
895  }
896 
897  res = transmit(&session);
898 
899  if (restore_digit_detect) {
900  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
901  }
902 
903  return res;
904 }
#define FALSE
Definition: app_minivm.c:521
char * file_name
Definition: app_fax.c:167
int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block)
Checks the value of an option.
Definition: channel.c:7542
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
int caller_mode
Definition: app_fax.c:166
const char * args
#define NULL
Definition: resample.c:96
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7522
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_channel * chan
Definition: app_fax.c:163
int direction
Definition: app_fax.c:165
#define ast_log
Definition: astobj2.c:42
static struct ast_mansession session
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
volatile int finished
Definition: app_fax.c:169
#define AST_OPTION_DIGIT_DETECT
#define LOG_ERROR
Definition: logger.h:285
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define AST_OPTION_FAX_DETECT
#define TRUE
Definition: app_minivm.c:518
static int transmit(fax_session *s)
Definition: app_fax.c:779
union ast_frame::@263 data
static struct test_options options
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ span_message()

static void span_message ( int  level,
const char *  msg 
)
static

Definition at line 172 of file app_fax.c.

References ast_debug, ast_log, LOG_ERROR, and LOG_WARNING.

Referenced by set_logging().

173 {
174  if (level == SPAN_LOG_ERROR) {
175  ast_log(LOG_ERROR, "%s", msg);
176  } else if (level == SPAN_LOG_WARNING) {
177  ast_log(LOG_WARNING, "%s", msg);
178  } else {
179  ast_debug(1, "%s", msg);
180  }
181 }
#define LOG_WARNING
Definition: logger.h:274
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285

◆ t38_tx_packet_handler()

static int t38_tx_packet_handler ( t38_core_state_t *  s,
void *  user_data,
const uint8_t *  buf,
int  len,
int  count 
)
static

Definition at line 183 of file app_fax.c.

References AST_FRAME_MODEM, AST_FRAME_SET_BUFFER, ast_log, AST_MODEM_T38, ast_write(), errno, ast_frame::frametype, and LOG_WARNING.

Referenced by transmit_t38().

184 {
185  struct ast_channel *chan = (struct ast_channel *) user_data;
186 
187  struct ast_frame outf = {
189  .subclass.integer = AST_MODEM_T38,
190  .src = __FUNCTION__,
191  };
192 
193  /* TODO: Asterisk does not provide means of resending the same packet multiple
194  times so count is ignored at the moment */
195 
196  AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
197 
198  if (ast_write(chan, &outf) < 0) {
199  ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
200  return -1;
201  }
202 
203  return 0;
204 }
Main Channel structure associated with a channel.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
#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)
int errno
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_MODEM_T38
Data structure associated with a single frame of data.
enum ast_frame_type frametype

◆ transmit()

static int transmit ( fax_session s)
static

Definition at line 779 of file app_fax.c.

References ast_answer(), ast_channel_get_t38_state(), ast_channel_name(), ast_debug, ast_log, AST_STATE_UP, fax_session::chan, fax_session::finished, LOG_ERROR, LOG_WARNING, NULL, pbx_builtin_setvar_helper(), T38_STATE_NEGOTIATED, fax_session::t38state, transmit_audio(), and transmit_t38().

Referenced by rcvfax_exec(), and sndfax_exec().

780 {
781  int res = 0;
782 
783  /* Clear all channel variables which to be set by the application.
784  Pre-set status to error so in case of any problems we can just leave */
785  pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED");
786  pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems");
787 
788  pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
789  pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
790  pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0");
791  pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
792  pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL);
793 
794  if (ast_channel_state(s->chan) != AST_STATE_UP) {
795  /* Shouldn't need this, but checking to see if channel is already answered
796  * Theoretically asterisk should already have answered before running the app */
797  res = ast_answer(s->chan);
798  if (res) {
799  ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(s->chan));
800  return res;
801  }
802  }
803 
805  if (s->t38state != T38_STATE_NEGOTIATED) {
806  /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */
807  pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio");
808  res = transmit_audio(s);
809  if (res > 0) {
810  /* transmit_audio reports switchover to T38. Update t38state */
812  if (s->t38state != T38_STATE_NEGOTIATED) {
813  ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
814  }
815  }
816  }
817 
818  if (s->t38state == T38_STATE_NEGOTIATED) {
819  pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38");
820  res = transmit_t38(s);
821  }
822 
823  if (res) {
824  ast_log(LOG_WARNING, "Transmission error\n");
825  res = -1;
826  } else if (s->finished < 0) {
827  ast_log(LOG_WARNING, "Transmission failed\n");
828  } else if (s->finished > 0) {
829  ast_debug(1, "Transmission finished Ok\n");
830  }
831 
832  return res;
833 }
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
#define LOG_WARNING
Definition: logger.h:274
ast_channel_state
ast_channel states
Definition: channelstate.h:35
#define NULL
Definition: resample.c:96
struct ast_channel * chan
Definition: app_fax.c:163
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
volatile int finished
Definition: app_fax.c:169
static int transmit_t38(fax_session *s)
Definition: app_fax.c:603
#define LOG_ERROR
Definition: logger.h:285
static int transmit_audio(fax_session *s)
Definition: app_fax.c:367
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
const char * ast_channel_name(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
enum ast_t38_state t38state
Definition: app_fax.c:164

◆ transmit_audio()

static int transmit_audio ( fax_session s)
static

Definition at line 367 of file app_fax.c.

References ao2_bump, ao2_ref, ast_activate_generator(), ast_channel_get_t38_state(), ast_channel_name(), ast_channel_readformat(), ast_channel_writeformat(), AST_CONTROL_T38_PARAMETERS, ast_deactivate_generator(), ast_debug, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_get_name(), ast_format_slin, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_frfree, ast_indicate_data(), ast_log, ast_read(), ast_set_read_format(), ast_set_write_format(), AST_T38_NEGOTIATED, AST_T38_RATE_14400, AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, ast_tvdiff_sec(), ast_tvnow(), ast_waitfor(), fax_session::caller_mode, fax_session::chan, ast_frame::data, ast_frame::datalen, done, FALSE, fax_session::finished, ast_frame_subclass::format, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, NULL, phase_e_handler(), ast_frame::ptr, ast_control_t38_parameters::request_response, ast_frame::samples, set_ecm(), set_file(), set_local_info(), set_logging(), ast_frame::subclass, T38_STATE_NEGOTIATED, T38_STATE_UNAVAILABLE, fax_session::t38parameters, timeout, TRUE, ast_control_t38_parameters::version, WATCHDOG_STATE_TIMEOUT, and WATCHDOG_TOTAL_TIMEOUT.

Referenced by transmit().

368 {
369  int res = -1;
370  struct ast_format *original_read_fmt;
371  struct ast_format *original_write_fmt = NULL;
372  fax_state_t fax;
373  t30_state_t *t30state;
374  struct ast_frame *inf = NULL;
375  int last_state = 0;
376  struct timeval now, start, state_change;
378  struct ast_control_t38_parameters t38_parameters = { .version = 0,
379  .max_ifp = 800,
380  .rate = AST_T38_RATE_14400,
381  .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
382  .fill_bit_removal = 1,
383 /*
384  * spandsp has API calls to support MMR and JBIG transcoding, but they aren't
385  * implemented quite yet... so don't offer them to the remote endpoint
386  * .transcoding_mmr = 1,
387  * .transcoding_jbig = 1,
388 */
389  };
390 
391  /* if in called party mode, try to use T.38 */
392  if (s->caller_mode == FALSE) {
393  /* check if we are already in T.38 mode (unlikely), or if we can request
394  * a switch... if so, request it now and wait for the result, rather
395  * than starting an audio FAX session that will have to be cancelled
396  */
397  if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
398  return 1;
399  } else if ((t38_state != T38_STATE_UNAVAILABLE) &&
401  (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
402  /* wait up to five seconds for negotiation to complete */
403  unsigned int timeout = 5000;
404  int ms;
405 
406  ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan));
407  while (timeout > 0) {
408  ms = ast_waitfor(s->chan, 1000);
409  if (ms < 0) {
410  ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
411  return -1;
412  }
413  if (!ms) {
414  /* nothing happened */
415  if (timeout > 0) {
416  timeout -= 1000;
417  continue;
418  } else {
419  ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan));
420  break;
421  }
422  }
423  if (!(inf = ast_read(s->chan))) {
424  return -1;
425  }
426  if ((inf->frametype == AST_FRAME_CONTROL) &&
428  (inf->datalen == sizeof(t38_parameters))) {
429  struct ast_control_t38_parameters *parameters = inf->data.ptr;
430 
431  switch (parameters->request_response) {
432  case AST_T38_NEGOTIATED:
433  ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan));
434  res = 1;
435  break;
436  case AST_T38_REFUSED:
437  ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan));
438  break;
439  default:
440  ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan));
441  break;
442  }
443  ast_frfree(inf);
444  if (res == 1) {
445  return 1;
446  } else {
447  break;
448  }
449  }
450  ast_frfree(inf);
451  }
452  }
453  }
454 
455 #if SPANDSP_RELEASE_DATE >= 20080725
456  /* for spandsp shaphots 0.0.6 and higher */
457  t30state = &fax.t30;
458 #else
459  /* for spandsp release 0.0.5 */
460  t30state = &fax.t30_state;
461 #endif
462 
463  original_read_fmt = ao2_bump(ast_channel_readformat(s->chan));
465  if (res < 0) {
466  ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
467  goto done;
468  }
469 
470  original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan));
472  if (res < 0) {
473  ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
474  goto done;
475  }
476 
477  /* Initialize T30 terminal */
478  fax_init(&fax, s->caller_mode);
479 
480  /* Setup logging */
481  set_logging(&fax.logging);
482  set_logging(&t30state->logging);
483 
484  /* Configure terminal */
485  set_local_info(t30state, s);
486  set_file(t30state, s);
487  set_ecm(t30state, TRUE);
488 
489  fax_set_transmit_on_idle(&fax, TRUE);
490 
491  t30_set_phase_e_handler(t30state, phase_e_handler, s);
492 
493  start = state_change = ast_tvnow();
494 
496 
497  while (!s->finished) {
498  inf = NULL;
499 
500  if ((res = ast_waitfor(s->chan, 25)) < 0) {
501  ast_debug(1, "Error waiting for a frame\n");
502  break;
503  }
504 
505  /* Watchdog */
506  now = ast_tvnow();
508  ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
509  res = -1;
510  break;
511  }
512 
513  if (!res) {
514  /* There was timeout waiting for a frame. Loop around and wait again */
515  continue;
516  }
517 
518  /* There is a frame available. Get it */
519  res = 0;
520 
521  if (!(inf = ast_read(s->chan))) {
522  ast_debug(1, "Channel hangup\n");
523  res = -1;
524  break;
525  }
526 
527  ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen);
528 
529  /* Check the frame type. Format also must be checked because there is a chance
530  that a frame in old format was already queued before we set channel format
531  to slinear so it will still be received by ast_read */
532  if (inf->frametype == AST_FRAME_VOICE &&
534  if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
535  /* I know fax_rx never returns errors. The check here is for good style only */
536  ast_log(LOG_WARNING, "fax_rx returned error\n");
537  res = -1;
538  break;
539  }
540  if (last_state != t30state->state) {
542  last_state = t30state->state;
543  }
544  } else if ((inf->frametype == AST_FRAME_CONTROL) &&
546  struct ast_control_t38_parameters *parameters = inf->data.ptr;
547 
548  if (parameters->request_response == AST_T38_NEGOTIATED) {
549  /* T38 switchover completed */
550  s->t38parameters = *parameters;
551  ast_debug(1, "T38 negotiated, finishing audio loop\n");
552  res = 1;
553  break;
554  } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
555  t38_parameters.request_response = AST_T38_NEGOTIATED;
556  ast_debug(1, "T38 request received, accepting\n");
557  /* Complete T38 switchover */
558  ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
559  /* Do not break audio loop, wait until channel driver finally acks switchover
560  * with AST_T38_NEGOTIATED
561  */
562  }
563  }
564 
565  ast_frfree(inf);
566  inf = NULL;
567  }
568 
569  ast_debug(1, "Loop finished, res=%d\n", res);
570 
571  if (inf)
572  ast_frfree(inf);
573 
575 
576  /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
577  by t30_terminate, display diagnostics and set status variables although no transmittion
578  has taken place yet. */
579  if (res > 0) {
580  t30_set_phase_e_handler(t30state, NULL, NULL);
581  }
582 
583  t30_terminate(t30state);
584  fax_release(&fax);
585 
586 done:
587  if (original_write_fmt) {
588  if (ast_set_write_format(s->chan, original_write_fmt) < 0)
589  ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan));
590  ao2_ref(original_write_fmt, -1);
591  }
592 
593  if (original_read_fmt) {
594  if (ast_set_read_format(s->chan, original_read_fmt) < 0)
595  ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan));
596  ao2_ref(original_read_fmt, -1);
597  }
598 
599  return res;
600 
601 }
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
#define FALSE
Definition: app_minivm.c:521
static void set_ecm(t30_state_t *state, int ecm)
Definition: app_fax.c:314
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2960
static void set_local_info(t30_state_t *state, fax_session *s)
Definition: app_fax.c:293
#define LOG_WARNING
Definition: logger.h:274
static int set_logging(logging_state_t *state)
Definition: app_fax.c:283
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:64
struct ast_control_t38_parameters t38parameters
Definition: app_fax.c:168
static int timeout
Definition: cdr_mysql.c:86
T.38 state information.
Definition: res_pjsip_t38.c:59
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
enum ast_control_t38 request_response
static void phase_e_handler(t30_state_t *f, void *user_data, int result)
Definition: app_fax.c:206
int caller_mode
Definition: app_fax.c:166
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
Definition of a media format.
Definition: format.c:43
ast_t38_state
Possible T38 states on channels.
Definition: channel.h:879
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
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
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
struct ast_channel * chan
Definition: app_fax.c:163
int done
Definition: test_amihooks.c:48
#define ao2_bump(obj)
Definition: astobj2.h:491
static void set_file(t30_state_t *state, fax_session *s)
Definition: app_fax.c:306
#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
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
volatile int finished
Definition: app_fax.c:169
#define LOG_ERROR
Definition: logger.h:285
static struct ast_generator generator
Definition: app_fax.c:359
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2902
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
const char * ast_channel_name(const struct ast_channel *chan)
#define TRUE
Definition: app_minivm.c:518
#define ast_frfree(fr)
Data structure associated with a single frame of data.
union ast_frame::@263 data
enum ast_frame_type frametype
struct ast_format * format
#define WATCHDOG_STATE_TIMEOUT
Definition: app_fax.c:160
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
#define WATCHDOG_TOTAL_TIMEOUT
Definition: app_fax.c:159

◆ transmit_t38()

static int transmit_t38 ( fax_session s)
static

Definition at line 603 of file app_fax.c.

References ast_channel_get_t38_state(), ast_channel_name(), AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FRAME_CONTROL, AST_FRAME_MODEM, ast_frfree, ast_indicate_data(), ast_log, AST_MODEM_T38, ast_read(), AST_T38_REFUSED, AST_T38_REQUEST_TERMINATE, AST_T38_TERMINATED, ast_tvdiff_sec(), ast_tvdiff_us(), ast_tvnow(), ast_waitfor(), fax_session::caller_mode, fax_session::chan, ast_frame::data, ast_frame::datalen, disable_t38(), FALSE, ast_control_t38_parameters::fill_bit_removal, fax_session::finished, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_control_t38_parameters::max_ifp, NULL, phase_e_handler(), ast_frame::ptr, ast_control_t38_parameters::request_response, ast_frame::seqno, set_ecm(), set_file(), set_local_info(), set_logging(), ast_frame::subclass, t38, T38_STATE_NEGOTIATED, t38_tx_packet_handler(), fax_session::t38parameters, timeout, ast_control_t38_parameters::transcoding_jbig, ast_control_t38_parameters::transcoding_mmr, TRUE, WATCHDOG_STATE_TIMEOUT, and WATCHDOG_TOTAL_TIMEOUT.

Referenced by transmit().

604 {
605  int res = 0;
606  t38_terminal_state_t t38;
607  struct ast_frame *inf = NULL;
608  int last_state = 0;
609  struct timeval now, start, state_change, last_frame;
610  t30_state_t *t30state;
611  t38_core_state_t *t38state;
612 
613 #if SPANDSP_RELEASE_DATE >= 20080725
614  /* for spandsp shaphots 0.0.6 and higher */
615  t30state = &t38.t30;
616  t38state = &t38.t38_fe.t38;
617 #else
618  /* for spandsp releases 0.0.5 */
619  t30state = &t38.t30_state;
620  t38state = &t38.t38;
621 #endif
622 
623  /* Initialize terminal */
624  memset(&t38, 0, sizeof(t38));
625  if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
626  ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
627  res = -1;
628  goto disable_t38;
629  }
630 
631  t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
632 
634  t38_set_fill_bit_removal(t38state, TRUE);
635  }
637  t38_set_mmr_transcoding(t38state, TRUE);
638  }
640  t38_set_jbig_transcoding(t38state, TRUE);
641  }
642 
643  /* Setup logging */
644  set_logging(&t38.logging);
645  set_logging(&t30state->logging);
646  set_logging(&t38state->logging);
647 
648  /* Configure terminal */
649  set_local_info(t30state, s);
650  set_file(t30state, s);
651  set_ecm(t30state, TRUE);
652 
653  t30_set_phase_e_handler(t30state, phase_e_handler, s);
654 
655  now = start = state_change = ast_tvnow();
656 
657  while (!s->finished) {
658  inf = NULL;
659 
660  if ((res = ast_waitfor(s->chan, 25)) < 0) {
661  ast_debug(1, "Error waiting for a frame\n");
662  break;
663  }
664 
665  last_frame = now;
666 
667  /* Watchdog */
668  now = ast_tvnow();
670  ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
671  res = -1;
672  break;
673  }
674 
675  t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
676 
677  if (!res) {
678  /* There was timeout waiting for a frame. Loop around and wait again */
679  continue;
680  }
681 
682  /* There is a frame available. Get it */
683  res = 0;
684 
685  if (!(inf = ast_read(s->chan))) {
686  ast_debug(1, "Channel hangup\n");
687  res = -1;
688  break;
689  }
690 
691  ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen);
692 
693  if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) {
694  t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
695  if (last_state != t30state->state) {
697  last_state = t30state->state;
698  }
700  struct ast_control_t38_parameters *parameters = inf->data.ptr;
701  if (parameters->request_response == AST_T38_TERMINATED) {
702  ast_debug(1, "T38 down, finishing\n");
703  break;
704  }
705  }
706 
707  ast_frfree(inf);
708  inf = NULL;
709  }
710 
711  ast_debug(1, "Loop finished, res=%d\n", res);
712 
713  if (inf)
714  ast_frfree(inf);
715 
716  t30_terminate(t30state);
717  t38_terminal_release(&t38);
718 
720  /* if we are not the caller, it's our job to shut down the T.38
721  * session when the FAX transmisson is complete.
722  */
723  if ((s->caller_mode == FALSE) &&
726 
727  if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
728  /* wait up to five seconds for negotiation to complete */
729  unsigned int timeout = 5000;
730  int ms;
731 
732  ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan));
733  while (timeout > 0) {
734  ms = ast_waitfor(s->chan, 1000);
735  if (ms < 0) {
736  ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
737  return -1;
738  }
739  if (!ms) {
740  /* nothing happened */
741  if (timeout > 0) {
742  timeout -= 1000;
743  continue;
744  } else {
745  ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan));
746  break;
747  }
748  }
749  if (!(inf = ast_read(s->chan))) {
750  return -1;
751  }
752  if ((inf->frametype == AST_FRAME_CONTROL) &&
754  (inf->datalen == sizeof(t38_parameters))) {
755  struct ast_control_t38_parameters *parameters = inf->data.ptr;
756 
757  switch (parameters->request_response) {
758  case AST_T38_TERMINATED:
759  ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan));
760  break;
761  case AST_T38_REFUSED:
762  ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan));
763  break;
764  default:
765  ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan));
766  break;
767  }
768  ast_frfree(inf);
769  break;
770  }
771  ast_frfree(inf);
772  }
773  }
774  }
775 
776  return res;
777 }
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
#define FALSE
Definition: app_minivm.c:521
static void set_ecm(t30_state_t *state, int ecm)
Definition: app_fax.c:314
static void set_local_info(t30_state_t *state, fax_session *s)
Definition: app_fax.c:293
#define LOG_WARNING
Definition: logger.h:274
static int set_logging(logging_state_t *state)
Definition: app_fax.c:283
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:64
struct ast_control_t38_parameters t38parameters
Definition: app_fax.c:168
static int timeout
Definition: cdr_mysql.c:86
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
enum ast_control_t38 request_response
static void phase_e_handler(t30_state_t *f, void *user_data, int result)
Definition: app_fax.c:206
int caller_mode
Definition: app_fax.c:166
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
t38state
T38 States for a call.
Definition: sip.h:665
#define NULL
Definition: resample.c:96
struct spandsp_fax_stats t38
struct ast_frame_subclass subclass
struct ast_channel * chan
Definition: app_fax.c:163
static void set_file(t30_state_t *state, fax_session *s)
Definition: app_fax.c:306
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static int disable_t38(struct ast_channel *chan)
Definition: res_fax.c:1527
volatile int finished
Definition: app_fax.c:169
#define LOG_ERROR
Definition: logger.h:285
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
const char * ast_channel_name(const struct ast_channel *chan)
#define TRUE
Definition: app_minivm.c:518
#define ast_frfree(fr)
#define AST_MODEM_T38
Data structure associated with a single frame of data.
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
Definition: app_fax.c:183
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:78
union ast_frame::@263 data
enum ast_frame_type frametype
#define WATCHDOG_STATE_TIMEOUT
Definition: app_fax.c:160
#define WATCHDOG_TOTAL_TIMEOUT
Definition: app_fax.c:159

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 975 of file app_fax.c.

References app_rcvfax_name, app_sndfax_name, and ast_unregister_application().

Referenced by load_module().

976 {
977  int res;
978 
981 
982  return res;
983 }
static const char app_sndfax_name[]
Definition: app_fax.c:148
static const char app_rcvfax_name[]
Definition: app_fax.c:149
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Simple FAX Application" , .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_DEPRECATED, .load = load_module, .unload = unload_module, }
static

Definition at line 1003 of file app_fax.c.

◆ app_rcvfax_name

const char app_rcvfax_name[] = "ReceiveFAX"
static

Definition at line 149 of file app_fax.c.

Referenced by load_module(), and unload_module().

◆ app_sndfax_name

const char app_sndfax_name[] = "SendFAX"
static

Definition at line 148 of file app_fax.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1003 of file app_fax.c.

◆ generator

struct ast_generator generator
static
Initial value:
= {
}
static void * fax_generator_alloc(struct ast_channel *chan, void *params)
Definition: app_fax.c:324
static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_fax.c:329

Definition at line 359 of file app_fax.c.

Referenced by ast_read_generator_actions(), ast_sip_pubsub_generate_body_content(), cli_alias_passthrough(), create_virtual_subscriptions(), deactivate_generator_nolock(), find_body_generator(), generator_write_format_change(), pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().