Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/tests/fax_tests.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * fax_tests.c | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2003 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: fax_tests.c,v 1.60 2006/11/19 14:07:27 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \page fax_tests_page FAX tests | |
29 \section fax_tests_page_sec_1 What does it do? | |
30 \section fax_tests_page_sec_2 How does it work? | |
31 */ | |
32 | |
33 #ifdef HAVE_CONFIG_H | |
34 #include "config.h" | |
35 #endif | |
36 | |
37 #include <inttypes.h> | |
38 #include <stdlib.h> | |
39 #include <stdio.h> | |
40 #include <string.h> | |
41 #if defined(HAVE_TGMATH_H) | |
42 #include <tgmath.h> | |
43 #endif | |
44 #if defined(HAVE_MATH_H) | |
45 #include <math.h> | |
46 #endif | |
47 #include <assert.h> | |
48 #include <audiofile.h> | |
49 #include <tiffio.h> | |
50 | |
51 #include "spandsp.h" | |
52 | |
53 #define SAMPLES_PER_CHUNK 160 | |
54 | |
55 #define INPUT_TIFF_FILE_NAME "../itutests/fax/itutests.tif" | |
56 | |
57 #define OUTPUT_FILE_NAME_WAVE "fax_tests.wav" | |
58 | |
59 #define FAX_MACHINES 2 | |
60 | |
61 struct machine_s | |
62 { | |
63 int chan; | |
64 int16_t amp[SAMPLES_PER_CHUNK]; | |
65 int len; | |
66 fax_state_t fax; | |
67 int done; | |
68 int succeeded; | |
69 char tag[50]; | |
70 int error_delay; | |
71 } machines[FAX_MACHINES]; | |
72 | |
73 int test_local_interrupt = FALSE; | |
74 | |
75 static void phase_b_handler(t30_state_t *s, void *user_data, int result) | |
76 { | |
77 int i; | |
78 | |
79 i = (intptr_t) user_data; | |
80 printf("%d: Phase B handler on channel %d - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
81 } | |
82 /*- End of function --------------------------------------------------------*/ | |
83 | |
84 static void phase_d_handler(t30_state_t *s, void *user_data, int result) | |
85 { | |
86 int i; | |
87 t30_stats_t t; | |
88 char ident[21]; | |
89 | |
90 i = (intptr_t) user_data; | |
91 printf("%d: Phase D handler on channel %d - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
92 t30_get_transfer_statistics(s, &t); | |
93 printf("%d: Phase D: bit rate %d\n", i, t.bit_rate); | |
94 printf("%d: Phase D: ECM %s\n", i, (t.error_correcting_mode) ? "on" : "off"); | |
95 printf("%d: Phase D: pages transferred %d\n", i, t.pages_transferred); | |
96 printf("%d: Phase D: image size %d x %d\n", i, t.width, t.length); | |
97 printf("%d: Phase D: image resolution %d x %d\n", i, t.x_resolution, t.y_resolution); | |
98 printf("%d: Phase D: bad rows %d\n", i, t.bad_rows); | |
99 printf("%d: Phase D: longest bad row run %d\n", i, t.longest_bad_row_run); | |
100 printf("%d: Phase D: compression type %d\n", i, t.encoding); | |
101 printf("%d: Phase D: image size %d\n", i, t.image_size); | |
102 t30_get_local_ident(s, ident); | |
103 printf("%d: Phase D: local ident '%s'\n", i, ident); | |
104 t30_get_far_ident(s, ident); | |
105 printf("%d: Phase D: remote ident '%s'\n", i, ident); | |
106 | |
107 if (test_local_interrupt) | |
108 { | |
109 if (i == 0) | |
110 { | |
111 printf("%d: Initiating interrupt request\n", i); | |
112 t30_local_interrupt_request(s, TRUE); | |
113 } | |
114 else | |
115 { | |
116 switch (result) | |
117 { | |
118 case T30_PIP: | |
119 case T30_PRI_MPS: | |
120 case T30_PRI_EOM: | |
121 case T30_PRI_EOP: | |
122 printf("%d: Accepting interrupt request\n", i); | |
123 t30_local_interrupt_request(s, TRUE); | |
124 break; | |
125 case T30_PIN: | |
126 break; | |
127 } | |
128 } | |
129 } | |
130 } | |
131 /*- End of function --------------------------------------------------------*/ | |
132 | |
133 static void phase_e_handler(t30_state_t *s, void *user_data, int result) | |
134 { | |
135 int i; | |
136 t30_stats_t t; | |
137 const char *u; | |
138 char ident[21]; | |
139 | |
140 i = (intptr_t) user_data; | |
141 printf("%d: Phase E handler on channel %d - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); | |
142 t30_get_transfer_statistics(s, &t); | |
143 printf("%d: Phase E: bit rate %d\n", i, t.bit_rate); | |
144 printf("%d: Phase E: ECM %s\n", i, (t.error_correcting_mode) ? "on" : "off"); | |
145 printf("%d: Phase E: pages transferred %d\n", i, t.pages_transferred); | |
146 printf("%d: Phase E: image size %d x %d\n", i, t.width, t.length); | |
147 printf("%d: Phase E: image resolution %d x %d\n", i, t.x_resolution, t.y_resolution); | |
148 printf("%d: Phase E: bad rows %d\n", i, t.bad_rows); | |
149 printf("%d: Phase E: longest bad row run %d\n", i, t.longest_bad_row_run); | |
150 printf("%d: Phase E: coding method %s\n", i, t4_encoding_to_str(t.encoding)); | |
151 printf("%d: Phase E: image size %d bytes\n", i, t.image_size); | |
152 t30_get_local_ident(s, ident); | |
153 printf("%d: Phase E: local ident '%s'\n", i, ident); | |
154 t30_get_far_ident(s, ident); | |
155 printf("%d: Phase E: remote ident '%s'\n", i, ident); | |
156 if ((u = t30_get_far_country(s))) | |
157 printf("%d: Phase E: Remote was made in '%s'\n", i, u); | |
158 if ((u = t30_get_far_vendor(s))) | |
159 printf("%d: Phase E: Remote was made by '%s'\n", i, u); | |
160 if ((u = t30_get_far_model(s))) | |
161 printf("%d: Phase E: Remote is model '%s'\n", i, u); | |
162 machines[i].succeeded = (result == T30_ERR_OK) && (t.pages_transferred == 12); | |
163 machines[i].done = TRUE; | |
164 } | |
165 /*- End of function --------------------------------------------------------*/ | |
166 | |
167 static int document_handler(t30_state_t *s, void *user_data, int event) | |
168 { | |
169 int i; | |
170 | |
171 i = (intptr_t) user_data; | |
172 printf("%d: Document handler on channel %d - event %d\n", i, i, event); | |
173 return FALSE; | |
174 } | |
175 /*- End of function --------------------------------------------------------*/ | |
176 | |
177 int main(int argc, char *argv[]) | |
178 { | |
179 AFfilesetup filesetup; | |
180 AFfilehandle wave_handle; | |
181 AFfilehandle input_wave_handle; | |
182 int i; | |
183 int j; | |
184 int k; | |
185 struct machine_s *mc; | |
186 int outframes; | |
187 char buf[128 + 1]; | |
188 int16_t silence[SAMPLES_PER_CHUNK]; | |
189 int16_t out_amp[2*SAMPLES_PER_CHUNK]; | |
190 int alldone; | |
191 const char *input_tiff_file_name; | |
192 const char *input_audio_file_name; | |
193 int log_audio; | |
194 int use_ecm; | |
195 int use_tep; | |
196 int use_line_hits; | |
197 int polled_mode; | |
198 char *page_header_info; | |
199 | |
200 log_audio = FALSE; | |
201 input_tiff_file_name = INPUT_TIFF_FILE_NAME; | |
202 input_audio_file_name = NULL; | |
203 use_ecm = FALSE; | |
204 use_line_hits = FALSE; | |
205 use_tep = FALSE; | |
206 polled_mode = FALSE; | |
207 page_header_info = NULL; | |
208 for (i = 1; i < argc; i++) | |
209 { | |
210 if (strcmp(argv[i], "-e") == 0) | |
211 { | |
212 use_ecm = TRUE; | |
213 continue; | |
214 } | |
215 if (strcmp(argv[i], "-h") == 0) | |
216 { | |
217 use_line_hits = TRUE; | |
218 continue; | |
219 } | |
220 if (strcmp(argv[i], "-H") == 0) | |
221 { | |
222 page_header_info = argv[++i]; | |
223 continue; | |
224 } | |
225 if (strcmp(argv[i], "-i") == 0) | |
226 { | |
227 input_tiff_file_name = argv[++i]; | |
228 continue; | |
229 } | |
230 if (strcmp(argv[i], "-I") == 0) | |
231 { | |
232 input_audio_file_name = argv[++i]; | |
233 continue; | |
234 } | |
235 if (strcmp(argv[i], "-l") == 0) | |
236 { | |
237 log_audio = TRUE; | |
238 continue; | |
239 } | |
240 if (strcmp(argv[i], "-p") == 0) | |
241 { | |
242 polled_mode = TRUE; | |
243 continue; | |
244 } | |
245 if (strcmp(argv[i], "-t") == 0) | |
246 { | |
247 use_tep = TRUE; | |
248 continue; | |
249 } | |
250 } | |
251 | |
252 input_wave_handle = AF_NULL_FILEHANDLE; | |
253 if (input_audio_file_name) | |
254 { | |
255 if ((input_wave_handle = afOpenFile(input_audio_file_name, "r", NULL)) == AF_NULL_FILEHANDLE) | |
256 { | |
257 fprintf(stderr, " Cannot open wave file '%s'\n", input_audio_file_name); | |
258 exit(2); | |
259 } | |
260 } | |
261 | |
262 filesetup = AF_NULL_FILESETUP; | |
263 wave_handle = AF_NULL_FILEHANDLE; | |
264 if (log_audio) | |
265 { | |
266 if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) | |
267 { | |
268 fprintf(stderr, " Failed to create file setup\n"); | |
269 exit(2); | |
270 } | |
271 afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); | |
272 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); | |
273 afInitFileFormat(filesetup, AF_FILE_WAVE); | |
274 afInitChannels(filesetup, AF_DEFAULT_TRACK, 2); | |
275 | |
276 if ((wave_handle = afOpenFile(OUTPUT_FILE_NAME_WAVE, "w", filesetup)) == AF_NULL_FILEHANDLE) | |
277 { | |
278 fprintf(stderr, " Cannot create wave file '%s'\n", OUTPUT_FILE_NAME_WAVE); | |
279 exit(2); | |
280 } | |
281 } | |
282 | |
283 memset(silence, 0, sizeof(silence)); | |
284 for (j = 0; j < FAX_MACHINES; j++) | |
285 { | |
286 machines[j].chan = j; | |
287 mc = &machines[j]; | |
288 | |
289 i = mc->chan + 1; | |
290 sprintf(buf, "%d%d%d%d%d%d%d%d", i, i, i, i, i, i, i, i); | |
291 fax_init(&mc->fax, (mc->chan & 1) ? FALSE : TRUE); | |
292 fax_set_tep_mode(&mc->fax, use_tep); | |
293 t30_set_local_ident(&mc->fax.t30_state, buf); | |
294 t30_set_header_info(&mc->fax.t30_state, page_header_info); | |
295 t30_set_local_nsf(&mc->fax.t30_state, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); | |
296 t30_set_ecm_capability(&mc->fax.t30_state, use_ecm); | |
297 t30_set_supported_image_sizes(&mc->fax.t30_state, T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH | |
298 | T30_SUPPORT_215MM_WIDTH | T30_SUPPORT_255MM_WIDTH | T30_SUPPORT_303MM_WIDTH); | |
299 t30_set_supported_resolutions(&mc->fax.t30_state, T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION | |
300 | T30_SUPPORT_R8_RESOLUTION | T30_SUPPORT_R16_RESOLUTION); | |
301 if (use_ecm) | |
302 t30_set_supported_compressions(&mc->fax.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); | |
303 if ((mc->chan & 1)) | |
304 { | |
305 if (polled_mode) | |
306 { | |
307 t30_set_tx_file(&mc->fax.t30_state, input_tiff_file_name, -1, -1); | |
308 } | |
309 else | |
310 { | |
311 sprintf(buf, "fax_tests_%d.tif", (mc->chan + 1)/2); | |
312 t30_set_rx_file(&mc->fax.t30_state, buf, -1); | |
313 } | |
314 } | |
315 else | |
316 { | |
317 if (polled_mode) | |
318 { | |
319 sprintf(buf, "fax_tests_%d.tif", (mc->chan + 1)/2); | |
320 t30_set_rx_file(&mc->fax.t30_state, buf, -1); | |
321 } | |
322 else | |
323 { | |
324 t30_set_tx_file(&mc->fax.t30_state, input_tiff_file_name, -1, -1); | |
325 } | |
326 } | |
327 t30_set_phase_b_handler(&mc->fax.t30_state, phase_b_handler, (void *) (intptr_t) mc->chan); | |
328 t30_set_phase_d_handler(&mc->fax.t30_state, phase_d_handler, (void *) (intptr_t) mc->chan); | |
329 t30_set_phase_e_handler(&mc->fax.t30_state, phase_e_handler, (void *) (intptr_t) mc->chan); | |
330 t30_set_document_handler(&mc->fax.t30_state, document_handler, (void *) (intptr_t) mc->chan); | |
331 sprintf(mc->tag, "FAX-%d", j + 1); | |
332 span_log_set_level(&mc->fax.t30_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); | |
333 span_log_set_tag(&mc->fax.t30_state.logging, mc->tag); | |
334 span_log_set_level(&mc->fax.v29rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); | |
335 span_log_set_tag(&mc->fax.v29rx.logging, mc->tag); | |
336 span_log_set_level(&mc->fax.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); | |
337 span_log_set_tag(&mc->fax.logging, mc->tag); | |
338 memset(mc->amp, 0, sizeof(mc->amp)); | |
339 mc->done = FALSE; | |
340 } | |
341 for (;;) | |
342 { | |
343 alldone = TRUE; | |
344 for (j = 0; j < FAX_MACHINES; j++) | |
345 { | |
346 mc = &machines[j]; | |
347 | |
348 if ((j & 1) == 0 && input_audio_file_name) | |
349 { | |
350 mc->len = afReadFrames(input_wave_handle, AF_DEFAULT_TRACK, mc->amp, SAMPLES_PER_CHUNK); | |
351 if (mc->len == 0) | |
352 break; | |
353 } | |
354 else | |
355 { | |
356 mc->len = fax_tx(&mc->fax, mc->amp, SAMPLES_PER_CHUNK); | |
357 } | |
358 /* The receive side always expects a full block of samples, but the | |
359 transmit side may not be sending any when it doesn't need to. We | |
360 may need to pad with some silence. */ | |
361 if (mc->len < SAMPLES_PER_CHUNK) | |
362 { | |
363 memset(mc->amp + mc->len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - mc->len)); | |
364 mc->len = SAMPLES_PER_CHUNK; | |
365 } | |
366 | |
367 span_log_bump_samples(&mc->fax.t30_state.logging, mc->len); | |
368 span_log_bump_samples(&mc->fax.v29rx.logging, mc->len); | |
369 span_log_bump_samples(&mc->fax.logging, mc->len); | |
370 | |
371 if (log_audio) | |
372 { | |
373 for (k = 0; k < mc->len; k++) | |
374 out_amp[2*k + j] = mc->amp[k]; | |
375 } | |
376 if (machines[j ^ 1].len < SAMPLES_PER_CHUNK) | |
377 memset(machines[j ^ 1].amp + machines[j ^ 1].len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - machines[j ^ 1].len)); | |
378 if (use_line_hits) | |
379 { | |
380 /* TODO: This applied very crude line hits. improve it */ | |
381 if (mc->fax.t30_state.state == 22) | |
382 { | |
383 if (++mc->error_delay == 100) | |
384 { | |
385 fprintf(stderr, "HIT %d!\n", j); | |
386 mc->error_delay = 0; | |
387 for (k = 0; k < 5; k++) | |
388 mc->amp[k] = 0; | |
389 } | |
390 } | |
391 } | |
392 if (fax_rx(&mc->fax, machines[j ^ 1].amp, SAMPLES_PER_CHUNK)) | |
393 break; | |
394 if (!mc->done) | |
395 alldone = FALSE; | |
396 } | |
397 | |
398 if (log_audio) | |
399 { | |
400 outframes = afWriteFrames(wave_handle, AF_DEFAULT_TRACK, out_amp, SAMPLES_PER_CHUNK); | |
401 if (outframes != SAMPLES_PER_CHUNK) | |
402 break; | |
403 } | |
404 | |
405 if (alldone || j < FAX_MACHINES) | |
406 break; | |
407 } | |
408 for (j = 0; j < FAX_MACHINES; j++) | |
409 { | |
410 mc = &machines[j]; | |
411 fax_release(&mc->fax); | |
412 } | |
413 if (log_audio) | |
414 { | |
415 if (afCloseFile(wave_handle)) | |
416 { | |
417 fprintf(stderr, " Cannot close wave file '%s'\n", OUTPUT_FILE_NAME_WAVE); | |
418 exit(2); | |
419 } | |
420 afFreeFileSetup(filesetup); | |
421 } | |
422 if (input_audio_file_name) | |
423 { | |
424 if (afCloseFile(input_wave_handle)) | |
425 { | |
426 fprintf(stderr, " Cannot close wave file '%s'\n", input_audio_file_name); | |
427 exit(2); | |
428 } | |
429 afFreeFileSetup(filesetup); | |
430 } | |
431 return 0; | |
432 } | |
433 /*- End of function --------------------------------------------------------*/ | |
434 /*- End of file ------------------------------------------------------------*/ |