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 ------------------------------------------------------------*/ |