#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/manager.h"
Go to the source code of this file.
Data Structures | |
struct | fax_session |
Defines | |
#define | MAX_SAMPLES 240 |
#define | SPANDSP_EXPOSE_INTERNAL_STRUCTURES |
#define | WATCHDOG_STATE_TIMEOUT 5 * 60 |
#define | WATCHDOG_TOTAL_TIMEOUT 30 * 60 |
Functions | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Simple FAX Application",.load=load_module,.unload=unload_module,) | |
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 const char | app_rcvfax_name [] = "ReceiveFAX" |
static const char | app_sndfax_name [] = "SendFAX" |
static struct ast_generator | generator |
#define MAX_SAMPLES 240 |
Definition at line 148 of file app_fax.c.
Referenced by fax_generator_generate().
#define WATCHDOG_STATE_TIMEOUT 5 * 60 |
Definition at line 157 of file app_fax.c.
Referenced by transmit_audio(), and transmit_t38().
#define WATCHDOG_TOTAL_TIMEOUT 30 * 60 |
Definition at line 156 of file app_fax.c.
Referenced by transmit_audio(), and transmit_t38().
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"Simple FAX Application" | , | |||
. | load = load_module , |
|||
. | unload = unload_module | |||
) |
static void* fax_generator_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
static int fax_generator_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 331 of file app_fax.c.
References AST_FORMAT_SLINEAR, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), errno, ast_frame::frametype, LOG_WARNING, MAX_SAMPLES, and ast_frame::samples.
00332 { 00333 fax_state_t *fax = (fax_state_t*) data; 00334 uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)]; 00335 int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET); 00336 00337 struct ast_frame outf = { 00338 .frametype = AST_FRAME_VOICE, 00339 .subclass.codec = AST_FORMAT_SLINEAR, 00340 .src = __FUNCTION__, 00341 }; 00342 00343 if (samples > MAX_SAMPLES) { 00344 ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples); 00345 samples = MAX_SAMPLES; 00346 } 00347 00348 if ((len = fax_tx(fax, buf, samples)) > 0) { 00349 outf.samples = len; 00350 AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t)); 00351 00352 if (ast_write(chan, &outf) < 0) { 00353 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00354 return -1; 00355 } 00356 } 00357 00358 return 0; 00359 }
static int load_module | ( | void | ) | [static] |
Definition at line 988 of file app_fax.c.
References ast_register_application_xml, rcvfax_exec(), and sndfax_exec().
00989 { 00990 int res ; 00991 00992 res = ast_register_application_xml(app_sndfax_name, sndfax_exec); 00993 res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec); 00994 00995 /* The default SPAN message handler prints to stderr. It is something we do not want */ 00996 span_set_message_handler(NULL); 00997 00998 return res; 00999 }
static void phase_e_handler | ( | t30_state_t * | f, | |
void * | user_data, | |||
int | result | |||
) | [static] |
Definition at line 203 of file app_fax.c.
References ast_debug, ast_log(), ast_manager_event, ast_channel::caller, fax_session::chan, ast_channel::connected, fax_session::direction, EVENT_FLAG_CALL, ast_channel::exten, fax_session::file_name, fax_session::finished, ast_party_connected_line::id, ast_party_caller::id, LOG_WARNING, ast_party_id::name, ast_party_id::number, pbx_builtin_setvar_helper(), S_COR, S_OR, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.
Referenced by transmit_audio(), and transmit_t38().
00204 { 00205 const char *local_ident; 00206 const char *far_ident; 00207 char buf[20]; 00208 fax_session *s = (fax_session *) user_data; 00209 t30_stats_t stat; 00210 int pages_transferred; 00211 00212 ast_debug(1, "Fax phase E handler. result=%d\n", result); 00213 00214 t30_get_transfer_statistics(f, &stat); 00215 00216 s = (fax_session *) user_data; 00217 00218 if (result != T30_ERR_OK) { 00219 s->finished = -1; 00220 00221 /* FAXSTATUS is already set to FAILED */ 00222 pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result)); 00223 00224 ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result)); 00225 00226 return; 00227 } 00228 00229 s->finished = 1; 00230 00231 local_ident = S_OR(t30_get_tx_ident(f), ""); 00232 far_ident = S_OR(t30_get_rx_ident(f), ""); 00233 pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); 00234 pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); 00235 pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident); 00236 #if SPANDSP_RELEASE_DATE >= 20090220 00237 pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx; 00238 #else 00239 pages_transferred = stat.pages_transferred; 00240 #endif 00241 snprintf(buf, sizeof(buf), "%d", pages_transferred); 00242 pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf); 00243 snprintf(buf, sizeof(buf), "%d", stat.y_resolution); 00244 pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf); 00245 snprintf(buf, sizeof(buf), "%d", stat.bit_rate); 00246 pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); 00247 00248 ast_debug(1, "Fax transmitted successfully.\n"); 00249 ast_debug(1, " Remote station ID: %s\n", far_ident); 00250 ast_debug(1, " Pages transferred: %d\n", pages_transferred); 00251 ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution); 00252 ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate); 00253 00254 ast_manager_event(s->chan, EVENT_FLAG_CALL, 00255 s->direction ? "FaxSent" : "FaxReceived", 00256 "Channel: %s\r\n" 00257 "Exten: %s\r\n" 00258 "CallerID: %s\r\n" 00259 "CallerIDName: %s\r\n" 00260 "ConnectedLineNum: %s\r\n" 00261 "ConnectedLineName: %s\r\n" 00262 "RemoteStationID: %s\r\n" 00263 "LocalStationID: %s\r\n" 00264 "PagesTransferred: %d\r\n" 00265 "Resolution: %d\r\n" 00266 "TransferRate: %d\r\n" 00267 "FileName: %s\r\n", 00268 s->chan->name, 00269 s->chan->exten, 00270 S_COR(s->chan->caller.id.number.valid, s->chan->caller.id.number.str, ""), 00271 S_COR(s->chan->caller.id.name.valid, s->chan->caller.id.name.str, ""), 00272 S_COR(s->chan->connected.id.number.valid, s->chan->connected.id.number.str, ""), 00273 S_COR(s->chan->connected.id.name.valid, s->chan->connected.id.name.str, ""), 00274 far_ident, 00275 local_ident, 00276 pages_transferred, 00277 stat.y_resolution, 00278 stat.bit_rate, 00279 s->file_name); 00280 }
static int rcvfax_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 909 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, parse(), transmit(), and TRUE.
Referenced by load_module().
00910 { 00911 int res = 0; 00912 char *parse; 00913 fax_session session; 00914 char restore_digit_detect = 0; 00915 00916 AST_DECLARE_APP_ARGS(args, 00917 AST_APP_ARG(file_name); 00918 AST_APP_ARG(options); 00919 ); 00920 00921 if (chan == NULL) { 00922 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n"); 00923 return -1; 00924 } 00925 00926 /* The next few lines of code parse out the filename and header from the input string */ 00927 if (ast_strlen_zero(data)) { 00928 /* No data implies no filename or anything is present */ 00929 ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n"); 00930 return -1; 00931 } 00932 00933 parse = ast_strdupa(data); 00934 AST_STANDARD_APP_ARGS(args, parse); 00935 00936 session.caller_mode = FALSE; 00937 00938 if (args.options) { 00939 if (strchr(args.options, 'c')) 00940 session.caller_mode = TRUE; 00941 } 00942 00943 /* Done parsing */ 00944 session.direction = 0; 00945 session.file_name = args.file_name; 00946 session.chan = chan; 00947 session.finished = 0; 00948 00949 /* get current digit detection mode, then disable digit detection if enabled */ 00950 { 00951 int dummy = sizeof(restore_digit_detect); 00952 00953 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0); 00954 } 00955 00956 if (restore_digit_detect) { 00957 char new_digit_detect = 0; 00958 00959 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0); 00960 } 00961 00962 /* disable FAX tone detection if enabled */ 00963 { 00964 char new_fax_detect = 0; 00965 00966 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0); 00967 } 00968 00969 res = transmit(&session); 00970 00971 if (restore_digit_detect) { 00972 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0); 00973 } 00974 00975 return res; 00976 }
static void set_ecm | ( | t30_state_t * | state, | |
int | ecm | |||
) | [static] |
Definition at line 316 of file app_fax.c.
Referenced by transmit_audio(), and transmit_t38().
static void set_file | ( | t30_state_t * | state, | |
fax_session * | s | |||
) | [static] |
Definition at line 308 of file app_fax.c.
References fax_session::direction, and fax_session::file_name.
Referenced by transmit_audio(), and transmit_t38().
static void set_local_info | ( | t30_state_t * | state, | |
fax_session * | s | |||
) | [static] |
Definition at line 295 of file app_fax.c.
References ast_strlen_zero(), fax_session::chan, and pbx_builtin_getvar_helper().
Referenced by transmit_audio(), and transmit_t38().
00296 { 00297 const char *x; 00298 00299 x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID"); 00300 if (!ast_strlen_zero(x)) 00301 t30_set_tx_ident(state, x); 00302 00303 x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO"); 00304 if (!ast_strlen_zero(x)) 00305 t30_set_tx_page_header_info(state, x); 00306 }
static int set_logging | ( | logging_state_t * | state | ) | [static] |
Definition at line 285 of file app_fax.c.
References option_debug, and span_message().
Referenced by transmit_audio(), and transmit_t38().
00286 { 00287 int level = SPAN_LOG_WARNING + option_debug; 00288 00289 span_log_set_message_handler(state, span_message); 00290 span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 00291 00292 return 0; 00293 }
static int sndfax_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 840 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, parse(), transmit(), and TRUE.
Referenced by load_module().
00841 { 00842 int res = 0; 00843 char *parse; 00844 fax_session session = { 0, }; 00845 char restore_digit_detect = 0; 00846 00847 AST_DECLARE_APP_ARGS(args, 00848 AST_APP_ARG(file_name); 00849 AST_APP_ARG(options); 00850 ); 00851 00852 if (chan == NULL) { 00853 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n"); 00854 return -1; 00855 } 00856 00857 /* The next few lines of code parse out the filename and header from the input string */ 00858 if (ast_strlen_zero(data)) { 00859 /* No data implies no filename or anything is present */ 00860 ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n"); 00861 return -1; 00862 } 00863 00864 parse = ast_strdupa(data); 00865 AST_STANDARD_APP_ARGS(args, parse); 00866 00867 session.caller_mode = TRUE; 00868 00869 if (args.options) { 00870 if (strchr(args.options, 'a')) 00871 session.caller_mode = FALSE; 00872 } 00873 00874 /* Done parsing */ 00875 session.direction = 1; 00876 session.file_name = args.file_name; 00877 session.chan = chan; 00878 session.finished = 0; 00879 00880 /* get current digit detection mode, then disable digit detection if enabled */ 00881 { 00882 int dummy = sizeof(restore_digit_detect); 00883 00884 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0); 00885 } 00886 00887 if (restore_digit_detect) { 00888 char new_digit_detect = 0; 00889 00890 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0); 00891 } 00892 00893 /* disable FAX tone detection if enabled */ 00894 { 00895 char new_fax_detect = 0; 00896 00897 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0); 00898 } 00899 00900 res = transmit(&session); 00901 00902 if (restore_digit_detect) { 00903 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0); 00904 } 00905 00906 return res; 00907 }
static void span_message | ( | int | level, | |
const char * | msg | |||
) | [static] |
Definition at line 169 of file app_fax.c.
References ast_log(), LOG_DEBUG, LOG_ERROR, and LOG_WARNING.
Referenced by set_logging().
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 180 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().
00181 { 00182 struct ast_channel *chan = (struct ast_channel *) user_data; 00183 00184 struct ast_frame outf = { 00185 .frametype = AST_FRAME_MODEM, 00186 .subclass.integer = AST_MODEM_T38, 00187 .src = __FUNCTION__, 00188 }; 00189 00190 /* TODO: Asterisk does not provide means of resending the same packet multiple 00191 times so count is ignored at the moment */ 00192 00193 AST_FRAME_SET_BUFFER(&outf, buf, 0, len); 00194 00195 if (ast_write(chan, &outf) < 0) { 00196 ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); 00197 return -1; 00198 } 00199 00200 return 0; 00201 }
static int transmit | ( | fax_session * | s | ) | [static] |
Definition at line 782 of file app_fax.c.
References ast_channel::_state, ast_answer(), ast_channel_get_t38_state(), ast_debug, ast_log(), AST_STATE_UP, fax_session::chan, fax_session::finished, LOG_ERROR, LOG_WARNING, pbx_builtin_setvar_helper(), T38_STATE_NEGOTIATED, fax_session::t38state, transmit_audio(), and transmit_t38().
Referenced by rcvfax_exec(), and sndfax_exec().
00783 { 00784 int res = 0; 00785 00786 /* Clear all channel variables which to be set by the application. 00787 Pre-set status to error so in case of any problems we can just leave */ 00788 pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 00789 pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 00790 00791 pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL); 00792 pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL); 00793 pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0"); 00794 pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL); 00795 pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 00796 00797 if (s->chan->_state != AST_STATE_UP) { 00798 /* Shouldn't need this, but checking to see if channel is already answered 00799 * Theoretically asterisk should already have answered before running the app */ 00800 res = ast_answer(s->chan); 00801 if (res) { 00802 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name); 00803 return res; 00804 } 00805 } 00806 00807 s->t38state = ast_channel_get_t38_state(s->chan); 00808 if (s->t38state != T38_STATE_NEGOTIATED) { 00809 /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */ 00810 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 00811 res = transmit_audio(s); 00812 if (res > 0) { 00813 /* transmit_audio reports switchover to T38. Update t38state */ 00814 s->t38state = ast_channel_get_t38_state(s->chan); 00815 if (s->t38state != T38_STATE_NEGOTIATED) { 00816 ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n"); 00817 } 00818 } 00819 } 00820 00821 if (s->t38state == T38_STATE_NEGOTIATED) { 00822 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 00823 res = transmit_t38(s); 00824 } 00825 00826 if (res) { 00827 ast_log(LOG_WARNING, "Transmission error\n"); 00828 res = -1; 00829 } else if (s->finished < 0) { 00830 ast_log(LOG_WARNING, "Transmission failed\n"); 00831 } else if (s->finished > 0) { 00832 ast_debug(1, "Transmission finished Ok\n"); 00833 } 00834 00835 return res; 00836 }
static int transmit_audio | ( | fax_session * | s | ) | [static] |
Definition at line 369 of file app_fax.c.
References ast_activate_generator(), ast_channel_get_t38_state(), AST_CONTROL_T38_PARAMETERS, ast_deactivate_generator(), ast_debug, AST_FORMAT_SLINEAR, 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_subclass::codec, ast_frame::data, ast_frame::datalen, FALSE, fax_session::finished, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, phase_e_handler(), ast_frame::ptr, ast_channel::readformat, 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, TRUE, ast_control_t38_parameters::version, WATCHDOG_STATE_TIMEOUT, WATCHDOG_TOTAL_TIMEOUT, and ast_channel::writeformat.
Referenced by transmit().
00370 { 00371 int res = -1; 00372 int original_read_fmt = AST_FORMAT_SLINEAR; 00373 int original_write_fmt = AST_FORMAT_SLINEAR; 00374 fax_state_t fax; 00375 t30_state_t *t30state; 00376 struct ast_frame *inf = NULL; 00377 int last_state = 0; 00378 struct timeval now, start, state_change; 00379 enum ast_t38_state t38_state; 00380 struct ast_control_t38_parameters t38_parameters = { .version = 0, 00381 .max_ifp = 800, 00382 .rate = AST_T38_RATE_14400, 00383 .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, 00384 .fill_bit_removal = 1, 00385 /* 00386 * spandsp has API calls to support MMR and JBIG transcoding, but they aren't 00387 * implemented quite yet... so don't offer them to the remote endpoint 00388 * .transcoding_mmr = 1, 00389 * .transcoding_jbig = 1, 00390 */ 00391 }; 00392 00393 /* if in called party mode, try to use T.38 */ 00394 if (s->caller_mode == FALSE) { 00395 /* check if we are already in T.38 mode (unlikely), or if we can request 00396 * a switch... if so, request it now and wait for the result, rather 00397 * than starting an audio FAX session that will have to be cancelled 00398 */ 00399 if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) { 00400 return 1; 00401 } else if ((t38_state != T38_STATE_UNAVAILABLE) && 00402 (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE, 00403 (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) { 00404 /* wait up to five seconds for negotiation to complete */ 00405 unsigned int timeout = 5000; 00406 int ms; 00407 00408 ast_debug(1, "Negotiating T.38 for receive on %s\n", s->chan->name); 00409 while (timeout > 0) { 00410 ms = ast_waitfor(s->chan, 1000); 00411 if (ms < 0) { 00412 ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name); 00413 return -1; 00414 } 00415 if (!ms) { 00416 /* nothing happened */ 00417 if (timeout > 0) { 00418 timeout -= 1000; 00419 continue; 00420 } else { 00421 ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", s->chan->name); 00422 break; 00423 } 00424 } 00425 if (!(inf = ast_read(s->chan))) { 00426 return -1; 00427 } 00428 if ((inf->frametype == AST_FRAME_CONTROL) && 00429 (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && 00430 (inf->datalen == sizeof(t38_parameters))) { 00431 struct ast_control_t38_parameters *parameters = inf->data.ptr; 00432 00433 switch (parameters->request_response) { 00434 case AST_T38_NEGOTIATED: 00435 ast_debug(1, "Negotiated T.38 for receive on %s\n", s->chan->name); 00436 res = 1; 00437 break; 00438 case AST_T38_REFUSED: 00439 ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", s->chan->name); 00440 break; 00441 default: 00442 ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", s->chan->name); 00443 break; 00444 } 00445 ast_frfree(inf); 00446 if (res == 1) { 00447 return 1; 00448 } else { 00449 break; 00450 } 00451 } 00452 ast_frfree(inf); 00453 } 00454 } 00455 } 00456 00457 #if SPANDSP_RELEASE_DATE >= 20080725 00458 /* for spandsp shaphots 0.0.6 and higher */ 00459 t30state = &fax.t30; 00460 #else 00461 /* for spandsp release 0.0.5 */ 00462 t30state = &fax.t30_state; 00463 #endif 00464 00465 original_read_fmt = s->chan->readformat; 00466 if (original_read_fmt != AST_FORMAT_SLINEAR) { 00467 res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR); 00468 if (res < 0) { 00469 ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); 00470 goto done; 00471 } 00472 } 00473 00474 original_write_fmt = s->chan->writeformat; 00475 if (original_write_fmt != AST_FORMAT_SLINEAR) { 00476 res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR); 00477 if (res < 0) { 00478 ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); 00479 goto done; 00480 } 00481 } 00482 00483 /* Initialize T30 terminal */ 00484 fax_init(&fax, s->caller_mode); 00485 00486 /* Setup logging */ 00487 set_logging(&fax.logging); 00488 set_logging(&t30state->logging); 00489 00490 /* Configure terminal */ 00491 set_local_info(t30state, s); 00492 set_file(t30state, s); 00493 set_ecm(t30state, TRUE); 00494 00495 fax_set_transmit_on_idle(&fax, TRUE); 00496 00497 t30_set_phase_e_handler(t30state, phase_e_handler, s); 00498 00499 start = state_change = ast_tvnow(); 00500 00501 ast_activate_generator(s->chan, &generator, &fax); 00502 00503 while (!s->finished) { 00504 inf = NULL; 00505 00506 if ((res = ast_waitfor(s->chan, 25)) < 0) { 00507 ast_debug(1, "Error waiting for a frame\n"); 00508 break; 00509 } 00510 00511 /* Watchdog */ 00512 now = ast_tvnow(); 00513 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { 00514 ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); 00515 res = -1; 00516 break; 00517 } 00518 00519 if (!res) { 00520 /* There was timeout waiting for a frame. Loop around and wait again */ 00521 continue; 00522 } 00523 00524 /* There is a frame available. Get it */ 00525 res = 0; 00526 00527 if (!(inf = ast_read(s->chan))) { 00528 ast_debug(1, "Channel hangup\n"); 00529 res = -1; 00530 break; 00531 } 00532 00533 ast_debug(10, "frame %d/%llu, len=%d\n", inf->frametype, (unsigned long long) inf->subclass.codec, inf->datalen); 00534 00535 /* Check the frame type. Format also must be checked because there is a chance 00536 that a frame in old format was already queued before we set channel format 00537 to slinear so it will still be received by ast_read */ 00538 if (inf->frametype == AST_FRAME_VOICE && inf->subclass.codec == AST_FORMAT_SLINEAR) { 00539 if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) { 00540 /* I know fax_rx never returns errors. The check here is for good style only */ 00541 ast_log(LOG_WARNING, "fax_rx returned error\n"); 00542 res = -1; 00543 break; 00544 } 00545 if (last_state != t30state->state) { 00546 state_change = ast_tvnow(); 00547 last_state = t30state->state; 00548 } 00549 } else if ((inf->frametype == AST_FRAME_CONTROL) && 00550 (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) { 00551 struct ast_control_t38_parameters *parameters = inf->data.ptr; 00552 00553 if (parameters->request_response == AST_T38_NEGOTIATED) { 00554 /* T38 switchover completed */ 00555 s->t38parameters = *parameters; 00556 ast_debug(1, "T38 negotiated, finishing audio loop\n"); 00557 res = 1; 00558 break; 00559 } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) { 00560 t38_parameters.request_response = AST_T38_NEGOTIATED; 00561 ast_debug(1, "T38 request received, accepting\n"); 00562 /* Complete T38 switchover */ 00563 ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)); 00564 /* Do not break audio loop, wait until channel driver finally acks switchover 00565 * with AST_T38_NEGOTIATED 00566 */ 00567 } 00568 } 00569 00570 ast_frfree(inf); 00571 inf = NULL; 00572 } 00573 00574 ast_debug(1, "Loop finished, res=%d\n", res); 00575 00576 if (inf) 00577 ast_frfree(inf); 00578 00579 ast_deactivate_generator(s->chan); 00580 00581 /* If we are switching to T38, remove phase E handler. Otherwise it will be executed 00582 by t30_terminate, display diagnostics and set status variables although no transmittion 00583 has taken place yet. */ 00584 if (res > 0) { 00585 t30_set_phase_e_handler(t30state, NULL, NULL); 00586 } 00587 00588 t30_terminate(t30state); 00589 fax_release(&fax); 00590 00591 done: 00592 if (original_write_fmt != AST_FORMAT_SLINEAR) { 00593 if (ast_set_write_format(s->chan, original_write_fmt) < 0) 00594 ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name); 00595 } 00596 00597 if (original_read_fmt != AST_FORMAT_SLINEAR) { 00598 if (ast_set_read_format(s->chan, original_read_fmt) < 0) 00599 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name); 00600 } 00601 00602 return res; 00603 00604 }
static int transmit_t38 | ( | fax_session * | s | ) | [static] |
Definition at line 606 of file app_fax.c.
References ast_channel_get_t38_state(), 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, 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, ast_control_t38_parameters::transcoding_jbig, ast_control_t38_parameters::transcoding_mmr, TRUE, WATCHDOG_STATE_TIMEOUT, and WATCHDOG_TOTAL_TIMEOUT.
Referenced by transmit().
00607 { 00608 int res = 0; 00609 t38_terminal_state_t t38; 00610 struct ast_frame *inf = NULL; 00611 int last_state = 0; 00612 struct timeval now, start, state_change, last_frame; 00613 t30_state_t *t30state; 00614 t38_core_state_t *t38state; 00615 00616 #if SPANDSP_RELEASE_DATE >= 20080725 00617 /* for spandsp shaphots 0.0.6 and higher */ 00618 t30state = &t38.t30; 00619 t38state = &t38.t38_fe.t38; 00620 #else 00621 /* for spandsp releases 0.0.5 */ 00622 t30state = &t38.t30_state; 00623 t38state = &t38.t38; 00624 #endif 00625 00626 /* Initialize terminal */ 00627 memset(&t38, 0, sizeof(t38)); 00628 if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) { 00629 ast_log(LOG_WARNING, "Unable to start T.38 termination.\n"); 00630 res = -1; 00631 goto disable_t38; 00632 } 00633 00634 t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp); 00635 00636 if (s->t38parameters.fill_bit_removal) { 00637 t38_set_fill_bit_removal(t38state, TRUE); 00638 } 00639 if (s->t38parameters.transcoding_mmr) { 00640 t38_set_mmr_transcoding(t38state, TRUE); 00641 } 00642 if (s->t38parameters.transcoding_jbig) { 00643 t38_set_jbig_transcoding(t38state, TRUE); 00644 } 00645 00646 /* Setup logging */ 00647 set_logging(&t38.logging); 00648 set_logging(&t30state->logging); 00649 set_logging(&t38state->logging); 00650 00651 /* Configure terminal */ 00652 set_local_info(t30state, s); 00653 set_file(t30state, s); 00654 set_ecm(t30state, TRUE); 00655 00656 t30_set_phase_e_handler(t30state, phase_e_handler, s); 00657 00658 now = start = state_change = ast_tvnow(); 00659 00660 while (!s->finished) { 00661 inf = NULL; 00662 00663 if ((res = ast_waitfor(s->chan, 25)) < 0) { 00664 ast_debug(1, "Error waiting for a frame\n"); 00665 break; 00666 } 00667 00668 last_frame = now; 00669 00670 /* Watchdog */ 00671 now = ast_tvnow(); 00672 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { 00673 ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); 00674 res = -1; 00675 break; 00676 } 00677 00678 t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000)); 00679 00680 if (!res) { 00681 /* There was timeout waiting for a frame. Loop around and wait again */ 00682 continue; 00683 } 00684 00685 /* There is a frame available. Get it */ 00686 res = 0; 00687 00688 if (!(inf = ast_read(s->chan))) { 00689 ast_debug(1, "Channel hangup\n"); 00690 res = -1; 00691 break; 00692 } 00693 00694 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen); 00695 00696 if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) { 00697 t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno); 00698 if (last_state != t30state->state) { 00699 state_change = ast_tvnow(); 00700 last_state = t30state->state; 00701 } 00702 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) { 00703 struct ast_control_t38_parameters *parameters = inf->data.ptr; 00704 if (parameters->request_response == AST_T38_TERMINATED) { 00705 ast_debug(1, "T38 down, finishing\n"); 00706 break; 00707 } 00708 } 00709 00710 ast_frfree(inf); 00711 inf = NULL; 00712 } 00713 00714 ast_debug(1, "Loop finished, res=%d\n", res); 00715 00716 if (inf) 00717 ast_frfree(inf); 00718 00719 t30_terminate(t30state); 00720 t38_terminal_release(&t38); 00721 00722 disable_t38: 00723 /* if we are not the caller, it's our job to shut down the T.38 00724 * session when the FAX transmisson is complete. 00725 */ 00726 if ((s->caller_mode == FALSE) && 00727 (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) { 00728 struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, }; 00729 00730 if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) { 00731 /* wait up to five seconds for negotiation to complete */ 00732 unsigned int timeout = 5000; 00733 int ms; 00734 00735 ast_debug(1, "Shutting down T.38 on %s\n", s->chan->name); 00736 while (timeout > 0) { 00737 ms = ast_waitfor(s->chan, 1000); 00738 if (ms < 0) { 00739 ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name); 00740 return -1; 00741 } 00742 if (!ms) { 00743 /* nothing happened */ 00744 if (timeout > 0) { 00745 timeout -= 1000; 00746 continue; 00747 } else { 00748 ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", s->chan->name); 00749 break; 00750 } 00751 } 00752 if (!(inf = ast_read(s->chan))) { 00753 return -1; 00754 } 00755 if ((inf->frametype == AST_FRAME_CONTROL) && 00756 (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && 00757 (inf->datalen == sizeof(t38_parameters))) { 00758 struct ast_control_t38_parameters *parameters = inf->data.ptr; 00759 00760 switch (parameters->request_response) { 00761 case AST_T38_TERMINATED: 00762 ast_debug(1, "Shut down T.38 on %s\n", s->chan->name); 00763 break; 00764 case AST_T38_REFUSED: 00765 ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", s->chan->name); 00766 break; 00767 default: 00768 ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", s->chan->name); 00769 break; 00770 } 00771 ast_frfree(inf); 00772 break; 00773 } 00774 ast_frfree(inf); 00775 } 00776 } 00777 } 00778 00779 return res; 00780 }
static int unload_module | ( | void | ) | [static] |
Definition at line 978 of file app_fax.c.
References ast_unregister_application().
00979 { 00980 int res; 00981 00982 res = ast_unregister_application(app_sndfax_name); 00983 res |= ast_unregister_application(app_rcvfax_name); 00984 00985 return res; 00986 }
const char app_rcvfax_name[] = "ReceiveFAX" [static] |
const char app_sndfax_name[] = "SendFAX" [static] |
struct ast_generator generator [static] |
{ alloc: fax_generator_alloc, generate: fax_generator_generate, }
Definition at line 361 of file app_fax.c.
Referenced by cli_alias_passthrough().