]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Removed use of _NONSTD for Windows builds of spandsp, so (hopefully) eliminate
authorSteve Underwood <steveu@coppice.org>
Mon, 28 Sep 2015 13:47:27 +0000 (21:47 +0800)
committerSteve Underwood <steveu@coppice.org>
Mon, 28 Sep 2015 13:47:27 +0000 (21:47 +0800)
compatibility problems with recent versions of MSVC

60 files changed:
libs/broadvoice/autogen.sh
libs/broadvoice/tests/regression_tests.sh.in
libs/broadvoice/tests/timing.h
libs/spandsp/src/async.c
libs/spandsp/src/fax.c
libs/spandsp/src/fax_modems.c
libs/spandsp/src/fsk.c
libs/spandsp/src/hdlc.c
libs/spandsp/src/modem_connect_tones.c
libs/spandsp/src/silence_gen.c
libs/spandsp/src/spandsp/async.h
libs/spandsp/src/spandsp/fax.h
libs/spandsp/src/spandsp/fax_modems.h
libs/spandsp/src/spandsp/fsk.h
libs/spandsp/src/spandsp/hdlc.h
libs/spandsp/src/spandsp/modem_connect_tones.h
libs/spandsp/src/spandsp/silence_gen.h
libs/spandsp/src/spandsp/stdbool.h
libs/spandsp/src/spandsp/t30.h
libs/spandsp/src/spandsp/t31.h
libs/spandsp/src/spandsp/t38_core.h
libs/spandsp/src/spandsp/t38_gateway.h
libs/spandsp/src/spandsp/t38_non_ecm_buffer.h
libs/spandsp/src/spandsp/telephony.h
libs/spandsp/src/spandsp/tone_generate.h
libs/spandsp/src/spandsp/v17rx.h
libs/spandsp/src/spandsp/v17tx.h
libs/spandsp/src/spandsp/v18.h
libs/spandsp/src/spandsp/v22bis.h
libs/spandsp/src/spandsp/v27ter_rx.h
libs/spandsp/src/spandsp/v27ter_tx.h
libs/spandsp/src/spandsp/v29rx.h
libs/spandsp/src/spandsp/v29tx.h
libs/spandsp/src/spandsp/v42.h
libs/spandsp/src/spandsp/v8.h
libs/spandsp/src/t30.c
libs/spandsp/src/t31.c
libs/spandsp/src/t38_core.c
libs/spandsp/src/t38_gateway.c
libs/spandsp/src/t38_non_ecm_buffer.c
libs/spandsp/src/tone_generate.c
libs/spandsp/src/v17rx.c
libs/spandsp/src/v17tx.c
libs/spandsp/src/v18.c
libs/spandsp/src/v22bis_rx.c
libs/spandsp/src/v22bis_tx.c
libs/spandsp/src/v27ter_rx.c
libs/spandsp/src/v27ter_tx.c
libs/spandsp/src/v29rx.c
libs/spandsp/src/v29tx.c
libs/spandsp/src/v42.c
libs/spandsp/src/v8.c
libs/spandsp/tests/Makefile.am
libs/spandsp/tests/fax_tester.c
libs/spandsp/tests/fax_tester.h
libs/spandsp/tests/fax_tests.c
libs/spandsp/tests/fax_tests.sh
libs/spandsp/tests/pcap_parse.c
libs/spandsp/tests/tsb85_tests.c
src/mod/endpoints/mod_gsmopen/mobigater [deleted symlink]

index cc2a3321fae2a23a68c91043f6bb5d4d4404e75d..842a9d19b6bb441b9f056b9e31e1209edf28ac7d 100755 (executable)
@@ -16,9 +16,6 @@
 # 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.
-#
-# $Id: autogen.sh,v 1.1.1.1 2009/11/19 12:10:48 steveu Exp $
-#
 
 UNAME=`uname`
 
index f7adfdf706b89b8fb3ac426eb1fa6bba7ffd16fc..ede719f3798b0abfda7a93a5a3a319a16da7f499 100644 (file)
@@ -16,9 +16,6 @@
 # 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.
-#
-# $Id: regression_tests.sh.in,v 1.2 2009/11/20 13:12:24 steveu Exp $
-#
 
 STDOUT_DEST=xyzzy
 STDERR_DEST=xyzzy2
index d3bfd3413900eab32b5dbba95166e9ce288b2c93..9368894bcf248a6d1cb195f9e7c706d2d36cbe04 100644 (file)
@@ -21,8 +21,6 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: timing.h,v 1.1.1.1 2009/11/19 12:10:48 steveu Exp $
  */
 
 #if !defined(_TIMING_H_)
index bd4166aab97c7f85b8c889e37756aa240dd90455..28d44b41303047931c73a196197328840e222639 100644 (file)
@@ -90,7 +90,7 @@ SPAN_DECLARE(const char *) signal_status_to_str(int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) async_rx_put_bit(void *user_data, int bit)
+SPAN_DECLARE(void) async_rx_put_bit(void *user_data, int bit)
 {
     async_rx_state_t *s;
 
@@ -215,7 +215,7 @@ SPAN_DECLARE(int) async_rx_free(async_rx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) async_tx_get_bit(void *user_data)
+SPAN_DECLARE(int) async_tx_get_bit(void *user_data)
 {
     async_tx_state_t *s;
     int bit;
index d3dff3fe97a9b7d6f10d280a1b9ace72751088c0..b34bb8231e00e53380b2577e2e925030fbe92765 100644 (file)
@@ -161,7 +161,7 @@ static void hdlc_underflow_handler(void *user_data)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len)
+SPAN_DECLARE(int) fax_rx(fax_state_t *s, int16_t *amp, int len)
 {
     int i;
 
@@ -180,7 +180,7 @@ SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len)
+SPAN_DECLARE(int) fax_rx_fillin(fax_state_t *s, int len)
 {
     /* To mitigate the effect of lost packets on a packet network we should
        try to sustain the status quo. If there is no receive modem running, keep
@@ -209,7 +209,7 @@ SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len)
+SPAN_DECLARE(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len)
 {
     int len;
 #if defined(LOG_FAX_AUDIO)
index 78d5b198d0e4c9fb25431ce144faac5507d94ec2..0b405cc246137dc11d5745cbac15379b761af3a2 100644 (file)
@@ -152,7 +152,7 @@ SPAN_DECLARE(const char *) fax_modem_to_str(int modem)
 /*- End of function --------------------------------------------------------*/
 
 //static void fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
-SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
+SPAN_DECLARE(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
 {
     fax_modems_state_t *s;
 
@@ -168,7 +168,7 @@ SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_accept(void *user_data, const uint8_t
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len)
+SPAN_DECLARE(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len)
 {
     fax_modems_state_t *s;
 
@@ -206,7 +206,7 @@ static void v17_rx_status_handler(void *user_data, int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len)
+SPAN_DECLARE(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len)
 {
     fax_modems_state_t *s;
 
@@ -224,7 +224,7 @@ SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t am
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len)
+SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len)
 {
     fax_modems_state_t *s;
 
@@ -253,7 +253,7 @@ static void v27ter_rx_status_handler(void *user_data, int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
+SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
 {
     fax_modems_state_t *s;
 
@@ -271,7 +271,7 @@ SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len)
+SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len)
 {
     fax_modems_state_t *s;
 
@@ -300,7 +300,7 @@ static void v29_rx_status_handler(void *user_data, int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len)
+SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len)
 {
     fax_modems_state_t *s;
 
@@ -318,7 +318,7 @@ SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx(void *user_data, const int16_t am
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len)
+SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len)
 {
     fax_modems_state_t *s;
 
index 07c242bfc498df65e1e354da2c44d41d645d9ebc..8b714d1c1d2eabda521dc677747082d95f4b63ea 100644 (file)
@@ -200,7 +200,7 @@ SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len)
 {
     int sample;
     int bit;
@@ -382,7 +382,7 @@ static void report_status_change(fsk_rx_state_t *s, int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
+SPAN_DECLARE(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
 {
     int buf_ptr;
     int baudstate;
@@ -626,7 +626,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) fsk_rx_fillin(fsk_rx_state_t *s, int len)
+SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len)
 {
     int buf_ptr;
     int i;
index c3de12d01e92c8a982b9957406096494e7f6213b..80062fe4c7030e1fb2d998a9a94c0d01579a4735 100644 (file)
@@ -299,7 +299,7 @@ static __inline__ void hdlc_rx_put_bit_core(hdlc_rx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit)
+SPAN_DECLARE(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit)
 {
     if (new_bit < 0)
     {
@@ -312,7 +312,7 @@ SPAN_DECLARE_NONSTD(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte)
+SPAN_DECLARE(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte)
 {
     int i;
 
@@ -332,7 +332,7 @@ SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len)
+SPAN_DECLARE(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len)
 {
     int i;
 
@@ -517,7 +517,7 @@ SPAN_DECLARE(int) hdlc_tx_corrupt_frame(hdlc_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s)
+SPAN_DECLARE(int) hdlc_tx_get_byte(hdlc_tx_state_t *s)
 {
     int i;
     int byte_in_progress;
@@ -636,7 +636,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get_bit(hdlc_tx_state_t *s)
+SPAN_DECLARE(int) hdlc_tx_get_bit(hdlc_tx_state_t *s)
 {
     int txbit;
 
@@ -652,7 +652,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_bit(hdlc_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len)
+SPAN_DECLARE(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len)
 {
     size_t i;
     int x;
index 98262a1cad102ce7d314054358dc242268c76bd2..cb43f219e0a2977894fe34381e4f68b8175796d4 100644 (file)
@@ -110,9 +110,9 @@ SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
-                                                int16_t amp[],
-                                                int len)
+SPAN_DECLARE(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
+                                         int16_t amp[],
+                                         int len)
 {
     int16_t mod;
     int i;
@@ -456,9 +456,9 @@ static void v21_put_bit(void *user_data, int bit)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
-                                                const int16_t amp[],
-                                                int len)
+SPAN_DECLARE(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
+                                         const int16_t amp[],
+                                         int len)
 {
     int i;
     int16_t notched;
@@ -700,7 +700,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len)
+SPAN_DECLARE(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len)
 {
     return 0;
 }
index 7c24f4334e31a3f9ab070dd75a855f557d6b54e2..e2da8fa387a0c2e69b10cbcf05b7b9af62addd16 100644 (file)
@@ -57,7 +57,7 @@
 
 #include "spandsp/private/silence_gen.h"
 
-SPAN_DECLARE_NONSTD(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len)
+SPAN_DECLARE(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len)
 {
     if (s->remaining_samples != INT_MAX)
     {
@@ -151,7 +151,7 @@ SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s)
 /* The following dummy routines, to absorb data, don't really have a proper home,
    so they have been put here. */
 
-SPAN_DECLARE_NONSTD(int) span_dummy_rx(void *user_data, const int16_t amp[], int len)
+SPAN_DECLARE(int) span_dummy_rx(void *user_data, const int16_t amp[], int len)
 {
     return 0;
 }
@@ -163,7 +163,7 @@ SPAN_DECLARE(int) span_dummy_mod(void *user_data, int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) span_dummy_rx_fillin(void *user_data, int len)
+SPAN_DECLARE(int) span_dummy_rx_fillin(void *user_data, int len)
 {
     return 0;
 }
index eabb41d3f10d0e0215fced993af5009f58f3db39..290b3acc1dd729eca9076936724afb8842add98f 100644 (file)
@@ -156,7 +156,7 @@ SPAN_DECLARE(const char *) signal_status_to_str(int status);
         - SIG_STATUS_TRAINING_SUCCEEDED
         - SIG_STATUS_TRAINING_FAILED
         - SIG_STATUS_END_OF_DATA */
-SPAN_DECLARE_NONSTD(void) async_rx_put_bit(void *user_data, int bit);
+SPAN_DECLARE(void) async_rx_put_bit(void *user_data, int bit);
 
 /*! Initialise an asynchronous data receiver context.
     \brief Initialise an asynchronous data receiver context.
@@ -190,7 +190,7 @@ SPAN_DECLARE(void) async_tx_presend_bits(async_tx_state_t *s, int bits);
     \brief Get the next bit of a transmitted serial bit stream.
     \param user_data An opaque point which must point to a transmitter context.
     \return the next bit, or PUTBIT_END_OF_DATA to indicate the data stream has ended. */
-SPAN_DECLARE_NONSTD(int) async_tx_get_bit(void *user_data);
+SPAN_DECLARE(int) async_tx_get_bit(void *user_data);
 
 /*! Initialise an asynchronous data transmit context.
     \brief Initialise an asynchronous data transmit context.
index 499b2b3b25d9f6f8e90d6f368fc53db2b92ec177..de6d52da0e1244eb813e2e709aff7d3c1446c2b7 100644 (file)
@@ -50,7 +50,7 @@ extern "C"
     \return The number of samples unprocessed. This should only be non-zero if
             the software has reached the end of the FAX call.
 */
-SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
+SPAN_DECLARE(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
 
 /*! Apply fake T.30 receive processing when a block of audio samples is missing (e.g due
     to packet loss).
@@ -60,7 +60,7 @@ SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
     \return The number of samples unprocessed. This should only be non-zero if
             the software has reached the end of the FAX call.
 */
-SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len);
+SPAN_DECLARE(int) fax_rx_fillin(fax_state_t *s, int len);
 
 /*! Apply T.30 transmit processing to generate a block of audio samples.
     \brief Apply T.30 transmit processing to generate a block of audio samples.
@@ -70,7 +70,7 @@ SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len);
     \return The number of samples actually generated. This will be zero when
             there is nothing to send.
 */
-SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len);
+SPAN_DECLARE(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len);
 
 /*! Select whether silent audio will be sent when FAX transmit is idle.
     \brief Select whether silent audio will be sent when FAX transmit is idle.
index a076c0332f53204f6444c62688ed9ba0695505f0..15cc802474a0761b4db4752f708c83079d8040d6 100644 (file)
@@ -64,7 +64,7 @@ extern "C"
 #endif
 
 /* TEMPORARY FUDGE */
-SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok);
+SPAN_DECLARE(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok);
 
 /*! Convert a FAX modem type to a short text description.
     \brief Convert a FAX modem type to a short text description.
@@ -73,14 +73,14 @@ SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_accept(void *user_data, const uint8_t
 SPAN_DECLARE(const char *) fax_modem_to_str(int modem);
 
 /* N.B. the following are currently a work in progress */
-SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len);
-
-SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len);
+SPAN_DECLARE(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len);
+
+SPAN_DECLARE(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len);
 
 SPAN_DECLARE(void) fax_modems_hdlc_tx_flags(fax_modems_state_t *s, int flags);
 
index b65cd7842f1f674a0a957b82a544b99925a1ce53..c016eca8a5453631dbac5bb45e6842b3988503aa 100644 (file)
@@ -187,7 +187,7 @@ SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_stat
     \param len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len);
 
 /*! Get the current received signal power.
     \param s The modem context.
@@ -228,7 +228,7 @@ SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s);
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
+SPAN_DECLARE(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
 
 /*! Fake processing of a missing block of received FSK modem audio samples
     (e.g due to packet loss).
@@ -237,7 +237,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
     \param len The number of samples to fake.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) fsk_rx_fillin(fsk_rx_state_t *s, int len);
+SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len);
 
 SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data);
 
index a9369475c1dfad1528a5bca5f32e941550849395..1349a57a0437d53926e547d5cee6299998e2fe93 100644 (file)
@@ -160,20 +160,20 @@ SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s,
     \param s A pointer to an HDLC receiver context.
     \param new_bit The bit.
 */
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit);
+SPAN_DECLARE(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit);
 
 /*! \brief Put a byte of data to an HDLC receiver.
     \param s A pointer to an HDLC receiver context.
     \param new_byte The byte of data.
 */
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte);
+SPAN_DECLARE(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte);
 
 /*! \brief Put a series of bytes of data to an HDLC receiver.
     \param s A pointer to an HDLC receiver context.
     \param buf The buffer of data.
     \param len The length of the data in the buffer.
 */
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len);
+SPAN_DECLARE(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len);
 
 /*! Initialise an HDLC transmitter context.
     \brief Initialise an HDLC transmitter context.
@@ -250,13 +250,13 @@ SPAN_DECLARE(int) hdlc_tx_abort(hdlc_tx_state_t *s);
     \param s A pointer to an HDLC transmitter context.
     \return The next bit for transmission.
 */
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get_bit(hdlc_tx_state_t *s);
+SPAN_DECLARE(int) hdlc_tx_get_bit(hdlc_tx_state_t *s);
 
 /*! \brief Get the next byte for transmission.
     \param s A pointer to an HDLC transmitter context.
     \return The next byte for transmission.
 */
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
+SPAN_DECLARE(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
 
 /*! \brief Get the next sequence of bytes for transmission.
     \param s A pointer to an HDLC transmitter context.
@@ -264,7 +264,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
     \param max_len The number of bytes to get.
     \return The number of bytes actually got.
 */
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len);
+SPAN_DECLARE(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len);
 
 #if defined(__cplusplus)
 }
index 713f813bbbd8cfa07199ebca333b2cd057946f91..bbfc6f3b9777b860f7a187322dc0f2d9a56e8a9a 100644 (file)
@@ -127,9 +127,9 @@ SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s)
     \param len The number of samples to generate.
     \return The number of samples generated.
 */
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
-                                                int16_t amp[],
-                                                int len);
+SPAN_DECLARE(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
+                                         int16_t amp[],
+                                         int len);
 
 /*! \brief Process a block of samples through an instance of the modem connect
            tones detector.
@@ -138,9 +138,9 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *
     \param len The number of samples in the array.
     \return The number of unprocessed samples.
 */
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
-                                                const int16_t amp[],
-                                                int len);
+SPAN_DECLARE(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
+                                         const int16_t amp[],
+                                         int len);
 
 /*! Fake processing of a missing block of received modem connect tone samples
     (e.g due to packet loss).
@@ -149,7 +149,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
     \param len The number of samples to fake.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len);
+SPAN_DECLARE(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len);
 
 /*! \brief Test if a modem_connect tone has been detected.
     \param s The context.
index df90ec0e9e778a9ef9543606190886edf616b465..94357b72476cbc2cb0ca12733c3165ffd975bad0 100644 (file)
@@ -41,7 +41,7 @@ extern "C"
     \return The number of samples actually generated. This will be zero when
             there is nothing to send.
 */
-SPAN_DECLARE_NONSTD(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len);
+SPAN_DECLARE(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len);
 
 /*! Set a silence generator context to output continuous silence.
     \brief Set a silence generator context to output continuous silence.
@@ -110,7 +110,7 @@ SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s);
     \param len The length of the signal buffer
     \return 0.
 */
-SPAN_DECLARE_NONSTD(int) span_dummy_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) span_dummy_rx(void *user_data, const int16_t amp[], int len);
 
 /*! A dummy routine to use as a signal modifier callback, when we aren't
     really trying to process the signal. It just returns without affecting
@@ -131,7 +131,7 @@ SPAN_DECLARE(int) span_dummy_mod(void *user_data, int16_t amp[], int len);
     \param len The length of the signal buffer
     \return 0.
 */
-SPAN_DECLARE_NONSTD(int) span_dummy_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) span_dummy_rx_fillin(void *user_data, int len);
 
 #if defined(__cplusplus)
 }
index ce1dc387b527e938f4a289677b87cc2a8845e592..faceaac3f97642ac871b8518641fadf627980d0b 100644 (file)
 
 #if !defined(_STDBOOL_H)
 #define _STDBOOL_H
+
 #ifdef _MSC_VER 
 #pragma warning (disable: 4005)
 #endif
+
 #if !defined(__cplusplus)
 
 #define _Bool   int
-#define false   0
 #define bool    int
+#define false   0
 #define true    (!false)
 
 #else
index b3c0b6ad36c57f569b159a4b8b9a5c5a6ded1968..00749004f2484ea4fa3be5a596c1e57ba08fe4ff 100644 (file)
@@ -576,7 +576,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status);
     \brief Get a bit of received non-ECM image data.
     \param user_data An opaque pointer, which must point to the T.30 context.
     \return The next bit to transmit. */
-SPAN_DECLARE_NONSTD(int) t30_non_ecm_get_bit(void *user_data);
+SPAN_DECLARE(int) t30_non_ecm_get_bit(void *user_data);
 
 /*! Get a chunk of received non-ECM image data.
     \brief Get a bit of received non-ECM image data.
@@ -590,7 +590,7 @@ SPAN_DECLARE(int) t30_non_ecm_get(void *user_data, uint8_t buf[], int max_len);
     \brief Process a bit of received non-ECM image data
     \param user_data An opaque pointer, which must point to the T.30 context.
     \param bit The received bit. */
-SPAN_DECLARE_NONSTD(void) t30_non_ecm_put_bit(void *user_data, int bit);
+SPAN_DECLARE(void) t30_non_ecm_put_bit(void *user_data, int bit);
 
 /*! Process a chunk of received non-ECM image data.
     \brief Process a chunk of received non-ECM image data
@@ -605,7 +605,7 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len
     \param msg The HDLC message.
     \param len The length of the message, in octets.
     \param ok True if the frame was received without error. */
-SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t msg[], int len, int ok);
+SPAN_DECLARE(void) t30_hdlc_accept(void *user_data, const uint8_t msg[], int len, int ok);
 
 /*! Report the passage of time to the T.30 engine.
     \brief Report the passage of time to the T.30 engine.
index b61a4142f9a9409f87a5d4844fdffadc820991ab..45237c4e7c83ab6c6ec7f37d1ee27745038c10bd 100644 (file)
@@ -65,7 +65,7 @@ SPAN_DECLARE(int) t31_at_rx(t31_state_t *s, const char *t, int len);
     \param amp The audio sample buffer.
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) t31_rx(t31_state_t *s, int16_t amp[], int len);
 
 /*! Fake processing of a missing block of received T.31 modem audio samples
     (e.g due to packet loss).
@@ -73,7 +73,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len);
     \param s The T.31 modem context.
     \param len The number of samples to fake.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len);
+SPAN_DECLARE(int) t31_rx_fillin(t31_state_t *s, int len);
 
 /*! Generate a block of T.31 modem audio samples.
     \brief Generate a block of T.31 modem audio samples.
@@ -82,7 +82,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len);
     \param max_len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len);
+SPAN_DECLARE(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len);
 
 SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples);
 
index 86e45089ac637ea24c4e857d3f58c4f946f16a2d..3d3d83da51878360305d30a951cc4318502de94d 100644 (file)
@@ -288,7 +288,7 @@ SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_t
     \param len The length of the packet contents.
     \param seq_no The packet sequence number.
     \return 0 for OK, else -1. */
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no);
+SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no);
 
 /*! \brief Process a received T.38 IFP packet from a reliable stream (e.g. TCP).
     \param s The T.38 context.
@@ -296,7 +296,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8
     \param len The length of the packet contents.
     \param seq_no The packet sequence number, used for logging purposes.
     \return The length of the packet processed, or -1 if there is an error in the packet, or too few bytes of data to complete it. */
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no);
+SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no);
 
 /*! Set the method to be used for data rate management, as per the T.38 spec.
     \param s The T.38 context.
index 8d7f2e05008f5649a5d82927047a383254780db3..c6f4a876f39e438478a9a2d0c89791340ca0b5e7 100644 (file)
@@ -102,7 +102,7 @@ SPAN_DECLARE(int) t38_gateway_free(t38_gateway_state_t *s);
     \param amp The audio sample buffer.
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len);
 
 /*! Apply fake processing when a block of audio samples is missing (e.g due
     to packet loss).
@@ -112,7 +112,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
     \return The number of samples unprocessed. This should only be non-zero if
             the software has reached the end of the FAX call.
 */
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len);
+SPAN_DECLARE(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len);
 
 /*! Generate a block of FAX audio samples.
     \brief Generate a block of FAX audio samples.
@@ -121,7 +121,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len);
     \param max_len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len);
+SPAN_DECLARE(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len);
 
 /*! Control whether error correcting mode (ECM) is allowed.
     \brief Control whether error correcting mode (ECM) is allowed.
index 3ca28c3d12a977d621b6b5a35fd2c55d202b91c7..a841177d6017d13e175b4bd7ffbe49f596522d74 100644 (file)
@@ -124,7 +124,7 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_st
 /*! \brief Get the next bit of data from a T.38 rate adapting non-ECM buffer context.
     \param user_data The buffer context, cast to a void pointer.
     \return The next bit, or one of the values indicating a change of modem status. */
-SPAN_DECLARE_NONSTD(int) t38_non_ecm_buffer_get_bit(void *user_data);
+SPAN_DECLARE(int) t38_non_ecm_buffer_get_bit(void *user_data);
 
 #if defined(__cplusplus)
 }
index 58a8e29c6a5dd29555c66e08b5057c8090309e1f..0d0f306fe1088db21f0f52fd0ea28913ae7a9d30 100644 (file)
 
 #if defined(_M_IX86)  ||  defined(_M_X64)
 #if defined(LIBSPANDSP_EXPORTS)
-#define SPAN_DECLARE(type)              __declspec(dllexport) type __stdcall
-#define SPAN_DECLARE_NONSTD(type)       __declspec(dllexport) type __cdecl
+#define SPAN_DECLARE(type)              __declspec(dllexport) type
 #define SPAN_DECLARE_DATA               __declspec(dllexport)
 #else
-#define SPAN_DECLARE(type)              __declspec(dllimport) type __stdcall
-#define SPAN_DECLARE_NONSTD(type)       __declspec(dllimport) type __cdecl
+#define SPAN_DECLARE(type)              __declspec(dllimport) type
 #define SPAN_DECLARE_DATA               __declspec(dllimport)
 #endif
 #elif defined(SPANDSP_USE_EXPORT_CAPABILITY)  &&  (defined(__GNUC__)  ||  defined(__SUNCC__))
 #define SPAN_DECLARE(type)              __attribute__((visibility("default"))) type
-#define SPAN_DECLARE_NONSTD(type)       __attribute__((visibility("default"))) type
 #define SPAN_DECLARE_DATA               __attribute__((visibility("default")))
 #else
 #define SPAN_DECLARE(type)              /**/ type
-#define SPAN_DECLARE_NONSTD(type)       /**/ type
 #define SPAN_DECLARE_DATA               /**/
 #endif
 
index 7fe140c21670fba1f5ddd707c13986538b14dd71..a3d1b5a893bf10fc1e5ad3cd7e54044c3fbdfdf0 100644 (file)
@@ -88,7 +88,7 @@ SPAN_DECLARE(tone_gen_descriptor_t *) tone_gen_descriptor_init(tone_gen_descript
 
 SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s);
 
-SPAN_DECLARE_NONSTD(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples);
+SPAN_DECLARE(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples);
 
 SPAN_DECLARE(tone_gen_state_t *) tone_gen_init(tone_gen_state_t *s, tone_gen_descriptor_t *t);
 
index 8aebe8526304d772611b003f2db29e39b3388e03..8f6c34993de114b09d37a2b0e63047a32e00d6e5 100644 (file)
@@ -284,7 +284,7 @@ SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_stat
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len);
 
 /*! Fake processing of a missing block of received V.17 modem audio samples.
     (e.g due to packet loss).
@@ -293,7 +293,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
     \param len The number of samples to fake.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len);
+SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len);
 
 /*! Get a snapshot of the current equalizer coefficients.
     \brief Get a snapshot of the current equalizer coefficients.
index 02fb7309ade7f38dff2a0b5223eeb12fbf88faa1..79d65629fc63cb5603f0856dd62d5ddf09a30840 100644 (file)
@@ -155,7 +155,7 @@ SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_stat
     \param len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len);
 
 #if defined(__cplusplus)
 }
index 04c0db7c154b4a56cd4222021af1698decdd3181..50aa5ab260b7c5b579ccaaf1a0fa401f8cd3593c 100644 (file)
@@ -143,7 +143,7 @@ SPAN_DECLARE(int) v18_free(v18_state_t *s);
     \param max_len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len);
+SPAN_DECLARE(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len);
 
 /*! Process a block of received V.18 audio samples.
     \brief Process a block of received V.18 audio samples.
@@ -152,7 +152,7 @@ SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len);
     \param len The number of samples in the buffer.
     \return The number of unprocessed samples.
 */
-SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v18_rx(v18_state_t *s, const int16_t amp[], int len);
 
 /*! Fake processing of a missing block of received V.18 audio samples.
     (e.g due to packet loss).
@@ -161,7 +161,7 @@ SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len);
     \param len The number of samples to fake.
     \return The number of unprocessed samples.
 */
-SPAN_DECLARE_NONSTD(int) v18_rx_fillin(v18_state_t *s, int len);
+SPAN_DECLARE(int) v18_rx_fillin(v18_state_t *s, int len);
 
 /*! \brief Put a string to a V.18 context's input buffer.
     \param s The V.18 context.
index 50b2fb44672e1ee876f893f77fb0ee61bb41027f..fd93373cec2c337d9c0ca929726b804c1059f0c5 100644 (file)
@@ -78,7 +78,7 @@ extern "C"
     \param amp The audio sample buffer.
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len);
 
 /*! Fake processing of a missing block of received V.22bis modem audio samples.
     (e.g due to packet loss).
@@ -86,7 +86,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
     \param s The modem context.
     \param len The number of samples to fake.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len);
+SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len);
 
 /*! Get a snapshot of the current equalizer coefficients.
     \brief Get a snapshot of the current equalizer coefficients.
@@ -130,7 +130,7 @@ SPAN_DECLARE(void) v22bis_rx_set_qam_report_handler(v22bis_state_t *s, qam_repor
     \param amp The audio sample buffer.
     \param len The number of samples to be generated.
     \return The number of samples actually generated. */
-SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len);
 
 /*! Adjust a V.22bis modem transmit context's power output.
     \brief Adjust a V.22bis modem transmit context's output power.
index 80fdb3655f551ff31b3970cba863a0f46b76e282..cf8eaa99f7b3ec13a598ef8161d091af64e112b2 100644 (file)
@@ -117,7 +117,7 @@ SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, mode
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len);
 
 /*! Fake processing of a missing block of received V.27ter modem audio samples.
     (e.g due to packet loss).
@@ -126,7 +126,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
     \param len The number of samples to fake.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE_NONSTD(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len);
+SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len);
 
 /*! Get a snapshot of the current equalizer coefficients.
     \brief Get a snapshot of the current equalizer coefficients.
index fba064fea01341374d232df2f81abb459ae416f3..96a0df5f54a3e3c140aeb7380e6dc70b0cfa4a55 100644 (file)
@@ -136,7 +136,7 @@ SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, mode
     \param len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len);
 
 #if defined(__cplusplus)
 }
index 378d4fe95539420360c83ab1b8df1f046be29f3c..9ef548e4c7875c90426de47cf9e5762b4ab949a1 100644 (file)
@@ -196,7 +196,7 @@ SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_stat
     \param amp The audio sample buffer.
     \param len The number of samples in the buffer.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len);
 
 /*! Fake processing of a missing block of received V.29 modem audio samples.
     (e.g due to packet loss).
@@ -204,7 +204,7 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
     \param s The modem context.
     \param len The number of samples to fake.
     \return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v29_rx_fillin(v29_rx_state_t *s, int len);
+SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len);
 
 /*! Get a snapshot of the current equalizer coefficients.
     \brief Get a snapshot of the current equalizer coefficients.
index 18bcf66b6ac3a19b76d447435e8f6dad4c45f6ec..6bdb5de9e7a46b7fcaaa699b554720dd41a09231 100644 (file)
@@ -167,7 +167,7 @@ SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_stat
     \param len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len);
 
 #if defined(__cplusplus)
 }
index 8002d43eed3116463c45bc9f16caeddbe5fa8335..fa1d7c1b5f57f8f221757c38486a02105978d88f 100644 (file)
@@ -45,7 +45,7 @@ extern "C"
 
 SPAN_DECLARE(const char *) lapm_status_to_str(int status);
 
-SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok);
+SPAN_DECLARE(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok);
 
 SPAN_DECLARE(void) v42_start(v42_state_t *s);
 
index 9ded271aec15b2aadaa316d162d8bc8466c8a3da..ab3d1466c5dba154dd375c52ee8a0b28e2b43435 100644 (file)
@@ -173,7 +173,7 @@ SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s);
     \param max_len The number of samples to be generated.
     \return The number of samples actually generated.
 */
-SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len);
+SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len);
 
 /*! Process a block of received V.8 audio samples.
     \brief Process a block of received V.8 audio samples.
@@ -181,7 +181,7 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len);
     \param amp The audio sample buffer.
     \param len The number of samples in the buffer.
 */
-SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len);
+SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len);
 
 /*! Log the list of supported modulations.
     \brief Log the list of supported modulations.
index 3a31893e3064c1c59123e29cd6042e8b53a37218..f13d4eb879460444286f3a43b9112f6dd45436cc 100644 (file)
@@ -6401,7 +6401,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) t30_non_ecm_put_bit(void *user_data, int bit)
+SPAN_DECLARE(void) t30_non_ecm_put_bit(void *user_data, int bit)
 {
     t30_state_t *s;
     int res;
@@ -6499,7 +6499,7 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t30_non_ecm_get_bit(void *user_data)
+SPAN_DECLARE(int) t30_non_ecm_get_bit(void *user_data)
 {
     int bit;
     t30_state_t *s;
@@ -6705,7 +6705,7 @@ static void t30_hdlc_rx_status(void *user_data, int status)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
+SPAN_DECLARE(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
 {
     t30_state_t *s;
 
index e63eb229e85ce97c0fd7a89fc06a3d854b5795c5..91e1e8063c4841eb4bc7cb974fb6c144a561b448 100644 (file)
@@ -2772,7 +2772,7 @@ static int initial_timed_rx(void *user_data, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) t31_rx(t31_state_t *s, int16_t amp[], int len)
 {
     int i;
     int32_t power;
@@ -2822,7 +2822,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len)
+SPAN_DECLARE(int) t31_rx_fillin(t31_state_t *s, int len)
 {
     /* To mitigate the effect of lost packets on a packet network we should
        try to sustain the status quo. If there is no receive modem running, keep
@@ -2848,7 +2848,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len)
+SPAN_DECLARE(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len)
 {
     int len;
 
index de13af3e11aa03b58bf26041a5f3a08e00e96f01..347549549f9b2479b5f7f2669f438d3ebc6d49f5 100644 (file)
@@ -347,7 +347,7 @@ static __inline__ int classify_seq_no_offset(int expected, int actual)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no)
+SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no)
 {
     int i;
     int t30_indicator;
@@ -668,7 +668,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no)
+SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no)
 {
     int log_seq_no;
     int ptr;
index 4467a615adc838bde52a8fe9853619df4a2a33ca..53c877e5919652fc85cd1bc03a09489e6a431833 100644 (file)
@@ -2134,7 +2134,7 @@ static void update_rx_timing(t38_gateway_state_t *s, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
 {
     int i;
 
@@ -2153,7 +2153,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
+SPAN_DECLARE(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
 {
     /* To mitigate the effect of lost packets on a packet network we should
        try to sustain the status quo. If there is no receive modem running, keep
@@ -2181,7 +2181,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len)
+SPAN_DECLARE(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len)
 {
     int len;
 #if defined(LOG_FAX_AUDIO)
index b5b2c8244b5248fb99a12927814e8d820a97bbaf..99fa456a967897cc0e833842b416231d28e51608 100644 (file)
@@ -85,7 +85,7 @@ static void restart_buffer(t38_non_ecm_buffer_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_non_ecm_buffer_get_bit(void *user_data)
+SPAN_DECLARE(int) t38_non_ecm_buffer_get_bit(void *user_data)
 {
     t38_non_ecm_buffer_state_t *s;
     int bit;
index be3f6854a432fb0d3a661b94955bef5ad8f2cb26..c01c970674e1e8342d1aa0dbc3582e24cc57db8d 100644 (file)
@@ -119,7 +119,7 @@ SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples)
+SPAN_DECLARE(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples)
 {
     int samples;
     int limit;
index aea4e5913d9c86f97ddfa03d549d00dba14af0f6..cda544990e2349a88d9d8fb99d3aa90c49cc77fa 100644 (file)
@@ -1229,7 +1229,7 @@ static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
 {
     int i;
     int step;
@@ -1341,7 +1341,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len)
+SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len)
 {
     int i;
 
index 4d3d8f999047b30a04dbcaee5039663239a1213a..a57bc9f7050e9cca2408949e800736b427ef61a5 100644 (file)
@@ -296,7 +296,7 @@ static __inline__ complexf_t getbaud(v17_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len)
 {
 #if defined(SPANDSP_USE_FIXED_POINT)
     complexi16_t v;
index 3b72b296e111294dff82c4d72b0b40fc12dbff9c..0f344157208570d6e0f7453c81ed50ec130e7525 100644 (file)
@@ -978,7 +978,7 @@ static void v18_textphone_put_async_byte(void *user_data, int byte)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len)
+SPAN_DECLARE(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len)
 {
     int len;
     int lenx;
@@ -1006,7 +1006,7 @@ SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v18_rx(v18_state_t *s, const int16_t amp[], int len)
 {
     if (s->rx_suppression > 0)
     {
@@ -1037,7 +1037,7 @@ SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v18_rx_fillin(v18_state_t *s, int len)
+SPAN_DECLARE(int) v18_rx_fillin(v18_state_t *s, int len)
 {
     if (s->rx_suppression > 0)
     {
index af922882a64d6efb9c49cc09344b895da92cee6a..cfb4e1378aaecc14144e000fa0b0dd375ff8b2ae 100644 (file)
@@ -776,7 +776,7 @@ static __inline__ void process_half_baud(v22bis_state_t *s, const complexf_t *sa
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
 {
     int i;
     int step;
@@ -919,7 +919,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
+SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
 {
     int i;
 
index 430ebc5d8486e71c20809b566fbe495039c9afe9..41afff55c770a6212bcf8e6afa265c57dbc24fb1 100644 (file)
@@ -469,7 +469,7 @@ static complexf_t getbaud(v22bis_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
 {
 #if defined(SPANDSP_USE_FIXED_POINT)
     complexi16_t v;
index 93d3b4680db6521513210ee93d24bf7c28d988d5..9383d46af088b2b7d1fe8de67bdf01ac6add3923 100644 (file)
@@ -828,7 +828,7 @@ static __inline__ int signal_detect(v27ter_rx_state_t *s, int16_t amp)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
 {
     int i;
     int step;
@@ -978,7 +978,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len)
+SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len)
 {
     int i;
 
index f6b69917bbc80d58ff711cc738ad552c2164675e..e0f2aaf1af5d3406ce36289dbac946233ac153e6 100644 (file)
@@ -241,7 +241,7 @@ static complexf_t getbaud(v27ter_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len)
 {
 #if defined(SPANDSP_USE_FIXED_POINT)
     complexi16_t v;
index da1ef0c909a40b141e0bd00bff8b3e65921b8631..4bed319246e315699b8aceff2d420c72e98f1669 100644 (file)
@@ -910,7 +910,7 @@ static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
 {
     int i;
     int step;
@@ -1026,7 +1026,7 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v29_rx_fillin(v29_rx_state_t *s, int len)
+SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len)
 {
     int i;
 
index c36027701dc533c76a66ac9cdc05c67c233d7b63..bef54364e80b3e90317fd1fd70b0b863da4b3351 100644 (file)
@@ -212,7 +212,7 @@ static __inline__ complexf_t getbaud(v29_tx_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len)
 {
 #if defined(SPANDSP_USE_FIXED_POINT)
     complexi16_t v;
index 44e6bd01d92bfce44cc3ad43b6156ade0ad081e4..4dac118f65bbfca74e916c451521f4196623fe33 100644 (file)
@@ -1065,7 +1065,7 @@ static void lapm_hdlc_underflow(void *user_data)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok)
+SPAN_DECLARE(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok)
 {
     lapm_state_t *s;
     v42_state_t *ss;
index 40cc6feac15377cd00811dbdc31eb6ec04fe633b..4c5dd43244c4d08a663cca508ca1ccb6d2372ff2 100644 (file)
@@ -734,7 +734,7 @@ static void send_cm_jm(v8_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
+SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
 {
     int len;
 
@@ -852,7 +852,7 @@ static void handle_modem_connect_tone(v8_state_t *s, int tone)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
+SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
 {
     int residual_samples;
     int tone;
index 47ee06aec363af784db705d6e3552812de3c3880..55d84e4d9940574f0213a4714dc868a274331776 100644 (file)
@@ -225,7 +225,7 @@ echo_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspand
 fax_decode_SOURCES = fax_decode.c
 fax_decode_LDADD = $(LIBDIR) -lspandsp
 
-fax_tests_SOURCES = fax_tests.c fax_utils.c media_monitor.cpp
+fax_tests_SOURCES = fax_tests.c fax_utils.c media_monitor.cpp fax_tester.c
 fax_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp
 
 fsk_tests_SOURCES = fsk_tests.c
index fb5dcc1ac1f0e986a6d7efe996b60a39ceb4e954..88859579728f6212bd2b3e1370cba958413074b6 100644 (file)
@@ -85,7 +85,7 @@ struct xml_node_parms_s
     xmlChar *compression;
 };
 
-static struct
+struct
 {
     const char *tag;
     int code;
@@ -162,16 +162,278 @@ static void timer_update(faxtester_state_t *s, int len)
     if (s->timer > s->timeout)
     {
         s->timeout = 0x7FFFFFFFFFFFFFFFLL;
-        if (s->front_end_step_timeout_handler)
-            s->front_end_step_timeout_handler(s, s->front_end_step_timeout_user_data);
+        span_log(&s->logging, SPAN_LOG_FLOW, "FAX tester step timed out\n");
+        printf("Test failed\n");
+        exit(2);
     }
 }
 /*- End of function --------------------------------------------------------*/
 
 static void front_end_step_complete(faxtester_state_t *s)
 {
-    if (s->front_end_step_complete_handler)
-        s->front_end_step_complete_handler(s, s->front_end_step_complete_user_data);
+    while (faxtester_next_step(s) == 0)
+        ;
+    /*endwhile*/
+}
+/*- End of function --------------------------------------------------------*/
+
+static int faxtester_phase_b_handler(void *user_data, int result)
+{
+    int ch;
+    int status;
+    faxtester_state_t *s;
+    const char *u;
+
+    s = (faxtester_state_t *) user_data;
+    ch = s->far_tag;
+    status = T30_ERR_OK;
+    if ((u = t30_get_rx_ident(s->far_t30)))
+    {
+        printf("%c: Phase B: remote ident '%s'\n", ch, u);
+        if (s->expected_rx_info.ident[0]  &&  strcmp(s->expected_rx_info.ident, u))
+        {
+            printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, s->expected_rx_info.ident);
+            status = T30_ERR_IDENT_UNACCEPTABLE;
+        }
+    }
+    else
+    {
+        if (s->expected_rx_info.ident[0])
+        {
+            printf("%c: Phase B: remote ident missing!\n", ch);
+            status = T30_ERR_IDENT_UNACCEPTABLE;
+        }
+    }
+    if ((u = t30_get_rx_sub_address(s->far_t30)))
+    {
+        printf("%c: Phase B: remote sub-address '%s'\n", ch, u);
+        if (s->expected_rx_info.sub_address[0]  &&  strcmp(s->expected_rx_info.sub_address, u))
+        {
+            printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, s->expected_rx_info.sub_address);
+            status = T30_ERR_SUB_UNACCEPTABLE;
+        }
+    }
+    else
+    {
+        if (s->expected_rx_info.sub_address[0])
+        {
+            printf("%c: Phase B: remote sub-address missing!\n", ch);
+            status = T30_ERR_SUB_UNACCEPTABLE;
+        }
+    }
+    if ((u = t30_get_rx_polled_sub_address(s->far_t30)))
+    {
+        printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u);
+        if (s->expected_rx_info.polled_sub_address[0]  &&  strcmp(s->expected_rx_info.polled_sub_address, u))
+        {
+            printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, s->expected_rx_info.polled_sub_address);
+            status = T30_ERR_PSA_UNACCEPTABLE;
+        }
+    }
+    else
+    {
+        if (s->expected_rx_info.polled_sub_address[0])
+        {
+            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->far_t30)))
+    {
+        printf("%c: Phase B: remote selective polling address '%s'\n", ch, u);
+        if (s->expected_rx_info.selective_polling_address[0]  &&  strcmp(s->expected_rx_info.selective_polling_address, u))
+        {
+            printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, s->expected_rx_info.selective_polling_address);
+            status = T30_ERR_SEP_UNACCEPTABLE;
+        }
+    }
+    else
+    {
+        if (s->expected_rx_info.selective_polling_address[0])
+        {
+            printf("%c: Phase B: remote selective polling address missing!\n", ch);
+            status = T30_ERR_SEP_UNACCEPTABLE;
+        }
+    }
+    if ((u = t30_get_rx_sender_ident(s->far_t30)))
+    {
+        printf("%c: Phase B: remote sender ident '%s'\n", ch, u);
+        if (s->expected_rx_info.sender_ident[0]  &&  strcmp(s->expected_rx_info.sender_ident, u))
+        {
+            printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, s->expected_rx_info.sender_ident);
+            status = T30_ERR_SID_UNACCEPTABLE;
+        }
+    }
+    else
+    {
+        if (s->expected_rx_info.sender_ident[0])
+        {
+            printf("%c: Phase B: remote sender ident missing!\n", ch);
+            status = T30_ERR_SID_UNACCEPTABLE;
+        }
+    }
+    if ((u = t30_get_rx_password(s->far_t30)))
+    {
+        printf("%c: Phase B: remote password '%s'\n", ch, u);
+        if (s->expected_rx_info.password[0]  &&  strcmp(s->expected_rx_info.password, u))
+        {
+            printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, s->expected_rx_info.password);
+            status = T30_ERR_PWD_UNACCEPTABLE;
+        }
+    }
+    else
+    {
+        if (s->expected_rx_info.password[0])
+        {
+            printf("%c: Phase B: remote password missing!\n", ch);
+            status = T30_ERR_PWD_UNACCEPTABLE;
+        }
+    }
+    printf("%c: Phase B handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
+    return status;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int faxtester_phase_d_handler(void *user_data, int result)
+{
+    int i;
+    int ch;
+    faxtester_state_t *s;
+    char tag[20];
+
+    s = (faxtester_state_t *) user_data;
+    ch = s->far_tag;
+    i = 0;
+    snprintf(tag, sizeof(tag), "%c: Phase D", ch);
+    printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
+    fax_log_page_transfer_statistics(s->far_t30, tag);
+    fax_log_tx_parameters(s->far_t30, tag);
+    fax_log_rx_parameters(s->far_t30, tag);
+
+    if (s->use_receiver_not_ready)
+        t30_set_receiver_not_ready(s->far_t30, 3);
+
+    if (s->test_local_interrupt)
+    {
+        if (i == 0)
+        {
+            printf("%c: Initiating interrupt request\n", ch);
+            t30_local_interrupt_request(s->far_t30, true);
+        }
+        else
+        {
+            switch (result)
+            {
+            case T30_PIP:
+            case T30_PRI_MPS:
+            case T30_PRI_EOM:
+            case T30_PRI_EOP:
+                printf("%c: Accepting interrupt request\n", ch);
+                t30_local_interrupt_request(s->far_t30, true);
+                break;
+            case T30_PIN:
+                break;
+            }
+        }
+    }
+    return T30_ERR_OK;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void faxtester_phase_e_handler(void *user_data, int result)
+{
+    int ch;
+    faxtester_state_t *s;
+    char tag[20];
+
+    s = (faxtester_state_t *) user_data;
+    ch = s->far_tag;
+    snprintf(tag, sizeof(tag), "%c: Phase E", ch);
+    printf("%c: Phase E handler on channel %c - (%d) %s\n", ch, ch, result, t30_completion_code_to_str(result));
+    fax_log_final_transfer_statistics(s->far_t30, tag);
+    fax_log_tx_parameters(s->far_t30, tag);
+    fax_log_rx_parameters(s->far_t30, tag);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t30_real_time_frame_handler(void *user_data,
+                                        bool incoming,
+                                        const uint8_t *msg,
+                                        int len)
+{
+    if (msg == NULL)
+    {
+    }
+    else
+    {
+        fprintf(stderr,
+                "T.30: Real time frame handler - %s, %s, length = %d\n",
+                (incoming)  ?  "line->T.30"  : "T.30->line",
+                t30_frametype(msg[2]),
+                len);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static int faxtester_document_handler(void *user_data, int event)
+{
+    int ch;
+    faxtester_state_t *s;
+    t30_state_t *t;
+
+    s = (faxtester_state_t *) user_data;
+    ch = s->far_tag;
+    t = s->far_t30;
+    fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event);
+    if (s->next_tx_file[0])
+    {
+        t30_set_tx_file(t, s->next_tx_file, -1, -1);
+        s->next_tx_file[0] = '\0';
+        return true;
+    }
+    return false;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void faxtester_real_time_frame_handler(faxtester_state_t *s,
+                                              int direction,
+                                              const uint8_t *msg,
+                                              int len)
+{
+    if (msg == NULL)
+    {
+        while (faxtester_next_step(s) == 0)
+            ;
+        /*endwhile*/
+    }
+    else
+    {
+        fprintf(stderr,
+                "TST: Real time frame handler - %s, %s, length = %d\n",
+                (direction)  ?  "line->tester"  : "tester->line",
+                t30_frametype(msg[2]),
+                len);
+        if (direction  &&  msg[1] == s->awaited[1])
+        {
+            if ((s->awaited_len >= 0  &&  len != abs(s->awaited_len))
+                ||
+                (s->awaited_len < 0  &&  len < abs(s->awaited_len))
+                ||
+                memcmp(msg, s->awaited, abs(s->awaited_len)) != 0)
+            {
+                span_log_buf(&s->logging, SPAN_LOG_FLOW, "Expected", s->awaited, abs(s->awaited_len));
+                span_log_buf(&s->logging, SPAN_LOG_FLOW, "Received", msg, len);
+                printf("Test failed\n");
+                exit(2);
+            }
+        }
+        if (msg[1] == s->awaited[1])
+        {
+            while (faxtester_next_step(s) == 0)
+                ;
+            /*endwhile*/
+        }
+    }
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -295,29 +557,17 @@ static int non_ecm_get_bit(void *user_data)
 }
 /*- End of function --------------------------------------------------------*/
 
-void faxtester_set_non_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len)
+static void faxtester_set_ecm_image_buffer(faxtester_state_t *s, int block, int frame_size, int crc_hit)
 {
-    s->image_ptr = 0;
-    s->image_bit_ptr = 8;
-    s->image_len = len;
-    s->image_buffer = buf;
-}
-/*- End of function --------------------------------------------------------*/
-
-void faxtester_set_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len, int block, int frame_size, int crc_hit)
-{
-    int start;
-
-    start = 256*frame_size*block;
-    if (len > start + 256*frame_size)
-        len = start + 256*frame_size;
+    s->image_ptr = 256*frame_size*block;
+    if (s->image_len > s->image_ptr + 256*frame_size)
+        s->image_len = s->image_ptr + 256*frame_size;
 
     s->ecm_frame_size = frame_size;
-    s->image_ptr = start;
     s->image_bit_ptr = 8;
-    s->image_len = len;
-    s->image_buffer = buf;
     s->corrupt_crc = crc_hit;
+    s->image_buffer = s->image;
+
     /* Send the first frame */
     hdlc_underflow_handler(s);
 }
@@ -343,10 +593,7 @@ static void non_ecm_rx_status(void *user_data, int status)
         break;
     case SIG_STATUS_CARRIER_DOWN:
         if (s->modems.rx_trained)
-        {
-            if (s->real_time_frame_handler)
-                s->real_time_frame_handler(s, s->real_time_frame_user_data, true, NULL, 0);
-        }
+            faxtester_real_time_frame_handler(s, true, NULL, 0);
         s->modems.rx_signal_present = false;
         s->modems.rx_trained = false;
         break;
@@ -400,8 +647,7 @@ static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
         return;
     }
     s = (faxtester_state_t *) user_data;
-    if (s->real_time_frame_handler)
-        s->real_time_frame_handler(s, s->real_time_frame_user_data, true, msg, len);
+    faxtester_real_time_frame_handler(s, true, msg, len);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -546,7 +792,7 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr
         break;
     case T30_MODEM_CED:
     case T30_MODEM_CNG:
-        tone = (type == T30_MODEM_CED)  ?  MODEM_CONNECT_TONES_FAX_CED  :  MODEM_CONNECT_TONES_FAX_CNG;
+        tone = (type == T30_MODEM_CED)  ?  FAX_MODEM_CED_TONE_TX  :  FAX_MODEM_CNG_TONE_TX;
         fax_modems_start_slow_modem(t, tone);
         s->transmit = true;
         break;
@@ -613,34 +859,996 @@ void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep)
 }
 /*- End of function --------------------------------------------------------*/
 
-void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t handler, void *user_data)
+static void corrupt_image(faxtester_state_t *s, const char *bad_rows)
+{
+    int i;
+    int j;
+    int k;
+    uint32_t bits;
+    uint32_t bitsx;
+    int list[1000];
+    int x;
+    int row;
+    const char *t;
+
+    /* Form the list of rows to be hit */
+    x = 0;
+    t = bad_rows;
+    while (*t)
+    {
+        while (isspace((int) *t))
+            t++;
+        if (sscanf(t, "%d", &list[x]) < 1)
+            break;
+        x++;
+        while (isdigit((int) *t))
+            t++;
+        if (*t == ',')
+            t++;
+    }
+
+    /* Go through the image, and corrupt the first bit of every listed row */
+    bits = 0x7FF;
+    bitsx = 0x7FF;
+    row = 0;
+    for (i = 0;  i < s->image_len;  i++)
+    {
+        bits ^= (s->image[i] << 11);
+        bitsx ^= (s->image[i] << 11);
+        for (j = 0;  j < 8;  j++)
+        {
+            if ((bits & 0xFFF) == 0x800)
+            {
+                /* We are at an EOL. Is this row in the list of rows to be corrupted? */
+                row++;
+                for (k = 0;  k < x;  k++)
+                {
+                    if (list[k] == row)
+                    {
+                        /* Corrupt this row. TSB85 says to hit the first bit after the EOL */
+                        bitsx ^= 0x1000;
+                    }
+                }
+            }
+            bits >>= 1;
+            bitsx >>= 1;
+        }
+        s->image[i] = (bitsx >> 3) & 0xFF;
+    }
+    span_log(&s->logging, SPAN_LOG_FLOW, "%d rows found. %d corrupted\n", row, x);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int string_to_msg(uint8_t msg[], uint8_t mask[], const char buf[])
+{
+    int i;
+    int x;
+    const char *t;
+
+    msg[0] = 0;
+    mask[0] = 0xFF;
+    i = 0;
+    t = (char *) buf;
+    while (*t)
+    {
+        /* Skip white space */
+        while (isspace((int) *t))
+            t++;
+        /* If we find ... we allow arbitrary additional info beyond this point in the message */
+        if (t[0] == '.'  &&  t[1] == '.'  &&  t[2] == '.')
+        {
+            return -i;
+        }
+        else if (isxdigit((int) *t))
+        {
+            for (  ;  isxdigit((int) *t);  t++)
+            {
+                x = *t;
+                if (x >= 'a')
+                    x -= 0x20;
+                if (x >= 'A')
+                    x -= ('A' - 10);
+                else
+                    x -= '0';
+                msg[i] = (msg[i] << 4) | x;
+            }
+            mask[i] = 0xFF;
+            if (*t == '/')
+            {
+                /* There is a mask following the byte */
+                mask[i] = 0;
+                for (t++;  isxdigit((int) *t);  t++)
+                {
+                    x = *t;
+                    if (x >= 'a')
+                        x -= 0x20;
+                    if (x >= 'A')
+                        x -= ('A' - 10);
+                    else
+                        x -= '0';
+                    mask[i] = (mask[i] << 4) | x;
+                }
+            }
+            if (*t  &&  !isspace((int) *t))
+            {
+                /* Bad string */
+                return 0;
+            }
+            i++;
+        }
+    }
+    return i;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data)
+{
+    s->flush_handler = handler;
+    s->flush_user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void fax_prepare(faxtester_state_t *s)
+{
+    if (s->far_fax)
+    {
+        fax_set_transmit_on_idle(s->far_fax, true);
+        fax_set_tep_mode(s->far_fax, true);
+    }
+#if 0
+    t30_set_tx_ident(s->far_t30, "1234567890");
+    t30_set_tx_sub_address(s->far_t30, "Sub-address");
+    t30_set_tx_sender_ident(s->far_t30, "Sender ID");
+    t30_set_tx_password(s->far_t30, "Password");
+    t30_set_tx_polled_sub_address(s->far_t30, "Polled sub-address");
+    t30_set_tx_selective_polling_address(s->far_t30, "Sel polling address");
+#endif
+    t30_set_tx_nsf(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSF\x00", 16);
+    //t30_set_tx_nss(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSS\x00", 16);
+    t30_set_tx_nsc(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSC\x00", 16);
+    t30_set_ecm_capability(s->far_t30, true);
+    t30_set_supported_t30_features(s->far_t30,
+                                   T30_SUPPORT_IDENTIFICATION
+                                 | T30_SUPPORT_SELECTIVE_POLLING
+                                 | T30_SUPPORT_SUB_ADDRESSING);
+    t30_set_supported_image_sizes(s->far_t30,
+                                  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);
+    t30_set_supported_bilevel_resolutions(s->far_t30,
+                                          T4_RESOLUTION_R8_STANDARD
+                                        | T4_RESOLUTION_R8_FINE
+                                        | T4_RESOLUTION_R8_SUPERFINE
+                                        | T4_RESOLUTION_R16_SUPERFINE
+                                        | T4_RESOLUTION_100_100
+                                        | 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);
+    t30_set_supported_colour_resolutions(s->far_t30, 0);
+    t30_set_supported_modems(s->far_t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
+    t30_set_supported_compressions(s->far_t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6);
+    t30_set_phase_b_handler(s->far_t30, faxtester_phase_b_handler, (void *) s);
+    t30_set_phase_d_handler(s->far_t30, faxtester_phase_d_handler, (void *) s);
+    t30_set_phase_e_handler(s->far_t30, faxtester_phase_e_handler, (void *) s);
+    t30_set_real_time_frame_handler(s->far_t30, t30_real_time_frame_handler, (void *) s);
+    t30_set_document_handler(s->far_t30, faxtester_document_handler, (void *) s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void get_node_parms(struct xml_node_parms_s *parms, xmlNodePtr node)
+{
+    parms->dir = xmlGetProp(node, (const xmlChar *) "dir");
+    parms->type = xmlGetProp(node, (const xmlChar *) "type");
+    parms->modem = xmlGetProp(node, (const xmlChar *) "modem");
+    parms->value = xmlGetProp(node, (const xmlChar *) "value");
+    parms->tag = xmlGetProp(node, (const xmlChar *) "tag");
+    parms->bad_rows = xmlGetProp(node, (const xmlChar *) "bad_rows");
+    parms->crc_error = xmlGetProp(node, (const xmlChar *) "crc_error");
+    parms->pattern = xmlGetProp(node, (const xmlChar *) "pattern");
+    parms->timein = xmlGetProp(node, (const xmlChar *) "timein");
+    parms->timeout = xmlGetProp(node, (const xmlChar *) "timeout");
+    parms->min_bits = xmlGetProp(node, (const xmlChar *) "min_bits");
+    parms->frame_size = xmlGetProp(node, (const xmlChar *) "frame_size");
+    parms->block = xmlGetProp(node, (const xmlChar *) "block");
+    parms->compression = xmlGetProp(node, (const xmlChar *) "compression");
+}
+/*- End of function --------------------------------------------------------*/
+
+static void free_node_parms(struct xml_node_parms_s *parms)
+{
+    if (parms->dir)
+        xmlFree(parms->dir);
+    if (parms->type)
+        xmlFree(parms->type);
+    if (parms->modem)
+        xmlFree(parms->modem);
+    if (parms->value)
+        xmlFree(parms->value);
+    if (parms->tag)
+        xmlFree(parms->tag);
+    if (parms->bad_rows)
+        xmlFree(parms->bad_rows);
+    if (parms->crc_error)
+        xmlFree(parms->crc_error);
+    if (parms->pattern)
+        xmlFree(parms->pattern);
+    if (parms->timein)
+        xmlFree(parms->timein);
+    if (parms->timeout)
+        xmlFree(parms->timeout);
+    if (parms->min_bits)
+        xmlFree(parms->min_bits);
+    if (parms->frame_size)
+        xmlFree(parms->frame_size);
+    if (parms->block)
+        xmlFree(parms->block);
+    if (parms->compression)
+        xmlFree(parms->compression);
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(int) faxtester_next_step(faxtester_state_t *s)
+{
+    int delay;
+    int flags;
+    struct xml_node_parms_s parms;
+    uint8_t buf[1000];
+    uint8_t mask[1000];
+    char path[1024];
+    int i;
+    int j;
+    int hdlc;
+    int short_train;
+    int min_row_bits;
+    int ecm_frame_size;
+    int ecm_block;
+    int compression_type;
+    xmlChar *min;
+    xmlChar *max;
+    t4_tx_state_t t4_tx_state;
+    t30_stats_t t30_stats;
+
+    s->test_for_call_clear = false;
+    if (s->cur == NULL)
+    {
+        if (!s->final_delayed)
+        {
+            /* Add a bit of waiting at the end, to ensure everything gets flushed through,
+               any timers can expire, etc. */
+            faxtester_set_timeout(s, -1);
+            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+            faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, 120000, false);
+            s->final_delayed = true;
+            return 1;
+        }
+        /* Finished */
+        printf("Test passed\n");
+        exit(0);
+    }
+    for (;;)
+    {
+        if (s->cur == NULL)
+        {
+            if (s->repeat_parent == NULL)
+            {
+                /* Finished */
+                printf("Test passed\n");
+                exit(0);
+            }
+            if (++s->repeat_count > s->repeat_max)
+            {
+                /* Finished */
+                printf("Too many repeats\n");
+                printf("Test failed\n");
+                exit(0);
+            }
+            if (s->repeat_count < s->repeat_min)
+            {
+                s->cur = s->repeat_start;
+            }
+            else
+            {
+                s->cur = s->repeat_parent->next;
+                s->repeat_parent = NULL;
+            }
+        }
+        if (xmlStrcmp(s->cur->name, (const xmlChar *) "step") == 0)
+        {
+            break;
+        }
+        if (s->repeat_parent == NULL  &&  xmlStrcmp(s->cur->name, (const xmlChar *) "repeat") == 0)
+        {
+            min = xmlGetProp(s->cur, (const xmlChar *) "min");
+            max = xmlGetProp(s->cur, (const xmlChar *) "max");
+            s->repeat_min = min  ?  atoi((const char *) min)  :  0;
+            s->repeat_max = max  ?  atoi((const char *) max)  :  INT_MAX;
+            s->repeat_count = 0;
+            if (min)
+                xmlFree(min);
+            if (max)
+                xmlFree(max);
+            if (s->repeat_min > 0)
+            {
+                s->repeat_parent = s->cur;
+                s->repeat_start =
+                s->cur = s->cur->xmlChildrenNode;
+                continue;
+            }
+        }
+        s->cur = s->cur->next;
+    }
+
+    get_node_parms(&parms, s->cur);
+
+    s->cur = s->cur->next;
+
+    span_log(&s->logging,
+             SPAN_LOG_FLOW,
+             "Dir - %s, type - %s, modem - %s, value - %s, timein - %s, timeout - %s, tag - %s\n",
+             (parms.dir)  ?  (const char *) parms.dir  :  " ",
+             (parms.type)  ?  (const char *) parms.type  :  "",
+             (parms.modem)  ?  (const char *) parms.modem  :  "",
+             (parms.value)  ?  (const char *) parms.value  :  "",
+             (parms.timein)  ?  (const char *) parms.timein  :  "",
+             (parms.timeout)  ?  (const char *) parms.timeout  :  "",
+             (parms.tag)  ?  (const char *) parms.tag  :  "");
+    if (parms.type == NULL)
+    {
+        free_node_parms(&parms);
+        return 1;
+    }
+    s->timein_x = (parms.timein)  ?  atoi((const char *) parms.timein)  :  -1;
+    s->timeout_x = (parms.timeout)  ?  atoi((const char *) parms.timeout)  :  -1;
+
+    if (parms.dir  &&  strcasecmp((const char *) parms.dir, "R") == 0)
+    {
+        /* Receive always has a timeout applied. */
+        if (s->timeout_x < 0)
+            s->timeout_x = 7000;
+        faxtester_set_timeout(s, s->timeout_x);
+        if (parms.modem)
+        {
+            hdlc = (strcasecmp((const char *) parms.type, "PREAMBLE") == 0);
+            short_train = (strcasecmp((const char *) parms.type, "TCF") != 0);
+            faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
+            if (strcasecmp((const char *) parms.modem, "V.21") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V21, 300, false, true);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/14400") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/12000") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/9600") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/7200") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.29/9600") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V29, 9600, false, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.29/7200") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V29, 7200, false, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.27ter/4800") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.27ter/2400") == 0)
+            {
+                faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
+            }
+            else
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
+            }
+        }
+
+        if (strcasecmp((const char *) parms.type, "SET") == 0)
+        {
+            if (strcasecmp((const char *) parms.tag, "IDENT") == 0)
+                strcpy(s->expected_rx_info.ident, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "SUB") == 0)
+                strcpy(s->expected_rx_info.sub_address, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "SEP") == 0)
+                strcpy(s->expected_rx_info.selective_polling_address, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "PSA") == 0)
+                strcpy(s->expected_rx_info.polled_sub_address, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "SID") == 0)
+                strcpy(s->expected_rx_info.sender_ident, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "PWD") == 0)
+                strcpy(s->expected_rx_info.password, (const char *) parms.value);
+            free_node_parms(&parms);
+            return 0;
+        }
+        else if (strcasecmp((const char *) parms.type, "CNG") == 0)
+        {
+            /* Look for CNG */
+            faxtester_set_rx_type(s, T30_MODEM_CNG, 0, false, false);
+            faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
+        }
+        else if (strcasecmp((const char *) parms.type, "CED") == 0)
+        {
+            /* Look for CED */
+            faxtester_set_rx_type(s, T30_MODEM_CED, 0, false, false);
+            faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
+        }
+        else if (strcasecmp((const char *) parms.type, "HDLC") == 0)
+        {
+            i = string_to_msg(buf, mask, (const char *) parms.value);
+            bit_reverse(s->awaited, buf, abs(i));
+            s->awaited_len = i;
+        }
+        else if (strcasecmp((const char *) parms.type, "TCF") == 0)
+        {
+        }
+        else if (strcasecmp((const char *) parms.type, "MSG") == 0)
+        {
+        }
+        else if (strcasecmp((const char *) parms.type, "PP") == 0)
+        {
+        }
+        else if (strcasecmp((const char *) parms.type, "SILENCE") == 0)
+        {
+            faxtest_set_rx_silence(s);
+        }
+        else if (strcasecmp((const char *) parms.type, "CLEAR") == 0)
+        {
+            span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n");
+            s->test_for_call_clear = true;
+            s->call_clear_timer = 0;
+        }
+        else
+        {
+            span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) parms.type);
+            free_node_parms(&parms);
+            return 0;
+        }
+    }
+    else
+    {
+        faxtester_set_timeout(s, s->timeout_x);
+        if (parms.modem)
+        {
+            hdlc = (strcasecmp((const char *) parms.type, "PREAMBLE") == 0);
+            short_train = (strcasecmp((const char *) parms.type, "TCF") != 0);
+            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+            if (strcasecmp((const char *) parms.modem, "V.21") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V21, 300, false, true);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/14400") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/12000") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/9600") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.17/7200") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.29/9600") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V29, 9600, false, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.29/7200") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V29, 7200, false, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.27ter/4800") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
+            }
+            else if (strcasecmp((const char *) parms.modem, "V.27ter/2400") == 0)
+            {
+                faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
+            }
+            else
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
+            }
+        }
+
+        if (strcasecmp((const char *) parms.type, "SET") == 0)
+        {
+            if (strcasecmp((const char *) parms.tag, "IDENT") == 0)
+                t30_set_tx_ident(s->far_t30, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "SUB") == 0)
+                t30_set_tx_sub_address(s->far_t30, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "SEP") == 0)
+                t30_set_tx_selective_polling_address(s->far_t30, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "PSA") == 0)
+                t30_set_tx_polled_sub_address(s->far_t30, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "SID") == 0)
+                t30_set_tx_sender_ident(s->far_t30, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "PWD") == 0)
+                t30_set_tx_password(s->far_t30, (const char *) parms.value);
+            else if (strcasecmp((const char *) parms.tag, "RXFILE") == 0)
+            {
+                if (parms.value)
+                    t30_set_rx_file(s->far_t30, (const char *) parms.value, -1);
+                else
+                    t30_set_rx_file(s->far_t30, output_tiff_file_name, -1);
+            }
+            else if (strcasecmp((const char *) parms.tag, "TXFILE") == 0)
+            {
+                sprintf(s->next_tx_file, "%s/%s", s->image_path, (const char *) parms.value);
+                printf("Push '%s'\n", s->next_tx_file);
+            }
+            free_node_parms(&parms);
+            return 0;
+        }
+        else if (strcasecmp((const char *) parms.type, "CALL") == 0)
+        {
+            if (s->far_fax)
+                fax_restart(s->far_fax, false);
+            else
+                t38_terminal_restart(s->far_t38, false);
+            fax_prepare(s);
+            s->next_tx_file[0] = '\0';
+            t30_set_rx_file(s->far_t30, output_tiff_file_name, -1);
+            /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
+            t30_set_supported_output_compressions(s->far_t30, T4_COMPRESSION_T4_1D);
+            if (parms.value)
+            {
+                sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+                t30_set_tx_file(s->far_t30, path, -1, -1);
+            }
+            free_node_parms(&parms);
+            return 0;
+        }
+        else if (strcasecmp((const char *) parms.type, "ANSWER") == 0)
+        {
+            if (s->far_fax)
+                fax_restart(s->far_fax, true);
+            else
+                t38_terminal_restart(s->far_t38, true);
+            fax_prepare(s);
+            s->next_tx_file[0] = '\0';
+            /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
+            t30_set_supported_output_compressions(s->far_t30, T4_COMPRESSION_T4_1D);
+            if (parms.value)
+            {
+                sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+                t30_set_tx_file(s->far_t30, path, -1, -1);
+            }
+            free_node_parms(&parms);
+            return 0;
+        }
+        else if (strcasecmp((const char *) parms.type, "CNG") == 0)
+        {
+            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+            faxtester_set_tx_type(s, T30_MODEM_CNG, 0, false, false);
+        }
+        else if (strcasecmp((const char *) parms.type, "CED") == 0)
+        {
+            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+            faxtester_set_tx_type(s, T30_MODEM_CED, 0, false, false);
+        }
+        else if (strcasecmp((const char *) parms.type, "WAIT") == 0)
+        {
+            delay = (parms.value)  ?  atoi((const char *) parms.value)  :  1;
+            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+            faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, delay, false);
+        }
+        else if (strcasecmp((const char *) parms.type, "PREAMBLE") == 0)
+        {
+            flags = (parms.value)  ?  atoi((const char *) parms.value)  :  37;
+            faxtester_send_hdlc_flags(s, flags);
+        }
+        else if (strcasecmp((const char *) parms.type, "POSTAMBLE") == 0)
+        {
+            flags = (parms.value)  ?  atoi((const char *) parms.value)  :  5;
+            faxtester_send_hdlc_flags(s, flags);
+        }
+        else if (strcasecmp((const char *) parms.type, "HDLC") == 0)
+        {
+            i = string_to_msg(buf, mask, (const char *) parms.value);
+            bit_reverse(buf, buf, abs(i));
+            if (parms.crc_error  &&  strcasecmp((const char *) parms.crc_error, "0") == 0)
+                faxtester_send_hdlc_msg(s, buf, abs(i), false);
+            else
+                faxtester_send_hdlc_msg(s, buf, abs(i), true);
+        }
+        else if (strcasecmp((const char *) parms.type, "TCF") == 0)
+        {
+            i = (parms.value)  ?  atoi((const char *) parms.value)  :  450;
+            if (parms.pattern)
+            {
+                /* TODO: implement proper patterns */
+                j = atoi((const char *) parms.pattern);
+                memset(s->image, 0x55, j);
+                if (i > j)
+                    memset(s->image + j, 0, i - j);
+            }
+            else
+            {
+                memset(s->image, 0, i);
+            }
+            s->image_ptr = 0;
+            s->image_bit_ptr = 8;
+            s->image_buffer = s->image;
+            s->image_len = i;
+        }
+        else if (strcasecmp((const char *) parms.type, "MSG") == 0)
+        {
+            /* A non-ECM page */
+            min_row_bits = (parms.min_bits)  ?  atoi((const char *) parms.min_bits)  :  0;
+            sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+            if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
+                printf("Test failed\n");
+                exit(2);
+            }
+            t4_tx_set_header_info(&t4_tx_state, NULL);
+            compression_type = T4_COMPRESSION_T4_1D;
+            if (parms.compression)
+            {
+                if (strcasecmp((const char *) parms.compression, "T.4 1D") == 0)
+                    compression_type = T4_COMPRESSION_T4_1D;
+                else if (strcasecmp((const char *) parms.compression, "T.4 2D") == 0)
+                    compression_type = T4_COMPRESSION_T4_2D;
+                else if (strcasecmp((const char *) parms.compression, "T.6") == 0)
+                    compression_type = T4_COMPRESSION_T6;
+                else if (strcasecmp((const char *) parms.compression, "T.85") == 0)
+                    compression_type = T4_COMPRESSION_T85;
+            }
+            if (t4_tx_set_tx_image_format(&t4_tx_state,
+                                          compression_type,
+                                          T4_SUPPORT_WIDTH_215MM
+                                        | T4_SUPPORT_LENGTH_US_LETTER
+                                        | T4_SUPPORT_LENGTH_US_LEGAL
+                                        | T4_SUPPORT_LENGTH_UNLIMITED,
+                                          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,
+                                          T4_RESOLUTION_100_100
+                                        | T4_RESOLUTION_200_200
+                                        | T4_RESOLUTION_300_300
+                                        | T4_RESOLUTION_400_400
+                                        | T4_RESOLUTION_600_600
+                                        | T4_RESOLUTION_1200_1200) < 0)
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
+                printf("Test failed\n");
+                exit(2);
+            }
+            t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
+            if (t4_tx_start_page(&t4_tx_state))
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
+                printf("Test failed\n");
+                exit(2);
+            }
+            s->image_len = t4_tx_get(&t4_tx_state, s->image, sizeof(s->image));
+            if (parms.bad_rows)
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
+                corrupt_image(s, (const char *) parms.bad_rows);
+            }
+            t4_tx_release(&t4_tx_state);
+            span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM image is %d bytes (min row bits %d)\n", s->image_len, min_row_bits);
+            s->image_ptr = 0;
+            s->image_bit_ptr = 8;
+            s->image_buffer = s->image;
+        }
+        else if (strcasecmp((const char *) parms.type, "PP") == 0)
+        {
+            min_row_bits = (parms.min_bits)  ?  atoi((const char *) parms.min_bits)  :  0;
+            ecm_block = (parms.block)  ?  atoi((const char *) parms.block)  :  0;
+            ecm_frame_size = (parms.frame_size)  ?  atoi((const char *) parms.frame_size)  :  64;
+            i = (parms.crc_error)  ?  atoi((const char *) parms.crc_error)  :  -1;
+            sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+            if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
+                printf("Test failed\n");
+                exit(2);
+            }
+            t4_tx_set_header_info(&t4_tx_state, NULL);
+            compression_type = T4_COMPRESSION_T4_1D;
+            if (parms.compression)
+            {
+                if (strcasecmp((const char *) parms.compression, "T.4 1D") == 0)
+                    compression_type = T4_COMPRESSION_T4_1D;
+                else if (strcasecmp((const char *) parms.compression, "T.4 2D") == 0)
+                    compression_type = T4_COMPRESSION_T4_2D;
+                else if (strcasecmp((const char *) parms.compression, "T.6") == 0)
+                    compression_type = T4_COMPRESSION_T6;
+                else if (strcasecmp((const char *) parms.compression, "T.85") == 0)
+                    compression_type = T4_COMPRESSION_T85;
+            }
+            if (t4_tx_set_tx_image_format(&t4_tx_state,
+                                          compression_type,
+                                          T4_SUPPORT_WIDTH_215MM
+                                        | T4_SUPPORT_LENGTH_US_LETTER
+                                        | T4_SUPPORT_LENGTH_US_LEGAL
+                                        | T4_SUPPORT_LENGTH_UNLIMITED,
+                                          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,
+                                          T4_RESOLUTION_100_100
+                                        | T4_RESOLUTION_200_200
+                                        | T4_RESOLUTION_300_300
+                                        | T4_RESOLUTION_400_400
+                                        | T4_RESOLUTION_600_600
+                                        | T4_RESOLUTION_1200_1200) < 0)
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
+                printf("Test failed\n");
+                exit(2);
+            }
+            t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
+            if (t4_tx_start_page(&t4_tx_state))
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
+                printf("Test failed\n");
+                exit(2);
+            }
+            /*endif*/
+            s->image_len = t4_tx_get(&t4_tx_state, s->image, sizeof(s->image));
+            if (parms.bad_rows)
+            {
+                span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
+                corrupt_image(s, (const char *) parms.bad_rows);
+            }
+            /*endif*/
+            t4_tx_release(&t4_tx_state);
+            span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", s->image_len, min_row_bits);
+            faxtester_set_ecm_image_buffer(s, ecm_block, ecm_frame_size, i);
+        }
+        else if (strcasecmp((const char *) parms.type, "CLEAR") == 0)
+        {
+            span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n");
+            t30_terminate(s->far_t30);
+            free_node_parms(&parms);
+            return 0;
+        }
+        else if (strcasecmp((const char *) parms.type, "STATUS") == 0)
+        {
+            if (parms.value)
+            {
+                for (i = 0;  t30_status[i].code >= 0;  i++)
+                {
+                    if (strcmp(t30_status[i].tag, (const char *) parms.value) == 0)
+                        break;
+                }
+                if (t30_status[i].code >= 0)
+                    delay = t30_status[i].code;
+                else
+                    delay = atoi((const char *) parms.value);
+                t30_get_transfer_statistics(s->far_t30, &t30_stats);
+                if (delay == t30_stats.current_status)
+                    span_log(&s->logging, SPAN_LOG_FLOW, "Expected status (%s) found\n", t30_status[i].tag);
+                else
+                    span_log(&s->logging, SPAN_LOG_FLOW, "Expected status %s, but found %s (%d)\n", t30_status[i].tag, t30_status[t30_stats.current_status].tag, t30_stats.current_status);
+                if (delay != t30_stats.current_status)
+                {
+                    printf("Test failed\n");
+                    exit(2);
+                }
+            }
+            free_node_parms(&parms);
+            return 0;
+        }
+        else
+        {
+            span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) parms.type);
+            free_node_parms(&parms);
+            return 0;
+        }
+        /*endif*/
+    }
+    /*endif*/
+    free_node_parms(&parms);
+    return 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int parse_config(faxtester_state_t *s, xmlNodePtr cur)
 {
-    s->real_time_frame_handler = handler;
-    s->real_time_frame_user_data = user_data;
+    xmlChar *x;
+    xmlChar *y;
+
+    while (cur)
+    {
+        if (xmlStrcmp(cur->name, (const xmlChar *) "path") == 0)
+        {
+            x = NULL;
+            y = NULL;
+            if ((x = xmlGetProp(cur, (const xmlChar *) "type"))
+                &&
+                (y = xmlGetProp(cur, (const xmlChar *) "value")))
+            {
+                if (strcasecmp((const char *) x, "IMAGE") == 0)
+                {
+                    span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s' '%s'\n", (char *) x, (char *) y);
+                    strcpy(s->image_path, (const char *) y);
+                }
+                /*endif*/
+            }
+            /*endif*/
+            if (x)
+                xmlFree(x);
+            /*endif*/
+            if (y)
+                xmlFree(y);
+            /*endif*/
+        }
+        /*endif*/
+        cur = cur->next;
+    }
+    /*endwhile*/
+    return -1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int parse_test_group(faxtester_state_t *s, xmlNodePtr cur, const char *test)
+{
+    xmlChar *x;
+
+    while (cur)
+    {
+        if (xmlStrcmp(cur->name, (const xmlChar *) "test") == 0)
+        {
+            if ((x = xmlGetProp(cur, (const xmlChar *) "name")))
+            {
+                if (xmlStrcmp(x, (const xmlChar *) test) == 0)
+                {
+                    span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s'\n", (char *) x);
+                    s->cur = cur->xmlChildrenNode;
+                    xmlFree(x);
+                    return 0;
+                }
+                /*endif*/
+                xmlFree(x);
+            }
+            /*endif*/
+        }
+        /*endif*/
+        cur = cur->next;
+    }
+    /*endwhile*/
+    return -1;
 }
 /*- End of function --------------------------------------------------------*/
 
-void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data)
+static int get_test_set(faxtester_state_t *s, const char *test_file, const char *test)
 {
-    s->front_end_step_complete_handler = handler;
-    s->front_end_step_complete_user_data = user_data;
+    xmlParserCtxtPtr ctxt;
+    xmlNodePtr cur;
+
+    if ((ctxt = xmlNewParserCtxt()) == NULL)
+    {
+        fprintf(stderr, "Failed to allocate XML parser context\n");
+        return -1;
+    }
+    /* parse the file, activating the DTD validation option */
+    if ((s->doc = xmlCtxtReadFile(ctxt, test_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
+    {
+        fprintf(stderr, "Failed to read the XML document\n");
+        return -1;
+    }
+    if (ctxt->valid == 0)
+    {
+        fprintf(stderr, "Failed to validate the XML document\n");
+       xmlFreeDoc(s->doc);
+        s->doc = NULL;
+        xmlFreeParserCtxt(ctxt);
+        return -1;
+    }
+    xmlFreeParserCtxt(ctxt);
+
+    /* Check the document is of the right kind */
+    if ((cur = xmlDocGetRootElement(s->doc)) == NULL)
+    {
+        xmlFreeDoc(s->doc);
+        s->doc = NULL;
+        fprintf(stderr, "Empty document\n");
+        return -1;
+    }
+    /*endif*/
+    if (xmlStrcmp(cur->name, (const xmlChar *) "fax-tests"))
+    {
+        xmlFreeDoc(s->doc);
+        s->doc = NULL;
+        fprintf(stderr, "Document of the wrong type, root node != fax-tests\n");
+        return -1;
+    }
+    /*endif*/
+    cur = cur->xmlChildrenNode;
+    while (cur  &&  xmlIsBlankNode(cur))
+        cur = cur->next;
+    /*endwhile*/
+    if (cur == NULL)
+    {
+        fprintf(stderr, "XML test not found\n");
+        return -1;
+    }
+    /*endif*/
+    xmlCleanupParser();
+    while (cur)
+    {
+        if (xmlStrcmp(cur->name, (const xmlChar *) "config") == 0)
+            parse_config(s, cur->xmlChildrenNode);
+        /*endif*/
+        if (xmlStrcmp(cur->name, (const xmlChar *) "test-group") == 0)
+        {
+            if (parse_test_group(s, cur->xmlChildrenNode, test) == 0)
+                return 0;
+            /*endif*/
+        }
+        /*endif*/
+        cur = cur->next;
+    }
+    /*endwhile*/
+    fprintf(stderr, "XML test not found\n");
+    return -1;
 }
 /*- End of function --------------------------------------------------------*/
 
-void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data)
+SPAN_DECLARE(logging_state_t *) faxtester_get_logging_state(faxtester_state_t *s)
 {
-    s->front_end_step_timeout_handler = handler;
-    s->front_end_step_timeout_user_data = user_data;
+    return &s->logging;
 }
 /*- End of function --------------------------------------------------------*/
 
-faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party)
+faxtester_state_t *faxtester_init(faxtester_state_t *s, const char *test_file, const char *test)
 {
     if (s == NULL)
     {
         if ((s = (faxtester_state_t *) malloc(sizeof(*s))) == NULL)
             return NULL;
     }
+    /*endif*/
 
     memset(s, 0, sizeof(*s));
     span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
@@ -656,29 +1864,38 @@ faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party)
     fax_modems_set_tep_mode(&s->modems, false);
     fax_modems_set_rx_active(&s->modems, true);
     faxtester_set_timeout(s, -1);
+    s->timein_x = -1;
+    s->timeout_x = -1;
     faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
-
+    strcpy(s->image_path, ".");
+    s->next_tx_file[0] = '\0';
+    if (get_test_set(s, test_file, test) < 0)
+    {
+        /* TODO: free the state, if it was allocated. */
+        return NULL;
+    }
+    /*endif*/
+    memset(&s->expected_rx_info, 0, sizeof(s->expected_rx_info));
     return s;
 }
 /*- End of function --------------------------------------------------------*/
 
 int faxtester_release(faxtester_state_t *s)
 {
+    if (s->doc)
+    {
+        xmlFreeDoc(s->doc);
+        s->doc = NULL;
+    }
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
 
 int faxtester_free(faxtester_state_t *s)
 {
+    faxtester_release(s);
     free(s);
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
-
-void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data)
-{
-    s->flush_handler = handler;
-    s->flush_user_data = user_data;
-}
-/*- End of function --------------------------------------------------------*/
 /*- End of file ------------------------------------------------------------*/
index 48308f73294b2d914ea33b989d2b463f735b4cb7..412c1fc340cc8e86954dc2fe48513c884f89e6c0 100644 (file)
@@ -39,23 +39,6 @@ typedef struct faxtester_state_s faxtester_state_t;
 
 typedef void (*faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which);
 
-/*!
-    FAX tester real time frame handler.
-    \brief FAX tester real time frame handler.
-    \param s The FAX tester context.
-    \param user_data An opaque pointer.
-    \param direction True for incoming, false for outgoing.
-    \param msg The HDLC message.
-    \param len The length of the message.
-*/
-typedef void (*faxtester_real_time_frame_handler_t)(faxtester_state_t *s,
-                                                    void *user_data,
-                                                    int direction,
-                                                    const uint8_t *msg,
-                                                    int len);
-
-typedef void (*faxtester_front_end_step_complete_handler_t)(faxtester_state_t *s, void *user_data);
-
 /*!
     FAX tester descriptor.
 */
@@ -63,9 +46,19 @@ struct faxtester_state_s
 {
     /*! \brief The far end FAX context */
     fax_state_t *far_fax;
+    t38_terminal_state_t *far_t38;
+    
+    int far_tag;
 
     /*! \brief The far end T.38 terminal context */
     t38_terminal_state_t *far_t38_fax;
+    
+    t30_state_t *far_t30;
+
+    t30_exchanged_info_t expected_rx_info;
+
+    bool use_receiver_not_ready;
+    bool test_local_interrupt;
 
     /*! \brief Path for the FAX image test files. */
     char image_path[1024];
@@ -74,27 +67,23 @@ struct faxtester_state_s
     xmlDocPtr doc;
     /*! \brief Pointer to our current step in the test. */
     xmlNodePtr cur;
+    
+    int repeat_min;
+    int repeat_max;
+    int repeat_count;
+    xmlNodePtr repeat_start;
+    xmlNodePtr repeat_parent;
 
     faxtester_flush_handler_t flush_handler;
     void *flush_user_data;
 
-    /*! \brief A pointer to a callback routine to be called when frames are
-        exchanged. */
-    faxtester_real_time_frame_handler_t real_time_frame_handler;
-    /*! \brief An opaque pointer supplied in real time frame callbacks. */
-    void *real_time_frame_user_data;
-
-    faxtester_front_end_step_complete_handler_t front_end_step_complete_handler;
-    void *front_end_step_complete_user_data;
-
-    faxtester_front_end_step_complete_handler_t front_end_step_timeout_handler;
-    void *front_end_step_timeout_user_data;
-
     const uint8_t *image_buffer;
     int image_len;
     int image_ptr;
     int image_bit_ptr;
 
+    uint8_t image[1000000];
+
     int ecm_frame_size;
     int corrupt_crc;
 
@@ -194,26 +183,24 @@ void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle);
 */
 void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep);
 
-void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t handler, void *user_data);
-
-void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data);
-
-void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data);
-
 void faxtester_set_timeout(faxtester_state_t *s, int timeout);
 
-void faxtester_set_non_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len);
+SPAN_DECLARE(int) faxtester_next_step(faxtester_state_t *s);
 
-void faxtester_set_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len, int block, int frame_size, int crc_hit);
+/*! Get the logging context associated with a FAX tester context.
+    \brief Get the logging context associated with a FAX tester context.
+    \param s The FAX tester context.
+    \return A pointer to the logging context */
+SPAN_DECLARE(logging_state_t *) faxtester_get_logging_state(faxtester_state_t *s);
 
-/*! Initialise a FAX context.
-    \brief Initialise a FAX context.
+/*! Initialise a FAX tester context.
+    \brief Initialise a FAX tester context.
     \param s The FAX tester context.
-    \param calling_party true if the context is for a calling party. FALSE if the
-           context is for an answering party.
+    \param test_file The name of the file of XML test scripts.
+    \param test The name of the XML script test.
     \return A pointer to the FAX context, or NULL if there was a problem.
 */
-faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party);
+faxtester_state_t *faxtester_init(faxtester_state_t *s, const char *test_file, const char *test);
 
 /*! Release a FAX context.
     \brief Release a FAX context.
index f3b34b91a3016ed1a901191bd46a10c4bd48ea50..57de0da361c9536d983352b89dc33769e6900723 100644 (file)
@@ -99,48 +99,80 @@ The T.31 and TSB85 parts are incomplete right now.
 
 #define INPUT_TIFF_FILE_NAME    "../test-data/itu/fax/itutests.tif"
 #define OUTPUT_TIFF_FILE_NAME   "fax_tests.tif"
+#define INPUT_WAVE_FILE_NAME    "fax_cap.wav"
 #define OUTPUT_WAVE_FILE_NAME   "fax_tests.wav"
 
 enum
 {
-    AUDIO_FAX,
-    T38_TERMINAL_FAX,
-    T38_GATEWAY_FAX,
+    AUDIO_FAX = 1,
+    T38_FAX,
     T31_AUDIO_FAX,
-    T31_T38_TERMINAL_FAX,
-    T31_T38_GATEWAY_FAX,
+    T31_T38_FAX,
     TSB85_AUDIO_FAX,
-    TSB85_T38_TERMINAL_FAX,
-    TSB85_T38_GATEWAY_FAX
+    TSB85_T38_FAX,
+    REPLAY_AUDIO_FAX,
+    REPLAY_T38_FAX,
+    AUDIO_TO_T38_GATEWAY,
+    PASSTHROUGH,
+    AUDIO_CHAN,
+    T38_CHAN
 };
 
-int mode[2] = {AUDIO_FAX, AUDIO_FAX};
+const char *output_tiff_file_name;
 
-t30_state_t *t30_state[2] = {NULL, NULL};
-fax_state_t *fax_state[2] = {NULL, NULL};
-t38_gateway_state_t *t38_gateway_state[2] = {NULL, NULL};
-t38_terminal_state_t *t38_state[2] = {NULL, NULL};
-t38_core_state_t *t38_core_state[2] = {NULL, NULL};
-faxtester_state_t *faxtester[2] = {NULL, NULL};
-g1050_state_t *g1050_path[2] = {NULL, NULL};
-awgn_state_t *awgn_state[2] = {NULL, NULL};
-int16_t audio_buffer[2*2][SAMPLES_PER_CHUNK];
+struct audio_buf_s
+{
+    int16_t amp[SAMPLES_PER_CHUNK];
+    int len;
+};
 
-int t38_subst_seq[2] = {0, 0};
+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];
+};
 
-t30_exchanged_info_t expected_rx_info[2];
+struct chain_element_s chain[7];
+int chain_elements = 2;
 
+bool t38_simulate_incrementing_repeats = false;
 bool use_receiver_not_ready = false;
 bool test_local_interrupt = false;
 
 double when = 0.0;
 
-bool phase_e_reached[2] = {false, false};
-bool completed[2] = {false, false};
-bool succeeded[2] = {false, false};
-
-bool t38_simulate_incrementing_repeats = false;
-
 static int phase_b_handler(void *user_data, int result)
 {
     int i;
@@ -151,10 +183,12 @@ static int phase_b_handler(void *user_data, int result)
     char tag[20];
     const char *u;
     const uint8_t *v;
+    t30_exchanged_info_t *info;
 
     i = (int) (intptr_t) user_data;
-    s = t30_state[i];
+    s = chain[i].t30_state;
     ch = i + 'A';
+    info = &chain[i].expected_rx_info;
     snprintf(tag, sizeof(tag), "%c: Phase B", ch);
     printf("%c: Phase B handler - (0x%X) %s\n", ch, result, t30_frametype(result));
     fax_log_rx_parameters(s, tag);
@@ -163,15 +197,15 @@ static int phase_b_handler(void *user_data, int result)
     if ((u = t30_get_rx_ident(s)))
     {
         printf("%c: Phase B remote ident '%s'\n", ch, u);
-        if (expected_rx_info[i].ident[0]  &&  strcmp(expected_rx_info[i].ident, u))
+        if (info->ident[0]  &&  strcmp(info->ident, u))
         {
-            printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, expected_rx_info[i].ident);
+            printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, info->ident);
             status = T30_ERR_IDENT_UNACCEPTABLE;
         }
     }
     else
     {
-        if (expected_rx_info[i].ident[0])
+        if (info->ident[0])
         {
             printf("%c: Phase B: remote ident missing!\n", ch);
             status = T30_ERR_IDENT_UNACCEPTABLE;
@@ -180,15 +214,15 @@ static int phase_b_handler(void *user_data, int result)
     if ((u = t30_get_rx_sub_address(s)))
     {
         printf("%c: Phase B: remote sub-address '%s'\n", ch, u);
-        if (expected_rx_info[i].sub_address[0]  &&  strcmp(expected_rx_info[i].sub_address, u))
+        if (info->sub_address[0]  &&  strcmp(info->sub_address, u))
         {
-            printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, expected_rx_info[i].sub_address);
+            printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, info->sub_address);
             status = T30_ERR_SUB_UNACCEPTABLE;
         }
     }
     else
     {
-        if (expected_rx_info[i].sub_address[0])
+        if (info->sub_address[0])
         {
             printf("%c: Phase B: remote sub-address missing!\n", ch);
             status = T30_ERR_SUB_UNACCEPTABLE;
@@ -197,15 +231,15 @@ static int phase_b_handler(void *user_data, int result)
     if ((u = t30_get_rx_polled_sub_address(s)))
     {
         printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u);
-        if (expected_rx_info[i].polled_sub_address[0]  &&  strcmp(expected_rx_info[i].polled_sub_address, u))
+        if (info->polled_sub_address[0]  &&  strcmp(info->polled_sub_address, u))
         {
-            printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, expected_rx_info[i].polled_sub_address);
+            printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, info->polled_sub_address);
             status = T30_ERR_PSA_UNACCEPTABLE;
         }
     }
     else
     {
-        if (expected_rx_info[i].polled_sub_address[0])
+        if (info->polled_sub_address[0])
         {
             printf("%c: Phase B: remote polled sub-address missing!\n", ch);
             status = T30_ERR_PSA_UNACCEPTABLE;
@@ -214,15 +248,15 @@ static int phase_b_handler(void *user_data, int result)
     if ((u = t30_get_rx_selective_polling_address(s)))
     {
         printf("%c: Phase B: remote selective polling address '%s'\n", ch, u);
-        if (expected_rx_info[i].selective_polling_address[0]  &&  strcmp(expected_rx_info[i].selective_polling_address, u))
+        if (info->selective_polling_address[0]  &&  strcmp(info->selective_polling_address, u))
         {
-            printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, expected_rx_info[i].selective_polling_address);
+            printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, info->selective_polling_address);
             status = T30_ERR_SEP_UNACCEPTABLE;
         }
     }
     else
     {
-        if (expected_rx_info[i].selective_polling_address[0])
+        if (info->selective_polling_address[0])
         {
             printf("%c: Phase B: remote selective polling address missing!\n", ch);
             status = T30_ERR_SEP_UNACCEPTABLE;
@@ -231,15 +265,15 @@ static int phase_b_handler(void *user_data, int result)
     if ((u = t30_get_rx_sender_ident(s)))
     {
         printf("%c: Phase B: remote sender ident '%s'\n", ch, u);
-        if (expected_rx_info[i].sender_ident[0]  &&  strcmp(expected_rx_info[i].sender_ident, u))
+        if (info->sender_ident[0]  &&  strcmp(info->sender_ident, u))
         {
-            printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, expected_rx_info[i].sender_ident);
+            printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, info->sender_ident);
             status = T30_ERR_SID_UNACCEPTABLE;
         }
     }
     else
     {
-        if (expected_rx_info[i].sender_ident[0])
+        if (info->sender_ident[0])
         {
             printf("%c: Phase B: remote sender ident missing!\n", ch);
             status = T30_ERR_SID_UNACCEPTABLE;
@@ -248,15 +282,15 @@ static int phase_b_handler(void *user_data, int result)
     if ((u = t30_get_rx_password(s)))
     {
         printf("%c: Phase B: remote password '%s'\n", ch, u);
-        if (expected_rx_info[i].password[0]  &&  strcmp(expected_rx_info[i].password, u))
+        if (info->password[0]  &&  strcmp(info->password, u))
         {
-            printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, expected_rx_info[i].password);
+            printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, info->password);
             status = T30_ERR_PWD_UNACCEPTABLE;
         }
     }
     else
     {
-        if (expected_rx_info[i].password[0])
+        if (info->password[0])
         {
             printf("%c: Phase B: remote password missing!\n", ch);
             status = T30_ERR_PWD_UNACCEPTABLE;
@@ -265,46 +299,46 @@ static int phase_b_handler(void *user_data, int result)
     if ((len = t30_get_rx_nsf(s, &v)))
     {
         printf("%c: Phase B: NSF %d bytes\n", ch, len);
-        if (expected_rx_info[i].nsf_len  &&  (expected_rx_info[i].nsf_len != len  ||  memcmp(expected_rx_info[i].nsf, v, len)))
+        if (info->nsf_len  &&  (info->nsf_len != len  ||  memcmp(info->nsf, v, len)))
         {
-            printf("%c: Phase B: remote NSF incorrect! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsf_len);
+            printf("%c: Phase B: remote NSF incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
         }
     }
     else
     {
-        if (expected_rx_info[i].nsf_len)
+        if (info->nsf_len)
         {
-            printf("%c: Phase B: remote NSF missing! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsf_len);
+            printf("%c: Phase B: remote NSF missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
         }
     }
     if ((len = t30_get_rx_nsc(s, &v)))
     {
         printf("%c: Phase B: NSC %d bytes\n", ch, len);
-        if (expected_rx_info[i].nsc_len  &&  (expected_rx_info[i].nsc_len != len  ||  memcmp(expected_rx_info[i].nsc, v, len)))
+        if (info->nsc_len  &&  (info->nsc_len != len  ||  memcmp(info->nsc, v, len)))
         {
-            printf("%c: Phase B: remote NSC incorrect! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsc_len);
+            printf("%c: Phase B: remote NSC incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsc_len);
         }
     }
     else
     {
-        if (expected_rx_info[i].nsc_len)
+        if (info->nsc_len)
         {
-            printf("%c: Phase B: remote NSC missing! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsc_len);
+            printf("%c: Phase B: remote NSC missing! - expected %u bytes\n", ch, (unsigned int) info->nsc_len);
         }
     }
     if ((len = t30_get_rx_nss(s, &v)))
     {
         printf("%c: Phase B: NSS %d bytes\n", ch, len);
-        if (expected_rx_info[i].nss_len  &&  (expected_rx_info[i].nss_len != len  ||  memcmp(expected_rx_info[i].nss, v, len)))
+        if (info->nss_len  &&  (info->nss_len != len  ||  memcmp(info->nss, v, len)))
         {
-            printf("%c: Phase B: remote NSS incorrect! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nss_len);
+            printf("%c: Phase B: remote NSS incorrect! - expected %u bytes\n", ch, (unsigned int) info->nss_len);
         }
     }
     else
     {
-        if (expected_rx_info[i].nss_len)
+        if (info->nss_len)
         {
-            printf("%c: Phase B: remote NSS missing! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsf_len);
+            printf("%c: Phase B: remote NSS missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
         }
     }
 
@@ -320,7 +354,7 @@ static int phase_d_handler(void *user_data, int result)
     char tag[20];
 
     i = (int) (intptr_t) user_data;
-    s = t30_state[i];
+    s = chain[i].t30_state;
     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));
@@ -367,7 +401,7 @@ static void phase_e_handler(void *user_data, int result)
     char tag[20];
 
     i = (int) (intptr_t) user_data;
-    s = t30_state[i];
+    s = chain[i].t30_state;
     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));
@@ -375,15 +409,15 @@ static void phase_e_handler(void *user_data, int result)
     fax_log_tx_parameters(s, tag);
     fax_log_rx_parameters(s, tag);
     t30_get_transfer_statistics(s, &t);
-    succeeded[i] = (result == T30_ERR_OK);
-    phase_e_reached[i] = true;
+    chain[i].succeeded = (result == T30_ERR_OK);
+    chain[i].phase_e_reached = true;
 }
 /*- End of function --------------------------------------------------------*/
 
-static void real_time_frame_handler(void *user_data,
-                                    bool incoming,
-                                    const uint8_t *msg,
-                                    int len)
+static void real_time_t30_frame_handler(void *user_data,
+                                        bool incoming,
+                                        const uint8_t *msg,
+                                        int len)
 {
     int i;
     int ch;
@@ -415,7 +449,7 @@ 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);
-    t30_set_real_time_frame_handler(t30, real_time_frame_handler, (void *) (intptr_t) chan);
+    t30_set_real_time_frame_handler(t30, real_time_t30_frame_handler, (void *) (intptr_t) chan);
     t30_set_document_handler(t30, document_handler, (void *) (intptr_t) chan);
 }
 /*- End of function --------------------------------------------------------*/
@@ -447,11 +481,11 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t
     {
         for (i = 0;  i < count;  i++)
         {
-            span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", t38_subst_seq[chan], len);
+            span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", chain[chan].t38_subst_seq, len);
 
-            if (g1050_put(g1050_path[chan], buf, len, t38_subst_seq[chan], when) < 0)
-                printf("Lost packet %d\n", t38_subst_seq[chan]);
-            t38_subst_seq[chan] = (t38_subst_seq[chan] + 1) & 0xFFFF;
+            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;
         }
     }
     else
@@ -460,7 +494,7 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t
 
         for (i = 0;  i < count;  i++)
         {
-            if (g1050_put(g1050_path[chan], buf, len, s->tx_seq_no, when) < 0)
+            if (g1050_put(chain[chan].path.g1050_path, buf, len, s->tx_seq_no, when) < 0)
                 printf("Lost packet %d\n", s->tx_seq_no);
         }
     }
@@ -468,36 +502,84 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t
 }
 /*- End of function --------------------------------------------------------*/
 
+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 --------------------------------------------------------*/
+
 int main(int argc, char *argv[])
 {
     int16_t silence[SAMPLES_PER_CHUNK];
-    int16_t t30_amp[2][SAMPLES_PER_CHUNK];
-    int16_t t38_amp[2][SAMPLES_PER_CHUNK];
     int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK];
     int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK];
-    int16_t out_amp[SAMPLES_PER_CHUNK*4];
-    int16_t *fax_rx_buf[2];
-    int16_t *fax_tx_buf[2];
-    int16_t *t38_gateway_rx_buf[2];
-    int16_t *t38_gateway_tx_buf[2];
-    int t30_len[2];
-    int t38_len[2];
+    int16_t audio_log[SAMPLES_PER_CHUNK*4];
     int hist_ptr;
     int log_audio;
     int msg_len;
     uint8_t msg[1024];
     int outframes;
     SNDFILE *wave_handle;
-    SNDFILE *input_wave_handle;
     bool use_ecm;
     bool use_tep;
-    int feedback_audio;
-    int use_transmit_on_idle;
+    bool use_polled_mode;
+    bool use_transmit_on_idle;
+    bool feedback_audio;
     int t38_version;
     const char *input_tiff_file_name;
-    const char *decode_file_name;
+    const char *replay_file_name;
     int i;
     int j;
+    int k;
     int seq_no;
     int g1050_model_no;
     int g1050_speed_pattern_no;
@@ -526,9 +608,13 @@ int main(int argc, char *argv[])
     int expected_pages;
     char *page_header_info;
     char *page_header_tz;
-    const char *tag;
     const char *xml_file_name;
+    const char *xml_test_name[2];
+    int xml_step;
     char buf[132 + 1];
+    int line_model_no;
+    int channel_codec;
+    int rbs_pattern;
 #if defined(ENABLE_GUI)
     int use_gui;
 #endif
@@ -540,6 +626,7 @@ int main(int argc, char *argv[])
     use_ecm = false;
     t38_version = 1;
     input_tiff_file_name = INPUT_TIFF_FILE_NAME;
+    output_tiff_file_name = OUTPUT_TIFF_FILE_NAME;
     t38_simulate_incrementing_repeats = false;
     g1050_model_no = 0;
     g1050_speed_pattern_no = 1;
@@ -547,6 +634,7 @@ int main(int argc, char *argv[])
     use_tep = false;
     feedback_audio = false;
     use_transmit_on_idle = true;
+    use_polled_mode = false;
     supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
     page_header_info = NULL;
     page_header_tz = NULL;
@@ -557,16 +645,22 @@ int main(int argc, char *argv[])
     signal_level = 0;
     noise_level = -99;
     scan_line_time = 0;
-    decode_file_name = NULL;
+    replay_file_name = INPUT_WAVE_FILE_NAME;
     code_to_look_up = -1;
     allowed_bilevel_resolutions[0] = 0;
     allowed_bilevel_resolutions[1] = 0;
     allowed = 0;
+    line_model_no = 0;
+    channel_codec = MUNGE_CODEC_NONE;
+    rbs_pattern = 0;
     colour_enabled = false;
     t37_like_output = false;
     t38_transport = T38_TRANSPORT_UDPTL;
     xml_file_name = "../spandsp/tsb85.xml";
-    while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:x:z:")) != -1)
+    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)
     {
         switch (opt)
         {
@@ -584,7 +678,7 @@ int main(int argc, char *argv[])
             colour_enabled = true;
             break;
         case 'd':
-            decode_file_name = optarg;
+            replay_file_name = optarg;
             break;
         case 'D':
             drop_frame_rate =
@@ -629,31 +723,75 @@ int main(int argc, char *argv[])
             noise_level = atoi(optarg);
             break;
         case 'p':
-            for (i = 0;  i < 2;  i++)
+            /*
+               -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++)
             {
-                switch (optarg[i])
+                if (optarg[i] != '-'  &&  optarg[i] != '\0')
+                    continue;
+                j = optarg[i];
+                optarg[i] = '\0';
+                if (strcmp(&optarg[k], "FAX") == 0)
                 {
-                case 'A':
-                    mode[i] = AUDIO_FAX;
-                    break;
-                case 'G':
-                    mode[i] = T38_GATEWAY_FAX;
-                    break;
-                case 'T':
-                    mode[i] = T38_TERMINAL_FAX;
-                    break;
-                default:
-                    fprintf(stderr, "Unknown FAX path element %c\n", optarg[i]);
+                    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]);
                     exit(2);
                 }
+                k = i + 1;
+                if (j == '\0')
+                    break;
             }
-            if ((mode[0] == AUDIO_FAX  &&  mode[1] != AUDIO_FAX)
+#if 0
+            if ((chain[0].node_type == AUDIO_FAX  &&  chain[chain_elements - 1].node_type != AUDIO_FAX)
                 ||
-                (mode[0] != AUDIO_FAX  &&  mode[1] == AUDIO_FAX))
+                (chain[0].node_type != AUDIO_FAX  &&  chain[chain_elements - 1].node_type == AUDIO_FAX))
             {
-                fprintf(stderr, "Invalid FAX path %s\n", optarg);
+                fprintf(stderr, "Invalid FAX path\n");
                 exit(2);
             }
+#endif
+            break;
+        case 'P':
+            use_polled_mode = true;
             break;
         case 's':
             g1050_speed_pattern_no = atoi(optarg);
@@ -692,6 +830,10 @@ int main(int argc, char *argv[])
             t38_version = atoi(optarg);
             break;
         case 'x':
+            xml_test_name[xml_step] = optarg;
+            xml_step ^= 1;
+            break;
+        case 'X':
             xml_file_name = optarg;
             break;
         case 'z':
@@ -726,336 +868,452 @@ int main(int argc, char *argv[])
     memset(silence, 0, sizeof(silence));
 
     srand48(0x1234567);
+
+    memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
+    memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));
+
     /* Set up the nodes */
-    input_wave_handle = NULL;
-    if (mode[0] == T38_TERMINAL_FAX)
-    {
-    }
-    else
-    {
-        if (decode_file_name)
-        {
-            if ((input_wave_handle = sf_open_telephony_read(decode_file_name, 1)) == NULL)
-            {
-                fprintf(stderr, "    Cannot open audio file '%s'\n", decode_file_name);
-                exit(2);
-            }
-        }
-    }
+    chain[0].peer = chain_elements - 1;
+    chain[chain_elements - 1].peer = 0;
 
-    for (i = 0;  i < 2;  i++)
+    for (i = 0;  i < chain_elements;  i++)
     {
-        tag = (i == 0)  ?  "A"  :  "B";
+        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));
 
-        memset(&expected_rx_info[i], 0, sizeof(expected_rx_info[i]));
-        switch (mode[i])
+        switch (chain[i].node_type)
         {
-        case T38_TERMINAL_FAX:
-            if ((t38_state[i] = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
+        case AUDIO_FAX:
+            if ((chain[i].node.fax_state = fax_init(NULL, (i == 0))) == NULL)
             {
-                fprintf(stderr, "Cannot start the T.38 terminal instance\n");
+                fprintf(stderr, "    Cannot start FAX instance\n");
                 exit(2);
             }
-            t30_state[i] = t38_terminal_get_t30_state(t38_state[i]);
-            t38_core_state[i] = t38_terminal_get_t38_core_state(t38_state[i]);
+            chain[i].t30_state = fax_get_t30_state(chain[i].node.fax_state);
 
-            logging = t38_terminal_get_logging_state(t38_state[i]);
+            logging = fax_get_logging_state(chain[i].node.fax_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, tag);
+            span_log_set_tag(logging, chain[i].tag);
 
-            logging = t38_core_get_logging_state(t38_core_state[i]);
+            logging = fax_modems_get_logging_state(&chain[i].node.fax_state->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, tag);
+            span_log_set_tag(logging, chain[i].tag);
 
-            logging = t30_get_logging_state(t30_state[i]);
+            logging = t30_get_logging_state(chain[i].t30_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, tag);
+            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);
+            }
             break;
-        case AUDIO_FAX:
-        case T38_GATEWAY_FAX:
-            if ((fax_state[i] = fax_init(NULL, (i == 0))) == NULL)
+        case T38_FAX:
+            if ((chain[i].node.t38_state = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
             {
-                fprintf(stderr, "Cannot start FAX instance\n");
+                fprintf(stderr, "    Cannot start the T.38 terminal instance\n");
                 exit(2);
             }
-            t30_state[i] = fax_get_t30_state(fax_state[i]);
+            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);
 
-            logging = fax_get_logging_state(fax_state[i]);
+            logging = t38_terminal_get_logging_state(chain[i].node.t38_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, tag);
+            span_log_set_tag(logging, chain[i].tag);
 
-            logging = fax_modems_get_logging_state(&fax_state[i]->modems);
+            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, tag);
+            span_log_set_tag(logging, chain[i].tag);
 
-            logging = t30_get_logging_state(t30_state[i]);
+            logging = t30_get_logging_state(chain[i].t30_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, tag);
+            span_log_set_tag(logging, chain[i].tag);
 
-            if (mode[i] == T38_GATEWAY_FAX)
+            set_t30_callbacks(chain[i].t30_state, i);
+
+            if (i == 0)
             {
-                if ((t38_gateway_state[i] = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
+                chain[i].t38_peer = i + 1;
+            }
+            else
+            {
+                switch (chain[i - 1].node_type)
                 {
-                    fprintf(stderr, "Cannot start the T.38 gateway instance\n");
-                    exit(2);
+                case T38_FAX:
+                case AUDIO_TO_T38_GATEWAY:
+                    chain[i].t38_peer = i - 1;
+                    break;
+                default:
+                    chain[i].t38_peer = i + 1;
+                    break;
                 }
-                t38_core_state[i] = t38_gateway_get_t38_core_state(t38_gateway_state[i]);
-
-                logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
-                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, tag);
+            }
+            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);
 
-                logging = fax_modems_get_logging_state(&t38_gateway_state[i]->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, tag);
+            faxtester_set_transmit_on_idle(chain[i].node.faxtester_state, true);
 
-                logging = t38_core_get_logging_state(t38_core_state[i]);
-                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, tag);
+            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];
 
-                fax_rx_buf[i] = t38_amp[i];
-                fax_tx_buf[i] = t30_amp[i];
-                t38_gateway_rx_buf[i] = t30_amp[i];
-                t38_gateway_tx_buf[i] = t38_amp[i];
+            if (i == 0)
+            {
+                chain[i].t38_peer = i + 1;
             }
             else
             {
-                fax_rx_buf[i] = t30_amp[i];
-                fax_tx_buf[i] = t30_amp[i ^ 1];
-                t38_gateway_rx_buf[i] = NULL;
-                t38_gateway_tx_buf[i] = NULL;
+                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;
+                }
             }
-            awgn_state[i] = NULL;
+
+            chain[i].awgn_state = NULL;
             signal_scaling = 1.0f;
             if (noise_level > -99)
             {
-                awgn_state[i] = awgn_init_dbm0(NULL, 1234567, noise_level);
+                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);
             }
             break;
-        case T31_AUDIO_FAX:
-            break;
-        case T31_T38_TERMINAL_FAX:
-        case T31_T38_GATEWAY_FAX:
-            break;
-        case TSB85_AUDIO_FAX:
-            break;
-        case TSB85_T38_TERMINAL_FAX:
-        case TSB85_T38_GATEWAY_FAX:
+        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];
             break;
+        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);
+            }
         }
-        set_t30_callbacks(t30_state[i], i);
-    }
-    /* Set up the channels */
-    for (i = 0;  i < 2;  i++)
-    {
-        if ((g1050_path[i] = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
+        if ((chain[i].path.g1050_path = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
         {
-            fprintf(stderr, "Failed to start IP network path model\n");
+            fprintf(stderr, "    Failed to start IP network path model\n");
             exit(2);
         }
-        memset(audio_buffer[2*i], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
-        memset(audio_buffer[2*i + 1], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
-        memset(t30_amp[i], 0, sizeof(t30_amp[i]));
-        memset(t38_amp[i], 0, sizeof(t38_amp[i]));
     }
-    memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
-    memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));
 
-    for (i = 0;  i < 2;  i++)
+    for (i = 0;  i < chain_elements;  i++)
     {
         j = i + 1;
-        sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j);
-        t30_set_tx_ident(t30_state[i], buf);
-        strcpy(expected_rx_info[i ^ 1].ident, buf);
-        sprintf(buf, "Sub-address %d", j);
-        t30_set_tx_sub_address(t30_state[i], buf);
-        //strcpy(expected_rx_info[i ^ 1].sub_address, buf);
-        sprintf(buf, "Sender ID %d", j);
-        t30_set_tx_sender_ident(t30_state[i], buf);
-        //strcpy(expected_rx_info[i ^ 1].sender_ident, buf);
-        sprintf(buf, "Password %d", j);
-        t30_set_tx_password(t30_state[i], buf);
-        //strcpy(expected_rx_info[i ^ 1].password, buf);
-        sprintf(buf, "Polled sub-add %d", j);
-        t30_set_tx_polled_sub_address(t30_state[i], buf);
-        //strcpy(expected_rx_info[i ^ 1].polled_sub_address, buf);
-        sprintf(buf, "Select poll add %d", j);
-        t30_set_tx_selective_polling_address(t30_state[i], buf);
-        //strcpy(expected_rx_info[i ^ 1].selective_polling_address, buf);
-        t30_set_tx_page_header_info(t30_state[i], page_header_info);
-        if (page_header_tz)
-            t30_set_tx_page_header_tz(t30_state[i], page_header_tz);
-
-        if ((i & 1) == 1)
+        if (chain[i].t30_state)
         {
-            t30_set_tx_nsf(t30_state[i], (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
-            expected_rx_info[i ^ 1].nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00";
-            expected_rx_info[i ^ 1].nsf_len = 12;
-        }
+            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;
+            }
 
-        t30_set_supported_modems(t30_state[i], supported_modems);
-        t30_set_supported_t30_features(t30_state[i],
-                                       T30_SUPPORT_IDENTIFICATION
-                                     | T30_SUPPORT_SELECTIVE_POLLING
-                                     | T30_SUPPORT_SUB_ADDRESSING);
-        t30_set_supported_image_sizes(t30_state[i],
-                                      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])
-        {
-        case 0:
-            /* Allow anything */
-            t30_set_supported_bilevel_resolutions(t30_state[i],
-                                                  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(t30_state[i],
-                                                  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(t30_state[i],
-                                                  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(t30_state[i],
-                                                  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(t30_state[i],
-                                                  T4_RESOLUTION_R8_STANDARD
-                                                | T4_RESOLUTION_200_100);
-            break;
-        }
-        if (colour_enabled)
-        {
-            t30_set_supported_colour_resolutions(t30_state[i],
-                                                 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(t30_state[i], 0);
-        }
-        if (t37_like_output)
-        {
-            t30_set_supported_output_compressions(t30_state[i],
-                                                  T4_COMPRESSION_T85
-                                                | T4_COMPRESSION_T85_L0
-                                                | T4_COMPRESSION_T6
-                                                | T4_COMPRESSION_T42_T81);
-        }
-        else
-        {
-            t30_set_supported_output_compressions(t30_state[i],
-                                                  T4_COMPRESSION_T6
-                                                | T4_COMPRESSION_JPEG);
-        }
+            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);
+            }
 
-        t30_set_ecm_capability(t30_state[i], use_ecm);
-        t30_set_supported_compressions(t30_state[i],
-                                       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(t30_state[i], scan_line_time);
-
-        if (mode[i] == T38_GATEWAY_FAX)
-        {
-            t38_gateway_set_transmit_on_idle(t38_gateway_state[i], use_transmit_on_idle);
-            t38_gateway_set_supported_modems(t38_gateway_state[i], supported_modems);
-            //t38_gateway_set_nsx_suppression(t38_state[i], NULL, 0, NULL, 0);
-            t38_gateway_set_fill_bit_removal(t38_gateway_state[i], remove_fill_bits);
-            t38_gateway_set_real_time_frame_handler(t38_gateway_state[i], real_time_gateway_frame_handler, (void *) (intptr_t) i);
-            t38_gateway_set_ecm_capability(t38_gateway_state[i], use_ecm);
-        }
-        if (mode[i] != AUDIO_FAX)
-        {
-            t38_set_t38_version(t38_core_state[i], t38_version);
+            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);
         }
 
-        if (mode[i] == T38_TERMINAL_FAX)
+        switch (chain[i].node_type)
         {
-            //t30_set_iaf_mode(t30_state[i], T30_IAF_MODE_NO_FILL_BITS);
+        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);
             switch (t38_transport)
             {
             case T38_TRANSPORT_UDPTL:
             case T38_TRANSPORT_RTP:
-                t38_terminal_set_fill_bit_removal(t38_state[i], remove_fill_bits);
-                t38_terminal_set_tep_mode(t38_state[i], use_tep);
+                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);
                 break;
             case T38_TRANSPORT_TCP:
             case T38_TRANSPORT_TCP_TPKT:
-                t38_terminal_set_fill_bit_removal(t38_state[i], true);
-                t38_terminal_set_config(t38_state[i], T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS);
-                t38_terminal_set_tep_mode(t38_state[i], false);
+                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);
                 break;
             }
+            break;
         }
-        else
+    }
+
+    for (i = 0;  i < chain_elements;  i++)
+    {
+        switch (chain[i].node_type)
         {
-            fax_set_transmit_on_idle(fax_state[i], use_transmit_on_idle);
-            fax_set_tep_mode(fax_state[i], use_tep);
+        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;
         }
     }
 
-    t30_set_tx_file(t30_state[0], input_tiff_file_name, start_page, end_page);
-    t30_set_rx_file(t30_state[1], OUTPUT_TIFF_FILE_NAME, -1);
+    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;
+    }
 
 #if defined(ENABLE_GUI)
     if (use_gui)
@@ -1064,144 +1322,225 @@ int main(int argc, char *argv[])
     hist_ptr = 0;
     for (;;)
     {
-        memset(out_amp, 0, sizeof(out_amp));
+        memset(audio_log, 0, sizeof(audio_log));
 
-        for (i = 0;  i < 2;  i++)
+        for (i = 0;  i < chain_elements;  i++)
         {
             /* Update T.30 timing */
-            logging = t30_get_logging_state(t30_state[i]);
-            span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
-
-            if (mode[i] == T38_TERMINAL_FAX)
+            switch (chain[i].node_type)
             {
-                /* Update T.38 termination timing */
-                logging = t38_terminal_get_logging_state(t38_state[i]);
+            case AUDIO_FAX:
+                /* Update timing */
+                logging = t30_get_logging_state(chain[i].t30_state);
                 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
-                logging = t38_core_get_logging_state(t38_core_state[i]);
+                logging = fax_get_logging_state(chain[i].node.fax_state);
                 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
-
-                completed[i] = t38_terminal_send_timeout(t38_state[i], SAMPLES_PER_CHUNK);
-            }
-            else
-            {
-                /* Update audio FAX timing */
-                logging = fax_get_logging_state(fax_state[i]);
+                logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems);
                 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.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
 
 #if 0
                 /* Mute the signal */
-                vec_zeroi16(fax_rx_buf[i], SAMPLES_PER_CHUNK);
+                vec_zeroi16(chain[i].path.audio_in_buf->amp, SAMPLES_PER_CHUNK);
+                chain[i].path.audio_in_buf->len = SAMPLES_PER_CHUNK;
 #endif
-                fax_rx(fax_state[i], fax_rx_buf[i], SAMPLES_PER_CHUNK);
-                if (!t30_call_active(t30_state[i]))
+                if (log_audio)
                 {
-                    completed[i] = true;
-                    continue;
+                    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];
                 }
-
-                if (i == 0  &&  input_wave_handle)
+                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))
                 {
-                    t30_len[i] = sf_readf_short(input_wave_handle, fax_tx_buf[i], SAMPLES_PER_CHUNK);
-                    if (t30_len[i] == 0)
-                        break;
+                    chain[i].completed = true;
+                    continue;
                 }
-                else
+
+                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)
                 {
-                    t30_len[i] = fax_tx(fax_state[i], fax_tx_buf[i], SAMPLES_PER_CHUNK);
-                    if (!use_transmit_on_idle)
+                    /* 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)
                     {
-                        /* 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 (t30_len[i] < SAMPLES_PER_CHUNK)
-                        {
-                            memset(t30_amp[i] + t30_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len[i]));
-                            t30_len[i] = SAMPLES_PER_CHUNK;
-                        }
-                    }
-                    if (awgn_state[i])
-                    {
-                        for (j = 0;  j < t30_len[i];  j++)
-                            fax_tx_buf[i][j] = ((int16_t) (fax_tx_buf[i][j]*signal_scaling)) + awgn(awgn_state[i]);
+                        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;
                     }
                 }
+                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);
+                }
                 if (log_audio)
                 {
-                    for (j = 0;  j < t30_len[i];  j++)
-                        out_amp[4*j + 2*i] = t30_amp[i][j];
+                    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 (feedback_audio)
                 {
-                    for (j = 0;  j < t30_len[i];  j++)
-                        t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
-                    memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
+                    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);
                 }
+                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);
 
-                if (mode[i] == T38_GATEWAY_FAX)
-                {
-                    /* Update T.38 gateway timing */
-                    logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
-                    span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
-                    logging = t38_core_get_logging_state(t38_core_state[i]);
-                    span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+                chain[i].completed = t38_terminal_send_timeout(chain[i].node.t38_state, SAMPLES_PER_CHUNK);
 
-                    if (drop_frame_rate  &&  --drop_frame == 0)
-                    {
-                        drop_frame = drop_frame_rate;
-                        if (t38_gateway_rx_fillin(t38_gateway_state[i], SAMPLES_PER_CHUNK))
-                            break;
-                    }
-                    else
-                    {
-                        if (t38_gateway_rx(t38_gateway_state[i], t38_gateway_rx_buf[i], SAMPLES_PER_CHUNK))
-                            break;
-                    }
+                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
 
-                    t38_len[i] = t38_gateway_tx(t38_gateway_state[i], t38_gateway_tx_buf[i], SAMPLES_PER_CHUNK);
-                    if (!use_transmit_on_idle)
+                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))
                     {
-                        if (t38_len[i] < SAMPLES_PER_CHUNK)
+                        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)
                         {
-                            memset(t38_amp[i] + t38_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len[i]));
-                            t38_len[i] = SAMPLES_PER_CHUNK;
+                            printf("Test failed\n");
+                            exit(2);
                         }
+                        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*/
                     }
-                    if (feedback_audio)
-                    {
-                        for (j = 0;  j < t30_len[i];  j++)
-                            t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
-                        memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
-                    }
+                    /*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
 
-                    if (log_audio)
+                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)
                     {
-                        for (j = 0;  j < t38_len[i];  j++)
-                            out_amp[4*j + 2*i + 1] = t38_amp[i][j];
+                        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;
                     }
                 }
-            }
-            if (mode[i] != AUDIO_FAX)
-            {
-                while ((msg_len = g1050_get(g1050_path[i], msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
+                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)
                 {
 #if defined(ENABLE_GUI)
                     if (use_gui)
                         media_monitor_rx(seq_no, tx_when, rx_when);
 #endif
-                   t38_core_rx_ifp_packet(t38_core_state[i ^ 1], msg, msg_len, seq_no);
+                    t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no);
                 }
+                break;
             }
         }
         if (log_audio)
         {
-            outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
+            outframes = sf_writef_short(wave_handle, audio_log, SAMPLES_PER_CHUNK);
             if (outframes != SAMPLES_PER_CHUNK)
                 break;
         }
 
         when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;
 
-        if (completed[0]  &&  completed[1])
+        if (chain[0].completed  &&  chain[chain_elements - 1].completed)
             break;
 #if defined(ENABLE_GUI)
         if (use_gui)
@@ -1210,24 +1549,19 @@ int main(int argc, char *argv[])
         if (++hist_ptr > 3)
             hist_ptr = 0;
     }
-    for (i = 0;  i < 2;  i++)
+
+    for (i = 0;  i < chain_elements;  i++)
     {
-        if (mode[i] == T38_GATEWAY_FAX)
+        switch (chain[i].node_type)
         {
-            t38_gateway_get_transfer_statistics(t38_gateway_state[i], &t38_stats);
+        case AUDIO_TO_T38_GATEWAY:
+            t38_gateway_get_transfer_statistics(chain[i].node.t38_gateway_state, &t38_stats);
             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");
-        }
-    }
-    if (input_wave_handle)
-    {
-        if (sf_close_telephony(input_wave_handle))
-        {
-            fprintf(stderr, "    Cannot close audio file '%s'\n", decode_file_name);
-            exit(2);
+            break;
         }
     }
     if (log_audio)
@@ -1246,14 +1580,16 @@ int main(int argc, char *argv[])
     if (start_page >= 0)
         expected_pages -= start_page;
     /* Check how many pages were transferred */
-    for (i = 0;  i < 2;  i++)
+    for (j = 0;  j < 2;  j++)
     {
-        if (!phase_e_reached[i])
+        i = (j == 0)  ?  0  :  (chain_elements - 1);
+        if (!chain[i].phase_e_reached)
             break;
-        if (!succeeded[i])
+        if (!chain[i].succeeded)
             break;
-        t30_get_transfer_statistics(t30_state[i], &t30_stats);
-        if (i & 1)
+
+        t30_get_transfer_statistics(chain[i].t30_state, &t30_stats);
+        if ((!use_polled_mode  &&  i != 0)  ||  (use_polled_mode  &&  i == 0))
         {
             if (t30_stats.pages_tx != 0  ||  t30_stats.pages_rx != expected_pages)
                 break;
@@ -1263,23 +1599,45 @@ int main(int argc, char *argv[])
             if (t30_stats.pages_tx != expected_pages  ||  t30_stats.pages_rx != 0)
                 break;
         }
-        if (mode[i] == T38_TERMINAL_FAX)
-            t38_terminal_free(t38_state[i]);
-        else
-            fax_free(fax_state[i]);
-        if (mode[i] == T38_GATEWAY_FAX)
-            t38_gateway_free(t38_gateway_state[i]);
-        if (g1050_path[i])
+    }
+    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)
         {
-            g1050_free(g1050_path[i]);
-            g1050_path[i] = NULL;
+            g1050_free(chain[i].path.g1050_path);
+            chain[i].path.g1050_path = NULL;
         }
     }
-    if (i < 2)
+    if (j < 2)
     {
         printf("Tests failed\n");
         exit(2);
     }
+    t33_tests();
     printf("Tests passed\n");
     return 0;
 }
index 0cacdcdd7bc165b3995a598bbddee7391bffdbad..140d8fddf9aa77c5d5c4ae86609d2c4433e26cf0 100755 (executable)
@@ -94,7 +94,7 @@ LOCALTESTS_DIR=../test-data/local
 TIFFCMP=tiffcmp
 
 # Colour/gray -> bilevel by not allowing ECM
-#for OPTS in "-p AA" "-p TT" "-p GG" "-p TG" "-p GT"
+#for OPTS in "-p FAX-FAX" "-p T38-T38" "-p FAX-T38gateway-T38gateway-FAX" "-p T38-T38gateway-FAX" "-p FAX-T38gateway-T38"
 #do
 #    IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
 #    OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-bilevel.tif"
@@ -118,7 +118,7 @@ TIFFCMP=tiffcmp
 #done
 
 # Colour/gray -> colour/gray
-#for OPTS in "-p AA -C -e" "-p TT -C -e" "-p GG -C -e" "-p TG -C -e" "-p GT -C -e"
+#for OPTS in "-p FAX-FAX -C -e" "-p T38-T38 -C -e" "-p FAX-T38gateway-T38gateway-FAX -C -e" "-p T38-T38gateway-FAX -C -e" "-p FAX-T38gateway-T38 -C -e"
 #do
 #    IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
 #    OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-out.tif"
@@ -142,7 +142,7 @@ TIFFCMP=tiffcmp
 #done
 
 # Bi-level tests with image squashing
-for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e"
+for OPTS in "-p FAX-FAX" "-p FAX-FAX -e" "-p T38-T38" "-p T38-T38 -e" "-p FAX-T38gateway-T38gateway-FAX" "-p FAX-T38gateway-T38gateway-FAX -e" "-p T38-T38gateway-FAX" "-p T38-T38gateway-FAX -e" "-p FAX-T38gateway-T38" "-p FAX-T38gateway-T38 -e"
 do
     IN_FILE="${ITUTESTS_DIR}/bilevel_R8_77_A4.tif"
     OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_77SQ_A4.tif"
@@ -241,7 +241,7 @@ do
 done
 
 # Bi-level tests
-for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e"
+for OPTS in "-p FAX-FAX" "-p FAX-FAX -e" "-p T38-T38" "-p T38-T38 -e" "-p FAX-T38gateway-T38gateway-FAX" "-p FAX-T38gateway-T38gateway-FAX -e" "-p T38-T38gateway-FAX" "-p T38-T38gateway-FAX -e" "-p FAX-T38gateway-T38" "-p FAX-T38gateway-T38 -e"
 do
     FILE="${ITUTESTS_DIR}/itutests.tif"
     run_fax_test
index 56d8d288e81c42fa8d0c28a42d37fb7ccce0ab40..bc3805af2affccbf7e54a7a941145bf32a7d0873 100644 (file)
@@ -113,7 +113,7 @@ typedef struct _null_hdr
 typedef struct _ipv6_hdr
 {
     char dontcare[6];
-    uint8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
+    u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
     char dontcare2[33];
 } ipv6_hdr;
 #endif
index 624dcb1f6cfa8ec3a6c4a294cc1ad4d0e2bfb2f0..5b199491f1e97efcae37390254effa5b5695e485 100644 (file)
 
 SNDFILE *out_handle;
 
-bool use_receiver_not_ready = false;
-bool test_local_interrupt = false;
-
 const char *output_tiff_file_name;
 
 bool log_audio = false;
 
-fax_state_t *fax;
-faxtester_state_t state;
-
-uint8_t image[1000000];
-
-uint8_t awaited[1000];
-int awaited_len = 0;
-
-char image_path[1024];
-
-t30_exchanged_info_t expected_rx_info;
-
-char next_tx_file[1000];
-
-static int timein_x = -1;
-static int timeout_x = -1;
-
-static int next_step(faxtester_state_t *s);
-
-static bool test_for_call_clear = false;
-static int call_clear_timer = 0;
-
-static bool far_end_cleared_call = false;
-
-struct
-{
-    const char *tag;
-    int code;
-} t30_status[] =
-{
-    {"OK", T30_ERR_OK},
-    {"CEDTONE", T30_ERR_CEDTONE},
-    {"T0_EXPIRED", T30_ERR_T0_EXPIRED},
-    {"T1_EXPIRED", T30_ERR_T1_EXPIRED},
-    {"T3_EXPIRED", T30_ERR_T3_EXPIRED},
-    {"HDLC_CARRIER", T30_ERR_HDLC_CARRIER},
-    {"CANNOT_TRAIN", T30_ERR_CANNOT_TRAIN},
-    {"OPER_INT_FAIL", T30_ERR_OPER_INT_FAIL},
-    {"INCOMPATIBLE", T30_ERR_INCOMPATIBLE},
-    {"RX_INCAPABLE", T30_ERR_RX_INCAPABLE},
-    {"TX_INCAPABLE", T30_ERR_TX_INCAPABLE},
-    {"NORESSUPPORT", T30_ERR_NORESSUPPORT},
-    {"NOSIZESUPPORT", T30_ERR_NOSIZESUPPORT},
-    {"UNEXPECTED", T30_ERR_UNEXPECTED},
-    {"TX_BADDCS", T30_ERR_TX_BADDCS},
-    {"TX_BADPG", T30_ERR_TX_BADPG},
-    {"TX_ECMPHD", T30_ERR_TX_ECMPHD},
-    {"TX_GOTDCN", T30_ERR_TX_GOTDCN},
-    {"TX_INVALRSP", T30_ERR_TX_INVALRSP},
-    {"TX_NODIS", T30_ERR_TX_NODIS},
-    {"TX_PHBDEAD", T30_ERR_TX_PHBDEAD},
-    {"TX_PHDDEAD", T30_ERR_TX_PHDDEAD},
-    {"TX_T5EXP", T30_ERR_TX_T5EXP},
-    {"RX_ECMPHD", T30_ERR_RX_ECMPHD},
-    {"RX_GOTDCS", T30_ERR_RX_GOTDCS},
-    {"RX_INVALCMD", T30_ERR_RX_INVALCMD},
-    {"RX_NOCARRIER", T30_ERR_RX_NOCARRIER},
-    {"RX_NOEOL", T30_ERR_RX_NOEOL},
-    {"RX_NOFAX", T30_ERR_RX_NOFAX},
-    {"RX_T2EXPDCN", T30_ERR_RX_T2EXPDCN},
-    {"RX_T2EXPD", T30_ERR_RX_T2EXPD},
-    {"RX_T2EXPFAX", T30_ERR_RX_T2EXPFAX},
-    {"RX_T2EXPMPS", T30_ERR_RX_T2EXPMPS},
-    {"RX_T2EXPRR", T30_ERR_RX_T2EXPRR},
-    {"RX_T2EXP", T30_ERR_RX_T2EXP},
-    {"RX_DCNWHY", T30_ERR_RX_DCNWHY},
-    {"RX_DCNDATA", T30_ERR_RX_DCNDATA},
-    {"RX_DCNFAX", T30_ERR_RX_DCNFAX},
-    {"RX_DCNPHD", T30_ERR_RX_DCNPHD},
-    {"RX_DCNRRD", T30_ERR_RX_DCNRRD},
-    {"RX_DCNNORTN", T30_ERR_RX_DCNNORTN},
-    {"FILEERROR", T30_ERR_FILEERROR},
-    {"NOPAGE", T30_ERR_NOPAGE},
-    {"BADTIFF", T30_ERR_BADTIFF},
-    {"BADPAGE", T30_ERR_BADPAGE},
-    {"BADTAG", T30_ERR_BADTAG},
-    {"BADTIFFHDR", T30_ERR_BADTIFFHDR},
-    {"NOMEM", T30_ERR_NOMEM},
-    {"RETRYDCN", T30_ERR_RETRYDCN},
-    {"CALLDROPPED", T30_ERR_CALLDROPPED},
-    {"NOPOLL", T30_ERR_NOPOLL},
-    {"IDENT_UNACCEPTABLE", T30_ERR_IDENT_UNACCEPTABLE},
-    {"SUB_UNACCEPTABLE", T30_ERR_SUB_UNACCEPTABLE},
-    {"SEP_UNACCEPTABLE", T30_ERR_SEP_UNACCEPTABLE},
-    {"PSA_UNACCEPTABLE", T30_ERR_PSA_UNACCEPTABLE},
-    {"SID_UNACCEPTABLE", T30_ERR_SID_UNACCEPTABLE},
-    {"PWD_UNACCEPTABLE", T30_ERR_PWD_UNACCEPTABLE},
-    {"TSA_UNACCEPTABLE", T30_ERR_TSA_UNACCEPTABLE},
-    {"IRA_UNACCEPTABLE", T30_ERR_IRA_UNACCEPTABLE},
-    {"CIA_UNACCEPTABLE", T30_ERR_CIA_UNACCEPTABLE},
-    {"ISP_UNACCEPTABLE", T30_ERR_ISP_UNACCEPTABLE},
-    {"CSA_UNACCEPTABLE", T30_ERR_CSA_UNACCEPTABLE},
-    {NULL, -1}
-};
-
-static int phase_b_handler(void *user_data, int result)
-{
-    int ch;
-    int status;
-    t30_state_t *s;
-    const char *u;
-
-    s = (t30_state_t *) user_data;
-    ch = 'A';
-    status = T30_ERR_OK;
-    if ((u = t30_get_rx_ident(s)))
-    {
-        printf("%c: Phase B: remote ident '%s'\n", ch, u);
-        if (expected_rx_info.ident[0]  &&  strcmp(expected_rx_info.ident, u))
-        {
-            printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, expected_rx_info.ident);
-            status = T30_ERR_IDENT_UNACCEPTABLE;
-        }
-    }
-    else
-    {
-        if (expected_rx_info.ident[0])
-        {
-            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);
-        if (expected_rx_info.sub_address[0]  &&  strcmp(expected_rx_info.sub_address, u))
-        {
-            printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, expected_rx_info.sub_address);
-            status = T30_ERR_SUB_UNACCEPTABLE;
-        }
-    }
-    else
-    {
-        if (expected_rx_info.sub_address[0])
-        {
-            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);
-        if (expected_rx_info.polled_sub_address[0]  &&  strcmp(expected_rx_info.polled_sub_address, u))
-        {
-            printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, expected_rx_info.polled_sub_address);
-            status = T30_ERR_PSA_UNACCEPTABLE;
-        }
-    }
-    else
-    {
-        if (expected_rx_info.polled_sub_address[0])
-        {
-            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);
-        if (expected_rx_info.selective_polling_address[0]  &&  strcmp(expected_rx_info.selective_polling_address, u))
-        {
-            printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, expected_rx_info.selective_polling_address);
-            status = T30_ERR_SEP_UNACCEPTABLE;
-        }
-    }
-    else
-    {
-        if (expected_rx_info.selective_polling_address[0])
-        {
-            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);
-        if (expected_rx_info.sender_ident[0]  &&  strcmp(expected_rx_info.sender_ident, u))
-        {
-            printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, expected_rx_info.sender_ident);
-            status = T30_ERR_SID_UNACCEPTABLE;
-        }
-    }
-    else
-    {
-        if (expected_rx_info.sender_ident[0])
-        {
-            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);
-        if (expected_rx_info.password[0]  &&  strcmp(expected_rx_info.password, u))
-        {
-            printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, expected_rx_info.password);
-            status = T30_ERR_PWD_UNACCEPTABLE;
-        }
-    }
-    else
-    {
-        if (expected_rx_info.password[0])
-        {
-            printf("%c: Phase B: remote password missing!\n", ch);
-            status = T30_ERR_PWD_UNACCEPTABLE;
-        }
-    }
-    printf("%c: Phase B handler on channel %d - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
-    return status;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int phase_d_handler(void *user_data, int result)
-{
-    int i;
-    int ch;
-    t30_state_t *s;
-    char tag[20];
-
-    i = 0;
-    s = (t30_state_t *) user_data;
-    ch = i + 'A';
-    snprintf(tag, sizeof(tag), "%c: Phase D", ch);
-    printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
-    fax_log_page_transfer_statistics(s, tag);
-    fax_log_tx_parameters(s, tag);
-    fax_log_rx_parameters(s, tag);
-
-    if (use_receiver_not_ready)
-        t30_set_receiver_not_ready(s, 3);
-
-    if (test_local_interrupt)
-    {
-        if (i == 0)
-        {
-            printf("%c: Initiating interrupt request\n", ch);
-            t30_local_interrupt_request(s, true);
-        }
-        else
-        {
-            switch (result)
-            {
-            case T30_PIP:
-            case T30_PRI_MPS:
-            case T30_PRI_EOM:
-            case T30_PRI_EOP:
-                printf("%c: Accepting interrupt request\n", ch);
-                t30_local_interrupt_request(s, true);
-                break;
-            case T30_PIN:
-                break;
-            }
-        }
-    }
-    return T30_ERR_OK;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void phase_e_handler(void *user_data, int result)
-{
-    int ch;
-    t30_state_t *s;
-    char tag[20];
-
-    ch = 'A';
-    s = (t30_state_t *) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase E", ch);
-    printf("%c: Phase E handler on channel %c - (%d) %s\n", ch, ch, result, t30_completion_code_to_str(result));
-    fax_log_final_transfer_statistics(s, tag);
-    fax_log_tx_parameters(s, tag);
-    fax_log_rx_parameters(s, tag);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void t30_real_time_frame_handler(void *user_data,
-                                        bool incoming,
-                                        const uint8_t *msg,
-                                        int len)
-{
-    if (msg == NULL)
-    {
-    }
-    else
-    {
-        fprintf(stderr,
-                "T.30: Real time frame handler - %s, %s, length = %d\n",
-                (incoming)  ?  "line->T.30"  : "T.30->line",
-                t30_frametype(msg[2]),
-                len);
-    }
-}
-/*- End of function --------------------------------------------------------*/
-
-static int document_handler(void *user_data, int event)
-{
-    int ch;
-    t30_state_t *s;
-
-    ch = 'A';
-    s = (t30_state_t *) user_data;
-    fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event);
-    if (next_tx_file[0])
-    {
-        t30_set_tx_file(s, next_tx_file, -1, -1);
-        next_tx_file[0] = '\0';
-        return true;
-    }
-    return false;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void faxtester_real_time_frame_handler(faxtester_state_t *s,
-                                              void *user_data,
-                                              int direction,
-                                              const uint8_t *msg,
-                                              int len)
-{
-    if (msg == NULL)
-    {
-        while (next_step(s) == 0)
-            ;
-        /*endwhile*/
-    }
-    else
-    {
-        fprintf(stderr,
-                "TST: Real time frame handler - %s, %s, length = %d\n",
-                (direction)  ?  "line->tester"  : "tester->line",
-                t30_frametype(msg[2]),
-                len);
-        if (direction  &&  msg[1] == awaited[1])
-        {
-            if ((awaited_len >= 0  &&  len != abs(awaited_len))
-                ||
-                (awaited_len < 0  &&  len < abs(awaited_len))
-                ||
-                memcmp(msg, awaited, abs(awaited_len)) != 0)
-            {
-                span_log_buf(&s->logging, SPAN_LOG_FLOW, "Expected", awaited, abs(awaited_len));
-                span_log_buf(&s->logging, SPAN_LOG_FLOW, "Received", msg, len);
-                printf("Test failed\n");
-                exit(2);
-            }
-        }
-        if (msg[1] == awaited[1])
-        {
-            while (next_step(s) == 0)
-                ;
-            /*endwhile*/
-        }
-    }
-}
-/*- End of function --------------------------------------------------------*/
-
-static void faxtester_front_end_step_complete_handler(faxtester_state_t *s, void *user_data)
-{
-    while (next_step(s) == 0)
-        ;
-    /*endwhile*/
-}
-/*- End of function --------------------------------------------------------*/
-
-static void faxtester_front_end_step_timeout_handler(faxtester_state_t *s, void *user_data)
-{
-    span_log(&s->logging, SPAN_LOG_FLOW, "FAX tester step timed out\n");
-    printf("Test failed\n");
-    exit(2);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void fax_prepare(void)
-{
-    t30_state_t *t30;
-    logging_state_t *logging;
-
-    t30 = fax_get_t30_state(fax);
-    fax_set_transmit_on_idle(fax, true);
-    fax_set_tep_mode(fax, true);
-#if 0
-    t30_set_tx_ident(t30, "1234567890");
-    t30_set_tx_sub_address(t30, "Sub-address");
-    t30_set_tx_sender_ident(t30, "Sender ID");
-    t30_set_tx_password(t30, "Password");
-    t30_set_tx_polled_sub_address(t30, "Polled sub-address");
-    t30_set_tx_selective_polling_address(t30, "Sel polling address");
-#endif
-    t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSF\x00", 16);
-    //t30_set_tx_nss(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSS\x00", 16);
-    t30_set_tx_nsc(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSC\x00", 16);
-    t30_set_ecm_capability(t30, true);
-    t30_set_supported_t30_features(t30,
-                                   T30_SUPPORT_IDENTIFICATION
-                                 | T30_SUPPORT_SELECTIVE_POLLING
-                                 | T30_SUPPORT_SUB_ADDRESSING);
-    t30_set_supported_image_sizes(t30,
-                                  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);
-    t30_set_supported_bilevel_resolutions(t30,
-                                          T4_RESOLUTION_R8_STANDARD
-                                        | T4_RESOLUTION_R8_FINE
-                                        | T4_RESOLUTION_R8_SUPERFINE
-                                        | T4_RESOLUTION_R16_SUPERFINE
-                                        | T4_RESOLUTION_100_100
-                                        | 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);
-    t30_set_supported_colour_resolutions(t30, 0);
-    t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
-    t30_set_supported_compressions(t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6);
-    t30_set_phase_b_handler(t30, phase_b_handler, (void *) t30);
-    t30_set_phase_d_handler(t30, phase_d_handler, (void *) t30);
-    t30_set_phase_e_handler(t30, phase_e_handler, (void *) t30);
-    t30_set_real_time_frame_handler(t30, t30_real_time_frame_handler, (void *) t30);
-    t30_set_document_handler(t30, document_handler, (void *) t30);
-
-    logging = fax_get_logging_state(fax);
-    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-    span_log_set_tag(logging, "A");
-
-    logging = t30_get_logging_state(t30);
-    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-    span_log_set_tag(logging, "A");
-
-#if 0
-    span_log_set_level(&fax.modems.v27ter_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-    span_log_set_tag(&fax.modems.v27ter_rx.logging, "A");
-    span_log_set_level(&fax.modems.v29_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-    span_log_set_tag(&fax.modems.v29_rx.logging, "A");
-    span_log_set_level(&fax.modems.v17_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-    span_log_set_tag(&fax.modems.v17_rx.logging, "A");
-#endif
-}
-/*- End of function --------------------------------------------------------*/
-
-static int string_to_msg(uint8_t msg[], uint8_t mask[], const char buf[])
-{
-    int i;
-    int x;
-    const char *t;
-
-    msg[0] = 0;
-    mask[0] = 0xFF;
-    i = 0;
-    t = (char *) buf;
-    while (*t)
-    {
-        /* Skip white space */
-        while (isspace((int) *t))
-            t++;
-        /* If we find ... we allow arbitrary addition info beyond this point in the message */
-        if (t[0] == '.'  &&  t[1] == '.'  &&  t[2] == '.')
-        {
-            return -i;
-        }
-        else if (isxdigit((int) *t))
-        {
-            for (  ;  isxdigit((int) *t);  t++)
-            {
-                x = *t;
-                if (x >= 'a')
-                    x -= 0x20;
-                if (x >= 'A')
-                    x -= ('A' - 10);
-                else
-                    x -= '0';
-                msg[i] = (msg[i] << 4) | x;
-            }
-            mask[i] = 0xFF;
-            if (*t == '/')
-            {
-                /* There is a mask following the byte */
-                mask[i] = 0;
-                for (t++;  isxdigit((int) *t);  t++)
-                {
-                    x = *t;
-                    if (x >= 'a')
-                        x -= 0x20;
-                    if (x >= 'A')
-                        x -= ('A' - 10);
-                    else
-                        x -= '0';
-                    mask[i] = (mask[i] << 4) | x;
-                }
-            }
-            if (*t  &&  !isspace((int) *t))
-            {
-                /* Bad string */
-                return 0;
-            }
-            i++;
-        }
-    }
-    return i;
-}
-/*- End of function --------------------------------------------------------*/
-
-#if 0
-static void string_test2(const uint8_t msg[], int len)
-{
-    int i;
-
-    if (len > 0)
-    {
-        for (i = 0;  i < len - 1;  i++)
-            printf("%02X ", msg[i]);
-        printf("%02X", msg[i]);
-    }
-}
-/*- End of function --------------------------------------------------------*/
-
-static void string_test3(const char buf[])
-{
-    uint8_t msg[1000];
-    uint8_t mask[1000];
-    int len;
-    int i;
-
-    len = string_to_msg(msg, mask, buf);
-    printf("Len = %d: ", len);
-    string_test2(msg, abs(len));
-    printf("/");
-    string_test2(mask, abs(len));
-    printf("\n");
-}
-/*- End of function --------------------------------------------------------*/
-
-static int string_test(void)
-{
-    string_test3("FF C8 12 34 56 78");
-    string_test3("FF C8 12/55 34 56/aA 78 ");
-    string_test3("FF C8 12/55 34 56/aA 78 ...");
-    string_test3("FF C8 12/55 34 56/aA 78...");
-    string_test3("FF C8 12/55 34 56/aA 78 ... 99 88 77");
-    exit(0);
-}
-/*- End of function --------------------------------------------------------*/
-#endif
-
-static void corrupt_image(faxtester_state_t *s, uint8_t image[], int len, const char *bad_rows)
-{
-    int i;
-    int j;
-    int k;
-    uint32_t bits;
-    uint32_t bitsx;
-    int list[1000];
-    int x;
-    int row;
-    const char *t;
-
-    /* Form the list of rows to be hit */
-    x = 0;
-    t = bad_rows;
-    while (*t)
-    {
-        while (isspace((int) *t))
-            t++;
-        if (sscanf(t, "%d", &list[x]) < 1)
-            break;
-        x++;
-        while (isdigit((int) *t))
-            t++;
-        if (*t == ',')
-            t++;
-    }
-
-    /* Go through the image, and corrupt the first bit of every listed row */
-    bits = 0x7FF;
-    bitsx = 0x7FF;
-    row = 0;
-    for (i = 0;  i < len;  i++)
-    {
-        bits ^= (image[i] << 11);
-        bitsx ^= (image[i] << 11);
-        for (j = 0;  j < 8;  j++)
-        {
-            if ((bits & 0xFFF) == 0x800)
-            {
-                /* We are at an EOL. Is this row in the list of rows to be corrupted? */
-                row++;
-                for (k = 0;  k < x;  k++)
-                {
-                    if (list[k] == row)
-                    {
-                        /* Corrupt this row. TSB85 says to hit the first bit after the EOL */
-                        bitsx ^= 0x1000;
-                    }
-                }
-            }
-            bits >>= 1;
-            bitsx >>= 1;
-        }
-        image[i] = (bitsx >> 3) & 0xFF;
-    }
-    span_log(&s->logging, SPAN_LOG_FLOW, "%d rows found. %d corrupted\n", row, x);
-}
-/*- End of function --------------------------------------------------------*/
-
-static int next_step(faxtester_state_t *s)
-{
-    int delay;
-    int flags;
-    xmlChar *dir;
-    xmlChar *type;
-    xmlChar *modem;
-    xmlChar *value;
-    xmlChar *tag;
-    xmlChar *bad_rows;
-    xmlChar *crc_error;
-    xmlChar *pattern;
-    xmlChar *timein;
-    xmlChar *timeout;
-    xmlChar *min_bits;
-    xmlChar *frame_size;
-    xmlChar *block;
-    xmlChar *compression;
-    uint8_t buf[1000];
-    uint8_t mask[1000];
-    char path[1024];
-    int i;
-    int j;
-    int hdlc;
-    int short_train;
-    int min_row_bits;
-    int ecm_frame_size;
-    int ecm_block;
-    int compression_type;
-    int len;
-    t4_tx_state_t t4_tx_state;
-    t30_state_t *t30;
-    t30_stats_t t30_stats;
-
-    test_for_call_clear = false;
-    if (s->cur == NULL)
-    {
-        if (!s->final_delayed)
-        {
-            /* Add a bit of waiting at the end, to ensure everything gets flushed through,
-               any timers can expire, etc. */
-            faxtester_set_timeout(s, -1);
-            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
-            faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, 120000, false);
-            s->final_delayed = true;
-            return 1;
-        }
-        /* Finished */
-        printf("Test passed\n");
-        exit(0);
-    }
-    while (s->cur  &&  xmlStrcmp(s->cur->name, (const xmlChar *) "step") != 0)
-        s->cur = s->cur->next;
-    if (s->cur == NULL)
-    {
-        /* Finished */
-        printf("Test passed\n");
-        exit(0);
-    }
-
-    dir = xmlGetProp(s->cur, (const xmlChar *) "dir");
-    type = xmlGetProp(s->cur, (const xmlChar *) "type");
-    modem = xmlGetProp(s->cur, (const xmlChar *) "modem");
-    value = xmlGetProp(s->cur, (const xmlChar *) "value");
-    tag = xmlGetProp(s->cur, (const xmlChar *) "tag");
-    bad_rows = xmlGetProp(s->cur, (const xmlChar *) "bad_rows");
-    crc_error = xmlGetProp(s->cur, (const xmlChar *) "crc_error");
-    pattern = xmlGetProp(s->cur, (const xmlChar *) "pattern");
-    timein = xmlGetProp(s->cur, (const xmlChar *) "timein");
-    timeout = xmlGetProp(s->cur, (const xmlChar *) "timeout");
-    min_bits = xmlGetProp(s->cur, (const xmlChar *) "min_bits");
-    frame_size = xmlGetProp(s->cur, (const xmlChar *) "frame_size");
-    block = xmlGetProp(s->cur, (const xmlChar *) "block");
-    compression = xmlGetProp(s->cur, (const xmlChar *) "compression");
-
-    s->cur = s->cur->next;
-
-    span_log(&s->logging,
-             SPAN_LOG_FLOW,
-             "Dir - %s, type - %s, modem - %s, value - %s, timein - %s, timeout - %s, tag - %s\n",
-             (dir)  ?  (const char *) dir  :  "",
-             (type)  ?  (const char *) type  :  "",
-             (modem)  ?  (const char *) modem  :  "",
-             (value)  ?  (const char *) value  :  "",
-             (timein)  ?  (const char *) timein  :  "",
-             (timeout)  ?  (const char *) timeout  :  "",
-             (tag)  ?  (const char *) tag  :  "");
-    if (type == NULL)
-        return 1;
-    if (timein)
-        timein_x = atoi((const char *) timein);
-    else
-        timein_x = -1;
-    if (timeout)
-        timeout_x = atoi((const char *) timeout);
-    else
-        timeout_x = -1;
-
-    if (dir  &&  strcasecmp((const char *) dir, "R") == 0)
-    {
-        /* Receive always has a timeout applied. */
-        if (timeout_x < 0)
-            timeout_x = 7000;
-        faxtester_set_timeout(s, timeout_x);
-        if (modem)
-        {
-            hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0);
-            short_train = (strcasecmp((const char *) type, "TCF") != 0);
-            faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
-            if (strcasecmp((const char *) modem, "V.21") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V21, 300, false, true);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/14400") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/12000") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/9600") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/7200") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.29/9600") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V29, 9600, false, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.29/7200") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V29, 7200, false, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.27ter/4800") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.27ter/2400") == 0)
-            {
-                faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
-            }
-            else
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
-            }
-        }
-
-        if (strcasecmp((const char *) type, "SET") == 0)
-        {
-            if (strcasecmp((const char *) tag, "IDENT") == 0)
-                strcpy(expected_rx_info.ident, (const char *) value);
-            else if (strcasecmp((const char *) tag, "SUB") == 0)
-                strcpy(expected_rx_info.sub_address, (const char *) value);
-            else if (strcasecmp((const char *) tag, "SEP") == 0)
-                strcpy(expected_rx_info.selective_polling_address, (const char *) value);
-            else if (strcasecmp((const char *) tag, "PSA") == 0)
-                strcpy(expected_rx_info.polled_sub_address, (const char *) value);
-            else if (strcasecmp((const char *) tag, "SID") == 0)
-                strcpy(expected_rx_info.sender_ident, (const char *) value);
-            else if (strcasecmp((const char *) tag, "PWD") == 0)
-                strcpy(expected_rx_info.password, (const char *) value);
-            return 0;
-        }
-        else if (strcasecmp((const char *) type, "CNG") == 0)
-        {
-            /* Look for CNG */
-            faxtester_set_rx_type(s, T30_MODEM_CNG, 0, false, false);
-            faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
-        }
-        else if (strcasecmp((const char *) type, "CED") == 0)
-        {
-            /* Look for CED */
-            faxtester_set_rx_type(s, T30_MODEM_CED, 0, false, false);
-            faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
-        }
-        else if (strcasecmp((const char *) type, "HDLC") == 0)
-        {
-            i = string_to_msg(buf, mask, (const char *) value);
-            bit_reverse(awaited, buf, abs(i));
-            awaited_len = i;
-        }
-        else if (strcasecmp((const char *) type, "TCF") == 0)
-        {
-        }
-        else if (strcasecmp((const char *) type, "MSG") == 0)
-        {
-        }
-        else if (strcasecmp((const char *) type, "PP") == 0)
-        {
-        }
-        else if (strcasecmp((const char *) type, "SILENCE") == 0)
-        {
-            faxtest_set_rx_silence(s);
-        }
-        else if (strcasecmp((const char *) type, "CLEAR") == 0)
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n");
-            test_for_call_clear = true;
-            call_clear_timer = 0;
-        }
-        else
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) type);
-            return 0;
-        }
-    }
-    else
-    {
-        faxtester_set_timeout(s, timeout_x);
-        if (modem)
-        {
-            hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0);
-            short_train = (strcasecmp((const char *) type, "TCF") != 0);
-            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
-            if (strcasecmp((const char *) modem, "V.21") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V21, 300, false, true);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/14400") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/12000") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/9600") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.17/7200") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.29/9600") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V29, 9600, false, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.29/7200") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V29, 7200, false, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.27ter/4800") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
-            }
-            else if (strcasecmp((const char *) modem, "V.27ter/2400") == 0)
-            {
-                faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
-            }
-            else
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
-            }
-        }
-
-        if (strcasecmp((const char *) type, "SET") == 0)
-        {
-            t30 = fax_get_t30_state(fax);
-            if (strcasecmp((const char *) tag, "IDENT") == 0)
-                t30_set_tx_ident(t30, (const char *) value);
-            else if (strcasecmp((const char *) tag, "SUB") == 0)
-                t30_set_tx_sub_address(t30, (const char *) value);
-            else if (strcasecmp((const char *) tag, "SEP") == 0)
-                t30_set_tx_selective_polling_address(t30, (const char *) value);
-            else if (strcasecmp((const char *) tag, "PSA") == 0)
-                t30_set_tx_polled_sub_address(t30, (const char *) value);
-            else if (strcasecmp((const char *) tag, "SID") == 0)
-                t30_set_tx_sender_ident(t30, (const char *) value);
-            else if (strcasecmp((const char *) tag, "PWD") == 0)
-                t30_set_tx_password(t30, (const char *) value);
-            else if (strcasecmp((const char *) tag, "RXFILE") == 0)
-            {
-                if (value)
-                    t30_set_rx_file(t30, (const char *) value, -1);
-                else
-                    t30_set_rx_file(t30, output_tiff_file_name, -1);
-            }
-            else if (strcasecmp((const char *) tag, "TXFILE") == 0)
-            {
-                sprintf(next_tx_file, "%s/%s", image_path, (const char *) value);
-                printf("Push '%s'\n", next_tx_file);
-            }
-            return 0;
-        }
-        else if (strcasecmp((const char *) type, "CALL") == 0)
-        {
-            fax = fax_init(NULL, false);
-            fax_prepare();
-            next_tx_file[0] = '\0';
-            t30 = fax_get_t30_state(fax);
-            t30_set_rx_file(t30, output_tiff_file_name, -1);
-            /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
-            t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D);
-            if (value)
-            {
-                sprintf(path, "%s/%s", image_path, (const char *) value);
-                t30_set_tx_file(t30, path, -1, -1);
-            }
-            return 0;
-        }
-        else if (strcasecmp((const char *) type, "ANSWER") == 0)
-        {
-            fax = fax_init(NULL, true);
-            fax_prepare();
-            next_tx_file[0] = '\0';
-            t30 = fax_get_t30_state(fax);
-            /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
-            t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D);
-            if (value)
-            {
-                sprintf(path, "%s/%s", image_path, (const char *) value);
-                t30_set_tx_file(t30, path, -1, -1);
-            }
-            return 0;
-        }
-        else if (strcasecmp((const char *) type, "CNG") == 0)
-        {
-            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
-            faxtester_set_tx_type(s, T30_MODEM_CNG, 0, false, false);
-        }
-        else if (strcasecmp((const char *) type, "CED") == 0)
-        {
-            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
-            faxtester_set_tx_type(s, T30_MODEM_CED, 0, false, false);
-        }
-        else if (strcasecmp((const char *) type, "WAIT") == 0)
-        {
-            delay = (value)  ?  atoi((const char *) value)  :  1;
-            faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
-            faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, delay, false);
-        }
-        else if (strcasecmp((const char *) type, "PREAMBLE") == 0)
-        {
-            flags = (value)  ?  atoi((const char *) value)  :  37;
-            faxtester_send_hdlc_flags(s, flags);
-        }
-        else if (strcasecmp((const char *) type, "POSTAMBLE") == 0)
-        {
-            flags = (value)  ?  atoi((const char *) value)  :  5;
-            faxtester_send_hdlc_flags(s, flags);
-        }
-        else if (strcasecmp((const char *) type, "HDLC") == 0)
-        {
-            i = string_to_msg(buf, mask, (const char *) value);
-            bit_reverse(buf, buf, abs(i));
-            if (crc_error  &&  strcasecmp((const char *) crc_error, "0") == 0)
-                faxtester_send_hdlc_msg(s, buf, abs(i), false);
-            else
-                faxtester_send_hdlc_msg(s, buf, abs(i), true);
-        }
-        else if (strcasecmp((const char *) type, "TCF") == 0)
-        {
-            if (value)
-                i = atoi((const char *) value);
-            else
-                i = 450;
-            if (pattern)
-            {
-                /* TODO: implement proper patterns */
-                j = atoi((const char *) pattern);
-                memset(image, 0x55, j);
-                if (i > j)
-                    memset(image + j, 0, i - j);
-            }
-            else
-            {
-                memset(image, 0, i);
-            }
-            faxtester_set_non_ecm_image_buffer(s, image, i);
-        }
-        else if (strcasecmp((const char *) type, "MSG") == 0)
-        {
-            /* A non-ECM page */
-            min_row_bits = (min_bits)  ?  atoi((const char *) min_bits)  :  0;
-            sprintf(path, "%s/%s", image_path, (const char *) value);
-            if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
-                printf("Test failed\n");
-                exit(2);
-            }
-            t4_tx_set_header_info(&t4_tx_state, NULL);
-            compression_type = T4_COMPRESSION_T4_1D;
-            if (compression)
-            {
-                if (strcasecmp((const char *) compression, "T.4 2D") == 0)
-                    compression_type = T4_COMPRESSION_T4_2D;
-                else if (strcasecmp((const char *) compression, "T.6") == 0)
-                    compression_type = T4_COMPRESSION_T6;
-            }
-            if (t4_tx_set_tx_image_format(&t4_tx_state,
-                                          compression_type,
-                                          T4_SUPPORT_WIDTH_215MM
-                                        | T4_SUPPORT_LENGTH_US_LETTER
-                                        | T4_SUPPORT_LENGTH_US_LEGAL
-                                        | T4_SUPPORT_LENGTH_UNLIMITED,
-                                          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,
-                                          T4_RESOLUTION_100_100
-                                        | T4_RESOLUTION_200_200
-                                        | T4_RESOLUTION_300_300
-                                        | T4_RESOLUTION_400_400
-                                        | T4_RESOLUTION_600_600
-                                        | T4_RESOLUTION_1200_1200) < 0)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
-                printf("Test failed\n");
-                exit(2);
-            }
-            t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
-            if (t4_tx_start_page(&t4_tx_state))
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
-                printf("Test failed\n");
-                exit(2);
-            }
-            len = t4_tx_get(&t4_tx_state, image, sizeof(image));
-            if (bad_rows)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
-                corrupt_image(s, image, len, (const char *) bad_rows);
-            }
-            t4_tx_release(&t4_tx_state);
-            span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM image is %d bytes (min row bits %d)\n", len, min_row_bits);
-            faxtester_set_non_ecm_image_buffer(s, image, len);
-        }
-        else if (strcasecmp((const char *) type, "PP") == 0)
-        {
-            min_row_bits = (min_bits)  ?  atoi((const char *) min_bits)  :  0;
-            ecm_block = (block)  ?  atoi((const char *) block)  :  0;
-            ecm_frame_size = (frame_size)  ?  atoi((const char *) frame_size)  :  64;
-            i = (crc_error)  ?  atoi((const char *) crc_error)  :  -1;
-            sprintf(path, "%s/%s", image_path, (const char *) value);
-            if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
-                printf("Test failed\n");
-                exit(2);
-            }
-            t4_tx_set_header_info(&t4_tx_state, NULL);
-            compression_type = T4_COMPRESSION_T4_1D;
-            if (compression)
-            {
-                if (strcasecmp((const char *) compression, "T.4 2D") == 0)
-                    compression_type = T4_COMPRESSION_T4_2D;
-                else if (strcasecmp((const char *) compression, "T.6") == 0)
-                    compression_type = T4_COMPRESSION_T6;
-            }
-            if (t4_tx_set_tx_image_format(&t4_tx_state,
-                                          compression_type,
-                                          T4_SUPPORT_WIDTH_215MM
-                                        | T4_SUPPORT_LENGTH_US_LETTER
-                                        | T4_SUPPORT_LENGTH_US_LEGAL
-                                        | T4_SUPPORT_LENGTH_UNLIMITED,
-                                          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,
-                                          T4_RESOLUTION_100_100
-                                        | T4_RESOLUTION_200_200
-                                        | T4_RESOLUTION_300_300
-                                        | T4_RESOLUTION_400_400
-                                        | T4_RESOLUTION_600_600
-                                        | T4_RESOLUTION_1200_1200) < 0)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
-                printf("Test failed\n");
-                exit(2);
-            }
-            t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
-            if (t4_tx_start_page(&t4_tx_state))
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
-                printf("Test failed\n");
-                exit(2);
-            }
-            /*endif*/
-            len = t4_tx_get(&t4_tx_state, image, sizeof(image));
-            if (bad_rows)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
-                corrupt_image(s, image, len, (const char *) bad_rows);
-            }
-            /*endif*/
-            t4_tx_release(&t4_tx_state);
-            span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", len, min_row_bits);
-            faxtester_set_ecm_image_buffer(s, image, len, ecm_block, ecm_frame_size, i);
-        }
-        else if (strcasecmp((const char *) type, "CLEAR") == 0)
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n");
-            t30 = fax_get_t30_state(fax);
-            t30_terminate(t30);
-            return 0;
-        }
-        else if (strcasecmp((const char *) type, "STATUS") == 0)
-        {
-            if (value)
-            {
-                for (i = 0;  t30_status[i].code >= 0;  i++)
-                {
-                    if (strcmp(t30_status[i].tag, (const char *) value) == 0)
-                        break;
-                }
-                if (t30_status[i].code >= 0)
-                    delay = t30_status[i].code;
-                else
-                    delay = atoi((const char *) value);
-                t30 = fax_get_t30_state(fax);
-                t30_get_transfer_statistics(t30, &t30_stats);
-                span_log(&s->logging, SPAN_LOG_FLOW, "Expect status %d. Got %d\n", delay, t30_stats.current_status);
-                if (delay != t30_stats.current_status)
-                {
-                    printf("Test failed\n");
-                    exit(2);
-                }
-            }
-            return 0;
-        }
-        else
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) type);
-            return 0;
-        }
-        /*endif*/
-    }
-    /*endif*/
-    return 1;
-}
-/*- End of function --------------------------------------------------------*/
+faxtester_state_t *state;
 
 static void exchange(faxtester_state_t *s)
 {
@@ -1270,21 +102,37 @@ static void exchange(faxtester_state_t *s)
 
     total_audio_time = 0;
 
-    faxtester_set_transmit_on_idle(&state, true);
-    faxtester_set_real_time_frame_handler(&state, faxtester_real_time_frame_handler, NULL);
-    faxtester_set_front_end_step_complete_handler(&state, faxtester_front_end_step_complete_handler, NULL);
-    faxtester_set_front_end_step_timeout_handler(&state, faxtester_front_end_step_timeout_handler, NULL);
+    faxtester_set_transmit_on_idle(s, true);
 
-    fax = fax_init(NULL, false);
-    fax_prepare();
-    next_tx_file[0] = '\0';
+    s->far_fax = fax_init(NULL, false);
+    s->far_t30 = fax_get_t30_state(s->far_fax);
+    s->far_tag = 'A';
+
+    if (s->far_fax)
+        logging = fax_get_logging_state(s->far_fax);
+    else
+        logging = t38_terminal_get_logging_state(s->far_t38);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+    span_log_set_tag(logging, "A");
 
-    while (next_step(s) == 0)
+    logging = t30_get_logging_state(s->far_t30);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+    span_log_set_tag(logging, "A");
+
+#if 0
+    span_log_set_level(&fax.modems.v27ter_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+    span_log_set_tag(&fax.modems.v27ter_rx.logging, "A");
+    span_log_set_level(&fax.modems.v29_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+    span_log_set_tag(&fax.modems.v29_rx.logging, "A");
+    span_log_set_level(&fax.modems.v17_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+    span_log_set_tag(&fax.modems.v17_rx.logging, "A");
+#endif
+    while (faxtester_next_step(s) == 0)
         ;
     /*endwhile*/
     for (;;)
     {
-        len = fax_tx(fax, amp, SAMPLES_PER_CHUNK);
+        len = fax_tx(s->far_fax, amp, SAMPLES_PER_CHUNK);
         faxtester_rx(s, amp, len);
         if (log_audio)
         {
@@ -1296,20 +144,21 @@ static void exchange(faxtester_state_t *s)
 
         total_audio_time += SAMPLES_PER_CHUNK;
 
-        logging = t30_get_logging_state(fax_get_t30_state(fax));
+        logging = t30_get_logging_state(s->far_t30);
         span_log_bump_samples(logging, len);
 #if 0
         span_log_bump_samples(&fax.modems.v27ter_rx.logging, len);
         span_log_bump_samples(&fax.modems.v29_rx.logging, len);
         span_log_bump_samples(&fax.modems.v17_rx.logging, len);
 #endif
-        logging = fax_get_logging_state(fax);
+        logging = fax_get_logging_state(s->far_fax);
         span_log_bump_samples(logging, len);
 
-        span_log_bump_samples(&s->logging, len);
+        logging = faxtester_get_logging_state(s);
+        span_log_bump_samples(logging, len);
 
         len = faxtester_tx(s, amp, SAMPLES_PER_CHUNK);
-        if (fax_rx(fax, amp, len))
+        if (fax_rx(s->far_fax, amp, len))
             break;
         /*endif*/
         if (log_audio)
@@ -1322,21 +171,21 @@ static void exchange(faxtester_state_t *s)
             /*endif*/
         }
         /*endif*/
-        if (test_for_call_clear  &&  !far_end_cleared_call)
+        if (s->test_for_call_clear  &&  !s->far_end_cleared_call)
         {
-            call_clear_timer += len;
-            if (!t30_call_active(fax_get_t30_state(fax)))
+            s->call_clear_timer += len;
+            if (!t30_call_active(s->far_t30))
             {
-                span_log(&s->logging, SPAN_LOG_FLOW, "Far end cleared after %dms (limits %dms to %dms)\n", call_clear_timer/8, timein_x, timeout_x);
-                if (call_clear_timer/8 < timein_x  ||  call_clear_timer/8 > timeout_x)
+                span_log(faxtester_get_logging_state(s), SPAN_LOG_FLOW, "Far end cleared after %dms (limits %dms to %dms)\n", s->call_clear_timer/8, s->timein_x, s->timeout);
+                if (s->call_clear_timer/8 < s->timein_x  ||  s->call_clear_timer/8 > s->timeout_x)
                 {
                     printf("Test failed\n");
                     exit(2);
                 }
-                span_log(&s->logging, SPAN_LOG_FLOW, "Clear time OK\n");
-                far_end_cleared_call = true;
-                test_for_call_clear = false;
-                while (next_step(s) == 0)
+                span_log(faxtester_get_logging_state(s), SPAN_LOG_FLOW, "Clear time OK\n");
+                s->far_end_cleared_call = true;
+                s->test_for_call_clear = false;
+                while (faxtester_next_step(s) == 0)
                     ;
                 /*endwhile*/
             }
@@ -1359,154 +208,11 @@ static void exchange(faxtester_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-static int parse_config(faxtester_state_t *s, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur)
-{
-    xmlChar *x;
-    xmlChar *y;
-
-    while (cur)
-    {
-        if (xmlStrcmp(cur->name, (const xmlChar *) "path") == 0)
-        {
-            if ((x = xmlGetProp(cur, (const xmlChar *) "type"))
-                &&
-                (y = xmlGetProp(cur, (const xmlChar *) "value")))
-            {
-                if (strcasecmp((const char *) x, "IMAGE") == 0)
-                {
-                    span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s' '%s'\n", (char *) x, (char *) y);
-                    strcpy(image_path, (const char *) y);
-                }
-                /*endif*/
-            }
-            /*endif*/
-        }
-        /*endif*/
-        cur = cur->next;
-    }
-    /*endwhile*/
-    return -1;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int parse_test_group(faxtester_state_t *s, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, const char *test)
-{
-    xmlChar *x;
-
-    while (cur)
-    {
-        if (xmlStrcmp(cur->name, (const xmlChar *) "test") == 0)
-        {
-            if ((x = xmlGetProp(cur, (const xmlChar *) "name")))
-            {
-                if (xmlStrcmp(x, (const xmlChar *) test) == 0)
-                {
-                    span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s'\n", (char *) x);
-                    s->cur = cur->xmlChildrenNode;
-                    return 0;
-                }
-                /*endif*/
-            }
-            /*endif*/
-        }
-        /*endif*/
-        cur = cur->next;
-    }
-    /*endwhile*/
-    return -1;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int get_test_set(faxtester_state_t *s, const char *test_file, const char *test)
-{
-    xmlParserCtxtPtr ctxt;
-    xmlNsPtr ns;
-    xmlNodePtr cur;
-
-    ns = NULL;
-    xmlKeepBlanksDefault(0);
-    xmlCleanupParser();
-
-    if ((ctxt = xmlNewParserCtxt()) == NULL)
-    {
-        fprintf(stderr, "Failed to allocate parser context\n");
-        printf("Test failed\n");
-        exit(2);
-    }
-    /* parse the file, activating the DTD validation option */
-    if ((s->doc = xmlCtxtReadFile(ctxt, test_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
-    {
-        fprintf(stderr, "Failed to read the XML document\n");
-        printf("Test failed\n");
-        exit(2);
-    }
-    if (ctxt->valid == 0)
-    {
-        fprintf(stderr, "Failed to validate the XML document\n");
-       xmlFreeDoc(s->doc);
-        xmlFreeParserCtxt(ctxt);
-        printf("Test failed\n");
-        exit(2);
-    }
-    xmlFreeParserCtxt(ctxt);
-
-    /* Check the document is of the right kind */
-    if ((cur = xmlDocGetRootElement(s->doc)) == NULL)
-    {
-        xmlFreeDoc(s->doc);
-        fprintf(stderr, "Empty document\n");
-        printf("Test failed\n");
-        exit(2);
-    }
-    /*endif*/
-    if (xmlStrcmp(cur->name, (const xmlChar *) "fax-tests"))
-    {
-        xmlFreeDoc(s->doc);
-        fprintf(stderr, "Document of the wrong type, root node != fax-tests");
-        printf("Test failed\n");
-        exit(2);
-    }
-    /*endif*/
-    cur = cur->xmlChildrenNode;
-    while (cur  &&  xmlIsBlankNode(cur))
-        cur = cur->next;
-    /*endwhile*/
-    if (cur == NULL)
-    {
-        printf("Test failed\n");
-        exit(2);
-    }
-    /*endif*/
-    while (cur)
-    {
-        if (xmlStrcmp(cur->name, (const xmlChar *) "config") == 0)
-        {
-            parse_config(s, s->doc, ns, cur->xmlChildrenNode);
-        }
-        /*endif*/
-        if (xmlStrcmp(cur->name, (const xmlChar *) "test-group") == 0)
-        {
-            if (parse_test_group(s, s->doc, ns, cur->xmlChildrenNode, test) == 0)
-            {
-                /* We found the test we want, so run it. */
-                exchange(s);
-                break;
-            }
-            /*endif*/
-        }
-        /*endif*/
-        cur = cur->next;
-    }
-    /*endwhile*/
-    xmlFreeDoc(s->doc);
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
 int main(int argc, char *argv[])
 {
     const char *xml_file_name;
     const char *test_name;
+    logging_state_t *logging;
     int opt;
 
 #if 0
@@ -1537,13 +243,18 @@ int main(int argc, char *argv[])
     if (argc > 0)
         test_name = argv[0];
 
-    strcpy(image_path, ".");
-    faxtester_init(&state, true);
-    memset(&expected_rx_info, 0, sizeof(expected_rx_info));
-    span_log_set_level(&state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-    span_log_set_tag(&state.logging, "B");
-    get_test_set(&state, xml_file_name, test_name);
-    faxtester_release(&state);
+    if ((state = faxtester_init(NULL, xml_file_name, test_name)) == NULL)
+    {
+        fprintf(stderr, "Cannot start FAX tester instance\n");
+        printf("Test failed\n");
+        exit(2);
+    }
+    logging = faxtester_get_logging_state(state);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+    span_log_set_tag(logging, "B");
+    /* We found the test we want, so run it. */
+    exchange(state);
+    faxtester_free(state);
     printf("Done\n");
     return 0;
 }
diff --git a/src/mod/endpoints/mod_gsmopen/mobigater b/src/mod/endpoints/mod_gsmopen/mobigater
deleted file mode 120000 (symlink)
index cfea4c0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-alsa_nogsmlib_nocplusplus
\ No newline at end of file