Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/tests/t38_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_gateway_tests.c - Tests for the T.38 FoIP gateway module. | |
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_gateway_tests.c,v 1.82.4.1 2009/12/19 09:47:57 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 /*! \page t38_gateway_tests_page T.38 gateway tests | |
31 \section t38_gateway_tests_page_sec_1 What does it do? | |
32 These tests exercise the path | |
33 | |
34 FAX machine <-> T.38 gateway <-> 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_gateway.wav" | |
76 #define OUTPUT_FILE_NAME_T30A "t38_gateway_t30a.wav" | |
77 #define OUTPUT_FILE_NAME_T38A "t38_gateway_t38a.wav" | |
78 #define OUTPUT_FILE_NAME_T30B "t38_gateway_t30b.wav" | |
79 #define OUTPUT_FILE_NAME_T38B "t38_gateway_t38b.wav" | |
80 | |
81 fax_state_t *fax_state_a; | |
82 t38_gateway_state_t *t38_state_a; | |
83 t38_gateway_state_t *t38_state_b; | |
84 fax_state_t *fax_state_b; | |
85 | |
86 g1050_state_t *path_a_to_b; | |
87 g1050_state_t *path_b_to_a; | |
88 | |
89 double when = 0.0; | |
90 | |
91 int done[2] = {FALSE, FALSE}; | |
92 int succeeded[2] = {FALSE, FALSE}; | |
93 | |
94 int simulate_incrementing_repeats = FALSE; | |
95 | |
96 static int phase_b_handler(t30_state_t *s, void *user_data, int result) | |
97 { | |
98 int i; | |
99 char tag[20]; | |
100 | |
101 i = (int) (intptr_t) user_data; | |
102 snprintf(tag, sizeof(tag), "%c: Phase B", i); | |
103 printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
104 log_rx_parameters(s, tag); | |
105 return T30_ERR_OK; | |
106 } | |
107 /*- End of function --------------------------------------------------------*/ | |
108 | |
109 static int phase_d_handler(t30_state_t *s, void *user_data, int result) | |
110 { | |
111 int i; | |
112 char tag[20]; | |
113 | |
114 i = (int) (intptr_t) user_data; | |
115 snprintf(tag, sizeof(tag), "%c: Phase D", i); | |
116 printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
117 log_transfer_statistics(s, tag); | |
118 log_tx_parameters(s, tag); | |
119 log_rx_parameters(s, tag); | |
120 return T30_ERR_OK; | |
121 } | |
122 /*- End of function --------------------------------------------------------*/ | |
123 | |
124 static void phase_e_handler(t30_state_t *s, void *user_data, int result) | |
125 { | |
126 int i; | |
127 t30_stats_t t; | |
128 char tag[20]; | |
129 | |
130 i = (int) (intptr_t) user_data; | |
131 snprintf(tag, sizeof(tag), "%c: Phase E", i); | |
132 printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); | |
133 log_transfer_statistics(s, tag); | |
134 log_tx_parameters(s, tag); | |
135 log_rx_parameters(s, tag); | |
136 t30_get_transfer_statistics(s, &t); | |
137 succeeded[i - 'A'] = (result == T30_ERR_OK) && (t.pages_tx == 12 || t.pages_rx == 12); | |
138 done[i - 'A'] = TRUE; | |
139 } | |
140 /*- End of function --------------------------------------------------------*/ | |
141 | |
142 static void real_time_frame_handler(t38_gateway_state_t *s, | |
143 void *user_data, | |
144 int direction, | |
145 const uint8_t *msg, | |
146 int len) | |
147 { | |
148 int i; | |
149 | |
150 i = (intptr_t) user_data; | |
151 printf("%d: Real time frame handler on channel %d - %s, %s, length = %d\n", | |
152 i, | |
153 i, | |
154 (direction) ? "PSTN->T.38" : "T.38->PSTN", | |
155 t30_frametype(msg[2]), | |
156 len); | |
157 } | |
158 /*- End of function --------------------------------------------------------*/ | |
159 | |
160 static int tx_packet_handler_a(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) | |
161 { | |
162 t38_terminal_state_t *t; | |
163 int i; | |
164 static int subst_seq = 0; | |
165 | |
166 /* This routine queues messages between two instances of T.38 processing */ | |
167 t = (t38_terminal_state_t *) user_data; | |
168 if (simulate_incrementing_repeats) | |
169 { | |
170 for (i = 0; i < count; i++) | |
171 { | |
172 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", subst_seq, len); | |
173 | |
174 g1050_put(path_a_to_b, buf, len, subst_seq, when); | |
175 subst_seq = (subst_seq + 1) & 0xFFFF; | |
176 } | |
177 } | |
178 else | |
179 { | |
180 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); | |
181 | |
182 for (i = 0; i < count; i++) | |
183 g1050_put(path_a_to_b, buf, len, s->tx_seq_no, when); | |
184 } | |
185 return 0; | |
186 } | |
187 /*- End of function --------------------------------------------------------*/ | |
188 | |
189 static int tx_packet_handler_b(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) | |
190 { | |
191 t38_terminal_state_t *t; | |
192 int i; | |
193 static int subst_seq = 0; | |
194 | |
195 /* This routine queues messages between two instances of T.38 processing */ | |
196 t = (t38_terminal_state_t *) user_data; | |
197 if (simulate_incrementing_repeats) | |
198 { | |
199 for (i = 0; i < count; i++) | |
200 { | |
201 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", subst_seq, len); | |
202 | |
203 g1050_put(path_b_to_a, buf, len, subst_seq, when); | |
204 subst_seq = (subst_seq + 1) & 0xFFFF; | |
205 } | |
206 } | |
207 else | |
208 { | |
209 span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); | |
210 | |
211 for (i = 0; i < count; i++) | |
212 g1050_put(path_b_to_a, buf, len, s->tx_seq_no, when); | |
213 } | |
214 return 0; | |
215 } | |
216 /*- End of function --------------------------------------------------------*/ | |
217 | |
218 int main(int argc, char *argv[]) | |
219 { | |
220 int16_t silence[SAMPLES_PER_CHUNK]; | |
221 int16_t t30_amp_a[SAMPLES_PER_CHUNK]; | |
222 int16_t t38_amp_a[SAMPLES_PER_CHUNK]; | |
223 int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK]; | |
224 int16_t t38_amp_b[SAMPLES_PER_CHUNK]; | |
225 int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK]; | |
226 int16_t t30_amp_b[SAMPLES_PER_CHUNK]; | |
227 int16_t out_amp[SAMPLES_PER_CHUNK*4]; | |
228 int t30_len_a; | |
229 int t38_len_a; | |
230 int t38_len_b; | |
231 int t30_len_b; | |
232 int hist_ptr; | |
233 int log_audio; | |
234 int msg_len; | |
235 uint8_t msg[1024]; | |
236 int outframes; | |
237 SNDFILE *wave_handle; | |
238 int use_ecm; | |
239 int use_tep; | |
240 int feedback_audio; | |
241 int use_transmit_on_idle; | |
242 int t38_version; | |
243 const char *input_file_name; | |
244 int i; | |
245 int seq_no; | |
246 int model_no; | |
247 int speed_pattern_no; | |
248 double tx_when; | |
249 double rx_when; | |
250 int supported_modems; | |
251 int fill_removal; | |
252 int use_gui; | |
253 int opt; | |
254 t38_stats_t stats; | |
255 fax_state_t *fax; | |
256 t30_state_t *t30; | |
257 t38_gateway_state_t *t38; | |
258 t38_core_state_t *t38_core; | |
259 logging_state_t *logging; | |
260 | |
261 log_audio = FALSE; | |
262 use_ecm = FALSE; | |
263 t38_version = 1; | |
264 input_file_name = INPUT_FILE_NAME; | |
265 simulate_incrementing_repeats = FALSE; | |
266 model_no = 0; | |
267 speed_pattern_no = 1; | |
268 fill_removal = FALSE; | |
269 use_gui = FALSE; | |
270 use_tep = FALSE; | |
271 feedback_audio = FALSE; | |
272 use_transmit_on_idle = TRUE; | |
273 supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; | |
274 while ((opt = getopt(argc, argv, "efFgi:Ilm:M:s:tv:")) != -1) | |
275 { | |
276 switch (opt) | |
277 { | |
278 case 'e': | |
279 use_ecm = TRUE; | |
280 break; | |
281 case 'f': | |
282 feedback_audio = TRUE; | |
283 break; | |
284 case 'F': | |
285 fill_removal = TRUE; | |
286 break; | |
287 case 'g': | |
288 #if defined(ENABLE_GUI) | |
289 use_gui = TRUE; | |
290 #else | |
291 fprintf(stderr, "Graphical monitoring not available\n"); | |
292 exit(2); | |
293 #endif | |
294 break; | |
295 case 'i': | |
296 input_file_name = optarg; | |
297 break; | |
298 case 'I': | |
299 simulate_incrementing_repeats = TRUE; | |
300 break; | |
301 case 'l': | |
302 log_audio = TRUE; | |
303 break; | |
304 case 'm': | |
305 supported_modems = atoi(optarg); | |
306 break; | |
307 case 'M': | |
308 model_no = optarg[0] - 'A' + 1; | |
309 break; | |
310 case 's': | |
311 speed_pattern_no = atoi(optarg); | |
312 break; | |
313 case 't': | |
314 use_tep = TRUE; | |
315 break; | |
316 case 'v': | |
317 t38_version = atoi(optarg); | |
318 break; | |
319 default: | |
320 //usage(); | |
321 exit(2); | |
322 break; | |
323 } | |
324 } | |
325 | |
326 printf("Using T.38 version %d\n", t38_version); | |
327 if (use_ecm) | |
328 printf("Using ECM\n"); | |
329 | |
330 wave_handle = NULL; | |
331 if (log_audio) | |
332 { | |
333 if ((wave_handle = sf_open_telephony_write(OUTPUT_FILE_NAME_WAVE, 4)) == NULL) | |
334 { | |
335 fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME_WAVE); | |
336 exit(2); | |
337 } | |
338 } | |
339 memset(silence, 0, sizeof(silence)); | |
340 | |
341 srand48(0x1234567); | |
342 if ((path_a_to_b = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL) | |
343 { | |
344 fprintf(stderr, "Failed to start IP network path model\n"); | |
345 exit(2); | |
346 } | |
347 if ((path_b_to_a = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL) | |
348 { | |
349 fprintf(stderr, "Failed to start IP network path model\n"); | |
350 exit(2); | |
351 } | |
352 | |
353 if ((fax_state_a = fax_init(NULL, TRUE)) == NULL) | |
354 { | |
355 fprintf(stderr, "Cannot start FAX\n"); | |
356 exit(2); | |
357 } | |
358 fax = fax_state_a; | |
359 t30 = fax_get_t30_state(fax); | |
360 fax_set_transmit_on_idle(fax, use_transmit_on_idle); | |
361 fax_set_tep_mode(fax, use_tep); | |
362 t30_set_supported_modems(t30, supported_modems); | |
363 t30_set_tx_ident(t30, "11111111"); | |
364 t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); | |
365 t30_set_tx_file(t30, input_file_name, -1, -1); | |
366 t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'A'); | |
367 t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A'); | |
368 t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A'); | |
369 t30_set_ecm_capability(t30, use_ecm); | |
370 if (use_ecm) | |
371 t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); | |
372 t30_set_minimum_scan_line_time(t30, 40); | |
373 //t30_set_iaf_mode(t30, T30_IAF_MODE_NO_FILL_BITS); | |
374 | |
375 logging = fax_get_logging_state(fax); | |
376 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
377 span_log_set_tag(logging, "FAX-A "); | |
378 | |
379 logging = t30_get_logging_state(t30); | |
380 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
381 span_log_set_tag(logging, "FAX-A "); | |
382 | |
383 memset(t30_amp_a, 0, sizeof(t30_amp_a)); | |
384 memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a)); | |
385 memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b)); | |
386 | |
387 if ((t38_state_a = t38_gateway_init(NULL, tx_packet_handler_a, t38_state_b)) == NULL) | |
388 { | |
389 fprintf(stderr, "Cannot start the T.38 channel\n"); | |
390 exit(2); | |
391 } | |
392 t38 = t38_state_a; | |
393 t38_core = t38_gateway_get_t38_core_state(t38); | |
394 t38_gateway_set_transmit_on_idle(t38, use_transmit_on_idle); | |
395 t38_gateway_set_supported_modems(t38, supported_modems); | |
396 //t38_gateway_set_nsx_suppression(t38, NULL, 0, NULL, 0); | |
397 t38_gateway_set_fill_bit_removal(t38, fill_removal); | |
398 t38_gateway_set_real_time_frame_handler(t38, real_time_frame_handler, NULL); | |
399 t38_set_t38_version(t38_core, t38_version); | |
400 t38_gateway_set_ecm_capability(t38, use_ecm); | |
401 | |
402 logging = t38_gateway_get_logging_state(t38); | |
403 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
404 span_log_set_tag(logging, "T.38-A"); | |
405 | |
406 logging = t38_core_get_logging_state(t38_core); | |
407 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
408 span_log_set_tag(logging, "T.38-A"); | |
409 memset(t38_amp_a, 0, sizeof(t38_amp_a)); | |
410 | |
411 if ((t38_state_b = t38_gateway_init(NULL, tx_packet_handler_b, t38_state_a)) == NULL) | |
412 { | |
413 fprintf(stderr, "Cannot start the T.38 channel\n"); | |
414 exit(2); | |
415 } | |
416 t38 = t38_state_b; | |
417 t38_core = t38_gateway_get_t38_core_state(t38); | |
418 t38_gateway_set_transmit_on_idle(t38, use_transmit_on_idle); | |
419 t38_gateway_set_supported_modems(t38, supported_modems); | |
420 //t38_gateway_set_nsx_suppression(t38, FALSE); | |
421 t38_gateway_set_fill_bit_removal(t38, fill_removal); | |
422 t38_set_t38_version(t38_core, t38_version); | |
423 t38_gateway_set_ecm_capability(t38, use_ecm); | |
424 | |
425 logging = t38_gateway_get_logging_state(t38); | |
426 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
427 span_log_set_tag(logging, "T.38-B"); | |
428 | |
429 logging = t38_core_get_logging_state(t38_core); | |
430 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
431 span_log_set_tag(logging, "T.38-B"); | |
432 memset(t38_amp_b, 0, sizeof(t38_amp_b)); | |
433 | |
434 if ((fax_state_b = fax_init(NULL, FALSE)) == NULL) | |
435 { | |
436 fprintf(stderr, "Cannot start FAX\n"); | |
437 exit(2); | |
438 } | |
439 fax = fax_state_b; | |
440 t30 = fax_get_t30_state(fax); | |
441 fax_set_transmit_on_idle(fax, use_transmit_on_idle); | |
442 fax_set_tep_mode(fax, use_tep); | |
443 t30_set_supported_modems(t30, supported_modems); | |
444 t30_set_tx_ident(t30, "22222222"); | |
445 t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); | |
446 t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); | |
447 t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'B'); | |
448 t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'B'); | |
449 t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'B'); | |
450 t30_set_ecm_capability(t30, use_ecm); | |
451 if (use_ecm) | |
452 t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); | |
453 t30_set_minimum_scan_line_time(t30, 40); | |
454 | |
455 logging = fax_get_logging_state(fax); | |
456 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
457 span_log_set_tag(logging, "FAX-B "); | |
458 | |
459 logging = t30_get_logging_state(t30); | |
460 span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); | |
461 span_log_set_tag(logging, "FAX-B "); | |
462 | |
463 memset(t30_amp_b, 0, sizeof(t30_amp_b)); | |
464 | |
465 #if defined(ENABLE_GUI) | |
466 if (use_gui) | |
467 start_media_monitor(); | |
468 #endif | |
469 hist_ptr = 0; | |
470 for (;;) | |
471 { | |
472 logging = fax_get_logging_state(fax_state_a); | |
473 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
474 t30 = fax_get_t30_state(fax_state_a); | |
475 logging = t30_get_logging_state(t30); | |
476 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
477 logging = t38_gateway_get_logging_state(t38_state_a); | |
478 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
479 t38_core = t38_gateway_get_t38_core_state(t38_state_a); | |
480 logging = t38_core_get_logging_state(t38_core); | |
481 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
482 logging = t38_gateway_get_logging_state(t38_state_b); | |
483 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
484 t38_core = t38_gateway_get_t38_core_state(t38_state_b); | |
485 logging = t38_core_get_logging_state(t38_core); | |
486 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
487 logging = fax_get_logging_state(fax_state_b); | |
488 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
489 t30 = fax_get_t30_state(fax_state_b); | |
490 logging = t30_get_logging_state(t30); | |
491 span_log_bump_samples(logging, SAMPLES_PER_CHUNK); | |
492 memset(out_amp, 0, sizeof(out_amp)); | |
493 | |
494 t30_len_a = fax_tx(fax_state_a, t30_amp_a, SAMPLES_PER_CHUNK); | |
495 if (!use_transmit_on_idle) | |
496 { | |
497 /* The receive side always expects a full block of samples, but the | |
498 transmit side may not be sending any when it doesn't need to. We | |
499 may need to pad with some silence. */ | |
500 if (t30_len_a < SAMPLES_PER_CHUNK) | |
501 { | |
502 memset(t30_amp_a + t30_len_a, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len_a)); | |
503 t30_len_a = SAMPLES_PER_CHUNK; | |
504 } | |
505 } | |
506 if (log_audio) | |
507 { | |
508 for (i = 0; i < t30_len_a; i++) | |
509 out_amp[i*4] = t30_amp_a[i]; | |
510 } | |
511 if (feedback_audio) | |
512 { | |
513 for (i = 0; i < t30_len_a; i++) | |
514 t30_amp_a[i] += t38_amp_hist_a[hist_ptr][i] >> 1; | |
515 memcpy(t38_amp_hist_a[hist_ptr], t38_amp_a, sizeof(int16_t)*SAMPLES_PER_CHUNK); | |
516 } | |
517 if (t38_gateway_rx(t38_state_a, t30_amp_a, t30_len_a)) | |
518 break; | |
519 | |
520 t38_len_a = t38_gateway_tx(t38_state_a, t38_amp_a, SAMPLES_PER_CHUNK); | |
521 if (!use_transmit_on_idle) | |
522 { | |
523 if (t38_len_a < SAMPLES_PER_CHUNK) | |
524 { | |
525 memset(t38_amp_a + t38_len_a, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len_a)); | |
526 t38_len_a = SAMPLES_PER_CHUNK; | |
527 } | |
528 } | |
529 if (log_audio) | |
530 { | |
531 for (i = 0; i < t38_len_a; i++) | |
532 out_amp[i*4 + 1] = t38_amp_a[i]; | |
533 } | |
534 if (fax_rx(fax_state_a, t38_amp_a, SAMPLES_PER_CHUNK)) | |
535 break; | |
536 | |
537 t30_len_b = fax_tx(fax_state_b, t30_amp_b, SAMPLES_PER_CHUNK); | |
538 if (!use_transmit_on_idle) | |
539 { | |
540 /* The receive side always expects a full block of samples, but the | |
541 transmit side may not be sending any when it doesn't need to. We | |
542 may need to pad with some silence. */ | |
543 if (t30_len_b < SAMPLES_PER_CHUNK) | |
544 { | |
545 memset(t30_amp_b + t30_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len_b)); | |
546 t30_len_b = SAMPLES_PER_CHUNK; | |
547 } | |
548 } | |
549 if (log_audio) | |
550 { | |
551 for (i = 0; i < t30_len_b; i++) | |
552 out_amp[i*4 + 3] = t30_amp_b[i]; | |
553 } | |
554 if (feedback_audio) | |
555 { | |
556 for (i = 0; i < t30_len_b; i++) | |
557 t30_amp_b[i] += t38_amp_hist_b[hist_ptr][i] >> 1; | |
558 memcpy(t38_amp_hist_b[hist_ptr], t38_amp_b, sizeof(int16_t)*SAMPLES_PER_CHUNK); | |
559 } | |
560 if (t38_gateway_rx(t38_state_b, t30_amp_b, t30_len_b)) | |
561 break; | |
562 | |
563 t38_len_b = t38_gateway_tx(t38_state_b, t38_amp_b, SAMPLES_PER_CHUNK); | |
564 if (!use_transmit_on_idle) | |
565 { | |
566 if (t38_len_b < SAMPLES_PER_CHUNK) | |
567 { | |
568 memset(t38_amp_b + t38_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len_b)); | |
569 t38_len_b = SAMPLES_PER_CHUNK; | |
570 } | |
571 } | |
572 if (log_audio) | |
573 { | |
574 for (i = 0; i < t38_len_b; i++) | |
575 out_amp[i*4 + 2] = t38_amp_b[i]; | |
576 } | |
577 if (fax_rx(fax_state_b, t38_amp_b, SAMPLES_PER_CHUNK)) | |
578 break; | |
579 | |
580 when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE; | |
581 | |
582 while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) | |
583 { | |
584 #if defined(ENABLE_GUI) | |
585 if (use_gui) | |
586 media_monitor_rx(seq_no, tx_when, rx_when); | |
587 #endif | |
588 t38_core = t38_gateway_get_t38_core_state(t38_state_b); | |
589 t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); | |
590 } | |
591 while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) | |
592 { | |
593 #if defined(ENABLE_GUI) | |
594 if (use_gui) | |
595 media_monitor_rx(seq_no, tx_when, rx_when); | |
596 #endif | |
597 t38_core = t38_gateway_get_t38_core_state(t38_state_a); | |
598 t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); | |
599 } | |
600 if (log_audio) | |
601 { | |
602 outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK); | |
603 if (outframes != SAMPLES_PER_CHUNK) | |
604 break; | |
605 } | |
606 | |
607 if (done[0] && done[1]) | |
608 break; | |
609 #if defined(ENABLE_GUI) | |
610 if (use_gui) | |
611 media_monitor_update_display(); | |
612 #endif | |
613 if (++hist_ptr > 3) | |
614 hist_ptr = 0; | |
615 } | |
616 t38_gateway_get_transfer_statistics(t38_state_a, &stats); | |
617 printf("A side exchanged %d pages at %dbps, in %s mode\n", | |
618 stats.pages_transferred, | |
619 stats.bit_rate, | |
620 (stats.error_correcting_mode) ? "ECM" : "non-ECM"); | |
621 t38_gateway_get_transfer_statistics(t38_state_a, &stats); | |
622 printf("B side exchanged %d pages at %dbps, in %s mode\n", | |
623 stats.pages_transferred, | |
624 stats.bit_rate, | |
625 (stats.error_correcting_mode) ? "ECM" : "non-ECM"); | |
626 fax_release(fax_state_a); | |
627 fax_release(fax_state_b); | |
628 if (log_audio) | |
629 { | |
630 if (sf_close(wave_handle) != 0) | |
631 { | |
632 fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME_WAVE); | |
633 exit(2); | |
634 } | |
635 } | |
636 if (!succeeded[0] || !succeeded[1]) | |
637 { | |
638 printf("Tests failed\n"); | |
639 exit(2); | |
640 } | |
641 printf("Tests passed\n"); | |
642 return 0; | |
643 } | |
644 /*- End of function --------------------------------------------------------*/ | |
645 /*- End of file ------------------------------------------------------------*/ |