Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/tests/fax_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 * 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.102 2009/05/30 15:23:13 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 #if defined(HAVE_CONFIG_H) | |
| 34 #include "config.h" | |
| 35 #endif | |
| 36 | |
| 37 #include <stdlib.h> | |
| 38 #include <stdio.h> | |
| 39 #include <unistd.h> | |
| 40 #include <string.h> | |
| 41 #include <assert.h> | |
| 42 #include <sndfile.h> | |
| 43 | |
| 44 //#if defined(WITH_SPANDSP_INTERNALS) | |
| 45 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES | |
| 46 //#endif | |
| 47 | |
| 48 #include "spandsp.h" | |
| 49 #include "spandsp-sim.h" | |
| 50 | |
| 51 #include "fax_utils.h" | |
| 52 | |
| 53 #define SAMPLES_PER_CHUNK 160 | |
| 54 | |
| 55 #define INPUT_TIFF_FILE_NAME "../test-data/itu/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 awgn_state_t *awgn; | |
| 68 int done; | |
| 69 int succeeded; | |
| 70 char tag[50]; | |
| 71 int error_delay; | |
| 72 int total_audio_time; | |
| 73 } machines[FAX_MACHINES]; | |
| 74 | |
| 75 int use_receiver_not_ready = FALSE; | |
| 76 int test_local_interrupt = FALSE; | |
| 77 int t30_state_to_wreck = -1; | |
| 78 | |
| 79 static int phase_b_handler(t30_state_t *s, void *user_data, int result) | |
| 80 { | |
| 81 int i; | |
| 82 char tag[20]; | |
| 83 | |
| 84 i = (int) (intptr_t) user_data; | |
| 85 snprintf(tag, sizeof(tag), "%c: Phase B:", i); | |
| 86 printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
| 87 log_rx_parameters(s, tag); | |
| 88 return T30_ERR_OK; | |
| 89 } | |
| 90 /*- End of function --------------------------------------------------------*/ | |
| 91 | |
| 92 static int phase_d_handler(t30_state_t *s, void *user_data, int result) | |
| 93 { | |
| 94 int i; | |
| 95 char tag[20]; | |
| 96 | |
| 97 i = (int) (intptr_t) user_data; | |
| 98 snprintf(tag, sizeof(tag), "%c: Phase D:", i); | |
| 99 printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); | |
| 100 log_transfer_statistics(s, tag); | |
| 101 log_tx_parameters(s, tag); | |
| 102 log_rx_parameters(s, tag); | |
| 103 | |
| 104 if (use_receiver_not_ready) | |
| 105 t30_set_receiver_not_ready(s, 3); | |
| 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 return T30_ERR_OK; | |
| 131 } | |
| 132 /*- End of function --------------------------------------------------------*/ | |
| 133 | |
| 134 static void phase_e_handler(t30_state_t *s, void *user_data, int result) | |
| 135 { | |
| 136 int i; | |
| 137 t30_stats_t t; | |
| 138 char tag[20]; | |
| 139 | |
| 140 i = (intptr_t) user_data; | |
| 141 snprintf(tag, sizeof(tag), "%c: Phase E:", i); | |
| 142 printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); | |
| 143 log_transfer_statistics(s, tag); | |
| 144 log_tx_parameters(s, tag); | |
| 145 log_rx_parameters(s, tag); | |
| 146 t30_get_transfer_statistics(s, &t); | |
| 147 machines[i - 'A'].succeeded = (result == T30_ERR_OK) && (t.pages_tx == 12 || t.pages_rx == 12); | |
| 148 machines[i - 'A'].done = TRUE; | |
| 149 } | |
| 150 /*- End of function --------------------------------------------------------*/ | |
| 151 | |
| 152 static void real_time_frame_handler(t30_state_t *s, | |
| 153 void *user_data, | |
| 154 int direction, | |
| 155 const uint8_t *msg, | |
| 156 int len) | |
| 157 { | |
| 158 int i; | |
| 159 | |
| 160 i = (intptr_t) user_data; | |
| 161 printf("%c: Real time frame handler on channel %c - %s, %s, length = %d\n", | |
| 162 i, | |
| 163 i, | |
| 164 (direction) ? "line->T.30" : "T.30->line", | |
| 165 t30_frametype(msg[2]), | |
| 166 len); | |
| 167 } | |
| 168 /*- End of function --------------------------------------------------------*/ | |
| 169 | |
| 170 static int document_handler(t30_state_t *s, void *user_data, int event) | |
| 171 { | |
| 172 int i; | |
| 173 | |
| 174 i = (intptr_t) user_data; | |
| 175 printf("%c: Document handler on channel %c - event %d\n", i, i, event); | |
| 176 return FALSE; | |
| 177 } | |
| 178 /*- End of function --------------------------------------------------------*/ | |
| 179 | |
| 180 int main(int argc, char *argv[]) | |
| 181 { | |
| 182 SNDFILE *wave_handle; | |
| 183 SNDFILE *input_wave_handle; | |
| 184 int i; | |
| 185 int j; | |
| 186 int k; | |
| 187 struct machine_s *mc; | |
| 188 int outframes; | |
| 189 char buf[128 + 1]; | |
| 190 int16_t silence[SAMPLES_PER_CHUNK]; | |
| 191 int16_t out_amp[2*SAMPLES_PER_CHUNK]; | |
| 192 int alldone; | |
| 193 const char *input_tiff_file_name; | |
| 194 const char *input_audio_file_name; | |
| 195 int log_audio; | |
| 196 int use_ecm; | |
| 197 int use_tep; | |
| 198 int use_transmit_on_idle; | |
| 199 int use_line_hits; | |
| 200 int polled_mode; | |
| 201 int reverse_flow; | |
| 202 int use_page_limits; | |
| 203 int supported_modems; | |
| 204 int signal_level; | |
| 205 int noise_level; | |
| 206 float signal_scaling; | |
| 207 time_t start_time; | |
| 208 time_t end_time; | |
| 209 char *page_header_info; | |
| 210 int opt; | |
| 211 t30_state_t *t30; | |
| 212 logging_state_t *logging; | |
| 213 | |
| 214 log_audio = FALSE; | |
| 215 input_tiff_file_name = INPUT_TIFF_FILE_NAME; | |
| 216 input_audio_file_name = NULL; | |
| 217 use_ecm = FALSE; | |
| 218 use_line_hits = FALSE; | |
| 219 use_tep = FALSE; | |
| 220 polled_mode = FALSE; | |
| 221 page_header_info = NULL; | |
| 222 reverse_flow = FALSE; | |
| 223 use_transmit_on_idle = TRUE; | |
| 224 use_receiver_not_ready = FALSE; | |
| 225 use_page_limits = FALSE; | |
| 226 signal_level = 0; | |
| 227 noise_level = -99; | |
| 228 supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; | |
| 229 while ((opt = getopt(argc, argv, "ehH:i:I:lm:n:prRs:tTw:")) != -1) | |
| 230 { | |
| 231 switch (opt) | |
| 232 { | |
| 233 case 'e': | |
| 234 use_ecm = TRUE; | |
| 235 break; | |
| 236 case 'h': | |
| 237 use_line_hits = TRUE; | |
| 238 break; | |
| 239 case 'H': | |
| 240 page_header_info = optarg; | |
| 241 break; | |
| 242 case 'i': | |
| 243 input_tiff_file_name = optarg; | |
| 244 break; | |
| 245 case 'I': | |
| 246 input_audio_file_name = optarg; | |
| 247 break; | |
| 248 case 'l': | |
| 249 log_audio = TRUE; | |
| 250 break; | |
| 251 case 'm': | |
| 252 supported_modems = atoi(optarg); | |
| 253 break; | |
| 254 case 'n': | |
| 255 noise_level = atoi(optarg); | |
| 256 break; | |
| 257 case 'p': | |
| 258 polled_mode = TRUE; | |
| 259 break; | |
| 260 case 'r': | |
| 261 reverse_flow = TRUE; | |
| 262 break; | |
| 263 case 'R': | |
| 264 use_receiver_not_ready = TRUE; | |
| 265 break; | |
| 266 case 's': | |
| 267 signal_level = atoi(optarg); | |
| 268 break; | |
| 269 case 't': | |
| 270 use_tep = TRUE; | |
| 271 break; | |
| 272 case 'T': | |
| 273 use_page_limits = TRUE; | |
| 274 break; | |
| 275 case 'w': | |
| 276 t30_state_to_wreck = atoi(optarg); | |
| 277 break; | |
| 278 default: | |
| 279 //usage(); | |
| 280 exit(2); | |
| 281 break; | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 input_wave_handle = NULL; | |
| 286 if (input_audio_file_name) | |
| 287 { | |
| 288 if ((input_wave_handle = sf_open_telephony_read(input_audio_file_name, 1)) == NULL) | |
| 289 { | |
| 290 fprintf(stderr, " Cannot open audio file '%s'\n", input_audio_file_name); | |
| 291 exit(2); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 wave_handle = NULL; | |
| 296 if (log_audio) | |
| 297 { | |
| 298 if ((wave_handle = sf_open_telephony_write(OUTPUT_FILE_NAME_WAVE, 2)) == NULL) | |
| 299 { | |
| 300 fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME_WAVE); | |
| 301 exit(2); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 memset(silence, 0, sizeof(silence)); | |
| 306 for (j = 0; j < FAX_MACHINES; j++) | |
| 307 { | |
| 308 machines[j].chan = j; | |
| 309 mc = &machines[j]; | |
| 310 | |
| 311 i = mc->chan + 1; | |
| 312 sprintf(buf, "%d%d%d%d%d%d%d%d", i, i, i, i, i, i, i, i); | |
| 313 if (reverse_flow) | |
| 314 mc->fax = fax_init(NULL, (mc->chan & 1) ? TRUE : FALSE); | |
| 315 else | |
| 316 mc->fax = fax_init(NULL, (mc->chan & 1) ? FALSE : TRUE); | |
| 317 mc->awgn = NULL; | |
| 318 signal_scaling = 1.0f; | |
| 319 if (noise_level > -99) | |
| 320 { | |
| 321 mc->awgn = awgn_init_dbm0(NULL, 1234567, noise_level); | |
| 322 signal_scaling = powf(10.0f, signal_level/20.0f); | |
| 323 printf("Signal scaling %f\n", signal_scaling); | |
| 324 } | |
| 325 fax_set_transmit_on_idle(mc->fax, use_transmit_on_idle); | |
| 326 fax_set_tep_mode(mc->fax, use_tep); | |
| 327 t30 = fax_get_t30_state(mc->fax); | |
| 328 t30_set_tx_ident(t30, buf); | |
| 329 t30_set_tx_sub_address(t30, "Sub-address"); | |
| 330 t30_set_tx_sender_ident(t30, "Sender ID"); | |
| 331 t30_set_tx_password(t30, "Password"); | |
| 332 t30_set_tx_polled_sub_address(t30, "Polled sub-address"); | |
| 333 t30_set_tx_selective_polling_address(t30, "Selective polling address"); | |
| 334 t30_set_tx_page_header_info(t30, page_header_info); | |
| 335 t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); | |
| 336 t30_set_ecm_capability(t30, use_ecm); | |
| 337 t30_set_supported_t30_features(t30, | |
| 338 T30_SUPPORT_IDENTIFICATION | |
| 339 | T30_SUPPORT_SELECTIVE_POLLING | |
| 340 | T30_SUPPORT_SUB_ADDRESSING); | |
| 341 | |
| 342 if ((mc->chan & 1)) | |
| 343 t30_set_minimum_scan_line_time(t30, 40); | |
| 344 t30_set_supported_image_sizes(t30, | |
| 345 T30_SUPPORT_US_LETTER_LENGTH | |
| 346 | T30_SUPPORT_US_LEGAL_LENGTH | |
| 347 | T30_SUPPORT_UNLIMITED_LENGTH | |
| 348 | T30_SUPPORT_215MM_WIDTH | |
| 349 | T30_SUPPORT_255MM_WIDTH | |
| 350 | T30_SUPPORT_303MM_WIDTH); | |
| 351 t30_set_supported_resolutions(t30, | |
| 352 T30_SUPPORT_STANDARD_RESOLUTION | |
| 353 | T30_SUPPORT_FINE_RESOLUTION | |
| 354 | T30_SUPPORT_SUPERFINE_RESOLUTION | |
| 355 | T30_SUPPORT_R8_RESOLUTION | |
| 356 | T30_SUPPORT_R16_RESOLUTION | |
| 357 | T30_SUPPORT_300_300_RESOLUTION | |
| 358 | T30_SUPPORT_400_400_RESOLUTION | |
| 359 | T30_SUPPORT_600_600_RESOLUTION | |
| 360 | T30_SUPPORT_1200_1200_RESOLUTION | |
| 361 | T30_SUPPORT_300_600_RESOLUTION | |
| 362 | T30_SUPPORT_400_800_RESOLUTION | |
| 363 | T30_SUPPORT_600_1200_RESOLUTION); | |
| 364 t30_set_supported_modems(t30, supported_modems); | |
| 365 if (use_ecm) | |
| 366 t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); | |
| 367 if ((mc->chan & 1)) | |
| 368 { | |
| 369 if (polled_mode) | |
| 370 { | |
| 371 if (use_page_limits) | |
| 372 t30_set_tx_file(t30, input_tiff_file_name, 3, 6); | |
| 373 else | |
| 374 t30_set_tx_file(t30, input_tiff_file_name, -1, -1); | |
| 375 } | |
| 376 else | |
| 377 { | |
| 378 sprintf(buf, "fax_tests_%d.tif", (mc->chan + 1)/2); | |
| 379 t30_set_rx_file(t30, buf, -1); | |
| 380 t30_set_rx_encoding(t30, T4_COMPRESSION_ITU_T6); | |
| 381 } | |
| 382 } | |
| 383 else | |
| 384 { | |
| 385 if (polled_mode) | |
| 386 { | |
| 387 sprintf(buf, "fax_tests_%d.tif", (mc->chan + 1)/2); | |
| 388 t30_set_rx_file(t30, buf, -1); | |
| 389 t30_set_rx_encoding(t30, T4_COMPRESSION_ITU_T6); | |
| 390 } | |
| 391 else | |
| 392 { | |
| 393 if (use_page_limits) | |
| 394 t30_set_tx_file(t30, input_tiff_file_name, 3, 6); | |
| 395 else | |
| 396 t30_set_tx_file(t30, input_tiff_file_name, -1, -1); | |
| 397 } | |
| 398 } | |
| 399 t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) mc->chan + 'A'); | |
| 400 t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) mc->chan + 'A'); | |
| 401 t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) mc->chan + 'A'); | |
| 402 t30_set_real_time_frame_handler(t30, real_time_frame_handler, (void *) (intptr_t) mc->chan + 'A'); | |
| 403 t30_set_document_handler(t30, document_handler, (void *) (intptr_t) mc->chan + 'A'); | |
| 404 sprintf(mc->tag, "FAX-%d", j + 1); | |
| 405 | |
| 406 logging = t30_get_logging_state(t30); | |
| 407 span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); | |
| 408 span_log_set_tag(logging, mc->tag); | |
| 409 span_log_set_level(&t30->t4.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); | |
| 410 span_log_set_tag(&t30->t4.logging, mc->tag); | |
| 411 | |
| 412 logging = fax_get_logging_state(mc->fax); | |
| 413 span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); | |
| 414 span_log_set_tag(logging, mc->tag); | |
| 415 | |
| 416 memset(mc->amp, 0, sizeof(mc->amp)); | |
| 417 mc->total_audio_time = 0; | |
| 418 mc->done = FALSE; | |
| 419 } | |
| 420 time(&start_time); | |
| 421 for (;;) | |
| 422 { | |
| 423 alldone = TRUE; | |
| 424 for (j = 0; j < FAX_MACHINES; j++) | |
| 425 { | |
| 426 mc = &machines[j]; | |
| 427 | |
| 428 if ((j & 1) == 0 && input_audio_file_name) | |
| 429 { | |
| 430 mc->len = sf_readf_short(input_wave_handle, mc->amp, SAMPLES_PER_CHUNK); | |
| 431 if (mc->len == 0) | |
| 432 break; | |
| 433 } | |
| 434 else | |
| 435 { | |
| 436 mc->len = fax_tx(mc->fax, mc->amp, SAMPLES_PER_CHUNK); | |
| 437 if (mc->awgn) | |
| 438 { | |
| 439 for (k = 0; k < mc->len; k++) | |
| 440 mc->amp[k] = ((int16_t) (mc->amp[k]*signal_scaling)) + awgn(mc->awgn); | |
| 441 } | |
| 442 } | |
| 443 mc->total_audio_time += SAMPLES_PER_CHUNK; | |
| 444 if (!use_transmit_on_idle) | |
| 445 { | |
| 446 /* The receive side always expects a full block of samples, but the | |
| 447 transmit side may not be sending any when it doesn't need to. We | |
| 448 may need to pad with some silence. */ | |
| 449 if (mc->len < SAMPLES_PER_CHUNK) | |
| 450 { | |
| 451 memset(mc->amp + mc->len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - mc->len)); | |
| 452 mc->len = SAMPLES_PER_CHUNK; | |
| 453 } | |
| 454 } | |
| 455 t30 = fax_get_t30_state(mc->fax); | |
| 456 logging = t30_get_logging_state(t30); | |
| 457 span_log_bump_samples(logging, mc->len); | |
| 458 logging = fax_get_logging_state(mc->fax); | |
| 459 span_log_bump_samples(logging, mc->len); | |
| 460 | |
| 461 if (log_audio) | |
| 462 { | |
| 463 for (k = 0; k < mc->len; k++) | |
| 464 out_amp[2*k + j] = mc->amp[k]; | |
| 465 } | |
| 466 if (machines[j ^ 1].len < SAMPLES_PER_CHUNK) | |
| 467 memset(machines[j ^ 1].amp + machines[j ^ 1].len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - machines[j ^ 1].len)); | |
| 468 t30 = fax_get_t30_state(mc->fax); | |
| 469 #if defined(WITH_SPANDSP_INTERNALS) | |
| 470 if (use_line_hits) | |
| 471 { | |
| 472 /* TODO: This applies very crude line hits. improve it */ | |
| 473 if (t30->state == 22) | |
| 474 { | |
| 475 if (++mc->error_delay == 100) | |
| 476 { | |
| 477 fprintf(stderr, "HIT %d!\n", j); | |
| 478 mc->error_delay = 0; | |
| 479 for (k = 0; k < 5; k++) | |
| 480 mc->amp[k] = 0; | |
| 481 } | |
| 482 } | |
| 483 } | |
| 484 if (t30->state == t30_state_to_wreck) | |
| 485 memset(machines[j ^ 1].amp, 0, sizeof(int16_t)*SAMPLES_PER_CHUNK); | |
| 486 #endif | |
| 487 if (fax_rx(mc->fax, machines[j ^ 1].amp, SAMPLES_PER_CHUNK)) | |
| 488 break; | |
| 489 if (!mc->done) | |
| 490 alldone = FALSE; | |
| 491 } | |
| 492 | |
| 493 if (log_audio) | |
| 494 { | |
| 495 outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK); | |
| 496 if (outframes != SAMPLES_PER_CHUNK) | |
| 497 break; | |
| 498 } | |
| 499 | |
| 500 if (alldone || j < FAX_MACHINES) | |
| 501 break; | |
| 502 } | |
| 503 time(&end_time); | |
| 504 for (j = 0; j < FAX_MACHINES; j++) | |
| 505 { | |
| 506 mc = &machines[j]; | |
| 507 fax_release(mc->fax); | |
| 508 } | |
| 509 if (log_audio) | |
| 510 { | |
| 511 if (sf_close(wave_handle)) | |
| 512 { | |
| 513 fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME_WAVE); | |
| 514 exit(2); | |
| 515 } | |
| 516 } | |
| 517 if (input_audio_file_name) | |
| 518 { | |
| 519 if (sf_close(input_wave_handle)) | |
| 520 { | |
| 521 fprintf(stderr, " Cannot close audio file '%s'\n", input_audio_file_name); | |
| 522 exit(2); | |
| 523 } | |
| 524 } | |
| 525 printf("Total audio time = %ds (wall time %ds)\n", machines[0].total_audio_time/8000, (int) (end_time - start_time)); | |
| 526 return 0; | |
| 527 } | |
| 528 /*- End of function --------------------------------------------------------*/ | |
| 529 /*- End of file ------------------------------------------------------------*/ |
