comparison spandsp-0.0.6pre17/tests/t38_terminal_to_gateway_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 * t38_terminal_to_gateway_tests.c - Joint tests for the T.38 FoIP terminal and gateway modules.
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2005, 2006 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: t38_terminal_to_gateway_tests.c,v 1.65.4.1 2009/12/19 09:47:57 steveu Exp $
26 */
27
28 /*! \file */
29
30 /*! \page t38_terminal_to_gateway_tests_page T.38 mixed gateway and termination tests
31 \section t38_terminal_to_gateway_tests_page_sec_1 What does it do?
32 These tests exercise the path
33
34 T.38 termination -> T.38 gateway -> FAX machine
35 */
36
37 /* Enable the following definition to enable direct probing into the FAX structures */
38 //#define WITH_SPANDSP_INTERNALS
39
40 #if defined(HAVE_CONFIG_H)
41 #include <config.h>
42 #endif
43
44 #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
45 #define ENABLE_GUI
46 #endif
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <fcntl.h>
51 #include <string.h>
52 #include <assert.h>
53 #include <errno.h>
54 #include <sndfile.h>
55 #if !defined(_WIN32)
56 #include <unistd.h>
57 #endif
58
59 //#if defined(WITH_SPANDSP_INTERNALS)
60 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
61 //#endif
62
63 #include "spandsp.h"
64 #include "spandsp-sim.h"
65
66 #if defined(ENABLE_GUI)
67 #include "media_monitor.h"
68 #endif
69 #include "fax_utils.h"
70
71 #define SAMPLES_PER_CHUNK 160
72
73 #define INPUT_FILE_NAME "../test-data/itu/fax/itutests.tif"
74 #define OUTPUT_FILE_NAME "t38.tif"
75 #define OUTPUT_FILE_NAME_WAVE "t38_terminal_to_gateway.wav"
76
77 t38_terminal_state_t *t38_state_a;
78 t38_gateway_state_t *t38_state_b;
79 fax_state_t *fax_state_b;
80
81 g1050_state_t *path_a_to_b;
82 g1050_state_t *path_b_to_a;
83
84 double when = 0.0;
85
86 int done[2] = {FALSE, FALSE};
87 int succeeded[2] = {FALSE, FALSE};
88
89 int simulate_incrementing_repeats = FALSE;
90
91 static int phase_b_handler(t30_state_t *s, void *user_data, int result)
92 {
93 int i;
94 char tag[20];
95
96 i = (int) (intptr_t) user_data;
97 snprintf(tag, sizeof(tag), "%c: Phase B", i);
98 printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
99 log_rx_parameters(s, tag);
100 return T30_ERR_OK;
101 }
102 /*- End of function --------------------------------------------------------*/
103
104 static int phase_d_handler(t30_state_t *s, void *user_data, int result)
105 {
106 int i;
107 char tag[20];
108
109 i = (int) (intptr_t) user_data;
110 snprintf(tag, sizeof(tag), "%c: Phase D", i);
111 printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
112 log_transfer_statistics(s, tag);
113 log_tx_parameters(s, tag);
114 log_rx_parameters(s, tag);
115 return T30_ERR_OK;
116 }
117 /*- End of function --------------------------------------------------------*/
118
119 static void phase_e_handler(t30_state_t *s, void *user_data, int result)
120 {
121 int i;
122 t30_stats_t t;
123 char tag[20];
124
125 i = (int) (intptr_t) user_data;
126 snprintf(tag, sizeof(tag), "%c: Phase E", i);
127 printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));
128 log_transfer_statistics(s, tag);
129 log_tx_parameters(s, tag);
130 log_rx_parameters(s, tag);
131 t30_get_transfer_statistics(s, &t);
132 succeeded[i - 'A'] = (result == T30_ERR_OK) && (t.pages_tx == 12 || t.pages_rx == 12);
133 done[i - 'A'] = TRUE;
134 }
135 /*- End of function --------------------------------------------------------*/
136
137 static int tx_packet_handler_a(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
138 {
139 t38_terminal_state_t *t;
140 int i;
141 static int subst_seq = 0;
142
143 /* This routine queues messages between two instances of T.38 processing */
144 t = (t38_terminal_state_t *) user_data;
145 if (simulate_incrementing_repeats)
146 {
147 for (i = 0; i < count; i++)
148 {
149 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", subst_seq, len);
150
151 g1050_put(path_a_to_b, buf, len, subst_seq, when);
152 subst_seq = (subst_seq + 1) & 0xFFFF;
153 }
154 }
155 else
156 {
157 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count);
158
159 for (i = 0; i < count; i++)
160 g1050_put(path_a_to_b, buf, len, s->tx_seq_no, when);
161 }
162 return 0;
163 }
164 /*- End of function --------------------------------------------------------*/
165
166 static int tx_packet_handler_b(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
167 {
168 t38_terminal_state_t *t;
169 int i;
170 static int subst_seq = 0;
171
172 /* This routine queues messages between two instances of T.38 processing */
173 t = (t38_terminal_state_t *) user_data;
174 if (simulate_incrementing_repeats)
175 {
176 for (i = 0; i < count; i++)
177 {
178 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", subst_seq, len);
179
180 g1050_put(path_b_to_a, buf, len, subst_seq, when);
181 subst_seq = (subst_seq + 1) & 0xFFFF;
182 }
183 }
184 else
185 {
186 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count);
187
188 for (i = 0; i < count; i++)
189 g1050_put(path_b_to_a, buf, len, s->tx_seq_no, when);
190 }
191 return 0;
192 }
193 /*- End of function --------------------------------------------------------*/
194
195 int main(int argc, char *argv[])
196 {
197 int16_t t38_amp_b[SAMPLES_PER_CHUNK];
198 int16_t t30_amp_b[SAMPLES_PER_CHUNK];
199 int16_t out_amp[2*SAMPLES_PER_CHUNK];
200 int t38_len_b;
201 int t30_len_b;
202 int msg_len;
203 uint8_t msg[1024];
204 int log_audio;
205 int outframes;
206 SNDFILE *wave_handle;
207 int t38_version;
208 int use_ecm;
209 int use_tep;
210 int feedback_audio;
211 int use_transmit_on_idle;
212 const char *input_file_name;
213 int i;
214 int seq_no;
215 int model_no;
216 int speed_pattern_no;
217 double tx_when;
218 double rx_when;
219 int use_gui;
220 int supported_modems;
221 int opt;
222 t30_state_t *t30;
223 t38_core_state_t *t38_core;
224 logging_state_t *logging;
225
226 log_audio = FALSE;
227 t38_version = 1;
228 use_ecm = FALSE;
229 input_file_name = INPUT_FILE_NAME;
230 simulate_incrementing_repeats = FALSE;
231 model_no = 0;
232 speed_pattern_no = 1;
233 use_gui = FALSE;
234 use_tep = FALSE;
235 feedback_audio = FALSE;
236 use_transmit_on_idle = TRUE;
237 supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
238 while ((opt = getopt(argc, argv, "efgi:Ilm:M:s:tv:")) != -1)
239 {
240 switch (opt)
241 {
242 case 'e':
243 use_ecm = TRUE;
244 break;
245 case 'f':
246 feedback_audio = TRUE;
247 break;
248 case 'g':
249 #if defined(ENABLE_GUI)
250 use_gui = TRUE;
251 #else
252 fprintf(stderr, "Graphical monitoring not available\n");
253 exit(2);
254 #endif
255 break;
256 case 'i':
257 input_file_name = optarg;
258 break;
259 case 'I':
260 simulate_incrementing_repeats = TRUE;
261 break;
262 case 'l':
263 log_audio = TRUE;
264 break;
265 case 'm':
266 supported_modems = atoi(optarg);
267 break;
268 case 'M':
269 model_no = optarg[0] - 'A' + 1;
270 break;
271 case 's':
272 speed_pattern_no = atoi(optarg);
273 break;
274 case 't':
275 use_tep = TRUE;
276 break;
277 case 'v':
278 t38_version = atoi(optarg);
279 break;
280 default:
281 //usage();
282 exit(2);
283 break;
284 }
285 }
286
287 printf("Using T.38 version %d\n", t38_version);
288 if (use_ecm)
289 printf("Using ECM\n");
290
291 wave_handle = NULL;
292 if (log_audio)
293 {
294 if ((wave_handle = sf_open_telephony_write(OUTPUT_FILE_NAME_WAVE, 2)) == NULL)
295 {
296 fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME_WAVE);
297 exit(2);
298 }
299 }
300
301 srand48(0x1234567);
302 if ((path_a_to_b = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
303 {
304 fprintf(stderr, "Failed to start IP network path model\n");
305 exit(2);
306 }
307 if ((path_b_to_a = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
308 {
309 fprintf(stderr, "Failed to start IP network path model\n");
310 exit(2);
311 }
312
313 if ((t38_state_a = t38_terminal_init(NULL, TRUE, tx_packet_handler_a, &t38_state_b)) == NULL)
314 {
315 fprintf(stderr, "Cannot start the T.38 channel\n");
316 exit(2);
317 }
318 t30 = t38_terminal_get_t30_state(t38_state_a);
319 t38_core = t38_terminal_get_t38_core_state(t38_state_a);
320 t38_set_t38_version(t38_core, t38_version);
321
322 logging = t38_terminal_get_logging_state(t38_state_a);
323 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
324 span_log_set_tag(logging, "T.38-A");
325
326 logging = t38_core_get_logging_state(t38_core);
327 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
328 span_log_set_tag(logging, "T.38-A");
329
330 logging = t30_get_logging_state(t30);
331 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
332 span_log_set_tag(logging, "T.38-A");
333
334 t30_set_supported_modems(t30, supported_modems);
335 t30_set_tx_ident(t30, "11111111");
336 t30_set_tx_file(t30, input_file_name, -1, -1);
337 t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'A');
338 t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A');
339 t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A');
340 t30_set_ecm_capability(t30, use_ecm);
341 if (use_ecm)
342 t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
343
344 if ((t38_state_b = t38_gateway_init(NULL, tx_packet_handler_b, &t38_state_a)) == NULL)
345 {
346 fprintf(stderr, "Cannot start the T.38 channel\n");
347 exit(2);
348 }
349 t38_core = t38_gateway_get_t38_core_state(t38_state_b);
350 t38_gateway_set_transmit_on_idle(t38_state_b, use_transmit_on_idle);
351 t38_set_t38_version(t38_core, t38_version);
352 t38_gateway_set_ecm_capability(t38_state_b, use_ecm);
353
354 logging = t38_gateway_get_logging_state(t38_state_b);
355 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
356 span_log_set_tag(logging, "T.38-B");
357
358 logging = t38_core_get_logging_state(t38_core);
359 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
360 span_log_set_tag(logging, "T.38-B");
361
362 memset(t38_amp_b, 0, sizeof(t38_amp_b));
363
364 if ((fax_state_b = fax_init(NULL, FALSE)) == NULL)
365 {
366 fprintf(stderr, "Cannot start FAX\n");
367 exit(2);
368 }
369 t30 = fax_get_t30_state(fax_state_b);
370 fax_set_transmit_on_idle(fax_state_b, use_transmit_on_idle);
371 fax_set_tep_mode(fax_state_b, use_tep);
372 t30_set_supported_modems(t30, supported_modems);
373 t30_set_tx_ident(t30, "22222222");
374 t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
375 t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1);
376 t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'B');
377 t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'B');
378 t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'B');
379 t30_set_ecm_capability(t30, use_ecm);
380 if (use_ecm)
381 t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
382
383 logging = fax_get_logging_state(fax_state_b);
384 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
385 span_log_set_tag(logging, "FAX-B ");
386
387 logging = t30_get_logging_state(t30);
388 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
389 span_log_set_tag(logging, "FAX-B ");
390
391 memset(t30_amp_b, 0, sizeof(t30_amp_b));
392
393 #if defined(ENABLE_GUI)
394 if (use_gui)
395 start_media_monitor();
396 #endif
397 for (;;)
398 {
399 logging = t38_terminal_get_logging_state(t38_state_a);
400 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
401 t38_core = t38_terminal_get_t38_core_state(t38_state_a);
402 logging = t38_core_get_logging_state(t38_core);
403 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
404 t30 = t38_terminal_get_t30_state(t38_state_a);
405 logging = t30_get_logging_state(t30);
406 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
407 logging = t38_gateway_get_logging_state(t38_state_b);
408 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
409 t38_core = t38_gateway_get_t38_core_state(t38_state_b);
410 logging = t38_core_get_logging_state(t38_core);
411 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
412 logging = fax_get_logging_state(fax_state_b);
413 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
414 t30 = fax_get_t30_state(fax_state_b);
415 logging = t30_get_logging_state(t30);
416 span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
417 memset(out_amp, 0, sizeof(out_amp));
418
419 t38_terminal_send_timeout(t38_state_a, SAMPLES_PER_CHUNK);
420
421 t30_len_b = fax_tx(fax_state_b, t30_amp_b, SAMPLES_PER_CHUNK);
422 if (!use_transmit_on_idle)
423 {
424 /* The receive side always expects a full block of samples, but the
425 transmit side may not be sending any when it doesn't need to. We
426 may need to pad with some silence. */
427 if (t30_len_b < SAMPLES_PER_CHUNK)
428 {
429 memset(t30_amp_b + t30_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len_b));
430 t30_len_b = SAMPLES_PER_CHUNK;
431 }
432 }
433 if (feedback_audio)
434 {
435 for (i = 0; i < t30_len_b; i++)
436 t30_amp_b[i] += t38_amp_b[i] >> 1;
437 }
438 if (log_audio)
439 {
440 for (i = 0; i < t30_len_b; i++)
441 out_amp[2*i + 1] = t30_amp_b[i];
442 }
443 if (t38_gateway_rx(t38_state_b, t30_amp_b, t30_len_b))
444 break;
445
446 t38_len_b = t38_gateway_tx(t38_state_b, t38_amp_b, SAMPLES_PER_CHUNK);
447 if (!use_transmit_on_idle)
448 {
449 if (t38_len_b < SAMPLES_PER_CHUNK)
450 {
451 memset(t38_amp_b + t38_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len_b));
452 t38_len_b = SAMPLES_PER_CHUNK;
453 }
454 }
455 if (log_audio)
456 {
457 for (i = 0; i < t38_len_b; i++)
458 out_amp[2*i] = t38_amp_b[i];
459 }
460 if (fax_rx(fax_state_b, t38_amp_b, SAMPLES_PER_CHUNK))
461 break;
462
463 when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;
464
465 while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
466 {
467 #if defined(ENABLE_GUI)
468 if (use_gui)
469 media_monitor_rx(seq_no, tx_when, rx_when);
470 #endif
471 t38_core = t38_gateway_get_t38_core_state(t38_state_b);
472 t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
473 }
474 while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
475 {
476 #if defined(ENABLE_GUI)
477 if (use_gui)
478 media_monitor_rx(seq_no, tx_when, rx_when);
479 #endif
480 t38_core = t38_terminal_get_t38_core_state(t38_state_a);
481 t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
482 }
483 if (log_audio)
484 {
485 outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
486 if (outframes != SAMPLES_PER_CHUNK)
487 break;
488 }
489
490 if (done[0] && done[1])
491 break;
492 #if defined(ENABLE_GUI)
493 if (use_gui)
494 media_monitor_update_display();
495 #endif
496 }
497 t38_terminal_release(t38_state_a);
498 fax_release(fax_state_b);
499 if (log_audio)
500 {
501 if (sf_close(wave_handle) != 0)
502 {
503 fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME_WAVE);
504 exit(2);
505 }
506 }
507 if (!succeeded[0] || !succeeded[1])
508 {
509 printf("Tests failed\n");
510 exit(2);
511 }
512 printf("Tests passed\n");
513 return 0;
514 }
515 /*- End of function --------------------------------------------------------*/
516 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.