Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/tests/t31_tests.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
| author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
|---|---|
| date | Fri, 25 Jun 2010 15:50:58 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
|---|---|
| 1 /* | |
| 2 * SpanDSP - a series of DSP components for telephony | |
| 3 * | |
| 4 * t31_tests.c - Tests for the T.31 modem. | |
| 5 * | |
| 6 * Written by Steve Underwood <steveu@coppice.org> | |
| 7 * | |
| 8 * Copyright (C) 2004 Steve Underwood | |
| 9 * | |
| 10 * All rights reserved. | |
| 11 * | |
| 12 * This program is free software; you can redistribute it and/or modify | |
| 13 * it under the terms of the GNU General Public License version 2, as | |
| 14 * published by the Free Software Foundation. | |
| 15 * | |
| 16 * This program is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 * GNU General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU General Public License | |
| 22 * along with this program; if not, write to the Free Software | |
| 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 24 * | |
| 25 * $Id: t31_tests.c,v 1.72 2009/05/30 15:23:14 steveu Exp $ | |
| 26 */ | |
| 27 | |
| 28 /*! \file */ | |
| 29 | |
| 30 /*! \page t31_tests_page T.31 tests | |
| 31 \section t31_tests_page_sec_1 What does it do? | |
| 32 */ | |
| 33 | |
| 34 /* Enable the following definition to enable direct probing into the FAX structures */ | |
| 35 //#define WITH_SPANDSP_INTERNALS | |
| 36 | |
| 37 #if defined(HAVE_CONFIG_H) | |
| 38 #include "config.h" | |
| 39 #endif | |
| 40 | |
| 41 #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) | |
| 42 #define ENABLE_GUI | |
| 43 #endif | |
| 44 | |
| 45 #include <stdlib.h> | |
| 46 #include <stdio.h> | |
| 47 #include <fcntl.h> | |
| 48 #include <unistd.h> | |
| 49 #include <string.h> | |
| 50 #include <assert.h> | |
| 51 #include <sndfile.h> | |
| 52 | |
| 53 //#if defined(WITH_SPANDSP_INTERNALS) | |
| 54 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES | |
| 55 //#endif | |
| 56 | |
| 57 #include "spandsp.h" | |
| 58 #include "spandsp/t30_fcf.h" | |
| 59 #include "spandsp-sim.h" | |
| 60 | |
| 61 #if defined(ENABLE_GUI) | |
| 62 #include "media_monitor.h" | |
| 63 #endif | |
| 64 #include "fax_utils.h" | |
| 65 | |
| 66 #define INPUT_FILE_NAME "../test-data/itu/fax/itu1.tif" | |
| 67 #define OUTPUT_FILE_NAME "t31.tif" | |
| 68 #define OUTPUT_WAVE_FILE_NAME "t31_tests.wav" | |
| 69 | |
| 70 enum | |
| 71 { | |
| 72 ETX = 0x03, | |
| 73 DLE = 0x10, | |
| 74 SUB = 0x1A | |
| 75 }; | |
| 76 | |
| 77 #define MANUFACTURER "www.soft-switch.org" | |
| 78 | |
| 79 #define SAMPLES_PER_CHUNK 160 | |
| 80 | |
| 81 struct command_response_s | |
| 82 { | |
| 83 const char *command; | |
| 84 int len_command; | |
| 85 const char *response; | |
| 86 int len_response; | |
| 87 }; | |
| 88 | |
| 89 g1050_state_t *path_a_to_b; | |
| 90 g1050_state_t *path_b_to_a; | |
| 91 | |
| 92 double when = 0.0; | |
| 93 | |
| 94 #define EXCHANGE(a,b) {a, sizeof(a) - 1, b, sizeof(b) - 1} | |
| 95 #define RESPONSE(b) {"", 0, b, sizeof(b) - 1} | |
| 96 #define FAST_RESPONSE(b) {NULL, -1, b, sizeof(b) - 1} | |
| 97 #define FAST_SEND(b) {(const char *) 1, -2, b, sizeof(b) - 1} | |
| 98 #define FAST_SEND_TCF(b) {(const char *) 2, -2, b, sizeof(b) - 1} | |
| 99 | |
| 100 static const struct command_response_s fax_send_test_seq[] = | |
| 101 { | |
| 102 EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), | |
| 103 EXCHANGE("AT+FCLASS=1\r", "\r\nOK\r\n"), | |
| 104 EXCHANGE("ATD123456789\r", "\r\nCONNECT\r\n"), | |
| 105 //<NSF frame> AT+FRH=3 is implied when dialing in the AT+FCLASS=1 state | |
| 106 //RESPONSE("\xFF\x03\x10\x03"), | |
| 107 //RESPONSE("\r\nOK\r\n"), | |
| 108 //EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 109 //<CSI frame data> | |
| 110 RESPONSE("\xFF\x03\x40\x31\x31\x31\x31\x31\x31\x31\x31\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x1e\x46\x10\x03"), | |
| 111 RESPONSE("\r\nOK\r\n"), | |
| 112 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 113 //<DIS frame data> | |
| 114 RESPONSE("\xFF\x13\x80\x00\xEE\xF8\x80\x80\x91\x80\x80\x80\x18\x78\x57\x10\x03"), // For audio FAXing | |
| 115 //RESPONSE("\xFF\x13\x80\x04\xEE\xF8\x80\x80\x91\x80\x80\x80\x18\xE4\xE7\x10\x03"), // For T.38 FAXing | |
| 116 RESPONSE("\r\nOK\r\n"), | |
| 117 //EXCHANGE("AT+FRH=3\r", "\r\nNO CARRIER\r\n"), | |
| 118 EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), | |
| 119 //<TSI frame data> | |
| 120 EXCHANGE("\xFF\x03\x43\x32\x32\x32\x32\x32\x32\x32\x32\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x10\x03", "\r\nCONNECT\r\n"), | |
| 121 //<DCS frame data> | |
| 122 EXCHANGE("\xFF\x13\x83\x01\xC6\x80\x80\x80\x80\x01\xFD\x13\x10\x03", "\r\nOK\r\n"), | |
| 123 //Do a wait for timed silence at this point, or there won't be one in the tests | |
| 124 EXCHANGE("AT+FRS=7\r", "\r\nOK\r\n"), | |
| 125 //EXCHANGE("AT+FTS=8;+FTM=96\r", "\r\nCONNECT\r\n"), | |
| 126 EXCHANGE("AT+FTS=8\r", "\r\nOK\r\n"), | |
| 127 EXCHANGE("AT+FTM=96\r", "\r\nCONNECT\r\n"), | |
| 128 //<TCF data pattern> | |
| 129 FAST_SEND_TCF("\r\nOK\r\n"), | |
| 130 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 131 //<CFR frame data> | |
| 132 RESPONSE("\xFF\x13\x84\xEA\x7D\x10\x03"), | |
| 133 RESPONSE("\r\nOK\r\n"), | |
| 134 EXCHANGE("AT+FTM=96\r", "\r\nCONNECT\r\n"), | |
| 135 //<page image data> | |
| 136 FAST_SEND("\r\nOK\r\n"), | |
| 137 //EXCHANGE("AT+FTS=8;+FTH=3\r", "\r\nCONNECT\r\n"), | |
| 138 EXCHANGE("AT+FTS=8\r", "\r\nOK\r\n"), | |
| 139 EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), | |
| 140 //<EOP frame data> | |
| 141 EXCHANGE("\xFF\x13\x2E\x10\x03", "\r\nOK\r\n"), | |
| 142 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 143 //<MCF frame data> | |
| 144 RESPONSE("\xFF\x13\x8C\xA2\xF1\x10\x03"), | |
| 145 RESPONSE("\r\nOK\r\n"), | |
| 146 EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), | |
| 147 // <DCN frame data> | |
| 148 EXCHANGE("\xFF\x13\xFB\x10\x03", "\r\nOK\r\n"), | |
| 149 EXCHANGE("ATH0\r", "\r\nOK\r\n") | |
| 150 }; | |
| 151 | |
| 152 static const struct command_response_s fax_receive_test_seq[] = | |
| 153 { | |
| 154 EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), | |
| 155 EXCHANGE("AT+FCLASS=1\r", "\r\nOK\r\n"), | |
| 156 RESPONSE("\r\nRING\r\n"), | |
| 157 EXCHANGE("ATA\r", "\r\nCONNECT\r\n"), | |
| 158 //<CSI frame data> | |
| 159 EXCHANGE("\xFF\x03\x40\x32\x32\x32\x32\x32\x32\x32\x32\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x10\x03", "\r\nCONNECT\r\n"), | |
| 160 //<DIS frame data> | |
| 161 EXCHANGE("\xFF\x13\x80\x01\xCE\xF4\x80\x80\x81\x80\x80\x80\x18\x10\x03", "\r\nOK\r\n"), | |
| 162 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 163 //<TSI frame data> | |
| 164 RESPONSE("\xFF\x03\x43\x31\x31\x31\x31\x31\x31\x31\x31\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xAA\x1F\x10\x03"), | |
| 165 RESPONSE("\r\nOK\r\n"), | |
| 166 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 167 //<DCS frame data> | |
| 168 RESPONSE("\xFF\x13\x83\x00\xC6\x74\x53\x00\x10\x03"), | |
| 169 RESPONSE("\r\nOK\r\n"), | |
| 170 EXCHANGE("AT+FRM=96\r", "\r\nCONNECT\r\n"), | |
| 171 //<TCF data> | |
| 172 FAST_RESPONSE(NULL), | |
| 173 RESPONSE("\r\nNO CARRIER\r\n"), | |
| 174 EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), | |
| 175 //<CFR frame data> | |
| 176 EXCHANGE("\xFF\x13\x84\x10\x03", "\r\nOK\r\n"), | |
| 177 EXCHANGE("AT+FRM=96\r", "\r\nCONNECT\r\n"), | |
| 178 //<page image data> | |
| 179 FAST_RESPONSE(NULL), | |
| 180 RESPONSE("\r\nNO CARRIER\r\n"), | |
| 181 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 182 //<EOP frame data> | |
| 183 RESPONSE("\xFF\x13\x2F\x33\x66\x10\x03"), | |
| 184 RESPONSE("\r\nOK\r\n"), | |
| 185 EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), | |
| 186 //<MCF frame data> | |
| 187 EXCHANGE("\xFF\x13\x8C\x10\x03", "\r\nOK\r\n"), | |
| 188 EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), | |
| 189 //<DCN frame data> | |
| 190 RESPONSE("\xFF\x13\xfb\x9a\xf6\x10\x03"), | |
| 191 RESPONSE("\r\nOK\r\n"), | |
| 192 EXCHANGE("ATH0\r", "\r\nOK\r\n") | |
| 193 }; | |
| 194 | |
| 195 char *decode_test_file = NULL; | |
| 196 int countdown = 0; | |
| 197 int command_response_test_step = -1; | |
| 198 char response_buf[1000]; | |
| 199 int response_buf_ptr = 0; | |
| 200 int answered = FALSE; | |
| 201 int kick = FALSE; | |
| 202 int dled = FALSE; | |
| 203 int done = FALSE; | |
| 204 | |
| 205 static const struct command_response_s *fax_test_seq; | |
| 206 | |
| 207 int test_seq_ptr = 0; | |
| 208 | |
| 209 t31_state_t *t31_state; | |
| 210 | |
| 211 static int phase_b_handler(t30_state_t *s, void *user_data, int result) | |
| 212 { | |
| 213 int i; | |
| 214 char tag[20]; | |
| 215 | |
| 216 i = (int) (intptr_t) user_data; | |
| 217 snprintf(tag, sizeof(tag), "%c: Phase B:", i); | |
| 218 printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
| 219 log_rx_parameters(s, tag); | |
| 220 return T30_ERR_OK; | |
| 221 } | |
| 222 /*- End of function --------------------------------------------------------*/ | |
| 223 | |
| 224 static int phase_d_handler(t30_state_t *s, void *user_data, int result) | |
| 225 { | |
| 226 int i; | |
| 227 char tag[20]; | |
| 228 | |
| 229 i = (int) (intptr_t) user_data; | |
| 230 snprintf(tag, sizeof(tag), "%c: Phase D:", i); | |
| 231 printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
| 232 log_transfer_statistics(s, tag); | |
| 233 log_tx_parameters(s, tag); | |
| 234 log_rx_parameters(s, tag); | |
| 235 return T30_ERR_OK; | |
| 236 } | |
| 237 /*- End of function --------------------------------------------------------*/ | |
| 238 | |
| 239 static void phase_e_handler(t30_state_t *s, void *user_data, int result) | |
| 240 { | |
| 241 int i; | |
| 242 char tag[20]; | |
| 243 | |
| 244 i = (intptr_t) user_data; | |
| 245 snprintf(tag, sizeof(tag), "%c: Phase E:", i); | |
| 246 printf("Phase E handler on channel %c\n", i); | |
| 247 log_transfer_statistics(s, tag); | |
| 248 log_tx_parameters(s, tag); | |
| 249 log_rx_parameters(s, tag); | |
| 250 //exit(0); | |
| 251 } | |
| 252 /*- End of function --------------------------------------------------------*/ | |
| 253 | |
| 254 static int modem_call_control(t31_state_t *s, void *user_data, int op, const char *num) | |
| 255 { | |
| 256 switch (op) | |
| 257 { | |
| 258 case AT_MODEM_CONTROL_ANSWER: | |
| 259 printf("\nModem control - Answering\n"); | |
| 260 answered = TRUE; | |
| 261 break; | |
| 262 case AT_MODEM_CONTROL_CALL: | |
| 263 printf("\nModem control - Dialing '%s'\n", num); | |
| 264 t31_call_event(t31_state, AT_CALL_EVENT_CONNECTED); | |
| 265 break; | |
| 266 case AT_MODEM_CONTROL_HANGUP: | |
| 267 printf("\nModem control - Hanging up\n"); | |
| 268 done = TRUE; | |
| 269 break; | |
| 270 case AT_MODEM_CONTROL_OFFHOOK: | |
| 271 printf("\nModem control - Going off hook\n"); | |
| 272 break; | |
| 273 case AT_MODEM_CONTROL_DTR: | |
| 274 printf("\nModem control - DTR %d\n", (int) (intptr_t) num); | |
| 275 break; | |
| 276 case AT_MODEM_CONTROL_RTS: | |
| 277 printf("\nModem control - RTS %d\n", (int) (intptr_t) num); | |
| 278 break; | |
| 279 case AT_MODEM_CONTROL_CTS: | |
| 280 printf("\nModem control - CTS %d\n", (int) (intptr_t) num); | |
| 281 break; | |
| 282 case AT_MODEM_CONTROL_CAR: | |
| 283 printf("\nModem control - CAR %d\n", (int) (intptr_t) num); | |
| 284 break; | |
| 285 case AT_MODEM_CONTROL_RNG: | |
| 286 printf("\nModem control - RNG %d\n", (int) (intptr_t) num); | |
| 287 break; | |
| 288 case AT_MODEM_CONTROL_DSR: | |
| 289 printf("\nModem control - DSR %d\n", (int) (intptr_t) num); | |
| 290 break; | |
| 291 default: | |
| 292 printf("\nModem control - operation %d\n", op); | |
| 293 break; | |
| 294 } | |
| 295 /*endswitch*/ | |
| 296 return 0; | |
| 297 } | |
| 298 /*- End of function --------------------------------------------------------*/ | |
| 299 | |
| 300 static int at_tx_handler(at_state_t *s, void *user_data, const uint8_t *buf, size_t len) | |
| 301 { | |
| 302 size_t i; | |
| 303 | |
| 304 i = 0; | |
| 305 if (fax_test_seq[test_seq_ptr].command == NULL) | |
| 306 { | |
| 307 /* TCF or non-ECM image data expected */ | |
| 308 for ( ; i < len; i++) | |
| 309 { | |
| 310 if (dled) | |
| 311 { | |
| 312 if (buf[i] == ETX) | |
| 313 { | |
| 314 printf("\nFast data ended\n"); | |
| 315 response_buf_ptr = 0; | |
| 316 response_buf[response_buf_ptr] = '\0'; | |
| 317 test_seq_ptr++; | |
| 318 if (fax_test_seq[test_seq_ptr].command) | |
| 319 kick = TRUE; | |
| 320 break; | |
| 321 } | |
| 322 dled = FALSE; | |
| 323 } | |
| 324 else | |
| 325 { | |
| 326 if (buf[i] == DLE) | |
| 327 dled = TRUE; | |
| 328 } | |
| 329 } | |
| 330 i++; | |
| 331 if (i >= len) | |
| 332 return 0; | |
| 333 } | |
| 334 for ( ; i < len; i++) | |
| 335 { | |
| 336 response_buf[response_buf_ptr++] = buf[i]; | |
| 337 putchar(buf[i]); | |
| 338 } | |
| 339 response_buf[response_buf_ptr] = '\0'; | |
| 340 printf("Expected "); | |
| 341 for (i = 0; i < response_buf_ptr; i++) | |
| 342 printf("%02x ", fax_test_seq[test_seq_ptr].response[i] & 0xFF); | |
| 343 printf("\n"); | |
| 344 printf("Response "); | |
| 345 for (i = 0; i < response_buf_ptr; i++) | |
| 346 printf("%02x ", response_buf[i] & 0xFF); | |
| 347 printf("\n"); | |
| 348 printf("Match %d against %d\n", response_buf_ptr, fax_test_seq[test_seq_ptr].len_response); | |
| 349 if (response_buf_ptr >= fax_test_seq[test_seq_ptr].len_response | |
| 350 && | |
| 351 memcmp(fax_test_seq[test_seq_ptr].response, response_buf, fax_test_seq[test_seq_ptr].len_response) == 0) | |
| 352 { | |
| 353 printf("\nMatched\n"); | |
| 354 test_seq_ptr++; | |
| 355 response_buf_ptr = 0; | |
| 356 response_buf[response_buf_ptr] = '\0'; | |
| 357 if (fax_test_seq[test_seq_ptr].command) | |
| 358 kick = TRUE; | |
| 359 else | |
| 360 dled = FALSE; | |
| 361 } | |
| 362 return 0; | |
| 363 } | |
| 364 /*- End of function --------------------------------------------------------*/ | |
| 365 | |
| 366 static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) | |
| 367 { | |
| 368 t31_state_t *t; | |
| 369 int i; | |
| 370 | |
| 371 /* This routine queues messages between two instances of T.38 processing */ | |
| 372 t = (t31_state_t *) user_data; | |
| 373 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); | |
| 374 | |
| 375 for (i = 0; i < count; i++) | |
| 376 { | |
| 377 if (g1050_put(path_a_to_b, buf, len, s->tx_seq_no, when) < 0) | |
| 378 printf("Lost packet %d\n", s->tx_seq_no); | |
| 379 } | |
| 380 return 0; | |
| 381 } | |
| 382 /*- End of function --------------------------------------------------------*/ | |
| 383 | |
| 384 static int t31_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) | |
| 385 { | |
| 386 //t38_terminal_state_t *t; | |
| 387 int i; | |
| 388 | |
| 389 /* This routine queues messages between two instances of T.38 processing */ | |
| 390 //t = (t38_terminal_state_t *) user_data; | |
| 391 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); | |
| 392 | |
| 393 for (i = 0; i < count; i++) | |
| 394 { | |
| 395 if (g1050_put(path_b_to_a, buf, len, s->tx_seq_no, when) < 0) | |
| 396 printf("Lost packet %d\n", s->tx_seq_no); | |
| 397 } | |
| 398 return 0; | |
| 399 } | |
| 400 /*- End of function --------------------------------------------------------*/ | |
| 401 | |
| 402 static int t38_tests(int use_gui, int test_sending, int model_no, int speed_pattern_no) | |
| 403 { | |
| 404 t38_terminal_state_t *t38_state; | |
| 405 int fast_send; | |
| 406 int fast_send_tcf; | |
| 407 int fast_blocks; | |
| 408 uint8_t fast_buf[1000]; | |
| 409 int msg_len; | |
| 410 uint8_t msg[1024]; | |
| 411 int t38_version; | |
| 412 int without_pacing; | |
| 413 int use_tep; | |
| 414 int seq_no; | |
| 415 double tx_when; | |
| 416 double rx_when; | |
| 417 t30_state_t *t30; | |
| 418 t38_core_state_t *t38_core; | |
| 419 logging_state_t *logging; | |
| 420 int i; | |
| 421 | |
| 422 t38_version = 1; | |
| 423 without_pacing = FALSE; | |
| 424 use_tep = FALSE; | |
| 425 | |
| 426 srand48(0x1234567); | |
| 427 if ((path_a_to_b = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL) | |
| 428 { | |
| 429 fprintf(stderr, "Failed to start IP network path model\n"); | |
| 430 exit(2); | |
| 431 } | |
| 432 if ((path_b_to_a = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL) | |
| 433 { | |
| 434 fprintf(stderr, "Failed to start IP network path model\n"); | |
| 435 exit(2); | |
| 436 } | |
| 437 if ((t31_state = t31_init(NULL, at_tx_handler, NULL, modem_call_control, NULL, t31_tx_packet_handler, NULL)) == NULL) | |
| 438 { | |
| 439 fprintf(stderr, " Cannot start the T.31 T.38 modem\n"); | |
| 440 exit(2); | |
| 441 } | |
| 442 logging = t31_get_logging_state(t31_state); | |
| 443 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 444 span_log_set_tag(logging, "T.31"); | |
| 445 | |
| 446 t38_core = t31_get_t38_core_state(t31_state); | |
| 447 span_log_set_level(&t38_core->logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 448 span_log_set_tag(&t38_core->logging, "T.31"); | |
| 449 | |
| 450 span_log_set_level(&t31_state->at_state.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 451 span_log_set_tag(&t31_state->at_state.logging, "T.31"); | |
| 452 | |
| 453 t31_set_mode(t31_state, TRUE); | |
| 454 t38_set_t38_version(t38_core, t38_version); | |
| 455 | |
| 456 if (test_sending) | |
| 457 { | |
| 458 if ((t38_state = t38_terminal_init(NULL, FALSE, t38_tx_packet_handler, t31_state)) == NULL) | |
| 459 { | |
| 460 fprintf(stderr, "Cannot start the T.38 channel\n"); | |
| 461 exit(2); | |
| 462 } | |
| 463 t30 = t38_terminal_get_t30_state(t38_state); | |
| 464 t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); | |
| 465 fax_test_seq = fax_send_test_seq; | |
| 466 countdown = 0; | |
| 467 } | |
| 468 else | |
| 469 { | |
| 470 if ((t38_state = t38_terminal_init(NULL, TRUE, t38_tx_packet_handler, t31_state)) == NULL) | |
| 471 { | |
| 472 fprintf(stderr, "Cannot start the T.38 channel\n"); | |
| 473 exit(2); | |
| 474 } | |
| 475 t30 = t38_terminal_get_t30_state(t38_state); | |
| 476 t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1); | |
| 477 fax_test_seq = fax_receive_test_seq; | |
| 478 countdown = 250; | |
| 479 } | |
| 480 | |
| 481 t30 = t38_terminal_get_t30_state(t38_state); | |
| 482 t38_core = t38_terminal_get_t38_core_state(t38_state); | |
| 483 t38_set_t38_version(t38_core, t38_version); | |
| 484 t38_terminal_set_config(t38_state, without_pacing); | |
| 485 t38_terminal_set_tep_mode(t38_state, use_tep); | |
| 486 | |
| 487 t30_set_tx_ident(t30, "11111111"); | |
| 488 t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); | |
| 489 //t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); | |
| 490 t30_set_phase_b_handler(t30, phase_b_handler, (void *) 'A'); | |
| 491 t30_set_phase_d_handler(t30, phase_d_handler, (void *) 'A'); | |
| 492 t30_set_phase_e_handler(t30, phase_e_handler, (void *) 'A'); | |
| 493 | |
| 494 logging = t38_terminal_get_logging_state(t38_state); | |
| 495 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 496 span_log_set_tag(logging, "T.38"); | |
| 497 | |
| 498 t38_core = t38_terminal_get_t38_core_state(t38_state); | |
| 499 span_log_set_level(&t38_core->logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 500 span_log_set_tag(&t38_core->logging, "T.38"); | |
| 501 | |
| 502 logging = t30_get_logging_state(t30); | |
| 503 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 504 span_log_set_tag(logging, "T.38"); | |
| 505 | |
| 506 fast_send = FALSE; | |
| 507 fast_send_tcf = TRUE; | |
| 508 fast_blocks = 0; | |
| 509 kick = TRUE; | |
| 510 #if defined(ENABLE_GUI) | |
| 511 if (use_gui) | |
| 512 start_media_monitor(); | |
| 513 #endif | |
| 514 while (!done) | |
| 515 { | |
| 516 logging = t38_terminal_get_logging_state(t38_state); | |
| 517 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
| 518 t38_core = t38_terminal_get_t38_core_state(t38_state); | |
| 519 logging = t38_core_get_logging_state(t38_core); | |
| 520 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
| 521 t30 = t38_terminal_get_t30_state(t38_state); | |
| 522 logging = t30_get_logging_state(t30); | |
| 523 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
| 524 | |
| 525 logging = t31_get_logging_state(t31_state); | |
| 526 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
| 527 t38_core = t31_get_t38_core_state(t31_state); | |
| 528 logging = t38_core_get_logging_state(t38_core); | |
| 529 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
| 530 span_log_bump_samples(&t31_state->at_state.logging, SAMPLES_PER_CHUNK); | |
| 531 | |
| 532 t38_terminal_send_timeout(t38_state, SAMPLES_PER_CHUNK); | |
| 533 t31_t38_send_timeout(t31_state, SAMPLES_PER_CHUNK); | |
| 534 | |
| 535 when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE; | |
| 536 | |
| 537 if (kick) | |
| 538 { | |
| 539 kick = FALSE; | |
| 540 if (fax_test_seq[test_seq_ptr].command > (const char *) 2) | |
| 541 { | |
| 542 if (fax_test_seq[test_seq_ptr].command[0]) | |
| 543 { | |
| 544 printf("%s\n", fax_test_seq[test_seq_ptr].command); | |
| 545 t31_at_rx(t31_state, fax_test_seq[test_seq_ptr].command, fax_test_seq[test_seq_ptr].len_command); | |
| 546 } | |
| 547 } | |
| 548 else | |
| 549 { | |
| 550 if (fax_test_seq[test_seq_ptr].command == (const char *) 2) | |
| 551 { | |
| 552 printf("Fast send TCF\n"); | |
| 553 fast_send = TRUE; | |
| 554 fast_send_tcf = TRUE; | |
| 555 fast_blocks = 100; | |
| 556 } | |
| 557 else | |
| 558 { | |
| 559 printf("Fast send image\n"); | |
| 560 fast_send = TRUE; | |
| 561 fast_send_tcf = FALSE; | |
| 562 fast_blocks = 100; | |
| 563 } | |
| 564 } | |
| 565 } | |
| 566 if (fast_send) | |
| 567 { | |
| 568 /* Send fast modem data */ | |
| 569 if (fast_send_tcf) | |
| 570 { | |
| 571 memset(fast_buf, 0, 36); | |
| 572 } | |
| 573 else | |
| 574 { | |
| 575 if (fast_blocks == 1) | |
| 576 { | |
| 577 /* Create the end of page condition */ | |
| 578 for (i = 0; i < 36; i += 2) | |
| 579 { | |
| 580 fast_buf[i] = 0x00; | |
| 581 fast_buf[i + 1] = 0x80; | |
| 582 } | |
| 583 } | |
| 584 else | |
| 585 { | |
| 586 /* Create a chunk of white page */ | |
| 587 for (i = 0; i < 36; i += 4) | |
| 588 { | |
| 589 fast_buf[i] = 0x00; | |
| 590 fast_buf[i + 1] = 0x80; | |
| 591 fast_buf[i + 2] = 0xB2; | |
| 592 fast_buf[i + 3] = 0x01; | |
| 593 } | |
| 594 } | |
| 595 } | |
| 596 if (fast_blocks == 1) | |
| 597 { | |
| 598 /* Insert EOLs */ | |
| 599 fast_buf[35] = ETX; | |
| 600 fast_buf[34] = DLE; | |
| 601 fast_buf[31] = | |
| 602 fast_buf[28] = | |
| 603 fast_buf[25] = | |
| 604 fast_buf[22] = | |
| 605 fast_buf[19] = | |
| 606 fast_buf[16] = 1; | |
| 607 } | |
| 608 t31_at_rx(t31_state, (char *) fast_buf, 36); | |
| 609 if (--fast_blocks == 0) | |
| 610 fast_send = FALSE; | |
| 611 } | |
| 612 if (countdown) | |
| 613 { | |
| 614 if (answered) | |
| 615 { | |
| 616 countdown = 0; | |
| 617 t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED); | |
| 618 } | |
| 619 else if (--countdown == 0) | |
| 620 { | |
| 621 t31_call_event(t31_state, AT_CALL_EVENT_ALERTING); | |
| 622 countdown = 250; | |
| 623 } | |
| 624 } | |
| 625 while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) | |
| 626 { | |
| 627 #if defined(ENABLE_GUI) | |
| 628 if (use_gui) | |
| 629 media_monitor_rx(seq_no, tx_when, rx_when); | |
| 630 #endif | |
| 631 t38_core = t31_get_t38_core_state(t31_state); | |
| 632 t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); | |
| 633 } | |
| 634 while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) | |
| 635 { | |
| 636 #if defined(ENABLE_GUI) | |
| 637 if (use_gui) | |
| 638 media_monitor_rx(seq_no, tx_when, rx_when); | |
| 639 #endif | |
| 640 t38_core = t38_terminal_get_t38_core_state(t38_state); | |
| 641 t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); | |
| 642 } | |
| 643 #if defined(ENABLE_GUI) | |
| 644 if (use_gui) | |
| 645 media_monitor_update_display(); | |
| 646 #endif | |
| 647 } | |
| 648 t38_terminal_release(t38_state); | |
| 649 return 0; | |
| 650 } | |
| 651 /*- End of function --------------------------------------------------------*/ | |
| 652 | |
| 653 static int t30_tests(int log_audio, int test_sending) | |
| 654 { | |
| 655 int k; | |
| 656 int outframes; | |
| 657 fax_state_t *fax_state; | |
| 658 int16_t t30_amp[SAMPLES_PER_CHUNK]; | |
| 659 int16_t t31_amp[SAMPLES_PER_CHUNK]; | |
| 660 int16_t silence[SAMPLES_PER_CHUNK]; | |
| 661 int16_t out_amp[2*SAMPLES_PER_CHUNK]; | |
| 662 int t30_len; | |
| 663 int t31_len; | |
| 664 SNDFILE *wave_handle; | |
| 665 SNDFILE *in_handle; | |
| 666 int fast_send; | |
| 667 int fast_send_tcf; | |
| 668 int fast_blocks; | |
| 669 uint8_t fast_buf[1000]; | |
| 670 t30_state_t *t30; | |
| 671 logging_state_t *logging; | |
| 672 int i; | |
| 673 | |
| 674 wave_handle = NULL; | |
| 675 if (log_audio) | |
| 676 { | |
| 677 if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) | |
| 678 { | |
| 679 fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); | |
| 680 exit(2); | |
| 681 } | |
| 682 } | |
| 683 | |
| 684 memset(silence, 0, sizeof(silence)); | |
| 685 | |
| 686 in_handle = NULL; | |
| 687 if (decode_test_file) | |
| 688 { | |
| 689 if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL) | |
| 690 { | |
| 691 fprintf(stderr, " Cannot create audio file '%s'\n", decode_test_file); | |
| 692 exit(2); | |
| 693 } | |
| 694 } | |
| 695 | |
| 696 if ((t31_state = t31_init(NULL, at_tx_handler, NULL, modem_call_control, NULL, NULL, NULL)) == NULL) | |
| 697 { | |
| 698 fprintf(stderr, " Cannot start the T.31 FAX modem\n"); | |
| 699 exit(2); | |
| 700 } | |
| 701 logging = t31_get_logging_state(t31_state); | |
| 702 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 703 span_log_set_tag(logging, "T.31"); | |
| 704 | |
| 705 if (test_sending) | |
| 706 { | |
| 707 fax_state = fax_init(NULL, FALSE); | |
| 708 t30 = fax_get_t30_state(fax_state); | |
| 709 t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); | |
| 710 fax_test_seq = fax_send_test_seq; | |
| 711 countdown = 0; | |
| 712 } | |
| 713 else | |
| 714 { | |
| 715 fax_state = fax_init(NULL, TRUE); | |
| 716 t30 = fax_get_t30_state(fax_state); | |
| 717 t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1); | |
| 718 fax_test_seq = fax_receive_test_seq; | |
| 719 countdown = 250; | |
| 720 } | |
| 721 | |
| 722 t30_set_tx_ident(t30, "11111111"); | |
| 723 t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); | |
| 724 t30_set_phase_b_handler(t30, phase_b_handler, (void *) 'A'); | |
| 725 t30_set_phase_d_handler(t30, phase_d_handler, (void *) 'A'); | |
| 726 t30_set_phase_e_handler(t30, phase_e_handler, (void *) 'A'); | |
| 727 memset(t30_amp, 0, sizeof(t30_amp)); | |
| 728 | |
| 729 logging = t30_get_logging_state(t30); | |
| 730 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 731 span_log_set_tag(logging, "FAX"); | |
| 732 | |
| 733 logging = fax_get_logging_state(fax_state); | |
| 734 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
| 735 span_log_set_tag(logging, "FAX"); | |
| 736 | |
| 737 fast_send = FALSE; | |
| 738 fast_send_tcf = TRUE; | |
| 739 fast_blocks = 0; | |
| 740 kick = TRUE; | |
| 741 while (!done) | |
| 742 { | |
| 743 if (kick) | |
| 744 { | |
| 745 kick = FALSE; | |
| 746 if (fax_test_seq[test_seq_ptr].command > (const char *) 2) | |
| 747 { | |
| 748 if (fax_test_seq[test_seq_ptr].command[0]) | |
| 749 { | |
| 750 printf("%s\n", fax_test_seq[test_seq_ptr].command); | |
| 751 t31_at_rx(t31_state, fax_test_seq[test_seq_ptr].command, fax_test_seq[test_seq_ptr].len_command); | |
| 752 } | |
| 753 } | |
| 754 else | |
| 755 { | |
| 756 if (fax_test_seq[test_seq_ptr].command == (const char *) 2) | |
| 757 { | |
| 758 printf("Fast send TCF\n"); | |
| 759 fast_send = TRUE; | |
| 760 fast_send_tcf = TRUE; | |
| 761 fast_blocks = 100; | |
| 762 } | |
| 763 else | |
| 764 { | |
| 765 printf("Fast send image\n"); | |
| 766 fast_send = TRUE; | |
| 767 fast_send_tcf = FALSE; | |
| 768 fast_blocks = 100; | |
| 769 } | |
| 770 } | |
| 771 } | |
| 772 if (fast_send) | |
| 773 { | |
| 774 /* Send fast modem data */ | |
| 775 if (fast_send_tcf) | |
| 776 { | |
| 777 memset(fast_buf, 0, 36); | |
| 778 } | |
| 779 else | |
| 780 { | |
| 781 if (fast_blocks == 1) | |
| 782 { | |
| 783 /* Create the end of page condition */ | |
| 784 for (i = 0; i < 36; i += 2) | |
| 785 { | |
| 786 fast_buf[i] = 0x00; | |
| 787 fast_buf[i + 1] = 0x80; | |
| 788 } | |
| 789 } | |
| 790 else | |
| 791 { | |
| 792 /* Create a chunk of white page */ | |
| 793 for (i = 0; i < 36; i += 4) | |
| 794 { | |
| 795 fast_buf[i] = 0x00; | |
| 796 fast_buf[i + 1] = 0x80; | |
| 797 fast_buf[i + 2] = 0xB2; | |
| 798 fast_buf[i + 3] = 0x01; | |
| 799 } | |
| 800 } | |
| 801 } | |
| 802 if (fast_blocks == 1) | |
| 803 { | |
| 804 /* Insert EOLs */ | |
| 805 fast_buf[35] = ETX; | |
| 806 fast_buf[34] = DLE; | |
| 807 fast_buf[31] = | |
| 808 fast_buf[28] = | |
| 809 fast_buf[25] = | |
| 810 fast_buf[22] = | |
| 811 fast_buf[19] = | |
| 812 fast_buf[16] = 1; | |
| 813 } | |
| 814 t31_at_rx(t31_state, (char *) fast_buf, 36); | |
| 815 if (--fast_blocks == 0) | |
| 816 fast_send = FALSE; | |
| 817 } | |
| 818 t30_len = fax_tx(fax_state, t30_amp, SAMPLES_PER_CHUNK); | |
| 819 /* The receive side always expects a full block of samples, but the | |
| 820 transmit side may not be sending any when it doesn't need to. We | |
| 821 may need to pad with some silence. */ | |
| 822 if (t30_len < SAMPLES_PER_CHUNK) | |
| 823 { | |
| 824 memset(t30_amp + t30_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len)); | |
| 825 t30_len = SAMPLES_PER_CHUNK; | |
| 826 } | |
| 827 if (log_audio) | |
| 828 { | |
| 829 for (k = 0; k < t30_len; k++) | |
| 830 out_amp[2*k] = t30_amp[k]; | |
| 831 } | |
| 832 if (t31_rx(t31_state, t30_amp, t30_len)) | |
| 833 break; | |
| 834 if (countdown) | |
| 835 { | |
| 836 if (answered) | |
| 837 { | |
| 838 countdown = 0; | |
| 839 t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED); | |
| 840 } | |
| 841 else if (--countdown == 0) | |
| 842 { | |
| 843 t31_call_event(t31_state, AT_CALL_EVENT_ALERTING); | |
| 844 countdown = 250; | |
| 845 } | |
| 846 } | |
| 847 | |
| 848 t31_len = t31_tx(t31_state, t31_amp, SAMPLES_PER_CHUNK); | |
| 849 if (t31_len < SAMPLES_PER_CHUNK) | |
| 850 { | |
| 851 memset(t31_amp + t31_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t31_len)); | |
| 852 t31_len = SAMPLES_PER_CHUNK; | |
| 853 } | |
| 854 if (log_audio) | |
| 855 { | |
| 856 for (k = 0; k < t31_len; k++) | |
| 857 out_amp[2*k + 1] = t31_amp[k]; | |
| 858 } | |
| 859 if (fax_rx(fax_state, t31_amp, SAMPLES_PER_CHUNK)) | |
| 860 break; | |
| 861 | |
| 862 span_log_bump_samples(&fax_state->logging, SAMPLES_PER_CHUNK); | |
| 863 span_log_bump_samples(&t30->logging, SAMPLES_PER_CHUNK); | |
| 864 | |
| 865 if (log_audio) | |
| 866 { | |
| 867 outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK); | |
| 868 if (outframes != SAMPLES_PER_CHUNK) | |
| 869 break; | |
| 870 } | |
| 871 } | |
| 872 if (decode_test_file) | |
| 873 { | |
| 874 if (sf_close(in_handle) != 0) | |
| 875 { | |
| 876 fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); | |
| 877 exit(2); | |
| 878 } | |
| 879 } | |
| 880 if (log_audio) | |
| 881 { | |
| 882 if (sf_close(wave_handle) != 0) | |
| 883 { | |
| 884 fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); | |
| 885 exit(2); | |
| 886 } | |
| 887 } | |
| 888 return 0; | |
| 889 } | |
| 890 /*- End of function --------------------------------------------------------*/ | |
| 891 | |
| 892 int main(int argc, char *argv[]) | |
| 893 { | |
| 894 int log_audio; | |
| 895 int t38_mode; | |
| 896 int test_sending; | |
| 897 int use_gui; | |
| 898 int opt; | |
| 899 | |
| 900 decode_test_file = NULL; | |
| 901 log_audio = FALSE; | |
| 902 test_sending = FALSE; | |
| 903 t38_mode = FALSE; | |
| 904 use_gui = FALSE; | |
| 905 while ((opt = getopt(argc, argv, "d:glrst")) != -1) | |
| 906 { | |
| 907 switch (opt) | |
| 908 { | |
| 909 case 'd': | |
| 910 decode_test_file = optarg; | |
| 911 break; | |
| 912 case 'g': | |
| 913 #if defined(ENABLE_GUI) | |
| 914 use_gui = TRUE; | |
| 915 #else | |
| 916 fprintf(stderr, "Graphical monitoring not available\n"); | |
| 917 exit(2); | |
| 918 #endif | |
| 919 break; | |
| 920 case 'l': | |
| 921 log_audio = TRUE; | |
| 922 break; | |
| 923 case 'r': | |
| 924 test_sending = FALSE; | |
| 925 break; | |
| 926 case 's': | |
| 927 test_sending = TRUE; | |
| 928 break; | |
| 929 case 't': | |
| 930 t38_mode = TRUE; | |
| 931 break; | |
| 932 default: | |
| 933 //usage(); | |
| 934 exit(2); | |
| 935 break; | |
| 936 } | |
| 937 } | |
| 938 | |
| 939 if (t38_mode) | |
| 940 t38_tests(use_gui, test_sending, 0, 1); | |
| 941 else | |
| 942 t30_tests(log_audio, test_sending); | |
| 943 if (done) | |
| 944 { | |
| 945 printf("Tests passed\n"); | |
| 946 } | |
| 947 return 0; | |
| 948 } | |
| 949 /*- End of function --------------------------------------------------------*/ | |
| 950 /*- End of file ------------------------------------------------------------*/ |
