Various small cleanups in spandsp

This commit is contained in:
Steve Underwood 2014-05-07 13:11:53 +08:00
parent 88ce7dae1c
commit 44252a5d69
14 changed files with 1121 additions and 67 deletions

View File

@ -202,6 +202,18 @@ AC_CHECK_HEADERS([stdlib.h])
AC_CHECK_HEADERS([string.h])
AC_CHECK_HEADERS([strings.h])
AC_CHECK_HEADERS([malloc.h])
AC_CHECK_HEADERS([math.h], [INSERT_MATH_HEADER="#include <math.h>"])
AC_CHECK_HEADERS([float.h])
AC_CHECK_HEADERS([fcntl.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/select.h])
AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/fcntl.h])
AC_CHECK_HEADERS([sndfile.h])
AC_CHECK_HEADERS([fenv.h])
AC_CHECK_HEADERS([fftw3.h], , [AC_CHECK_HEADERS([fftw.h])])
AC_CHECK_HEADERS([pcap.h])
AC_CHECK_HEADERS([pthread.h])
case "$host" in
*dragonfly*)
@ -215,18 +227,6 @@ case "$host" in
;;
esac
AC_CHECK_HEADERS([math.h], [INSERT_MATH_HEADER="#include <math.h>"])
AC_CHECK_HEADERS([float.h])
AC_CHECK_HEADERS([fcntl.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/select.h])
AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/fcntl.h])
AC_CHECK_HEADERS([sndfile.h])
AC_CHECK_HEADERS([fenv.h])
AC_CHECK_HEADERS([fftw3.h], , [AC_CHECK_HEADERS([fftw.h])])
AC_CHECK_HEADERS([pcap.h])
AC_CHECK_HEADERS([pthread.h])
if test "${build}" == "${host}"
then
AC_CHECK_HEADERS([X11/X.h])

View File

@ -110,6 +110,7 @@ libspandsp_la_SOURCES = ademco_contactid.c \
complex_vector_float.c \
complex_vector_int.c \
crc.c \
data_modems.c \
dds_float.c \
dds_int.c \
dtmf.c \
@ -210,6 +211,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \
spandsp/complex_filters.h \
spandsp/complex_vector_float.h \
spandsp/complex_vector_int.h \
spandsp/data_modems.h \
spandsp/dc_restore.h \
spandsp/dds.h \
spandsp/dtmf.h \
@ -292,6 +294,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \
spandsp/private/bell_r2_mf.h \
spandsp/private/bert.h \
spandsp/private/bitstream.h \
spandsp/private/data_modems.h \
spandsp/private/dtmf.h \
spandsp/private/echo.h \
spandsp/private/fax.h \

View File

@ -124,6 +124,7 @@
#include <spandsp/t30_logging.h>
#include <spandsp/t35.h>
#include <spandsp/at_interpreter.h>
#include <spandsp/data_modems.h>
#include <spandsp/fax_modems.h>
#include <spandsp/fax.h>
#include <spandsp/t38_core.h>

View File

@ -82,7 +82,7 @@
#include <spandsp/private/v42.h>
#include <spandsp/private/v42bis.h>
#include <spandsp/private/at_interpreter.h>
//#include <spandsp/private/data_modems.h>
#include <spandsp/private/data_modems.h>
#include <spandsp/private/fax_modems.h>
#include <spandsp/private/timezone.h>
#include <spandsp/private/image_translate.h>

View File

@ -65,7 +65,7 @@
#include "spandsp/private/v27ter_tx.h"
#if defined(SPANDSP_USE_FIXED_POINT)
#define FP_SCALE FP_Q6_10
#define FP_SCALE(x) FP_Q6_10(x)
#else
#define FP_SCALE(x) (x)
#endif

View File

@ -70,7 +70,7 @@
enum
{
V8_WAIT_1S, /* Start point when sending CI */
V8_WAIT_1S = 0, /* Start point when sending CI */
V8_AWAIT_ANSAM, /* Start point when sending initial silence */
V8_CI_ON,
V8_CI_OFF,
@ -539,16 +539,16 @@ static void put_bit(void *user_data, int bit)
switch (s->preamble_type)
{
case V8_SYNC_CI:
tag = "CI: ";
tag = ">CI: ";
break;
case V8_SYNC_CM_JM:
tag = (s->calling_party) ? "JM: " : "CM: ";
tag = (s->calling_party) ? ">JM: " : ">CM: ";
break;
case V8_SYNC_V92:
tag = "V92: ";
tag = ">V.92: ";
break;
default:
tag = "??: ";
tag = ">??: ";
break;
}
span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr);
@ -639,20 +639,26 @@ static void v8_put_preamble(v8_state_t *s)
}
/*- End of function --------------------------------------------------------*/
static void v8_put_byte(v8_state_t *s, int data)
static void v8_put_bytes(v8_state_t *s, uint8_t buf[], int len)
{
int i;
int j;
uint8_t byte;
uint8_t bits[10];
/* Insert start & stop bits */
bits[0] = 0;
for (i = 1; i < 9; i++)
for (i = 0; i < len; i++)
{
bits[i] = (uint8_t) (data & 1);
data >>= 1;
bits[0] = 0;
byte = buf[i];
for (j = 1; j < 9; j++)
{
bits[j] = byte & 1;
byte >>= 1;
}
bits[9] = 1;
queue_write(s->tx_queue, bits, 10);
}
bits[9] = 1;
queue_write(s->tx_queue, bits, 10);
}
/*- End of function --------------------------------------------------------*/
@ -661,12 +667,15 @@ static void send_cm_jm(v8_state_t *s)
int val;
unsigned int offered_modulations;
int bytes;
uint8_t buf[10];
int ptr;
/* Send a CM, or a JM as appropriate */
v8_put_preamble(s);
v8_put_byte(s, V8_CM_JM_SYNC_OCTET);
ptr = 0;
buf[ptr++] = V8_CM_JM_SYNC_OCTET;
/* Data call */
v8_put_byte(s, (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG);
buf[ptr++] = (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG;
/* Supported modulations */
offered_modulations = s->result.modulations;
@ -676,7 +685,9 @@ static void send_cm_jm(v8_state_t *s)
val |= 0x20;
if (offered_modulations & V8_MOD_V34)
val |= 0x40;
v8_put_byte(s, val);
if (offered_modulations & V8_MOD_V34HDX)
val |= 0x80;
buf[ptr++] = val;
if (++bytes < s->modulation_bytes)
{
val = 0x10;
@ -690,7 +701,7 @@ static void send_cm_jm(v8_state_t *s)
val |= 0x40;
if (offered_modulations & V8_MOD_V27TER)
val |= 0x80;
v8_put_byte(s, val);
buf[ptr++] = val;
}
if (++bytes < s->modulation_bytes)
{
@ -705,19 +716,21 @@ static void send_cm_jm(v8_state_t *s)
val |= 0x40;
if (offered_modulations & V8_MOD_V21)
val |= 0x80;
v8_put_byte(s, val);
buf[ptr++] = val;
}
if (s->parms.protocol)
v8_put_byte(s, (s->parms.protocol << 5) | V8_PROTOCOLS_TAG);
buf[ptr++] = (s->parms.protocol << 5) | V8_PROTOCOLS_TAG;
if (s->parms.pstn_access)
v8_put_byte(s, (s->parms.pstn_access << 5) | V8_PSTN_ACCESS_TAG);
buf[ptr++] = (s->parms.pstn_access << 5) | V8_PSTN_ACCESS_TAG;
if (s->parms.pcm_modem_availability)
v8_put_byte(s, (s->parms.pcm_modem_availability << 5) | V8_PCM_MODEM_AVAILABILITY_TAG);
buf[ptr++] = (s->parms.pcm_modem_availability << 5) | V8_PCM_MODEM_AVAILABILITY_TAG;
if (s->parms.t66 >= 0)
v8_put_byte(s, (s->parms.t66 << 5) | V8_T66_TAG);
buf[ptr++] = (s->parms.t66 << 5) | V8_T66_TAG;
/* No NSF */
//v8_put_byte(s, (0 << 5) | V8_NSF_TAG);
//buf[ptr++] = (0 << 5) | V8_NSF_TAG;
span_log_buf(&s->logging, SPAN_LOG_FLOW, (s->calling_party) ? "<CM: " : "<JM: ", &buf[1], ptr - 1);
v8_put_bytes(s, buf, ptr);
}
/*- End of function --------------------------------------------------------*/
@ -729,7 +742,15 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
len = 0;
if (s->modem_connect_tone_tx_on)
{
if (s->modem_connect_tone_tx_on > ms_to_samples(75))
if (s->modem_connect_tone_tx_on == (ms_to_samples(75) + 2))
{
if (s->fsk_tx_on)
{
/* The initial silence is over */
s->modem_connect_tone_tx_on = 0;
}
}
else if (s->modem_connect_tone_tx_on == (ms_to_samples(75) + 1))
{
/* Send the ANSam tone */
len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len);
@ -752,14 +773,19 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
}
if (s->fsk_tx_on && len < max_len)
{
max_len -= len;
len = fsk_tx(&s->v21tx, amp + len, max_len);
len += fsk_tx(&s->v21tx, &amp[len], max_len - len);
if (len < max_len)
{
span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends\n");
span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends (%d/%d) %d %d\n", len, max_len, s->fsk_tx_on, s->state);
s->fsk_tx_on = false;
//s->state = V8_PARKED;
}
}
if (s->state != V8_PARKED && len < max_len)
{
vec_zeroi16(&amp[len], max_len - len);
len = max_len;
}
return len;
}
/*- End of function --------------------------------------------------------*/
@ -767,6 +793,7 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
static void send_v92(v8_state_t *s)
{
int i;
uint8_t buf[2];
if (s->result.v92 >= 0)
{
@ -774,8 +801,10 @@ static void send_v92(v8_state_t *s)
for (i = 0; i < 2; i++)
{
v8_put_preamble(s);
v8_put_byte(s, V8_V92_SYNC_OCTET);
v8_put_byte(s, s->result.v92);
buf[0] = V8_V92_SYNC_OCTET;
buf[1] = s->result.v92;
span_log_buf(&s->logging, SPAN_LOG_FLOW, "<V.92: ", &buf[1], 1);
v8_put_bytes(s, buf, 2);
}
}
}
@ -784,13 +813,16 @@ static void send_v92(v8_state_t *s)
static void send_ci(v8_state_t *s)
{
int i;
uint8_t buf[2];
/* Send 4 CI packets in a burst (the spec says at least 3) */
for (i = 0; i < 4; i++)
{
v8_put_preamble(s);
v8_put_byte(s, V8_CI_SYNC_OCTET);
v8_put_byte(s, (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG);
buf[0] = V8_CI_SYNC_OCTET;
buf[1] = (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG;
span_log_buf(&s->logging, SPAN_LOG_FLOW, "<CI: ", &buf[1], 1);
v8_put_bytes(s, buf, 2);
}
}
/*- End of function --------------------------------------------------------*/
@ -822,9 +854,9 @@ static void handle_modem_connect_tone(v8_state_t *s, int tone)
SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
{
int i;
int residual_samples;
int tone;
uint8_t buf[3];
//span_log(&s->logging, SPAN_LOG_FLOW, "v8_rx state %d\n", s->state);
residual_samples = 0;
@ -911,8 +943,9 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
/* Now JM has been detected, we send CJ and wait for 75 ms
before finishing the V.8 analysis. */
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
for (i = 0; i < 3; i++)
v8_put_byte(s, 0);
memset(buf, 0, 3);
v8_put_bytes(s, buf, 3);
span_log_buf(&s->logging, SPAN_LOG_FLOW, "<CJ: ", &buf[1], 2);
s->state = V8_CJ_ON;
s->fsk_tx_on = true;
break;
@ -1060,6 +1093,7 @@ SPAN_DECLARE(int) v8_restart(v8_state_t *s, bool calling_party, v8_parms_t *parm
}
modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL);
fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s);
s->modem_connect_tone_tx_on = ms_to_samples(75) + 2;
}
else
{

View File

@ -73,10 +73,12 @@ noinst_PROGRAMS = ademco_contactid_tests \
complex_vector_float_tests \
complex_vector_int_tests \
crc_tests \
data_modems_tests \
dc_restore_tests \
dds_tests \
dtmf_rx_tests \
dtmf_tx_tests \
dummy_modems_tests \
echo_tests \
fax_decode \
fax_tests \
@ -151,6 +153,7 @@ noinst_HEADERS = echo_monitor.h \
modem_monitor.h \
pcap_parse.h \
pseudo_terminals.h \
socket_harness.h \
udptl.h
ademco_contactid_tests_SOURCES = ademco_contactid_tests.c
@ -198,6 +201,9 @@ complex_vector_int_tests_LDADD = $(LIBDIR) -lspandsp
crc_tests_SOURCES = crc_tests.c
crc_tests_LDADD = $(LIBDIR) -lspandsp
data_modems_tests_SOURCES = data_modems_tests.c media_monitor.cpp
data_modems_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp
dc_restore_tests_SOURCES = dc_restore_tests.c
dc_restore_tests_LDADD = $(LIBDIR) -lspandsp
@ -210,6 +216,9 @@ dtmf_rx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lsp
dtmf_tx_tests_SOURCES = dtmf_tx_tests.c
dtmf_tx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp
dummy_modems_tests_SOURCES = dummy_modems_tests.c media_monitor.cpp socket_harness.c pseudo_terminals.c
dummy_modems_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp -lutil
echo_tests_SOURCES = echo_tests.c echo_monitor.cpp
echo_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp

View File

@ -0,0 +1,312 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* data_modems_tests.c - Tests for data_modems.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2011 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
/*! \page data_modems_tests_page Data modems tests
\section data_modems_tests_page_sec_1 What does it do?
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
#define ENABLE_GUI
#endif
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sndfile.h>
#include "spandsp.h"
#include "spandsp-sim.h"
#if defined(ENABLE_GUI)
#include "media_monitor.h"
#endif
#define INPUT_FILE_NAME "../test-data/itu/fax/itu1.tif"
#define OUTPUT_FILE_NAME "t31.tif"
#define OUTPUT_WAVE_FILE_NAME "data_modems.wav"
#define SAMPLES_PER_CHUNK 160
struct command_response_s
{
const char *command;
int len_command;
const char *response;
int len_response;
};
char *decode_test_file = NULL;
int countdown = 0;
int command_response_test_step = -1;
char response_buf[1000];
int response_buf_ptr = 0;
bool answered = false;
bool done = false;
bool sequence_terminated = false;
data_modems_state_t *data_modems_state[2];
static void reporter(void *user_data, int reason, bert_results_t *results)
{
int channel;
channel = (int) (intptr_t) user_data;
switch (reason)
{
case BERT_REPORT_SYNCED:
fprintf(stderr, "%d: BERT report synced\n", channel);
break;
case BERT_REPORT_UNSYNCED:
fprintf(stderr, "%d: BERT report unsync'ed\n", channel);
break;
case BERT_REPORT_REGULAR:
fprintf(stderr, "%d: BERT report regular - %d bits, %d bad bits, %d resyncs\n", channel, results->total_bits, results->bad_bits, results->resyncs);
break;
case BERT_REPORT_GT_10_2:
fprintf(stderr, "%d: BERT report > 1 in 10^2\n", channel);
break;
case BERT_REPORT_LT_10_2:
fprintf(stderr, "%d: BERT report < 1 in 10^2\n", channel);
break;
case BERT_REPORT_LT_10_3:
fprintf(stderr, "%d: BERT report < 1 in 10^3\n", channel);
break;
case BERT_REPORT_LT_10_4:
fprintf(stderr, "%d: BERT report < 1 in 10^4\n", channel);
break;
case BERT_REPORT_LT_10_5:
fprintf(stderr, "%d: BERT report < 1 in 10^5\n", channel);
break;
case BERT_REPORT_LT_10_6:
fprintf(stderr, "%d: BERT report < 1 in 10^6\n", channel);
break;
case BERT_REPORT_LT_10_7:
fprintf(stderr, "%d: BERT report < 1 in 10^7\n", channel);
break;
default:
fprintf(stderr, "%d: BERT report reason %d\n", channel, reason);
break;
}
}
/*- End of function --------------------------------------------------------*/
static int get_msg(void *user_data, uint8_t msg[], int len)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
static void put_msg(void *user_data, const uint8_t msg[], int len)
{
if (len < 0)
printf("Status %s\n", signal_status_to_str(len));
}
/*- End of function --------------------------------------------------------*/
static int modem_tests(int use_gui, int log_audio, int test_sending)
{
int mdm_len;
int16_t mdm_amp[SAMPLES_PER_CHUNK];
//int use_tep;
//logging_state_t *logging;
int outframes;
int16_t silence[SAMPLES_PER_CHUNK];
int16_t out_amp[2*SAMPLES_PER_CHUNK];
SNDFILE *wave_handle;
SNDFILE *in_handle;
int i;
int k;
int calling_party;
logging_state_t *logging;
bert_state_t *bert[2];
/* Test a pair of modems against each other */
/* Set up the test environment */
//use_tep = false;
wave_handle = NULL;
if (log_audio)
{
if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL)
{
fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
exit(2);
}
}
in_handle = NULL;
if (decode_test_file)
{
if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
{
fprintf(stderr, " Cannot create audio file '%s'\n", decode_test_file);
exit(2);
}
}
memset(silence, 0, sizeof(silence));
memset(mdm_amp, 0, sizeof(mdm_amp));
mdm_len = 0;
/* Now set up and run the modems */
calling_party = true;
for (i = 0; i < 2; i++)
{
bert[i] = bert_init(NULL, 1000000, BERT_PATTERN_ITU_O152_11, 2400, 20);
bert_set_report(bert[i], 100000, reporter, (void *) (intptr_t) i);
if ((data_modems_state[i] = data_modems_init(NULL,
calling_party,
put_msg,
get_msg,
NULL)) == NULL)
{
fprintf(stderr, " Cannot start the data modem\n");
exit(2);
}
logging = data_modems_get_logging_state(data_modems_state[i]);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
span_log_set_tag(logging, "Modem");
calling_party = false;
}
#if defined(ENABLE_GUI)
if (use_gui)
start_media_monitor();
#endif
while (!done)
{
for (i = 0; i < 2; i++)
{
/* 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. */
mdm_len = data_modems_tx(data_modems_state[i], mdm_amp, SAMPLES_PER_CHUNK);
if (mdm_len < SAMPLES_PER_CHUNK)
{
vec_zeroi16(mdm_amp + mdm_len, SAMPLES_PER_CHUNK - mdm_len);
mdm_len = SAMPLES_PER_CHUNK;
}
if (log_audio)
{
for (k = 0; k < mdm_len; k++)
out_amp[2*k + i] = mdm_amp[k];
}
if (data_modems_rx(data_modems_state[i ^ 1], mdm_amp, mdm_len))
break;
}
if (log_audio)
{
outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
if (outframes != SAMPLES_PER_CHUNK)
break;
}
}
if (decode_test_file)
{
if (sf_close_telephony(in_handle))
{
fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file);
exit(2);
}
}
if (log_audio)
{
if (sf_close_telephony(wave_handle))
{
fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
exit(2);
}
}
if (!done || !sequence_terminated)
{
printf("Tests failed\n");
return 2;
}
return 0;
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
{
int log_audio;
int test_sending;
int use_gui;
int opt;
decode_test_file = NULL;
log_audio = false;
test_sending = false;
use_gui = false;
while ((opt = getopt(argc, argv, "d:glrs")) != -1)
{
switch (opt)
{
case 'd':
decode_test_file = optarg;
break;
case 'g':
#if defined(ENABLE_GUI)
use_gui = true;
#else
fprintf(stderr, "Graphical monitoring not available\n");
exit(2);
#endif
break;
case 'l':
log_audio = true;
break;
case 'r':
test_sending = false;
break;
case 's':
test_sending = true;
break;
default:
//usage();
exit(2);
break;
}
}
modem_tests(use_gui, log_audio, test_sending);
printf("Tests passed\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,253 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* dummy_modems_tests.c - Tests for data_modems connected together by sockets.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2011 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
/*! \page dummy_modems_tests_page Dummy data modems tests
\section dummy_modems_tests_page_sec_1 What does it do?
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
#define ENABLE_GUI
#endif
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <termios.h>
#include <sndfile.h>
//#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
#include "spandsp.h"
#include "spandsp-sim.h"
#include "pseudo_terminals.h"
#include "socket_harness.h"
#if defined(ENABLE_GUI)
#include "media_monitor.h"
#endif
#define OUTPUT_WAVE_FILE_NAME "dummy_modems.wav"
#define SAMPLES_PER_CHUNK 160
SNDFILE *wave_handle = NULL;
int16_t wave_buffer[4096];
data_modems_state_t *data_modem_state;
static int get_msg(void *user_data, uint8_t msg[], int len)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
static void put_msg(void *user_data, const uint8_t msg[], int len)
{
if (len < 0)
printf("Status %s\n", signal_status_to_str(len));
else
printf("Put %d '%s'\n", len, msg);
}
/*- End of function --------------------------------------------------------*/
static void terminal_callback(void *user_data, const uint8_t msg[], int len)
{
printf("terminal callback %d\n", len);
}
/*- End of function --------------------------------------------------------*/
static int termios_callback(void *user_data, struct termios *termios)
{
printf("termios callback\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
static void hangup_callback(void *user_data, int status)
{
}
/*- End of function --------------------------------------------------------*/
static int terminal_free_space_callback(void *user_data)
{
return 42;
}
/*- End of function --------------------------------------------------------*/
static int rx_callback(void *user_data, const int16_t amp[], int samples)
{
int i;
int out_samples;
out_samples = data_modems_rx((data_modems_state_t *) user_data, amp, samples);
if (wave_handle)
{
for (i = 0; i < samples; i++)
wave_buffer[2*i] = amp[i];
}
return out_samples;
}
/*- End of function --------------------------------------------------------*/
static int rx_fillin_callback(void *user_data, int samples)
{
return data_modems_rx_fillin((data_modems_state_t *) user_data, samples);
}
/*- End of function --------------------------------------------------------*/
static int tx_callback(void *user_data, int16_t amp[], int samples)
{
int i;
int out_samples;
out_samples = data_modems_tx((data_modems_state_t *) user_data, amp, samples);
if (wave_handle)
{
if (out_samples < samples)
memset(&amp[out_samples], 0, (samples - out_samples)*2);
for (i = 0; i < samples; i++)
wave_buffer[2*i + 1] = amp[i];
sf_writef_short(wave_handle, wave_buffer, samples);
}
return samples;
}
/*- End of function --------------------------------------------------------*/
static int modem_tests(int use_gui, int log_audio, bool calling_party)
{
logging_state_t *logging;
socket_harness_state_t *s;
/* Now set up and run the modems */
if ((data_modem_state = data_modems_init(NULL,
calling_party,
put_msg,
get_msg,
NULL)) == NULL)
{
fprintf(stderr, " Cannot start the data modem\n");
exit(2);
}
logging = data_modems_get_logging_state(data_modem_state);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_DATE);
span_log_set_tag(logging, "Modem");
if ((s = socket_harness_init(NULL,
"/tmp/modemsocket",
"modemA",
calling_party,
terminal_callback,
termios_callback,
hangup_callback,
terminal_free_space_callback,
rx_callback,
rx_fillin_callback,
tx_callback,
data_modem_state)) == NULL)
{
fprintf(stderr, " Cannot start the socket harness\n");
exit(2);
}
wave_handle = NULL;
if (log_audio)
{
if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL)
{
fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
exit(2);
}
}
socket_harness_run(s);
if (log_audio)
{
if (sf_close_telephony(wave_handle))
{
fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
exit(2);
}
}
return 0;
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
{
int log_audio;
int use_gui;
int opt;
bool calling_party;
log_audio = false;
calling_party = false;
use_gui = false;
while ((opt = getopt(argc, argv, "acgl")) != -1)
{
switch (opt)
{
case 'a':
calling_party = false;
break;
case 'c':
calling_party = true;
break;
case 'g':
#if defined(ENABLE_GUI)
use_gui = true;
#else
fprintf(stderr, "Graphical monitoring not available\n");
exit(2);
#endif
break;
case 'l':
log_audio = true;
break;
default:
//usage();
exit(2);
break;
}
}
if (modem_tests(use_gui, log_audio, calling_party))
exit(2);
printf("Tests passed\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -29,15 +29,21 @@
\section fax_tests_page_sec_1 What does it do?
These tests exercise the following FAX to FAX paths:
+--Modems-+-----------TDM/RTP-----------+-Modems--+
| \ / |
| \ / |
T.30 <---+ T.38 gateway T.38 gateway +--->T.30
| \ / |
| \ / |
+---T.38---+----+----UDPTL/RTP----+----+---T.38---+
\ /
+----------TCP----------+
TSB85 <-----------+ +-----------> TSB85
\ /
T.31 <-----------+ \ / +-----------> T.31
\ \ / /
+--Modems-+-+-----------TDM/RTP-----------+-+-Modems--+
| \ / |
| \ / |
T.30 <---+ T.38 gateway T.38 gateway +---> T.30
| \ / |
| \ / |
+---T.38---+-+----+----UDPTL/RTP----+----+ +---T.38---+
/ / \ / \ \
T.31 <------------/ / +----------TCP----------+ \ +------------> T.31
/ \
TSB85 <------------+ +------------> TSB85
T.30<->Modems<-------------------------TDM/RTP------------------------->Modems<->T.30
T.30<->Modems<-TDM/RTP->T.38 gateway<-UDPTL/RTP->T.38 gateway<-TDM/RTP->Modems<->T.30
@ -45,6 +51,7 @@ T.30<->Modems<-TDM/RTP->T.38 gateway<-UDPTL/RTP-------------------------->T.38<-
T.30<->T.38<--------------------------UDPTL/RTP->T.38 gateway<-TDM/RTP->Modems<->T.30
T.30<->T.38<--------------------------UDPTL/RTP-------------------------->T.38<->T.30
The T.31 and TSB85 parts are incomplete right now.
*/
#if defined(HAVE_CONFIG_H)
@ -520,6 +527,7 @@ int main(int argc, char *argv[])
char *page_header_info;
char *page_header_tz;
const char *tag;
const char *xml_file_name;
char buf[132 + 1];
#if defined(ENABLE_GUI)
int use_gui;
@ -557,7 +565,8 @@ int main(int argc, char *argv[])
colour_enabled = false;
t37_like_output = false;
t38_transport = T38_TRANSPORT_UDPTL;
while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:z:")) != -1)
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)
{
switch (opt)
{
@ -682,6 +691,9 @@ int main(int argc, char *argv[])
case 'v':
t38_version = atoi(optarg);
break;
case 'x':
xml_file_name = optarg;
break;
case 'z':
page_header_tz = optarg;
break;
@ -736,8 +748,9 @@ int main(int argc, char *argv[])
tag = (i == 0) ? "A" : "B";
memset(&expected_rx_info[i], 0, sizeof(expected_rx_info[i]));
if (mode[i] == T38_TERMINAL_FAX)
switch (mode[i])
{
case T38_TERMINAL_FAX:
if ((t38_state[i] = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
{
fprintf(stderr, "Cannot start the T.38 terminal instance\n");
@ -757,9 +770,9 @@ int main(int argc, char *argv[])
logging = t30_get_logging_state(t30_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);
}
else
{
break;
case AUDIO_FAX:
case T38_GATEWAY_FAX:
if ((fax_state[i] = fax_init(NULL, (i == 0))) == NULL)
{
fprintf(stderr, "Cannot start FAX instance\n");
@ -783,7 +796,7 @@ int main(int argc, char *argv[])
{
if ((t38_gateway_state[i] = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
{
fprintf(stderr, "Cannot start the T.38 gateway instancel\n");
fprintf(stderr, "Cannot start the T.38 gateway instance\n");
exit(2);
}
t38_core_state[i] = t38_gateway_get_t38_core_state(t38_gateway_state[i]);
@ -820,6 +833,17 @@ int main(int argc, char *argv[])
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:
break;
}
set_t30_callbacks(t30_state[i], i);
}

View File

@ -0,0 +1,346 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* socket_harness.c
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2007 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \page bitstream_tests_page Bitstream tests
\section bitstream_tests_page_sec_1 What does it do?
\section bitstream_tests_page_sec_2 How is it used?
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#define _GNU_SOURCE
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
#include "spandsp.h"
#include "pseudo_terminals.h"
#include "socket_harness.h"
//#define SIMULATE_RING 1
#define CLOSE_COUNT_MAX 100
/* static data */
static int16_t inbuf[4096];
static int16_t outbuf[4096];
static volatile sig_atomic_t keep_running = true;
static void log_signal(int signum)
{
fprintf(stderr, "Signal %d: mark termination.\n", signum);
keep_running = false;
exit(2);
}
/*- End of function --------------------------------------------------------*/
int socket_harness_run(socket_harness_state_t *s)
{
struct timeval tmo;
fd_set rset;
fd_set eset;
struct termios termios;
int max_fd;
int count;
int samples;
int tx_samples;
int ret;
while (keep_running)
{
//if (s->modem->event)
// modem_event(s->modem);
#ifdef SIMULATE_RING
tmo.tv_sec = 0;
tmo.tv_usec= 1000000/RING_HZ;
#else
tmo.tv_sec = 1;
tmo.tv_usec= 0;
#endif
max_fd = 0;
FD_ZERO(&rset);
FD_ZERO(&eset);
FD_SET(s->audio_fd, &rset);
FD_SET(s->audio_fd, &eset);
FD_SET(s->pty_fd, &rset);
FD_SET(s->pty_fd, &eset);
if (s->audio_fd > max_fd)
max_fd = s->audio_fd;
if (s->pty_fd > max_fd)
max_fd = s->pty_fd;
if (s->pty_closed && s->close_count)
{
if (!s->started || s->close_count++ > CLOSE_COUNT_MAX)
s->close_count = 0;
}
else if (s->terminal_free_space_callback(s->user_data))
{
FD_SET(s->pty_fd, &rset);
if (s->pty_fd > max_fd)
max_fd = s->pty_fd;
}
if ((ret = select(max_fd + 1, &rset, NULL, &eset, &tmo)) < 0)
{
if (errno == EINTR)
continue;
fprintf(stderr, "Error: select: %s\n", strerror(errno));
return ret;
}
if (ret == 0)
{
/* Timeout */
#ifdef SIMULATE_RING
if (!modem->modem->started)
{
rcount++;
if (rcount <= RING_ON)
modem_ring(modem->modem);
else if (rcount > RING_OFF)
rcount = 0;
}
#endif
continue;
}
if (FD_ISSET(s->audio_fd, &rset))
{
if ((count = read(s->audio_fd, inbuf, sizeof(inbuf)/2)) < 0)
{
if (errno != EAGAIN)
{
fprintf(stderr, "Error: audio read: %s\n", strerror(errno));
return -1;
}
count = 0;
}
if (count == 0)
{
fprintf(stderr, "Audio socket closed\n");
return 0;
}
samples = count/2;
usleep(125*samples);
s->rx_callback(s->user_data, inbuf, samples);
tx_samples = s->tx_callback(s->user_data, outbuf, samples);
if (tx_samples < samples)
memset(&outbuf[tx_samples], 0, (samples - tx_samples)*2);
if ((count = write(s->audio_fd, outbuf, samples*2)) < 0)
{
if (errno != EAGAIN)
{
fprintf(stderr, "Error: audio write: %s\n", strerror(errno));
return -1;
}
/* TODO: */
}
if (count != samples*2)
fprintf(stderr, "audio write = %d\n", count);
}
if (FD_ISSET(s->pty_fd, &rset))
{
/* Check termios */
tcgetattr(s->pty_fd, &termios);
if (memcmp(&termios, &s->termios, sizeof(termios)))
s->termios_callback(s->user_data, &termios);
/* Read data */
if ((count = s->terminal_free_space_callback(s->user_data)))
{
if (count > sizeof(inbuf))
count = sizeof(inbuf);
if ((count = read(s->pty_fd, inbuf, count)) < 0)
{
if (errno == EAGAIN)
{
fprintf(stderr, "pty read, errno = EAGAIN\n");
}
else
{
if (errno == EIO)
{
if (!s->pty_closed)
{
fprintf(stderr, "pty closed.\n");
s->pty_closed = 1;
if ((termios.c_cflag & HUPCL))
s->hangup_callback(s->user_data, 0);
}
s->close_count = 1;
}
else
{
fprintf(stderr, "Error: pty read: %s\n", strerror(errno));
return -1;
}
}
}
else
{
if (count == 0)
fprintf(stderr, "pty read = 0\n");
s->pty_closed = false;
s->terminal_callback(s->user_data, (uint8_t *) inbuf, count);
}
}
}
}
return 0;
}
/*- End of function --------------------------------------------------------*/
socket_harness_state_t *socket_harness_init(socket_harness_state_t *s,
const char *socket_name,
const char *tag,
int caller,
put_msg_func_t terminal_callback,
termio_update_func_t termios_callback,
modem_status_func_t hangup_callback,
put_msg_free_space_func_t terminal_free_space_callback,
span_rx_handler_t rx_callback,
span_rx_fillin_handler_t rx_fillin_callback,
span_tx_handler_t tx_callback,
void *user_data)
{
int sockfd;
int listensockfd;
struct sockaddr_un serv_addr;
struct sockaddr_un cli_addr;
socklen_t servlen;
socklen_t clilen;
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
fprintf(stderr, "Socket failed - errno = %d\n", errno);
return NULL;
}
if (s == NULL)
{
if ((s = (socket_harness_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
signal(SIGINT, log_signal);
signal(SIGTERM, log_signal);
s->terminal_callback = terminal_callback;
s->termios_callback = termios_callback;
s->hangup_callback = hangup_callback;
s->terminal_free_space_callback = terminal_free_space_callback;
s->rx_callback = rx_callback;
s->rx_fillin_callback = rx_fillin_callback;
s->tx_callback = tx_callback;
s->user_data = user_data;
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
/* This is a generic Unix domain socket. */
strcpy(serv_addr.sun_path, socket_name);
printf("Creating socket '%s'\n", serv_addr.sun_path);
servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family) + 1;
if (caller)
{
fprintf(stderr, "Connecting to '%s'\n", serv_addr.sun_path);
if (connect(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0)
{
fprintf(stderr, "Connect failed - errno = %d\n", errno);
exit(2);
}
fprintf(stderr, "Connected to '%s'\n", serv_addr.sun_path);
}
else
{
fprintf(stderr, "Listening to '%s'\n", serv_addr.sun_path);
listensockfd = sockfd;
/* The file may or may not exist. Just try to delete it anyway. */
unlink(serv_addr.sun_path);
if (bind(listensockfd, (struct sockaddr *) &serv_addr, servlen) < 0)
{
fprintf(stderr, "Bind failed - errno = %d\n", errno);
exit(2);
}
listen(listensockfd, 5);
clilen = sizeof(cli_addr);
if ((sockfd = accept(listensockfd, (struct sockaddr *) &cli_addr, &clilen)) < 0)
{
fprintf(stderr, "Accept failed - errno = %d", errno);
exit(2);
}
fprintf(stderr, "Accepted on '%s'\n", serv_addr.sun_path);
}
if (pseudo_terminal_create(&s->modem))
{
fprintf(stderr, "Failed to create pseudo TTY\n");
exit(2);
}
s->audio_fd = sockfd;
s->pty_fd = s->modem.master;
return s;
}
/*- End of function --------------------------------------------------------*/
int socket_harness_release(socket_harness_state_t *s)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
int socket_harness_free(socket_harness_state_t *s)
{
free(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,73 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* socket_harness.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2012 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
typedef int (*termio_update_func_t)(void *user_data, struct termios *termios);
typedef int (*put_msg_free_space_func_t)(void *user_data);
typedef struct socket_harness_state_s
{
void *user_data;
put_msg_func_t terminal_callback;
termio_update_func_t termios_callback;
modem_status_func_t hangup_callback;
put_msg_free_space_func_t terminal_free_space_callback;
span_rx_handler_t rx_callback;
span_rx_fillin_handler_t rx_fillin_callback;
span_tx_handler_t tx_callback;
int audio_fd;
int pty_fd;
logging_state_t logging;
struct termios termios;
unsigned int delay;
unsigned int started;
unsigned pty_closed;
unsigned close_count;
modem_t modem;
} socket_harness_state_t;
int socket_harness_run(socket_harness_state_t *s);
socket_harness_state_t *socket_harness_init(socket_harness_state_t *s,
const char *socket_name,
const char *tag,
int caller,
put_msg_func_t terminal_callback,
termio_update_func_t termios_callback,
modem_status_func_t hangup_callback,
put_msg_free_space_func_t terminal_free_space_callback,
span_rx_handler_t rx_callback,
span_rx_fillin_handler_t rx_fillin_callback,
span_tx_handler_t tx_callback,
void *user_data);
int socket_harness_release(socket_harness_state_t *s);
int socket_harness_free(socket_harness_state_t *s);

View File

@ -53,7 +53,7 @@ else
cd gsm0610
fi
if [ $1x = --no-exe-runx ]
if [ $1x == --no-exe-runx ]
then
# Run the .exe files, which should be here
./FR_A.EXE
@ -77,7 +77,7 @@ rm -rf READ_FRA.TXT
rm -rf ACTION
rm -rf unpacked
if [ $1x = --no-exex ]
if [ $1x == --no-exex ]
then
# We need to prepare the .exe files to be run separately
rm -rf *.INP

View File

@ -1,5 +1,4 @@
:
#!/bin/sh
#
# Install the things which need adding to a fresh Fedora or Centos install to make it ready to build
# spandsp and its test suite
@ -19,7 +18,7 @@ yum install fftw-devel \
sox \
gcc-c++ \
libtool \
autconf \
autoconf \
automake \
m4 \
netpbm \