2008-09-03 19:02:00 +00:00
|
|
|
/*
|
|
|
|
* SpanDSP - a series of DSP components for telephony
|
|
|
|
*
|
2011-12-05 17:00:22 +00:00
|
|
|
* fax_tests.c - Tests for the audio and T.38 FAX modules.
|
2008-09-03 19:02:00 +00:00
|
|
|
*
|
|
|
|
* Written by Steve Underwood <steveu@coppice.org>
|
|
|
|
*
|
2011-12-05 17:00:22 +00:00
|
|
|
* Copyright (C) 2005, 2006, 2009, 2010 Steve Underwood
|
2008-09-03 19:02:00 +00:00
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2, as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
2011-12-05 17:00:22 +00:00
|
|
|
/*! \file */
|
|
|
|
|
2008-09-03 19:02:00 +00:00
|
|
|
/*! \page fax_tests_page FAX tests
|
|
|
|
\section fax_tests_page_sec_1 What does it do?
|
2012-03-28 13:43:13 +00:00
|
|
|
These tests exercise the following FAX to FAX paths:
|
|
|
|
|
2014-05-07 05:11:53 +00:00
|
|
|
TSB85 <-----------+ +-----------> TSB85
|
|
|
|
\ /
|
|
|
|
T.31 <-----------+ \ / +-----------> T.31
|
|
|
|
\ \ / /
|
|
|
|
+--Modems-+-+-----------TDM/RTP-----------+-+-Modems--+
|
|
|
|
| \ / |
|
|
|
|
| \ / |
|
|
|
|
T.30 <---+ T.38 gateway T.38 gateway +---> T.30
|
|
|
|
| \ / |
|
|
|
|
| \ / |
|
|
|
|
+---T.38---+-+----+----UDPTL/RTP----+----+ +---T.38---+
|
|
|
|
/ / \ / \ \
|
|
|
|
T.31 <------------/ / +----------TCP----------+ \ +------------> T.31
|
|
|
|
/ \
|
|
|
|
TSB85 <------------+ +------------> TSB85
|
2012-03-28 13:43:13 +00:00
|
|
|
|
|
|
|
T.30<->Modems<-------------------------TDM/RTP------------------------->Modems<->T.30
|
|
|
|
T.30<->Modems<-TDM/RTP->T.38 gateway<-UDPTL/RTP->T.38 gateway<-TDM/RTP->Modems<->T.30
|
|
|
|
T.30<->Modems<-TDM/RTP->T.38 gateway<-UDPTL/RTP-------------------------->T.38<->T.30
|
|
|
|
T.30<->T.38<--------------------------UDPTL/RTP->T.38 gateway<-TDM/RTP->Modems<->T.30
|
|
|
|
T.30<->T.38<--------------------------UDPTL/RTP-------------------------->T.38<->T.30
|
|
|
|
|
2014-05-07 05:11:53 +00:00
|
|
|
The T.31 and TSB85 parts are incomplete right now.
|
2008-09-03 19:02:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
|
|
|
|
#define ENABLE_GUI
|
|
|
|
#endif
|
|
|
|
|
2008-09-03 19:02:00 +00:00
|
|
|
#include <stdlib.h>
|
2011-12-05 17:00:22 +00:00
|
|
|
#include <inttypes.h>
|
2008-09-03 19:02:00 +00:00
|
|
|
#include <stdio.h>
|
2011-12-05 17:00:22 +00:00
|
|
|
#include <fcntl.h>
|
2008-09-03 19:02:00 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2011-12-05 17:00:22 +00:00
|
|
|
#include <errno.h>
|
2009-06-18 06:13:59 +00:00
|
|
|
#include <sndfile.h>
|
2011-12-05 17:00:22 +00:00
|
|
|
#if !defined(_WIN32)
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
#if defined(HAVE_LIBXML_XMLMEMORY_H)
|
|
|
|
#include <libxml/xmlmemory.h>
|
|
|
|
#endif
|
|
|
|
#if defined(HAVE_LIBXML_PARSER_H)
|
|
|
|
#include <libxml/parser.h>
|
|
|
|
#endif
|
|
|
|
#if defined(HAVE_LIBXML_XINCLUDE_H)
|
|
|
|
#include <libxml/xinclude.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "udptl.h"
|
2008-09-03 19:02:00 +00:00
|
|
|
#include "spandsp.h"
|
|
|
|
#include "spandsp-sim.h"
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
#if defined(ENABLE_GUI)
|
|
|
|
#include "media_monitor.h"
|
|
|
|
#endif
|
|
|
|
#include "fax_tester.h"
|
2009-02-20 18:30:05 +00:00
|
|
|
#include "fax_utils.h"
|
2012-03-28 13:43:13 +00:00
|
|
|
#include "pcap_parse.h"
|
2009-02-20 18:30:05 +00:00
|
|
|
|
2008-09-03 19:02:00 +00:00
|
|
|
#define SAMPLES_PER_CHUNK 160
|
|
|
|
|
|
|
|
#define INPUT_TIFF_FILE_NAME "../test-data/itu/fax/itutests.tif"
|
2012-03-28 13:43:13 +00:00
|
|
|
#define OUTPUT_TIFF_FILE_NAME "fax_tests.tif"
|
2015-09-28 13:47:27 +00:00
|
|
|
#define INPUT_WAVE_FILE_NAME "fax_cap.wav"
|
2012-03-28 13:43:13 +00:00
|
|
|
#define OUTPUT_WAVE_FILE_NAME "fax_tests.wav"
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
enum
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
AUDIO_FAX = 1,
|
|
|
|
T38_FAX,
|
2014-05-04 09:22:28 +00:00
|
|
|
T31_AUDIO_FAX,
|
2015-09-28 13:47:27 +00:00
|
|
|
T31_T38_FAX,
|
2014-05-04 09:22:28 +00:00
|
|
|
TSB85_AUDIO_FAX,
|
2015-09-28 13:47:27 +00:00
|
|
|
TSB85_T38_FAX,
|
|
|
|
REPLAY_AUDIO_FAX,
|
|
|
|
REPLAY_T38_FAX,
|
|
|
|
AUDIO_TO_T38_GATEWAY,
|
|
|
|
PASSTHROUGH,
|
|
|
|
AUDIO_CHAN,
|
|
|
|
T38_CHAN
|
2012-03-28 13:43:13 +00:00
|
|
|
};
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
const char *output_tiff_file_name;
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
struct audio_buf_s
|
|
|
|
{
|
|
|
|
int16_t amp[SAMPLES_PER_CHUNK];
|
|
|
|
int len;
|
|
|
|
};
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
struct chain_element_s
|
|
|
|
{
|
|
|
|
int node_type;
|
|
|
|
int left_chan_type;
|
|
|
|
int right_chan_type;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
fax_state_t *fax_state;
|
|
|
|
t38_terminal_state_t *t38_state;
|
|
|
|
faxtester_state_t *faxtester_state;
|
|
|
|
t38_gateway_state_t *t38_gateway_state;
|
|
|
|
SNDFILE *wave_handle;
|
|
|
|
} node;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
g1050_state_t *g1050_path;
|
|
|
|
both_ways_line_model_state_t *line_model;
|
|
|
|
struct audio_buf_s *audio_in_buf;
|
|
|
|
struct audio_buf_s *audio_out_buf;
|
|
|
|
} path;
|
|
|
|
t30_state_t *t30_state;
|
|
|
|
t38_core_state_t *t38_core_state;
|
|
|
|
int t38_subst_seq;
|
|
|
|
bool phase_e_reached;
|
|
|
|
bool completed;
|
|
|
|
bool succeeded;
|
|
|
|
t30_exchanged_info_t expected_rx_info;
|
|
|
|
|
|
|
|
awgn_state_t *awgn_state;
|
|
|
|
|
|
|
|
struct audio_buf_s audio_buf[2];
|
|
|
|
|
|
|
|
int peer;
|
|
|
|
int t38_peer;
|
|
|
|
|
|
|
|
char tag[10];
|
|
|
|
};
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
struct chain_element_s chain[7];
|
|
|
|
int chain_elements = 2;
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
bool t38_simulate_incrementing_repeats = false;
|
2013-08-08 13:40:28 +00:00
|
|
|
bool use_receiver_not_ready = false;
|
|
|
|
bool test_local_interrupt = false;
|
2012-03-28 13:43:13 +00:00
|
|
|
|
|
|
|
double when = 0.0;
|
|
|
|
|
2014-05-04 09:22:28 +00:00
|
|
|
static int phase_b_handler(void *user_data, int result)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2012-03-28 13:43:13 +00:00
|
|
|
int ch;
|
|
|
|
int status;
|
|
|
|
int len;
|
2014-05-04 09:22:28 +00:00
|
|
|
t30_state_t *s;
|
2009-02-20 18:30:05 +00:00
|
|
|
char tag[20];
|
2012-03-28 13:43:13 +00:00
|
|
|
const char *u;
|
|
|
|
const uint8_t *v;
|
2015-09-28 13:47:27 +00:00
|
|
|
t30_exchanged_info_t *info;
|
2009-02-20 18:30:05 +00:00
|
|
|
|
|
|
|
i = (int) (intptr_t) user_data;
|
2015-09-28 13:47:27 +00:00
|
|
|
s = chain[i].t30_state;
|
2012-03-28 13:43:13 +00:00
|
|
|
ch = i + 'A';
|
2015-09-28 13:47:27 +00:00
|
|
|
info = &chain[i].expected_rx_info;
|
2012-03-28 13:43:13 +00:00
|
|
|
snprintf(tag, sizeof(tag), "%c: Phase B", ch);
|
|
|
|
printf("%c: Phase B handler - (0x%X) %s\n", ch, result, t30_frametype(result));
|
2011-07-02 13:16:52 +00:00
|
|
|
fax_log_rx_parameters(s, tag);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_OK;
|
|
|
|
|
|
|
|
if ((u = t30_get_rx_ident(s)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B remote ident '%s'\n", ch, u);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->ident[0] && strcmp(info->ident, u))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, info->ident);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_IDENT_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->ident[0])
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote ident missing!\n", ch);
|
|
|
|
status = T30_ERR_IDENT_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((u = t30_get_rx_sub_address(s)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote sub-address '%s'\n", ch, u);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->sub_address[0] && strcmp(info->sub_address, u))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, info->sub_address);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_SUB_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->sub_address[0])
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote sub-address missing!\n", ch);
|
|
|
|
status = T30_ERR_SUB_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((u = t30_get_rx_polled_sub_address(s)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->polled_sub_address[0] && strcmp(info->polled_sub_address, u))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, info->polled_sub_address);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_PSA_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->polled_sub_address[0])
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote polled sub-address missing!\n", ch);
|
|
|
|
status = T30_ERR_PSA_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((u = t30_get_rx_selective_polling_address(s)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote selective polling address '%s'\n", ch, u);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->selective_polling_address[0] && strcmp(info->selective_polling_address, u))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, info->selective_polling_address);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_SEP_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->selective_polling_address[0])
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote selective polling address missing!\n", ch);
|
|
|
|
status = T30_ERR_SEP_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((u = t30_get_rx_sender_ident(s)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote sender ident '%s'\n", ch, u);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->sender_ident[0] && strcmp(info->sender_ident, u))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, info->sender_ident);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_SID_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->sender_ident[0])
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote sender ident missing!\n", ch);
|
|
|
|
status = T30_ERR_SID_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((u = t30_get_rx_password(s)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote password '%s'\n", ch, u);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->password[0] && strcmp(info->password, u))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, info->password);
|
2012-03-28 13:43:13 +00:00
|
|
|
status = T30_ERR_PWD_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->password[0])
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("%c: Phase B: remote password missing!\n", ch);
|
|
|
|
status = T30_ERR_PWD_UNACCEPTABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((len = t30_get_rx_nsf(s, &v)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: NSF %d bytes\n", ch, len);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->nsf_len && (info->nsf_len != len || memcmp(info->nsf, v, len)))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote NSF incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->nsf_len)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote NSF missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((len = t30_get_rx_nsc(s, &v)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: NSC %d bytes\n", ch, len);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->nsc_len && (info->nsc_len != len || memcmp(info->nsc, v, len)))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote NSC incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsc_len);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->nsc_len)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote NSC missing! - expected %u bytes\n", ch, (unsigned int) info->nsc_len);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((len = t30_get_rx_nss(s, &v)))
|
|
|
|
{
|
|
|
|
printf("%c: Phase B: NSS %d bytes\n", ch, len);
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->nss_len && (info->nss_len != len || memcmp(info->nss, v, len)))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote NSS incorrect! - expected %u bytes\n", ch, (unsigned int) info->nss_len);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (info->nss_len)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("%c: Phase B: remote NSS missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2014-05-04 09:22:28 +00:00
|
|
|
static int phase_d_handler(void *user_data, int result)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-05-04 09:22:28 +00:00
|
|
|
int ch;
|
|
|
|
t30_state_t *s;
|
2009-02-20 18:30:05 +00:00
|
|
|
char tag[20];
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2009-02-20 18:30:05 +00:00
|
|
|
i = (int) (intptr_t) user_data;
|
2015-09-28 13:47:27 +00:00
|
|
|
s = chain[i].t30_state;
|
2014-05-04 09:22:28 +00:00
|
|
|
ch = i + 'A';
|
|
|
|
snprintf(tag, sizeof(tag), "%c: Phase D", ch);
|
|
|
|
printf("%c: Phase D handler - (0x%X) %s\n", ch, result, t30_frametype(result));
|
2012-03-28 13:43:13 +00:00
|
|
|
fax_log_page_transfer_statistics(s, tag);
|
2011-07-02 13:16:52 +00:00
|
|
|
fax_log_tx_parameters(s, tag);
|
|
|
|
fax_log_rx_parameters(s, tag);
|
2008-09-03 19:02:00 +00:00
|
|
|
|
|
|
|
if (use_receiver_not_ready)
|
|
|
|
t30_set_receiver_not_ready(s, 3);
|
|
|
|
|
|
|
|
if (test_local_interrupt)
|
|
|
|
{
|
2014-05-04 09:22:28 +00:00
|
|
|
if (i == 0)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2014-05-04 09:22:28 +00:00
|
|
|
printf("%c: Initiating interrupt request\n", ch);
|
2013-08-08 13:40:28 +00:00
|
|
|
t30_local_interrupt_request(s, true);
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (result)
|
|
|
|
{
|
|
|
|
case T30_PIP:
|
|
|
|
case T30_PRI_MPS:
|
|
|
|
case T30_PRI_EOM:
|
|
|
|
case T30_PRI_EOP:
|
2014-05-04 09:22:28 +00:00
|
|
|
printf("%c: Accepting interrupt request\n", ch);
|
2013-08-08 13:40:28 +00:00
|
|
|
t30_local_interrupt_request(s, true);
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
|
|
|
case T30_PIN:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return T30_ERR_OK;
|
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2014-05-04 09:22:28 +00:00
|
|
|
static void phase_e_handler(void *user_data, int result)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-05-04 09:22:28 +00:00
|
|
|
int ch;
|
2008-09-03 19:02:00 +00:00
|
|
|
t30_stats_t t;
|
2014-05-04 09:22:28 +00:00
|
|
|
t30_state_t *s;
|
2009-02-20 18:30:05 +00:00
|
|
|
char tag[20];
|
2013-03-14 13:22:51 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
i = (int) (intptr_t) user_data;
|
2015-09-28 13:47:27 +00:00
|
|
|
s = chain[i].t30_state;
|
2014-05-04 09:22:28 +00:00
|
|
|
ch = i + 'A';
|
|
|
|
snprintf(tag, sizeof(tag), "%c: Phase E", ch);
|
|
|
|
printf("%c: Phase E handler - (%d) %s\n", ch, result, t30_completion_code_to_str(result));
|
2012-03-28 13:43:13 +00:00
|
|
|
fax_log_final_transfer_statistics(s, tag);
|
2011-07-02 13:16:52 +00:00
|
|
|
fax_log_tx_parameters(s, tag);
|
|
|
|
fax_log_rx_parameters(s, tag);
|
2008-09-03 19:02:00 +00:00
|
|
|
t30_get_transfer_statistics(s, &t);
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].succeeded = (result == T30_ERR_OK);
|
|
|
|
chain[i].phase_e_reached = true;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
static void real_time_t30_frame_handler(void *user_data,
|
|
|
|
bool incoming,
|
|
|
|
const uint8_t *msg,
|
|
|
|
int len)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-05-04 09:22:28 +00:00
|
|
|
int ch;
|
2013-03-14 13:22:51 +00:00
|
|
|
|
2008-09-03 19:02:00 +00:00
|
|
|
i = (intptr_t) user_data;
|
2014-05-04 09:22:28 +00:00
|
|
|
ch = i + 'A';
|
2012-03-28 13:43:13 +00:00
|
|
|
printf("%c: Real time frame handler - %s, %s, length = %d\n",
|
2014-05-04 09:22:28 +00:00
|
|
|
ch,
|
2013-08-08 13:40:28 +00:00
|
|
|
(incoming) ? "line->T.30" : "T.30->line",
|
2008-09-03 19:02:00 +00:00
|
|
|
t30_frametype(msg[2]),
|
|
|
|
len);
|
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2014-05-04 09:22:28 +00:00
|
|
|
static int document_handler(void *user_data, int event)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-05-04 09:22:28 +00:00
|
|
|
int ch;
|
2013-03-14 13:22:51 +00:00
|
|
|
|
2008-09-03 19:02:00 +00:00
|
|
|
i = (intptr_t) user_data;
|
2014-05-04 09:22:28 +00:00
|
|
|
ch = i + 'A';
|
|
|
|
printf("%c: Document handler - event %d\n", ch, event);
|
2013-08-08 13:40:28 +00:00
|
|
|
return false;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
static void set_t30_callbacks(t30_state_t *t30, int chan)
|
|
|
|
{
|
|
|
|
t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) chan);
|
|
|
|
t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) chan);
|
|
|
|
t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) chan);
|
2015-09-28 13:47:27 +00:00
|
|
|
t30_set_real_time_frame_handler(t30, real_time_t30_frame_handler, (void *) (intptr_t) chan);
|
2012-03-28 13:43:13 +00:00
|
|
|
t30_set_document_handler(t30, document_handler, (void *) (intptr_t) chan);
|
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2014-07-18 02:29:23 +00:00
|
|
|
static void real_time_gateway_frame_handler(void *user_data,
|
2013-08-08 13:40:28 +00:00
|
|
|
bool incoming,
|
2012-03-28 13:43:13 +00:00
|
|
|
const uint8_t *msg,
|
|
|
|
int len)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
2013-03-14 13:22:51 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
i = (intptr_t) user_data;
|
|
|
|
printf("%c: Real time gateway frame handler - %s, %s, length = %d\n",
|
|
|
|
i + 'A',
|
2013-08-08 13:40:28 +00:00
|
|
|
(incoming) ? "PSTN->T.38" : "T.38->PSTN",
|
2012-03-28 13:43:13 +00:00
|
|
|
t30_frametype(msg[2]),
|
|
|
|
len);
|
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int chan;
|
|
|
|
|
|
|
|
/* This routine queues messages between two instances of T.38 processing */
|
|
|
|
chan = (intptr_t) user_data;
|
|
|
|
if (t38_simulate_incrementing_repeats)
|
|
|
|
{
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", chain[chan].t38_subst_seq, len);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
if (g1050_put(chain[chan].path.g1050_path, buf, len, chain[chan].t38_subst_seq, when) < 0)
|
|
|
|
printf("Lost packet %d\n", chain[chan].t38_subst_seq);
|
|
|
|
chain[chan].t38_subst_seq = (chain[chan].t38_subst_seq + 1) & 0xFFFF;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count);
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (g1050_put(chain[chan].path.g1050_path, buf, len, s->tx_seq_no, when) < 0)
|
2012-03-28 13:43:13 +00:00
|
|
|
printf("Lost packet %d\n", s->tx_seq_no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
static void t33_tests(void)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
int item_no;
|
|
|
|
int type;
|
|
|
|
uint8_t num[21];
|
|
|
|
uint8_t new_t33[133];
|
|
|
|
/* These patterns are from the T.33 spec */
|
|
|
|
static const uint8_t *pkts[] =
|
|
|
|
{
|
|
|
|
(const uint8_t *) "#1234567890#1234",
|
|
|
|
(const uint8_t *) "1234#5678#8910",
|
|
|
|
(const uint8_t *) "#6174444100#1234#567",
|
|
|
|
(const uint8_t *) "1234#5678##2032223",
|
|
|
|
(const uint8_t *) "#2037445555##6446666",
|
|
|
|
(const uint8_t *) "#2037445555#1234##6446666#5678",
|
|
|
|
//(const uint8_t *) "#123456789012345678901#1234##6446666#5678",
|
|
|
|
(const uint8_t *) ""
|
|
|
|
};
|
|
|
|
|
|
|
|
printf("T.33 sub-address packing/unpacking tests\n");
|
|
|
|
for (n = 0; pkts[n][0]; n++)
|
|
|
|
{
|
|
|
|
new_t33[0] = '\0';
|
|
|
|
printf("'%s'\n", pkts[n]);
|
|
|
|
for (item_no = 0; item_no < 100; item_no++)
|
|
|
|
{
|
|
|
|
if ((type = t33_sub_address_extract_field(num, pkts[n], item_no)) <= 0)
|
|
|
|
{
|
|
|
|
if (type == T33_NONE)
|
|
|
|
break;
|
|
|
|
printf("Bad sub-address field\n");
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case T33_SST:
|
|
|
|
printf("SST '%s'\n", num);
|
|
|
|
t33_sub_address_add_field(new_t33, num, type);
|
|
|
|
break;
|
|
|
|
case T33_EXT:
|
|
|
|
printf(" EXT '%s'\n", num);
|
|
|
|
t33_sub_address_add_field(new_t33, num, type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strcmp((const char *) pkts[n], (const char *) new_t33))
|
|
|
|
{
|
|
|
|
printf("Re-encode mismatch '%s' '%s'\n", pkts[n], new_t33);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2008-09-03 19:02:00 +00:00
|
|
|
int16_t silence[SAMPLES_PER_CHUNK];
|
2012-03-28 13:43:13 +00:00
|
|
|
int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK];
|
|
|
|
int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK];
|
2015-09-28 13:47:27 +00:00
|
|
|
int16_t audio_log[SAMPLES_PER_CHUNK*4];
|
2012-03-28 13:43:13 +00:00
|
|
|
int hist_ptr;
|
2008-09-03 19:02:00 +00:00
|
|
|
int log_audio;
|
2012-03-28 13:43:13 +00:00
|
|
|
int msg_len;
|
|
|
|
uint8_t msg[1024];
|
|
|
|
int outframes;
|
|
|
|
SNDFILE *wave_handle;
|
2013-08-31 16:36:48 +00:00
|
|
|
bool use_ecm;
|
|
|
|
bool use_tep;
|
2015-09-28 13:47:27 +00:00
|
|
|
bool use_polled_mode;
|
|
|
|
bool use_transmit_on_idle;
|
|
|
|
bool feedback_audio;
|
2012-03-28 13:43:13 +00:00
|
|
|
int t38_version;
|
|
|
|
const char *input_tiff_file_name;
|
2015-09-28 13:47:27 +00:00
|
|
|
const char *replay_file_name;
|
2012-03-28 13:43:13 +00:00
|
|
|
int i;
|
|
|
|
int j;
|
2015-09-28 13:47:27 +00:00
|
|
|
int k;
|
2012-03-28 13:43:13 +00:00
|
|
|
int seq_no;
|
|
|
|
int g1050_model_no;
|
|
|
|
int g1050_speed_pattern_no;
|
|
|
|
int t38_transport;
|
|
|
|
double tx_when;
|
|
|
|
double rx_when;
|
2008-09-03 19:02:00 +00:00
|
|
|
int supported_modems;
|
2012-03-28 13:43:13 +00:00
|
|
|
int opt;
|
|
|
|
int start_page;
|
|
|
|
int end_page;
|
|
|
|
int drop_frame;
|
|
|
|
int drop_frame_rate;
|
|
|
|
float signal_scaling;
|
2009-01-28 04:48:03 +00:00
|
|
|
int signal_level;
|
|
|
|
int noise_level;
|
2012-03-28 13:43:13 +00:00
|
|
|
int code_to_look_up;
|
2010-07-24 19:29:44 +00:00
|
|
|
int scan_line_time;
|
2013-08-31 16:36:48 +00:00
|
|
|
int allowed_bilevel_resolutions[2];
|
|
|
|
int allowed;
|
|
|
|
bool remove_fill_bits;
|
|
|
|
bool colour_enabled;
|
|
|
|
bool t37_like_output;
|
2012-03-28 13:43:13 +00:00
|
|
|
t38_stats_t t38_stats;
|
|
|
|
t30_stats_t t30_stats;
|
|
|
|
logging_state_t *logging;
|
|
|
|
int expected_pages;
|
2008-09-03 19:02:00 +00:00
|
|
|
char *page_header_info;
|
2011-12-05 17:00:22 +00:00
|
|
|
char *page_header_tz;
|
2014-05-07 05:11:53 +00:00
|
|
|
const char *xml_file_name;
|
2015-09-28 13:47:27 +00:00
|
|
|
const char *xml_test_name[2];
|
|
|
|
int xml_step;
|
2012-03-28 13:43:13 +00:00
|
|
|
char buf[132 + 1];
|
2015-09-28 13:47:27 +00:00
|
|
|
int line_model_no;
|
|
|
|
int channel_codec;
|
|
|
|
int rbs_pattern;
|
2012-03-28 13:43:13 +00:00
|
|
|
#if defined(ENABLE_GUI)
|
|
|
|
int use_gui;
|
|
|
|
#endif
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
#if defined(ENABLE_GUI)
|
2013-08-08 13:40:28 +00:00
|
|
|
use_gui = false;
|
2012-03-28 13:43:13 +00:00
|
|
|
#endif
|
2013-08-08 13:40:28 +00:00
|
|
|
log_audio = false;
|
|
|
|
use_ecm = false;
|
2012-03-28 13:43:13 +00:00
|
|
|
t38_version = 1;
|
|
|
|
input_tiff_file_name = INPUT_TIFF_FILE_NAME;
|
2015-09-28 13:47:27 +00:00
|
|
|
output_tiff_file_name = OUTPUT_TIFF_FILE_NAME;
|
2013-08-08 13:40:28 +00:00
|
|
|
t38_simulate_incrementing_repeats = false;
|
2012-03-28 13:43:13 +00:00
|
|
|
g1050_model_no = 0;
|
|
|
|
g1050_speed_pattern_no = 1;
|
2013-08-08 13:40:28 +00:00
|
|
|
remove_fill_bits = false;
|
|
|
|
use_tep = false;
|
|
|
|
feedback_audio = false;
|
|
|
|
use_transmit_on_idle = true;
|
2015-09-28 13:47:27 +00:00
|
|
|
use_polled_mode = false;
|
2012-03-28 13:43:13 +00:00
|
|
|
supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
|
2008-09-03 19:02:00 +00:00
|
|
|
page_header_info = NULL;
|
2011-12-05 17:00:22 +00:00
|
|
|
page_header_tz = NULL;
|
2012-03-28 13:43:13 +00:00
|
|
|
drop_frame = 0;
|
|
|
|
drop_frame_rate = 0;
|
|
|
|
start_page = -1;
|
|
|
|
end_page = -1;
|
2009-01-28 04:48:03 +00:00
|
|
|
signal_level = 0;
|
|
|
|
noise_level = -99;
|
2010-07-24 19:29:44 +00:00
|
|
|
scan_line_time = 0;
|
2015-09-28 13:47:27 +00:00
|
|
|
replay_file_name = INPUT_WAVE_FILE_NAME;
|
2012-03-28 13:43:13 +00:00
|
|
|
code_to_look_up = -1;
|
2013-08-31 16:36:48 +00:00
|
|
|
allowed_bilevel_resolutions[0] = 0;
|
|
|
|
allowed_bilevel_resolutions[1] = 0;
|
|
|
|
allowed = 0;
|
2015-09-28 13:47:27 +00:00
|
|
|
line_model_no = 0;
|
|
|
|
channel_codec = MUNGE_CODEC_NONE;
|
|
|
|
rbs_pattern = 0;
|
2013-08-08 13:40:28 +00:00
|
|
|
colour_enabled = false;
|
2013-08-31 16:36:48 +00:00
|
|
|
t37_like_output = false;
|
2012-03-28 13:43:13 +00:00
|
|
|
t38_transport = T38_TRANSPORT_UDPTL;
|
2014-05-07 05:11:53 +00:00
|
|
|
xml_file_name = "../spandsp/tsb85.xml";
|
2015-09-28 13:47:27 +00:00
|
|
|
xml_test_name[0] = "MRGN01";
|
|
|
|
xml_test_name[1] = "MRGN01";
|
|
|
|
xml_step = 0;
|
|
|
|
while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:Ps:S:tT:u:v:x:X:z:")) != -1)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
|
|
|
switch (opt)
|
|
|
|
{
|
2013-08-31 16:36:48 +00:00
|
|
|
case '7':
|
|
|
|
t37_like_output = true;
|
|
|
|
break;
|
2013-07-19 07:40:22 +00:00
|
|
|
case 'b':
|
2013-08-31 16:36:48 +00:00
|
|
|
allowed_bilevel_resolutions[allowed] = atoi(optarg);
|
|
|
|
allowed ^= 1;
|
2013-07-19 07:40:22 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
case 'c':
|
|
|
|
code_to_look_up = atoi(optarg);
|
|
|
|
break;
|
2013-05-31 17:05:08 +00:00
|
|
|
case 'C':
|
2013-08-08 13:40:28 +00:00
|
|
|
colour_enabled = true;
|
2013-05-31 17:05:08 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
case 'd':
|
2015-09-28 13:47:27 +00:00
|
|
|
replay_file_name = optarg;
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
drop_frame_rate =
|
|
|
|
drop_frame = atoi(optarg);
|
|
|
|
break;
|
2008-09-03 19:02:00 +00:00
|
|
|
case 'e':
|
2013-08-08 13:40:28 +00:00
|
|
|
use_ecm = true;
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
case 'f':
|
2013-08-08 13:40:28 +00:00
|
|
|
feedback_audio = true;
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
|
|
|
case 'F':
|
2013-08-08 13:40:28 +00:00
|
|
|
remove_fill_bits = true;
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
#if defined(ENABLE_GUI)
|
2013-08-08 13:40:28 +00:00
|
|
|
use_gui = true;
|
2012-03-28 13:43:13 +00:00
|
|
|
#else
|
|
|
|
fprintf(stderr, "Graphical monitoring not available\n");
|
|
|
|
exit(2);
|
|
|
|
#endif
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
page_header_info = optarg;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
input_tiff_file_name = optarg;
|
|
|
|
break;
|
|
|
|
case 'I':
|
2013-08-08 13:40:28 +00:00
|
|
|
t38_simulate_incrementing_repeats = true;
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
|
|
|
case 'l':
|
2013-08-08 13:40:28 +00:00
|
|
|
log_audio = true;
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
supported_modems = atoi(optarg);
|
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
case 'M':
|
|
|
|
g1050_model_no = optarg[0] - 'A' + 1;
|
|
|
|
break;
|
2009-01-28 04:48:03 +00:00
|
|
|
case 'n':
|
|
|
|
noise_level = atoi(optarg);
|
|
|
|
break;
|
2008-09-03 19:02:00 +00:00
|
|
|
case 'p':
|
2015-09-28 13:47:27 +00:00
|
|
|
/*
|
|
|
|
-p FAX-audio-FAX
|
|
|
|
-p FAX-T38-FAX
|
|
|
|
-p FAX-audio-T38gateway-T38-T38gateway-audio-FAX
|
|
|
|
-p FAX-T38-T38gateway-audio-T38gateway-T38-FAX
|
|
|
|
-p FAX-T38-T38gateway-audio-FAX
|
|
|
|
-p FAX-audio-T38gateway-T38-FAX
|
|
|
|
-p tester-audio-FAX
|
|
|
|
-p tester-T38-FAX
|
|
|
|
-p tester-audio-T38gateway-T38-T38gateway-audio-FAX
|
|
|
|
-p tester-T38-T38gateway-audio-T38gateway-T38-FAX
|
|
|
|
-p tester-T38-T38gateway-audio-FAX
|
|
|
|
-p tester-audio-T38gateway-T38-FAX
|
|
|
|
*/
|
|
|
|
for (i = 0, chain_elements = 0, k = 0; chain_elements < 7; i++)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
if (optarg[i] != '-' && optarg[i] != '\0')
|
|
|
|
continue;
|
|
|
|
j = optarg[i];
|
|
|
|
optarg[i] = '\0';
|
|
|
|
if (strcmp(&optarg[k], "FAX") == 0)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[chain_elements++].node_type = AUDIO_FAX;
|
|
|
|
}
|
|
|
|
else if (strcmp(&optarg[k], "T38") == 0)
|
|
|
|
{
|
|
|
|
chain[chain_elements++].node_type = T38_FAX;
|
|
|
|
}
|
|
|
|
else if (strcmp(&optarg[k], "T31") == 0)
|
|
|
|
{
|
|
|
|
chain[chain_elements++].node_type = T31_AUDIO_FAX;
|
|
|
|
}
|
|
|
|
else if (strcmp(&optarg[k], "tester") == 0)
|
|
|
|
{
|
|
|
|
chain[chain_elements++].node_type = TSB85_AUDIO_FAX;
|
|
|
|
}
|
|
|
|
else if (strcmp(&optarg[k], "replay") == 0)
|
|
|
|
{
|
|
|
|
chain[chain_elements++].node_type = REPLAY_AUDIO_FAX;
|
|
|
|
}
|
|
|
|
else if (strcmp(&optarg[k], "T38gateway") == 0)
|
|
|
|
{
|
|
|
|
chain[chain_elements++].node_type = AUDIO_TO_T38_GATEWAY;
|
|
|
|
}
|
|
|
|
else if (strcmp(&optarg[k], "passthrough") == 0)
|
|
|
|
{
|
|
|
|
chain[chain_elements++].node_type = PASSTHROUGH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unknown FAX path element %s\n", &optarg[k]);
|
2012-03-28 13:43:13 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
k = i + 1;
|
|
|
|
if (j == '\0')
|
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
#if 0
|
|
|
|
if ((chain[0].node_type == AUDIO_FAX && chain[chain_elements - 1].node_type != AUDIO_FAX)
|
2012-03-28 13:43:13 +00:00
|
|
|
||
|
2015-09-28 13:47:27 +00:00
|
|
|
(chain[0].node_type != AUDIO_FAX && chain[chain_elements - 1].node_type == AUDIO_FAX))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
fprintf(stderr, "Invalid FAX path\n");
|
2012-03-28 13:43:13 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
use_polled_mode = true;
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
case 's':
|
|
|
|
g1050_speed_pattern_no = atoi(optarg);
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
#if 0
|
2009-01-28 04:48:03 +00:00
|
|
|
case 's':
|
|
|
|
signal_level = atoi(optarg);
|
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
#endif
|
2010-07-24 19:29:44 +00:00
|
|
|
case 'S':
|
|
|
|
scan_line_time = atoi(optarg);
|
|
|
|
break;
|
2008-09-03 19:02:00 +00:00
|
|
|
case 't':
|
2013-08-08 13:40:28 +00:00
|
|
|
use_tep = true;
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
|
|
|
case 'T':
|
2012-03-28 13:43:13 +00:00
|
|
|
start_page = 0;
|
|
|
|
end_page = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
if (strcasecmp(optarg, "udptl") == 0)
|
|
|
|
t38_transport = T38_TRANSPORT_UDPTL;
|
|
|
|
else if (strcasecmp(optarg, "rtp") == 0)
|
|
|
|
t38_transport = T38_TRANSPORT_RTP;
|
|
|
|
else if (strcasecmp(optarg, "tcp") == 0)
|
|
|
|
t38_transport = T38_TRANSPORT_TCP;
|
|
|
|
else if (strcasecmp(optarg, "tcp-tpkt") == 0)
|
|
|
|
t38_transport = T38_TRANSPORT_TCP_TPKT;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unknown T.38 transport mode\n");
|
|
|
|
exit(2);
|
|
|
|
}
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
case 'v':
|
|
|
|
t38_version = atoi(optarg);
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
2014-05-07 05:11:53 +00:00
|
|
|
case 'x':
|
2015-09-28 13:47:27 +00:00
|
|
|
xml_test_name[xml_step] = optarg;
|
|
|
|
xml_step ^= 1;
|
|
|
|
break;
|
|
|
|
case 'X':
|
2014-05-07 05:11:53 +00:00
|
|
|
xml_file_name = optarg;
|
|
|
|
break;
|
2011-12-05 17:00:22 +00:00
|
|
|
case 'z':
|
|
|
|
page_header_tz = optarg;
|
|
|
|
break;
|
2008-09-03 19:02:00 +00:00
|
|
|
default:
|
|
|
|
//usage();
|
|
|
|
exit(2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
if (code_to_look_up >= 0)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2012-03-28 13:43:13 +00:00
|
|
|
printf("Result code %d is %s\n", code_to_look_up, t30_completion_code_to_str(code_to_look_up));
|
|
|
|
exit(0);
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
printf("Using T.38 version %d\n", t38_version);
|
|
|
|
if (use_ecm)
|
|
|
|
printf("Using ECM\n");
|
|
|
|
|
2009-06-18 06:13:59 +00:00
|
|
|
wave_handle = NULL;
|
2008-09-03 19:02:00 +00:00
|
|
|
if (log_audio)
|
|
|
|
{
|
2012-03-28 13:43:13 +00:00
|
|
|
if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 4)) == NULL)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2012-03-28 13:43:13 +00:00
|
|
|
fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
|
2008-09-03 19:02:00 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memset(silence, 0, sizeof(silence));
|
2013-03-14 13:22:51 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
srand48(0x1234567);
|
2015-09-28 13:47:27 +00:00
|
|
|
|
|
|
|
memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
|
|
|
|
memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
/* Set up the nodes */
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[0].peer = chain_elements - 1;
|
|
|
|
chain[chain_elements - 1].peer = 0;
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
for (i = 0; i < chain_elements; i++)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].tag[0] = i + 'A';
|
|
|
|
chain[i].tag[1] = '\0';
|
|
|
|
|
|
|
|
memset(&chain[i].audio_buf[0], 0, sizeof(chain[i].audio_buf[0]));
|
|
|
|
memset(&chain[i].audio_buf[1], 0, sizeof(chain[i].audio_buf[1]));
|
|
|
|
memset(&chain[i].expected_rx_info, 0, sizeof(chain[i].expected_rx_info));
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
switch (chain[i].node_type)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
case AUDIO_FAX:
|
|
|
|
if ((chain[i].node.fax_state = fax_init(NULL, (i == 0))) == NULL)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
fprintf(stderr, " Cannot start FAX instance\n");
|
2012-03-28 13:43:13 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].t30_state = fax_get_t30_state(chain[i].node.fax_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = fax_get_logging_state(chain[i].node.fax_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = t30_get_logging_state(chain[i].t30_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
|
|
|
|
|
|
|
set_t30_callbacks(chain[i].t30_state, i);
|
|
|
|
|
|
|
|
chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0];
|
|
|
|
chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
|
|
|
|
|
|
|
|
chain[i].awgn_state = NULL;
|
|
|
|
signal_scaling = 1.0f;
|
|
|
|
if (noise_level > -99)
|
|
|
|
{
|
|
|
|
chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level);
|
|
|
|
signal_scaling = powf(10.0f, signal_level/20.0f);
|
|
|
|
printf("Signal scaling %f\n", signal_scaling);
|
|
|
|
}
|
2014-05-07 05:11:53 +00:00
|
|
|
break;
|
2015-09-28 13:47:27 +00:00
|
|
|
case T38_FAX:
|
|
|
|
if ((chain[i].node.t38_state = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
fprintf(stderr, " Cannot start the T.38 terminal instance\n");
|
2012-03-28 13:43:13 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].t30_state = t38_terminal_get_t30_state(chain[i].node.t38_state);
|
|
|
|
chain[i].t38_core_state = t38_terminal_get_t38_core_state(chain[i].node.t38_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = t38_terminal_get_logging_state(chain[i].node.t38_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = t38_core_get_logging_state(chain[i].t38_core_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = t30_get_logging_state(chain[i].t30_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
set_t30_callbacks(chain[i].t30_state, i);
|
|
|
|
|
|
|
|
if (i == 0)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].t38_peer = i + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (chain[i - 1].node_type)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
case T38_FAX:
|
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
chain[i].t38_peer = i - 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
chain[i].t38_peer = i + 1;
|
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T31_AUDIO_FAX:
|
|
|
|
break;
|
|
|
|
case T31_T38_FAX:
|
|
|
|
break;
|
|
|
|
case TSB85_AUDIO_FAX:
|
|
|
|
case TSB85_T38_FAX:
|
|
|
|
if ((chain[i].node.faxtester_state = faxtester_init(NULL, xml_file_name, xml_test_name[(i == 0) ? 0 : 1])) == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr, " Cannot start FAX tester instance\n");
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
logging = faxtester_get_logging_state(chain[i].node.faxtester_state);
|
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
faxtester_set_transmit_on_idle(chain[i].node.faxtester_state, true);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0];
|
|
|
|
chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
chain[i].t38_peer = i + 1;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
switch (chain[i - 1].node_type)
|
|
|
|
{
|
|
|
|
case T38_FAX:
|
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
chain[i].t38_peer = i - 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
chain[i].t38_peer = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
|
|
|
|
chain[i].awgn_state = NULL;
|
2012-03-28 13:43:13 +00:00
|
|
|
signal_scaling = 1.0f;
|
|
|
|
if (noise_level > -99)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level);
|
2012-03-28 13:43:13 +00:00
|
|
|
signal_scaling = powf(10.0f, signal_level/20.0f);
|
|
|
|
printf("Signal scaling %f\n", signal_scaling);
|
|
|
|
}
|
2014-05-07 05:11:53 +00:00
|
|
|
break;
|
2015-09-28 13:47:27 +00:00
|
|
|
case REPLAY_AUDIO_FAX:
|
|
|
|
if ((chain[i].node.wave_handle = sf_open_telephony_read(replay_file_name, 1)) == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr, " Cannot open audio file '%s'\n", replay_file_name);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0];
|
|
|
|
chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
|
2014-05-07 05:11:53 +00:00
|
|
|
break;
|
2015-09-28 13:47:27 +00:00
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
if ((chain[i].node.t38_gateway_state = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr, " Cannot start T.38 gateway instance\n");
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
chain[i].t38_core_state = t38_gateway_get_t38_core_state(chain[i].node.t38_gateway_state);
|
|
|
|
|
|
|
|
logging = t38_gateway_get_logging_state(chain[i].node.t38_gateway_state);
|
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
|
|
|
|
|
|
|
logging = fax_modems_get_logging_state(&chain[i].node.t38_gateway_state->audio.modems);
|
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
|
|
|
|
|
|
|
logging = t38_core_get_logging_state(chain[i].t38_core_state);
|
|
|
|
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
|
|
|
|
span_log_set_tag(logging, chain[i].tag);
|
|
|
|
|
|
|
|
t38_gateway_set_transmit_on_idle(chain[i].node.t38_gateway_state, use_transmit_on_idle);
|
|
|
|
t38_gateway_set_supported_modems(chain[i].node.t38_gateway_state, supported_modems);
|
|
|
|
//t38_gateway_set_nsx_suppression(chain[i].node.t38_state, NULL, 0, NULL, 0);
|
|
|
|
t38_gateway_set_fill_bit_removal(chain[i].node.t38_gateway_state, remove_fill_bits);
|
|
|
|
t38_gateway_set_real_time_frame_handler(chain[i].node.t38_gateway_state, real_time_gateway_frame_handler, (void *) (intptr_t) i);
|
|
|
|
t38_gateway_set_ecm_capability(chain[i].node.t38_gateway_state, use_ecm);
|
|
|
|
t38_set_t38_version(chain[i].t38_core_state, t38_version);
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
chain[i].t38_peer = i + 1;
|
|
|
|
chain[i].path.audio_in_buf = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (chain[i - 1].node_type)
|
|
|
|
{
|
|
|
|
case T38_FAX:
|
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
chain[i].t38_peer = i - 1;
|
|
|
|
chain[i].path.audio_in_buf = &chain[i + 1].audio_buf[0];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
chain[i].t38_peer = i + 1;
|
|
|
|
chain[i].path.audio_in_buf = &chain[i - 1].audio_buf[0];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
|
|
|
|
|
|
|
|
chain[i].awgn_state = NULL;
|
|
|
|
signal_scaling = 1.0f;
|
|
|
|
if (noise_level > -99)
|
|
|
|
{
|
|
|
|
chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level);
|
|
|
|
signal_scaling = powf(10.0f, signal_level/20.0f);
|
|
|
|
printf("Signal scaling %f\n", signal_scaling);
|
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
if ((chain[i].path.g1050_path = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
fprintf(stderr, " Failed to start IP network path model\n");
|
2012-03-28 13:43:13 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
for (i = 0; i < chain_elements; i++)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
j = i + 1;
|
2015-09-28 13:47:27 +00:00
|
|
|
if (chain[i].t30_state)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j);
|
|
|
|
t30_set_tx_ident(chain[i].t30_state, buf);
|
|
|
|
strcpy(chain[chain[i].peer].expected_rx_info.ident, buf);
|
|
|
|
sprintf(buf, "Sub-address %d", j);
|
|
|
|
t30_set_tx_sub_address(chain[i].t30_state, buf);
|
|
|
|
//strcpy(chain[chain[i].peer].expected_rx_info.sub_address, buf);
|
|
|
|
sprintf(buf, "Sender ID %d", j);
|
|
|
|
t30_set_tx_sender_ident(chain[i].t30_state, buf);
|
|
|
|
//strcpy(chain[chain[i].peer].expected_rx_info.sender_ident, buf);
|
|
|
|
sprintf(buf, "Password %d", j);
|
|
|
|
t30_set_tx_password(chain[i].t30_state, buf);
|
|
|
|
//strcpy(chain[chain[i].peer].expected_rx_info.password, buf);
|
|
|
|
sprintf(buf, "Polled sub-add %d", j);
|
|
|
|
t30_set_tx_polled_sub_address(chain[i].t30_state, buf);
|
|
|
|
//strcpy(chain[chain[i].peer].expected_rx_info.polled_sub_address, buf);
|
|
|
|
sprintf(buf, "Select poll add %d", j);
|
|
|
|
t30_set_tx_selective_polling_address(chain[i].t30_state, buf);
|
|
|
|
//strcpy(chain[chain[i].peer].expected_rx_info.selective_polling_address, buf);
|
|
|
|
t30_set_tx_page_header_info(chain[i].t30_state, page_header_info);
|
|
|
|
if (page_header_tz)
|
|
|
|
t30_set_tx_page_header_tz(chain[i].t30_state, page_header_tz);
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
t30_set_tx_nsf(chain[i].t30_state, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
|
|
|
|
chain[chain[i].peer].expected_rx_info.nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00";
|
|
|
|
chain[chain[i].peer].expected_rx_info.nsf_len = 12;
|
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
t30_set_supported_modems(chain[i].t30_state, supported_modems);
|
|
|
|
t30_set_supported_t30_features(chain[i].t30_state,
|
|
|
|
T30_SUPPORT_IDENTIFICATION
|
|
|
|
| T30_SUPPORT_SELECTIVE_POLLING
|
|
|
|
| T30_SUPPORT_SUB_ADDRESSING);
|
|
|
|
t30_set_supported_image_sizes(chain[i].t30_state,
|
|
|
|
T4_SUPPORT_WIDTH_215MM
|
|
|
|
| T4_SUPPORT_WIDTH_255MM
|
|
|
|
| T4_SUPPORT_WIDTH_303MM
|
|
|
|
| T4_SUPPORT_LENGTH_US_LETTER
|
|
|
|
| T4_SUPPORT_LENGTH_US_LEGAL
|
|
|
|
| T4_SUPPORT_LENGTH_UNLIMITED);
|
|
|
|
switch (allowed_bilevel_resolutions[(i == 0) ? 0 : 1])
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
/* Allow anything */
|
|
|
|
t30_set_supported_bilevel_resolutions(chain[i].t30_state,
|
|
|
|
T4_RESOLUTION_R8_STANDARD
|
|
|
|
| T4_RESOLUTION_R8_FINE
|
|
|
|
| T4_RESOLUTION_R8_SUPERFINE
|
|
|
|
| T4_RESOLUTION_R16_SUPERFINE
|
|
|
|
| T4_RESOLUTION_200_100
|
|
|
|
| T4_RESOLUTION_200_200
|
|
|
|
| T4_RESOLUTION_200_400
|
|
|
|
| T4_RESOLUTION_300_300
|
|
|
|
| T4_RESOLUTION_300_600
|
|
|
|
| T4_RESOLUTION_400_400
|
|
|
|
| T4_RESOLUTION_400_800
|
|
|
|
| T4_RESOLUTION_600_600
|
|
|
|
| T4_RESOLUTION_600_1200
|
|
|
|
| T4_RESOLUTION_1200_1200);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
/* Allow anything metric */
|
|
|
|
t30_set_supported_bilevel_resolutions(chain[i].t30_state,
|
|
|
|
T4_RESOLUTION_R8_STANDARD
|
|
|
|
| T4_RESOLUTION_R8_FINE
|
|
|
|
| T4_RESOLUTION_R8_SUPERFINE
|
|
|
|
| T4_RESOLUTION_R16_SUPERFINE);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
/* Allow anything inch based */
|
|
|
|
t30_set_supported_bilevel_resolutions(chain[i].t30_state,
|
|
|
|
T4_RESOLUTION_200_100
|
|
|
|
| T4_RESOLUTION_200_200
|
|
|
|
| T4_RESOLUTION_200_400
|
|
|
|
| T4_RESOLUTION_300_300
|
|
|
|
| T4_RESOLUTION_300_600
|
|
|
|
| T4_RESOLUTION_400_400
|
|
|
|
| T4_RESOLUTION_400_800
|
|
|
|
| T4_RESOLUTION_600_600
|
|
|
|
| T4_RESOLUTION_600_1200
|
|
|
|
| T4_RESOLUTION_1200_1200);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
/* Allow only restricted length resolution */
|
|
|
|
t30_set_supported_bilevel_resolutions(chain[i].t30_state,
|
|
|
|
T4_RESOLUTION_R8_STANDARD
|
|
|
|
| T4_RESOLUTION_R8_FINE
|
|
|
|
| T4_RESOLUTION_200_100
|
|
|
|
| T4_RESOLUTION_200_200);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
/* Allow only more restricted length resolution */
|
|
|
|
t30_set_supported_bilevel_resolutions(chain[i].t30_state,
|
|
|
|
T4_RESOLUTION_R8_STANDARD
|
|
|
|
| T4_RESOLUTION_200_100);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (colour_enabled)
|
|
|
|
{
|
|
|
|
t30_set_supported_colour_resolutions(chain[i].t30_state,
|
|
|
|
T4_RESOLUTION_100_100
|
|
|
|
| T4_RESOLUTION_200_200
|
|
|
|
| T4_RESOLUTION_300_300
|
|
|
|
| T4_RESOLUTION_400_400
|
|
|
|
| T4_RESOLUTION_600_600
|
|
|
|
| T4_RESOLUTION_1200_1200);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t30_set_supported_colour_resolutions(chain[i].t30_state, 0);
|
|
|
|
}
|
|
|
|
if (t37_like_output)
|
|
|
|
{
|
|
|
|
t30_set_supported_output_compressions(chain[i].t30_state,
|
|
|
|
T4_COMPRESSION_T85
|
|
|
|
| T4_COMPRESSION_T85_L0
|
|
|
|
| T4_COMPRESSION_T6
|
|
|
|
| T4_COMPRESSION_T42_T81);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t30_set_supported_output_compressions(chain[i].t30_state,
|
|
|
|
T4_COMPRESSION_T6
|
|
|
|
| T4_COMPRESSION_JPEG);
|
|
|
|
}
|
2013-08-31 16:36:48 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
t30_set_ecm_capability(chain[i].t30_state, use_ecm);
|
|
|
|
t30_set_supported_compressions(chain[i].t30_state,
|
|
|
|
T4_COMPRESSION_T4_1D
|
|
|
|
| T4_COMPRESSION_T4_2D
|
|
|
|
| T4_COMPRESSION_T6
|
|
|
|
| T4_COMPRESSION_T85
|
|
|
|
| T4_COMPRESSION_T85_L0
|
|
|
|
//| T4_COMPRESSION_T88
|
|
|
|
| T4_COMPRESSION_T43
|
|
|
|
| T4_COMPRESSION_T45
|
|
|
|
| T4_COMPRESSION_T42_T81
|
|
|
|
| T4_COMPRESSION_SYCC_T81
|
|
|
|
| T4_COMPRESSION_GRAYSCALE
|
|
|
|
| T4_COMPRESSION_COLOUR
|
|
|
|
| T4_COMPRESSION_12BIT
|
|
|
|
| T4_COMPRESSION_COLOUR_TO_GRAY
|
|
|
|
| T4_COMPRESSION_GRAY_TO_BILEVEL
|
|
|
|
| T4_COMPRESSION_COLOUR_TO_BILEVEL
|
|
|
|
| T4_COMPRESSION_RESCALING
|
|
|
|
| 0);
|
|
|
|
t30_set_minimum_scan_line_time(chain[i].t30_state, scan_line_time);
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
2009-01-28 04:48:03 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
switch (chain[i].node_type)
|
2010-07-24 19:29:44 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
case AUDIO_FAX:
|
|
|
|
fax_set_transmit_on_idle(chain[i].node.fax_state, use_transmit_on_idle);
|
|
|
|
fax_set_tep_mode(chain[i].node.fax_state, use_tep);
|
|
|
|
break;
|
|
|
|
case T38_FAX:
|
|
|
|
t38_set_t38_version(chain[i].t38_core_state, t38_version);
|
|
|
|
//t30_set_iaf_mode(chain[i].t30_state, T30_IAF_MODE_NO_FILL_BITS);
|
2012-03-28 13:43:13 +00:00
|
|
|
switch (t38_transport)
|
|
|
|
{
|
|
|
|
case T38_TRANSPORT_UDPTL:
|
|
|
|
case T38_TRANSPORT_RTP:
|
2015-09-28 13:47:27 +00:00
|
|
|
t38_terminal_set_fill_bit_removal(chain[i].node.t38_state, remove_fill_bits);
|
|
|
|
t38_terminal_set_tep_mode(chain[i].node.t38_state, use_tep);
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
|
|
|
case T38_TRANSPORT_TCP:
|
|
|
|
case T38_TRANSPORT_TCP_TPKT:
|
2015-09-28 13:47:27 +00:00
|
|
|
t38_terminal_set_fill_bit_removal(chain[i].node.t38_state, true);
|
|
|
|
t38_terminal_set_config(chain[i].node.t38_state, T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS);
|
|
|
|
t38_terminal_set_tep_mode(chain[i].node.t38_state, false);
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
break;
|
2010-07-24 19:29:44 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < chain_elements; i++)
|
|
|
|
{
|
|
|
|
switch (chain[i].node_type)
|
2010-07-24 19:29:44 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
case TSB85_AUDIO_FAX:
|
|
|
|
case TSB85_T38_FAX:
|
|
|
|
if (chain[chain[i].peer].node_type == AUDIO_FAX)
|
|
|
|
chain[i].node.faxtester_state->far_fax = chain[chain[i].peer].node.fax_state;
|
|
|
|
else
|
|
|
|
chain[i].node.faxtester_state->far_t38 = chain[chain[i].peer].node.t38_state;
|
|
|
|
chain[i].node.faxtester_state->far_t30 = chain[chain[i].peer].t30_state;
|
|
|
|
chain[i].node.faxtester_state->far_tag = chain[i].peer + 'A';
|
|
|
|
|
|
|
|
while (faxtester_next_step(chain[i].node.faxtester_state) == 0)
|
|
|
|
/*dummy loop*/;
|
|
|
|
/*endwhile*/
|
|
|
|
break;
|
|
|
|
case REPLAY_AUDIO_FAX:
|
|
|
|
break;
|
|
|
|
case PASSTHROUGH:
|
|
|
|
if (chain[i - 1].path.audio_in_buf == &chain[i].audio_buf[0])
|
|
|
|
chain[i - 1].path.audio_in_buf = &chain[i + 1].audio_buf[0];
|
|
|
|
if (chain[i + 1].path.audio_in_buf == &chain[i].audio_buf[0])
|
|
|
|
chain[i + 1].path.audio_in_buf = &chain[i - 1].audio_buf[0];
|
|
|
|
break;
|
2010-07-24 19:29:44 +00:00
|
|
|
}
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
switch (chain[chain_elements - 1].node_type)
|
|
|
|
{
|
|
|
|
case AUDIO_FAX:
|
|
|
|
case T38_FAX:
|
|
|
|
k = (use_polled_mode) ? (chain_elements - 1) : 0;
|
|
|
|
if (chain[k].t30_state)
|
|
|
|
t30_set_tx_file(chain[k].t30_state, input_tiff_file_name, start_page, end_page);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (chain[0].node_type)
|
|
|
|
{
|
|
|
|
case AUDIO_FAX:
|
|
|
|
case T38_FAX:
|
|
|
|
k = (use_polled_mode) ? 0 : (chain_elements - 1);
|
|
|
|
if (chain[k].t30_state)
|
|
|
|
t30_set_rx_file(chain[k].t30_state, output_tiff_file_name, -1);
|
|
|
|
break;
|
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
|
|
|
|
#if defined(ENABLE_GUI)
|
|
|
|
if (use_gui)
|
|
|
|
start_media_monitor();
|
|
|
|
#endif
|
|
|
|
hist_ptr = 0;
|
2008-09-03 19:02:00 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
memset(audio_log, 0, sizeof(audio_log));
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
for (i = 0; i < chain_elements; i++)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2012-03-28 13:43:13 +00:00
|
|
|
/* Update T.30 timing */
|
2015-09-28 13:47:27 +00:00
|
|
|
switch (chain[i].node_type)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
case AUDIO_FAX:
|
|
|
|
/* Update timing */
|
|
|
|
logging = t30_get_logging_state(chain[i].t30_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = fax_get_logging_state(chain[i].node.fax_state);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
2015-09-28 13:47:27 +00:00
|
|
|
logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems);
|
2012-03-28 13:43:13 +00:00
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
2015-09-28 13:47:27 +00:00
|
|
|
#if 0
|
|
|
|
/* Probe inside the modems to update their logs */
|
|
|
|
span_log_bump_samples(chain[i].node.fax_state->modems.v27ter_rx.logging, len);
|
|
|
|
span_log_bump_samples(chain[i].node.fax_state->modems.v29_rx.logging, len);
|
|
|
|
span_log_bump_samples(chain[i].node.fax_state->modems.v17_rx.logging, len);
|
|
|
|
#endif
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2013-04-21 14:02:09 +00:00
|
|
|
#if 0
|
|
|
|
/* Mute the signal */
|
2015-09-28 13:47:27 +00:00
|
|
|
vec_zeroi16(chain[i].path.audio_in_buf->amp, SAMPLES_PER_CHUNK);
|
|
|
|
chain[i].path.audio_in_buf->len = SAMPLES_PER_CHUNK;
|
2013-04-21 14:02:09 +00:00
|
|
|
#endif
|
2015-09-28 13:47:27 +00:00
|
|
|
if (log_audio)
|
2009-01-28 04:48:03 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
k = (i == 0) ? 0 : 2;
|
|
|
|
for (j = 0; j < chain[i].path.audio_in_buf->len; j++)
|
|
|
|
audio_log[4*j + k] = chain[i].path.audio_in_buf->amp[j];
|
2009-01-28 04:48:03 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
fax_rx(chain[i].node.fax_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len);
|
|
|
|
if (!t30_call_active(chain[i].t30_state))
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].completed = true;
|
|
|
|
continue;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
|
|
|
|
chain[i].path.audio_out_buf->len = fax_tx(chain[i].node.fax_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
|
|
|
|
if (!use_transmit_on_idle)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
/* The receive side always expects a full block of samples, but the
|
|
|
|
transmit side may not be sending any when it doesn't need to. We
|
|
|
|
may need to pad with some silence. */
|
|
|
|
if (chain[i].path.audio_out_buf->len < SAMPLES_PER_CHUNK)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
vec_zeroi16(&chain[i].path.audio_out_buf->amp[chain[i].path.audio_out_buf->len], SAMPLES_PER_CHUNK - chain[i].path.audio_out_buf->len);
|
|
|
|
chain[i].path.audio_out_buf->len = SAMPLES_PER_CHUNK;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
if (chain[i].awgn_state)
|
|
|
|
{
|
|
|
|
for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
|
|
|
|
chain[i].path.audio_out_buf->amp[j] = ((int16_t) (chain[i].path.audio_out_buf->amp[j]*signal_scaling)) + awgn(chain[i].awgn_state);
|
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
if (log_audio)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
k = (i == 0) ? 1 : 3;
|
|
|
|
for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
|
|
|
|
audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j];
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
|
|
|
if (feedback_audio)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
|
|
|
|
chain[i].path.audio_out_buf->amp[j] += t38_amp_hist_a[hist_ptr][j] >> 1;
|
|
|
|
memcpy(t38_amp_hist_a[hist_ptr], chain[i].path.audio_out_buf->amp, sizeof(int16_t)*SAMPLES_PER_CHUNK);
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
break;
|
|
|
|
case T38_FAX:
|
|
|
|
/* Update timing */
|
|
|
|
logging = t30_get_logging_state(chain[i].t30_state);
|
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
|
|
|
logging = t38_terminal_get_logging_state(chain[i].node.t38_state);
|
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
|
|
|
logging = t38_core_get_logging_state(chain[i].t38_core_state);
|
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
2008-09-03 19:02:00 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
chain[i].completed = t38_terminal_send_timeout(chain[i].node.t38_state, SAMPLES_PER_CHUNK);
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
while ((msg_len = g1050_get(chain[i].path.g1050_path, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
|
|
|
|
{
|
|
|
|
#if defined(ENABLE_GUI)
|
|
|
|
if (use_gui)
|
|
|
|
media_monitor_rx(seq_no, tx_when, rx_when);
|
|
|
|
#endif
|
|
|
|
t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TSB85_AUDIO_FAX:
|
|
|
|
/* Update timing */
|
|
|
|
logging = faxtester_get_logging_state(chain[i].node.faxtester_state);
|
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
|
|
|
#if 0
|
|
|
|
/* Probe inside the modems to update their logs */
|
|
|
|
span_log_bump_samples(&chain[i].node.faxtester_state->modems.v27ter_rx.logging, len);
|
|
|
|
span_log_bump_samples(&chain[i].node.faxtester_state->modems.v29_rx.logging, len);
|
|
|
|
span_log_bump_samples(&chain[i].node.faxtester_state->modems.v17_rx.logging, len);
|
|
|
|
#endif
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
if (log_audio)
|
|
|
|
{
|
|
|
|
k = (i == 0) ? 0 : 2;
|
|
|
|
for (j = 0; j < chain[i].path.audio_in_buf->len; j++)
|
|
|
|
audio_log[4*j + k] = chain[i].path.audio_in_buf->amp[j];
|
|
|
|
}
|
|
|
|
faxtester_rx(chain[i].node.faxtester_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len);
|
|
|
|
chain[i].path.audio_out_buf->len = faxtester_tx(chain[i].node.faxtester_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
|
|
|
|
if (chain[i].path.audio_out_buf->len == 0)
|
|
|
|
break;
|
|
|
|
if (log_audio)
|
|
|
|
{
|
|
|
|
k = (i == 0) ? 1 : 3;
|
|
|
|
for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
|
|
|
|
audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j];
|
|
|
|
}
|
|
|
|
if (chain[i].node.faxtester_state->test_for_call_clear && !chain[i].node.faxtester_state->far_end_cleared_call)
|
|
|
|
{
|
|
|
|
chain[i].node.faxtester_state->call_clear_timer += chain[i].path.audio_out_buf->len;
|
|
|
|
if (!t30_call_active(chain[i].node.faxtester_state->far_t30))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log(faxtester_get_logging_state(chain[i].node.faxtester_state),
|
|
|
|
SPAN_LOG_FLOW,
|
|
|
|
"Far end cleared after %dms (limits %dms to %dms)\n",
|
|
|
|
chain[i].node.faxtester_state->call_clear_timer/8,
|
|
|
|
chain[i].node.faxtester_state->timein_x,
|
|
|
|
chain[i].node.faxtester_state->timeout);
|
|
|
|
if (chain[i].node.faxtester_state->call_clear_timer/8 < chain[i].node.faxtester_state->timein_x || chain[i].node.faxtester_state->call_clear_timer/8 > chain[i].node.faxtester_state->timeout_x)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
printf("Test failed\n");
|
|
|
|
exit(2);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
span_log(faxtester_get_logging_state(chain[i].node.faxtester_state), SPAN_LOG_FLOW, "Clear time OK\n");
|
|
|
|
chain[i].node.faxtester_state->far_end_cleared_call = true;
|
|
|
|
chain[i].node.faxtester_state->test_for_call_clear = false;
|
|
|
|
while (faxtester_next_step(chain[i].node.faxtester_state) == 0)
|
|
|
|
/*dummy loop*/;
|
|
|
|
/*endwhile*/
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
/*endif*/
|
|
|
|
}
|
|
|
|
/*endif*/
|
|
|
|
break;
|
|
|
|
case REPLAY_AUDIO_FAX:
|
|
|
|
chain[i].path.audio_out_buf->len = sf_readf_short(chain[i].node.wave_handle, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
|
|
|
|
if (chain[i].path.audio_out_buf->len == 0)
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
/* Update timing */
|
|
|
|
logging = t38_gateway_get_logging_state(chain[i].node.t38_gateway_state);
|
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
|
|
|
logging = t38_core_get_logging_state(chain[i].t38_core_state);
|
|
|
|
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
|
|
|
|
#if 0
|
|
|
|
/* Probe inside the modems to update their logs */
|
|
|
|
span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v27ter_rx.logging, len);
|
|
|
|
span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v29_rx.logging, len);
|
|
|
|
span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v17_rx.logging, len);
|
|
|
|
#endif
|
2012-03-28 13:43:13 +00:00
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
if (drop_frame_rate && --drop_frame == 0)
|
|
|
|
{
|
|
|
|
drop_frame = drop_frame_rate;
|
|
|
|
if (t38_gateway_rx_fillin(chain[i].node.t38_gateway_state, SAMPLES_PER_CHUNK))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (t38_gateway_rx(chain[i].node.t38_gateway_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
chain[i].path.audio_out_buf->len = t38_gateway_tx(chain[i].node.t38_gateway_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
|
|
|
|
if (!use_transmit_on_idle)
|
|
|
|
{
|
|
|
|
if (chain[i].path.audio_out_buf->len < SAMPLES_PER_CHUNK)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
vec_zeroi16(&chain[i].path.audio_out_buf->amp[chain[i].path.audio_out_buf->len], SAMPLES_PER_CHUNK - chain[i].path.audio_out_buf->len);
|
|
|
|
chain[i].path.audio_out_buf->len = SAMPLES_PER_CHUNK;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
if (feedback_audio)
|
|
|
|
{
|
|
|
|
for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
|
|
|
|
chain[i].path.audio_out_buf->amp[j] += t38_amp_hist_a[hist_ptr][j] >> 1;
|
|
|
|
vec_movei16(t38_amp_hist_a[hist_ptr], chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (log_audio)
|
|
|
|
{
|
|
|
|
k = (i == 0) ? 1 : 3;
|
|
|
|
for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
|
|
|
|
audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
while ((msg_len = g1050_get(chain[i].path.g1050_path, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
#if defined(ENABLE_GUI)
|
|
|
|
if (use_gui)
|
|
|
|
media_monitor_rx(seq_no, tx_when, rx_when);
|
2009-01-28 04:48:03 +00:00
|
|
|
#endif
|
2015-09-28 13:47:27 +00:00
|
|
|
t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no);
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
if (log_audio)
|
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
outframes = sf_writef_short(wave_handle, audio_log, SAMPLES_PER_CHUNK);
|
2008-09-03 19:02:00 +00:00
|
|
|
if (outframes != SAMPLES_PER_CHUNK)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;
|
|
|
|
|
2015-09-28 13:47:27 +00:00
|
|
|
if (chain[0].completed && chain[chain_elements - 1].completed)
|
2008-09-03 19:02:00 +00:00
|
|
|
break;
|
2012-03-28 13:43:13 +00:00
|
|
|
#if defined(ENABLE_GUI)
|
|
|
|
if (use_gui)
|
|
|
|
media_monitor_update_display();
|
|
|
|
#endif
|
|
|
|
if (++hist_ptr > 3)
|
|
|
|
hist_ptr = 0;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
|
|
|
|
for (i = 0; i < chain_elements; i++)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
switch (chain[i].node_type)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
t38_gateway_get_transfer_statistics(chain[i].node.t38_gateway_state, &t38_stats);
|
2012-03-28 13:43:13 +00:00
|
|
|
printf("%c side exchanged %d pages at %dbps, in %s mode\n",
|
|
|
|
i + 'A',
|
|
|
|
t38_stats.pages_transferred,
|
|
|
|
t38_stats.bit_rate,
|
|
|
|
(t38_stats.error_correcting_mode) ? "ECM" : "non-ECM");
|
2015-09-28 13:47:27 +00:00
|
|
|
break;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
if (log_audio)
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2012-03-28 13:43:13 +00:00
|
|
|
if (sf_close_telephony(wave_handle))
|
2008-09-03 19:02:00 +00:00
|
|
|
{
|
2012-03-28 13:43:13 +00:00
|
|
|
fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
|
2008-09-03 19:02:00 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
}
|
2013-03-14 13:22:51 +00:00
|
|
|
|
2012-03-28 13:43:13 +00:00
|
|
|
/* Check how many pages should have been transferred */
|
|
|
|
expected_pages = get_tiff_total_pages(input_tiff_file_name);
|
|
|
|
if (end_page >= 0 && expected_pages > end_page + 1)
|
|
|
|
expected_pages = end_page + 1;
|
|
|
|
if (start_page >= 0)
|
|
|
|
expected_pages -= start_page;
|
|
|
|
/* Check how many pages were transferred */
|
2015-09-28 13:47:27 +00:00
|
|
|
for (j = 0; j < 2; j++)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
i = (j == 0) ? 0 : (chain_elements - 1);
|
|
|
|
if (!chain[i].phase_e_reached)
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
2015-09-28 13:47:27 +00:00
|
|
|
if (!chain[i].succeeded)
|
2012-03-28 13:43:13 +00:00
|
|
|
break;
|
2015-09-28 13:47:27 +00:00
|
|
|
|
|
|
|
t30_get_transfer_statistics(chain[i].t30_state, &t30_stats);
|
|
|
|
if ((!use_polled_mode && i != 0) || (use_polled_mode && i == 0))
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
if (t30_stats.pages_tx != 0 || t30_stats.pages_rx != expected_pages)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (t30_stats.pages_tx != expected_pages || t30_stats.pages_rx != 0)
|
|
|
|
break;
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < chain_elements; i++)
|
|
|
|
{
|
|
|
|
switch (chain[i].node_type)
|
|
|
|
{
|
|
|
|
case AUDIO_FAX:
|
|
|
|
fax_free(chain[i].node.fax_state);
|
|
|
|
break;
|
|
|
|
case T38_FAX:
|
|
|
|
t38_terminal_free(chain[i].node.t38_state);
|
|
|
|
break;
|
|
|
|
case TSB85_AUDIO_FAX:
|
|
|
|
case TSB85_T38_FAX:
|
|
|
|
faxtester_free(chain[i].node.faxtester_state);
|
|
|
|
break;
|
|
|
|
case REPLAY_AUDIO_FAX:
|
|
|
|
if (sf_close_telephony(chain[i].node.wave_handle))
|
|
|
|
{
|
|
|
|
fprintf(stderr, " Cannot close audio file '%s'\n", replay_file_name);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
chain[i].node.wave_handle = NULL;
|
|
|
|
break;
|
|
|
|
case AUDIO_TO_T38_GATEWAY:
|
|
|
|
t38_gateway_free(chain[i].node.t38_gateway_state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (chain[i].path.g1050_path)
|
2014-06-14 11:49:05 +00:00
|
|
|
{
|
2015-09-28 13:47:27 +00:00
|
|
|
g1050_free(chain[i].path.g1050_path);
|
|
|
|
chain[i].path.g1050_path = NULL;
|
2014-06-14 11:49:05 +00:00
|
|
|
}
|
2012-03-28 13:43:13 +00:00
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
if (j < 2)
|
2012-03-28 13:43:13 +00:00
|
|
|
{
|
|
|
|
printf("Tests failed\n");
|
|
|
|
exit(2);
|
|
|
|
}
|
2015-09-28 13:47:27 +00:00
|
|
|
t33_tests();
|
2012-03-28 13:43:13 +00:00
|
|
|
printf("Tests passed\n");
|
2012-08-12 14:11:06 +00:00
|
|
|
return 0;
|
2008-09-03 19:02:00 +00:00
|
|
|
}
|
|
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
/*- End of file ------------------------------------------------------------*/
|