mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
Fax gateway functionality (i.e. translating between a T.30 terminal and a T.38
terminal). Can be enabled on a channel by setting FAXOPT(gateway)=yes in the dialplan. Big thanks to irroot for porting this code to use the framehooks api. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@325816 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
10
CHANGES
10
CHANGES
@@ -150,6 +150,16 @@ pbx_lua
|
||||
stopped and restarted using the autoservice_stop() and autoservice_start()
|
||||
functions.
|
||||
|
||||
res_fax
|
||||
--------------------------
|
||||
* The ReceiveFAXStatus and SendFAXStatus manager events have been consolidated
|
||||
into a FAXStatus event with an 'Operation' header that will be either
|
||||
'send', 'receive', and 'gateway'.
|
||||
* T.38 gateway functionality has been added to res_fax (and res_fax_spandsp).
|
||||
Set FAXOPT(gateway)=yes to enable this functionality on a channel. This
|
||||
feature will handle converting a fax call between an audio T.30 fax terminal
|
||||
and an IFP T.38 fax terminal.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.8 ----------------
|
||||
------------------------------------------------------------------------------
|
||||
|
@@ -42,6 +42,8 @@ enum ast_fax_capabilities {
|
||||
AST_FAX_TECH_T38 = (1 << 3),
|
||||
/*! sending mulitple documents supported */
|
||||
AST_FAX_TECH_MULTI_DOC = (1 << 4),
|
||||
/*! T.38 - T.30 Gateway */
|
||||
AST_FAX_TECH_GATEWAY = (1 << 5),
|
||||
};
|
||||
|
||||
/*! \brief fax modem capabilities */
|
||||
@@ -168,6 +170,8 @@ struct ast_fax_session_details {
|
||||
struct ast_fax_t38_parameters our_t38_parameters;
|
||||
/*! the other endpoint's T.38 session parameters, if any */
|
||||
struct ast_fax_t38_parameters their_t38_parameters;
|
||||
/*! the id of the t.38 gateway framehook for this channel */
|
||||
int gateway_id;
|
||||
};
|
||||
|
||||
struct ast_fax_tech;
|
||||
@@ -204,6 +208,9 @@ struct ast_fax_session {
|
||||
struct ast_smoother *smoother;
|
||||
};
|
||||
|
||||
/* if this overlaps with any AST_FRFLAG_* values, problems will occur */
|
||||
#define AST_FAX_FRFLAG_GATEWAY (1 << 13)
|
||||
|
||||
/*! \brief used to register a FAX technology module with res_fax */
|
||||
struct ast_fax_tech {
|
||||
/*! the type of fax session supported with this ast_fax_tech structure */
|
||||
|
887
res/res_fax.c
887
res/res_fax.c
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,22 @@
|
||||
*
|
||||
* Matthew Nicholson <mnicholson@digium.com>
|
||||
*
|
||||
* Initial T.38-gateway code
|
||||
* 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
|
||||
* Created by Nethemba s.r.o. http://www.nethemba.com
|
||||
* Sponsored by IPEX a.s. http://www.ipex.cz
|
||||
*
|
||||
* T.38-gateway integration into asterisk app_fax and rework
|
||||
* 2008, Gregory Hinton Nietsky <gregory@dnstelecom.co.za>
|
||||
* dns Telecom http://www.dnstelecom.co.za
|
||||
*
|
||||
* Modified to make T.38-gateway compatible with Asterisk 1.6.2
|
||||
* 2010, Anton Verevkin <mymail@verevkin.it>
|
||||
* ViaNetTV http://www.vianettv.com
|
||||
*
|
||||
* Modified to make T.38-gateway work
|
||||
* 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
@@ -46,9 +62,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/timing.h"
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/res_fax.h"
|
||||
#include "asterisk/channel.h"
|
||||
|
||||
#define SPANDSP_FAX_SAMPLES 160
|
||||
#define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */
|
||||
#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
|
||||
|
||||
static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
|
||||
static void spandsp_fax_destroy(struct ast_fax_session *s);
|
||||
@@ -57,6 +75,9 @@ static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *
|
||||
static int spandsp_fax_start(struct ast_fax_session *s);
|
||||
static int spandsp_fax_cancel(struct ast_fax_session *s);
|
||||
static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
|
||||
static int spandsp_fax_gateway_start(struct ast_fax_session *s);
|
||||
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
|
||||
static void spandsp_fax_gateway_cleanup(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);
|
||||
@@ -75,7 +96,7 @@ static struct ast_fax_tech spandsp_fax_tech = {
|
||||
*/
|
||||
.version = "pre-20090220",
|
||||
#endif
|
||||
.caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE,
|
||||
.caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY,
|
||||
.new_session = spandsp_fax_new,
|
||||
.destroy_session = spandsp_fax_destroy,
|
||||
.read = spandsp_fax_read,
|
||||
@@ -114,6 +135,7 @@ static struct {
|
||||
struct spandsp_pvt {
|
||||
unsigned int ist38:1;
|
||||
unsigned int isdone:1;
|
||||
enum ast_t38_state ast_t38_state;
|
||||
fax_state_t fax_state;
|
||||
t38_terminal_state_t t38_state;
|
||||
t30_state_t *t30_state;
|
||||
@@ -121,6 +143,9 @@ struct spandsp_pvt {
|
||||
|
||||
struct spandsp_fax_stats *stats;
|
||||
|
||||
struct spandsp_fax_gw_stats *t38stats;
|
||||
t38_gateway_state_t t38_gw_state;
|
||||
|
||||
struct ast_timer *timer;
|
||||
AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
|
||||
};
|
||||
@@ -158,7 +183,9 @@ static void session_destroy(struct spandsp_pvt *p)
|
||||
*/
|
||||
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
|
||||
{
|
||||
struct spandsp_pvt *p = data;
|
||||
int res = -1;
|
||||
struct ast_fax_session *s = data;
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
struct ast_frame fax_frame = {
|
||||
.frametype = AST_FRAME_MODEM,
|
||||
.subclass.integer = AST_MODEM_T38,
|
||||
@@ -174,13 +201,23 @@ static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, c
|
||||
AST_FRAME_SET_BUFFER(f, buf, 0, len);
|
||||
|
||||
if (!(f = ast_frisolate(f))) {
|
||||
return -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* no need to lock, this all runs in the same thread */
|
||||
AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
ast_set_flag(f, AST_FAX_FRFLAG_GATEWAY);
|
||||
if (p->ast_t38_state == T38_STATE_NEGOTIATED) {
|
||||
res = ast_write(s->chan, f);
|
||||
} else {
|
||||
res = ast_queue_frame(s->chan, f);
|
||||
}
|
||||
ast_frfree(f);
|
||||
} else {
|
||||
/* no need to lock, this all runs in the same thread */
|
||||
AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int update_stats(struct spandsp_pvt *p, int completion_code)
|
||||
@@ -422,6 +459,11 @@ static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_toke
|
||||
goto e_return;
|
||||
}
|
||||
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
s->state = AST_FAX_STATE_INITIALIZED;
|
||||
return p;
|
||||
}
|
||||
|
||||
AST_LIST_HEAD_INIT(&p->read_frames);
|
||||
|
||||
if (s->details->caps & AST_FAX_TECH_RECEIVE) {
|
||||
@@ -450,7 +492,7 @@ static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_toke
|
||||
}
|
||||
|
||||
/* init t38 stuff */
|
||||
t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, p);
|
||||
t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
|
||||
set_logging(&p->t38_state.logging, s->details);
|
||||
}
|
||||
|
||||
@@ -475,7 +517,12 @@ static void spandsp_fax_destroy(struct ast_fax_session *s)
|
||||
{
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
|
||||
session_destroy(p);
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
spandsp_fax_gateway_cleanup(s);
|
||||
} else {
|
||||
session_destroy(p);
|
||||
}
|
||||
|
||||
ast_free(p);
|
||||
s->tech_pvt = NULL;
|
||||
s->fd = -1;
|
||||
@@ -536,6 +583,10 @@ static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *
|
||||
{
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
return spandsp_fax_gateway_process(s, f);
|
||||
}
|
||||
|
||||
/* XXX do we need to lock here? */
|
||||
if (s->state == AST_FAX_STATE_COMPLETE) {
|
||||
ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
|
||||
@@ -549,6 +600,182 @@ static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief generate T.30 packets sent to the T.30 leg of gateway
|
||||
* \param chan T.30 channel
|
||||
* \param data fax session structure
|
||||
* \param len not used
|
||||
* \param samples no of samples generated
|
||||
* \return -1 on failure or 0 on sucess*/
|
||||
static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
int res = -1;
|
||||
struct ast_fax_session *s = data;
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
|
||||
struct ast_frame *f;
|
||||
struct ast_frame t30_frame = {
|
||||
.frametype = AST_FRAME_VOICE,
|
||||
.src = "res_fax_spandsp_g711",
|
||||
.samples = samples,
|
||||
.flags = AST_FAX_FRFLAG_GATEWAY,
|
||||
};
|
||||
|
||||
AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
|
||||
|
||||
ast_format_set(&t30_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
|
||||
if (!(f = ast_frisolate(&t30_frame))) {
|
||||
return p->isdone ? -1 : res;
|
||||
}
|
||||
|
||||
/* generate a T.30 packet */
|
||||
if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
|
||||
f->datalen = f->samples * sizeof(int16_t);
|
||||
res = ast_write(chan, f);
|
||||
}
|
||||
ast_frfree(f);
|
||||
return p->isdone ? -1 : res;
|
||||
}
|
||||
|
||||
/*! \brief simple routine to allocate data to generator
|
||||
* \param chan channel
|
||||
* \param params generator data
|
||||
* \return data to use in generator call*/
|
||||
static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params) {
|
||||
ao2_ref(params, +1);
|
||||
return params;
|
||||
}
|
||||
|
||||
static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data) {
|
||||
ao2_ref(data, -1);
|
||||
}
|
||||
|
||||
/*! \brief activate a spandsp gateway based on the information in the given fax session
|
||||
* \param s fax session
|
||||
* \return -1 on error 0 on sucess*/
|
||||
static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
struct ast_fax_t38_parameters *t38_param;
|
||||
int i, modems = 0;
|
||||
struct ast_channel *peer;
|
||||
static struct ast_generator t30_gen = {
|
||||
alloc: spandsp_fax_gw_gen_alloc,
|
||||
release: spandsp_fax_gw_gen_release,
|
||||
generate: spandsp_fax_gw_t30_gen,
|
||||
};
|
||||
|
||||
#if SPANDSP_RELEASE_DATE >= 20081012
|
||||
/* for spandsp shaphots 0.0.6 and higher */
|
||||
p->t38_core_state=&p->t38_gw_state.t38x.t38;
|
||||
#else
|
||||
/* for spandsp release 0.0.5 */
|
||||
p->t38_core_state=&p->t38_gw_state.t38;
|
||||
#endif
|
||||
|
||||
if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->ist38 = 1;
|
||||
p->ast_t38_state = ast_channel_get_t38_state(s->chan);
|
||||
if (!(peer = ast_bridged_channel(s->chan))) {
|
||||
ast_channel_unlock(s->chan);
|
||||
return -1;
|
||||
}
|
||||
ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
|
||||
|
||||
set_logging(&p->t38_gw_state.logging, s->details);
|
||||
set_logging(&p->t38_core_state->logging, s->details);
|
||||
|
||||
t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
|
||||
t38_set_t38_version(p->t38_core_state, t38_param->version);
|
||||
t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
|
||||
t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
|
||||
t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
|
||||
t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
|
||||
t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
|
||||
t38_set_data_rate_management_method(p->t38_core_state,
|
||||
(t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
|
||||
|
||||
t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
|
||||
t38_set_sequence_number_handling(p->t38_core_state, TRUE);
|
||||
|
||||
if (AST_FAX_MODEM_V17 & s->details->modems) {
|
||||
modems |= T30_SUPPORT_V17;
|
||||
}
|
||||
if (AST_FAX_MODEM_V27 & s->details->modems) {
|
||||
modems |= T30_SUPPORT_V27TER;
|
||||
}
|
||||
if (AST_FAX_MODEM_V29 & s->details->modems) {
|
||||
modems |= T30_SUPPORT_V29;
|
||||
}
|
||||
if (AST_FAX_MODEM_V34 & s->details->modems) {
|
||||
#if defined(T30_SUPPORT_V34)
|
||||
modems |= T30_SUPPORT_V34;
|
||||
#elif defined(T30_SUPPORT_V34HDX)
|
||||
modems |= T30_SUPPORT_V34HDX;
|
||||
#else
|
||||
ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
t38_gateway_set_supported_modems(&p->t38_gw_state, modems);
|
||||
|
||||
/* engage udptl nat on other side of T38 line
|
||||
* (Asterisk changes media ports thus we send a few packets to reinitialize
|
||||
* pinholes in NATs and FWs
|
||||
*/
|
||||
for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
|
||||
#if SPANDSP_RELEASE_DATE >= 20091228
|
||||
t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
|
||||
#elif SPANDSP_RELEASE_DATE >= 20081012
|
||||
t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
|
||||
#else
|
||||
t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
s->state = AST_FAX_STATE_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief process a frame from the bridge
|
||||
* \param s fax session
|
||||
* \param f frame to process
|
||||
* \return 1 on sucess 0 on incorect packet*/
|
||||
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
|
||||
{
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
|
||||
/*invalid frame*/
|
||||
if (!f->data.ptr || !f->datalen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Process a IFP packet */
|
||||
if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
|
||||
return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
|
||||
} else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
|
||||
return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! \brief gather data and clean up after gateway ends
|
||||
* \param s fax session*/
|
||||
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
|
||||
{
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
t38_stats_t t38_stats;
|
||||
|
||||
t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
|
||||
|
||||
s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
|
||||
s->details->pages_transferred = t38_stats.pages_transferred;
|
||||
ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
|
||||
}
|
||||
|
||||
/*! \brief */
|
||||
static int spandsp_fax_start(struct ast_fax_session *s)
|
||||
{
|
||||
@@ -556,6 +783,10 @@ static int spandsp_fax_start(struct ast_fax_session *s)
|
||||
|
||||
s->state = AST_FAX_STATE_OPEN;
|
||||
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
return spandsp_fax_gateway_start(s);
|
||||
}
|
||||
|
||||
if (p->ist38) {
|
||||
#if SPANDSP_RELEASE_DATE >= 20080725
|
||||
/* for spandsp shaphots 0.0.6 and higher */
|
||||
@@ -625,6 +856,12 @@ static int spandsp_fax_start(struct ast_fax_session *s)
|
||||
static int spandsp_fax_cancel(struct ast_fax_session *s)
|
||||
{
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
p->isdone = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t30_terminate(p->t30_state);
|
||||
p->isdone = 1;
|
||||
return 0;
|
||||
@@ -653,7 +890,7 @@ static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
|
||||
/*! \brief */
|
||||
static char *spandsp_fax_cli_show_capabilities(int fd)
|
||||
{
|
||||
ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
|
||||
ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -661,35 +898,48 @@ static char *spandsp_fax_cli_show_capabilities(int fd)
|
||||
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
|
||||
{
|
||||
struct spandsp_pvt *p = s->tech_pvt;
|
||||
t30_stats_t stats;
|
||||
|
||||
ao2_lock(s);
|
||||
ast_cli(fd, "%-22s : %d\n", "session", s->id);
|
||||
ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
|
||||
ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
|
||||
if (s->state != AST_FAX_STATE_UNINITIALIZED) {
|
||||
t30_get_transfer_statistics(p->t30_state, &stats);
|
||||
ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
|
||||
ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
|
||||
ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
|
||||
ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
|
||||
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
|
||||
ast_cli(fd, "%-22s : %d\n", "session", s->id);
|
||||
ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
|
||||
ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
|
||||
if (s->state != AST_FAX_STATE_UNINITIALIZED) {
|
||||
t38_stats_t stats;
|
||||
t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
|
||||
ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
|
||||
ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
|
||||
ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
|
||||
}
|
||||
} else {
|
||||
ast_cli(fd, "%-22s : %d\n", "session", s->id);
|
||||
ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
|
||||
ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
|
||||
if (s->state != AST_FAX_STATE_UNINITIALIZED) {
|
||||
t30_stats_t stats;
|
||||
t30_get_transfer_statistics(p->t30_state, &stats);
|
||||
ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
|
||||
ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
|
||||
ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
|
||||
ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
|
||||
#if SPANDSP_RELEASE_DATE >= 20090220
|
||||
ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
|
||||
ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
|
||||
#else
|
||||
ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
|
||||
ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
|
||||
#endif
|
||||
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);
|
||||
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);
|
||||
|
||||
ast_cli(fd, "\nData Statistics:\n");
|
||||
ast_cli(fd, "\nData Statistics:\n");
|
||||
#if SPANDSP_RELEASE_DATE >= 20090220
|
||||
ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
|
||||
ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
|
||||
ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
|
||||
ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
|
||||
#else
|
||||
ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
|
||||
ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
|
||||
ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
|
||||
ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
|
||||
#endif
|
||||
ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
|
||||
ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
|
||||
ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
|
||||
ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
|
||||
}
|
||||
}
|
||||
ao2_unlock(s);
|
||||
ast_cli(fd, "\n\n");
|
||||
|
Reference in New Issue
Block a user