SPAN_DECLARE(void) fax_modems_start_slow_modem(fax_modems_state_t *s, int which) { switch (which) { case FAX_MODEM_V21_RX: fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); fax_modems_set_rx_handler(s, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx); fsk_rx_signal_cutoff(&s->v21_rx, -39.09f); s->rx_frame_received = false; break; case FAX_MODEM_CED_TONE_RX: modem_connect_tones_rx_init(&s->connect_rx, MODEM_CONNECT_TONES_FAX_CED, s->tone_callback, s->tone_callback_user_data); fax_modems_set_rx_handler(s, (span_rx_handler_t) &modem_connect_tones_rx, &s->connect_rx, (span_rx_fillin_handler_t) &modem_connect_tones_rx_fillin, &s->connect_rx); break; case FAX_MODEM_CNG_TONE_RX: modem_connect_tones_rx_init(&s->connect_rx, MODEM_CONNECT_TONES_FAX_CNG, s->tone_callback, s->tone_callback_user_data); fax_modems_set_rx_handler(s, (span_rx_handler_t) &modem_connect_tones_rx, &s->connect_rx, (span_rx_fillin_handler_t) &modem_connect_tones_rx_fillin, &s->connect_rx); break; case FAX_MODEM_V21_TX: fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); fax_modems_set_tx_handler(s, (span_tx_handler_t) &fsk_tx, &s->v21_tx); fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); break; case FAX_MODEM_CED_TONE_TX: modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CED); fax_modems_set_tx_handler(s, (span_tx_handler_t) &modem_connect_tones_tx, &s->connect_tx); fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); break; case FAX_MODEM_CNG_TONE_TX: modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG); fax_modems_set_tx_handler(s, (span_tx_handler_t) &modem_connect_tones_tx, &s->connect_tx); fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); break; } }
SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, int use_tep, hdlc_frame_handler_t hdlc_accept, hdlc_underflow_handler_t hdlc_tx_underflow, put_bit_func_t non_ecm_put_bit, get_bit_func_t non_ecm_get_bit, tone_report_func_t tone_callback, void *user_data) { if (s == NULL) { if ((s = (fax_modems_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } /*endif*/ memset(s, 0, sizeof(*s)); s->use_tep = use_tep; modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG); span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "FAX modems"); s->tone_callback = tone_callback; s->tone_callback_user_data = user_data; if (tone_callback) { modem_connect_tones_rx_init(&s->connect_rx, MODEM_CONNECT_TONES_FAX_CNG, s->tone_callback, s->tone_callback_user_data); } /*endif*/ dc_restore_init(&s->dc_restore); s->get_bit = non_ecm_get_bit; s->get_bit_user_data = user_data; s->put_bit = non_ecm_put_bit; s->put_bit_user_data = user_data; s->hdlc_accept = hdlc_accept; s->hdlc_accept_user_data = user_data; hdlc_rx_init(&s->hdlc_rx, false, false, HDLC_FRAMING_OK_THRESHOLD, fax_modems_hdlc_accept, s); hdlc_tx_init(&s->hdlc_tx, false, 2, false, hdlc_tx_underflow, user_data); fax_modems_start_slow_modem(s, FAX_MODEM_V21_RX); fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); silence_gen_init(&s->silence_gen, 0); s->rx_signal_present = false; s->rx_handler = (span_rx_handler_t) &span_dummy_rx; s->rx_fillin_handler = (span_rx_fillin_handler_t) &span_dummy_rx; s->rx_user_data = NULL; s->rx_fillin_user_data = NULL; s->tx_handler = (span_tx_handler_t) &silence_gen; s->tx_user_data = &s->silence_gen; return s; }
SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, int use_tep, hdlc_frame_handler_t hdlc_accept, hdlc_underflow_handler_t hdlc_tx_underflow, put_bit_func_t non_ecm_put_bit, get_bit_func_t non_ecm_get_bit, tone_report_func_t tone_callback, void *user_data) { if (s == NULL) { if ((s = (fax_modems_state_t *) malloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); s->use_tep = use_tep; hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, user_data); hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_tx_underflow, user_data); fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); fsk_rx_signal_cutoff(&s->v21_rx, -39.09f); fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); v17_rx_init(&s->v17_rx, 14400, non_ecm_put_bit, user_data); v17_tx_init(&s->v17_tx, 14400, s->use_tep, non_ecm_get_bit, user_data); v29_rx_init(&s->v29_rx, 9600, non_ecm_put_bit, user_data); v29_rx_signal_cutoff(&s->v29_rx, -45.5f); v29_tx_init(&s->v29_tx, 9600, s->use_tep, non_ecm_get_bit, user_data); v27ter_rx_init(&s->v27ter_rx, 4800, non_ecm_put_bit, user_data); v27ter_tx_init(&s->v27ter_tx, 4800, s->use_tep, non_ecm_get_bit, user_data); silence_gen_init(&s->silence_gen, 0); modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG); if (tone_callback) { modem_connect_tones_rx_init(&s->connect_rx, MODEM_CONNECT_TONES_FAX_CNG, tone_callback, user_data); } dc_restore_init(&s->dc_restore); s->rx_signal_present = FALSE; s->rx_handler = (span_rx_handler_t *) &span_dummy_rx; s->rx_user_data = NULL; s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &s->silence_gen; return s; }
int main(int argc, char *argv[]) { fsk_tx_state_t *caller_tx; fsk_rx_state_t *caller_rx; fsk_tx_state_t *answerer_tx; fsk_rx_state_t *answerer_rx; bert_state_t caller_bert; bert_state_t answerer_bert; bert_results_t bert_results; power_meter_t caller_meter; power_meter_t answerer_meter; int16_t caller_amp[BLOCK_LEN]; int16_t answerer_amp[BLOCK_LEN]; int16_t caller_model_amp[BLOCK_LEN]; int16_t answerer_model_amp[BLOCK_LEN]; int16_t out_amp[2*BLOCK_LEN]; AFfilehandle inhandle; AFfilehandle outhandle; int outframes; int i; int j; int samples; int test_bps; int noise_level; int noise_sweep; int bits_per_test; int line_model_no; int modem_under_test_1; int modem_under_test_2; int modems_set; int log_audio; int channel_codec; int rbs_pattern; int on_at; int off_at; tone_gen_descriptor_t tone_desc; tone_gen_state_t tone_tx; int opt; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; line_model_no = 0; decode_test_file = NULL; noise_sweep = FALSE; modem_under_test_1 = FSK_V21CH1; modem_under_test_2 = FSK_V21CH2; log_audio = FALSE; modems_set = 0; while ((opt = getopt(argc, argv, "c:dlm:nr:s:")) != -1) { switch (opt) { case 'c': channel_codec = atoi(optarg); break; case 'd': decode_test_file = optarg; break; case 'l': log_audio = TRUE; break; case 'm': line_model_no = atoi(optarg); break; case 'n': noise_sweep = TRUE; break; case 'r': rbs_pattern = atoi(optarg); break; case 's': switch (modems_set++) { case 0: modem_under_test_1 = atoi(optarg); break; case 1: modem_under_test_2 = atoi(optarg); break; } break; default: //usage(); exit(2); break; } } if (modem_under_test_1 >= 0) printf("Modem channel 1 is '%s'\n", preset_fsk_specs[modem_under_test_1].name); if (modem_under_test_2 >= 0) printf("Modem channel 2 is '%s'\n", preset_fsk_specs[modem_under_test_2].name); outhandle = AF_NULL_FILEHANDLE; if (log_audio) { if ((outhandle = afOpenFile_telephony_write(OUTPUT_FILE_NAME, 2)) == AF_NULL_FILEHANDLE) { fprintf(stderr, " Cannot create wave file '%s'\n", OUTPUT_FILE_NAME); exit(2); } } noise_level = -200; bits_per_test = 0; inhandle = NULL; memset(caller_amp, 0, sizeof(*caller_amp)); memset(answerer_amp, 0, sizeof(*answerer_amp)); memset(caller_model_amp, 0, sizeof(*caller_model_amp)); memset(answerer_model_amp, 0, sizeof(*answerer_model_amp)); power_meter_init(&caller_meter, 7); power_meter_init(&answerer_meter, 7); if (decode_test_file) { if ((inhandle = afOpenFile_telephony_read(decode_test_file, 1)) == AF_NULL_FILEHANDLE) { fprintf(stderr, " Cannot open wave file '%s'\n", decode_test_file); exit(2); } caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, put_bit, NULL); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; for (;;) { samples = afReadFrames(inhandle, AF_DEFAULT_TRACK, caller_model_amp, BLOCK_LEN); if (samples < BLOCK_LEN) break; for (i = 0; i < samples; i++) power_meter_update(&caller_meter, caller_model_amp[i]); fsk_rx(caller_rx, caller_model_amp, samples); } if (afCloseFile(inhandle) != 0) { fprintf(stderr, " Cannot close wave file '%s'\n", decode_test_file); exit(2); } } else { printf("Test cutoff level\n"); caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, cutoff_test_put_bit, NULL); fsk_rx_signal_cutoff(caller_rx, -30.0f); fsk_rx_set_modem_status_handler(caller_rx, cutoff_test_rx_status, (void *) &caller_rx); on_at = 0; for (i = -40; i < -25; i++) { make_tone_gen_descriptor(&tone_desc, 1500, i, 0, 0, 1, 0, 0, 0, TRUE); tone_gen_init(&tone_tx, &tone_desc); for (j = 0; j < 10; j++) { samples = tone_gen(&tone_tx, caller_model_amp, 160); fsk_rx(caller_rx, caller_model_amp, samples); } if (cutoff_test_carrier) break; } on_at = i; off_at = 0; for ( ; i > -40; i--) { make_tone_gen_descriptor(&tone_desc, 1500, i, 0, 0, 1, 0, 0, 0, TRUE); tone_gen_init(&tone_tx, &tone_desc); for (j = 0; j < 10; j++) { samples = tone_gen(&tone_tx, caller_model_amp, 160); fsk_rx(caller_rx, caller_model_amp, samples); } if (!cutoff_test_carrier) break; } off_at = i; printf("Carrier on at %d, off at %d\n", on_at, off_at); if (on_at < -29 || on_at > -26 || off_at < -35 || off_at > -31) { printf("Tests failed.\n"); exit(2); } printf("Test with BERT\n"); test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; if (modem_under_test_1 >= 0) { caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert); fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); } if (modem_under_test_2 >= 0) { answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; bits_per_test = 500000; noise_level = -24; bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1); bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, (float) noise_level, channel_codec, rbs_pattern)) == NULL) { fprintf(stderr, " Failed to create line model\n"); exit(2); } for (;;) { samples = fsk_tx(caller_tx, caller_amp, BLOCK_LEN); for (i = 0; i < samples; i++) power_meter_update(&caller_meter, caller_amp[i]); samples = fsk_tx(answerer_tx, answerer_amp, BLOCK_LEN); for (i = 0; i < samples; i++) power_meter_update(&answerer_meter, answerer_amp[i]); both_ways_line_model(model, caller_model_amp, caller_amp, answerer_model_amp, answerer_amp, samples); //printf("Powers %10.5fdBm0 %10.5fdBm0\n", power_meter_current_dbm0(&caller_meter), power_meter_current_dbm0(&answerer_meter)); fsk_rx(answerer_rx, caller_model_amp, samples); for (i = 0; i < samples; i++) out_amp[2*i] = caller_model_amp[i]; for ( ; i < BLOCK_LEN; i++) out_amp[2*i] = 0; fsk_rx(caller_rx, answerer_model_amp, samples); for (i = 0; i < samples; i++) out_amp[2*i + 1] = answerer_model_amp[i]; for ( ; i < BLOCK_LEN; i++) out_amp[2*i + 1] = 0; if (log_audio) { outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, out_amp, BLOCK_LEN); if (outframes != BLOCK_LEN) { fprintf(stderr, " Error writing wave file\n"); exit(2); } } if (samples < BLOCK_LEN) { bert_result(&caller_bert, &bert_results); fprintf(stderr, "%ddB AWGN, %d bits, %d bad bits, %d resyncs\n", noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); if (!noise_sweep) { if (bert_results.total_bits != bits_per_test - 43 || bert_results.bad_bits != 0 || bert_results.resyncs != 0) { printf("Tests failed.\n"); exit(2); } } bert_result(&answerer_bert, &bert_results); fprintf(stderr, "%ddB AWGN, %d bits, %d bad bits, %d resyncs\n", noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); if (!noise_sweep) { if (bert_results.total_bits != bits_per_test - 43 || bert_results.bad_bits != 0 || bert_results.resyncs != 0) { printf("Tests failed.\n"); exit(2); } break; } /* Put a little silence between the chunks in the file. */ memset(out_amp, 0, sizeof(out_amp)); if (log_audio) { for (i = 0; i < 200; i++) { outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, out_amp, BLOCK_LEN); } } if (modem_under_test_1 >= 0) { caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert); fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); } if (modem_under_test_2 >= 0) { answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } noise_level++; if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, noise_level, channel_codec, 0)) == NULL) { fprintf(stderr, " Failed to create line model\n"); exit(2); } bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1); bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); } } printf("Tests passed.\n"); } if (log_audio) { if (afCloseFile(outhandle) != 0) { fprintf(stderr, " Cannot close wave file '%s'\n", OUTPUT_FILE_NAME); exit(2); } } return 0; }
static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) { fax_state_t *s; get_bit_func_t get_bit_func; void *get_bit_user_data; fax_modems_state_t *t; int tone; s = (fax_state_t *) user_data; t = &s->modems; span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); if (t->current_tx_type == type) return; if (use_hdlc) { get_bit_func = (get_bit_func_t) hdlc_tx_get_bit; get_bit_user_data = (void *) &t->hdlc_tx; } else { get_bit_func = t30_non_ecm_get_bit; get_bit_user_data = (void *) &s->t30; } switch (type) { case T30_MODEM_PAUSE: silence_gen_alter(&t->silence_gen, ms_to_samples(short_train)); set_tx_handler(s, (span_tx_handler_t *) &silence_gen, &t->silence_gen); set_next_tx_handler(s, (span_tx_handler_t *) NULL, NULL); t->transmit = TRUE; break; case T30_MODEM_CED: case T30_MODEM_CNG: if (type == T30_MODEM_CED) tone = MODEM_CONNECT_TONES_FAX_CED; else tone = MODEM_CONNECT_TONES_FAX_CNG; modem_connect_tones_tx_init(&t->connect_tx, tone); set_tx_handler(s, (span_tx_handler_t *) &modem_connect_tones_tx, &t->connect_tx); set_next_tx_handler(s, (span_tx_handler_t *) NULL, NULL); t->transmit = TRUE; break; case T30_MODEM_V21: fsk_tx_init(&t->v21_tx, &preset_fsk_specs[FSK_V21CH2], get_bit_func, get_bit_user_data); /* The spec says 1s +-15% of preamble. So, the minimum is 32 octets. */ hdlc_tx_flags(&t->hdlc_tx, 32); /* Pause before switching from phase C, as per T.30 5.3.2.2. If we omit this, the receiver might not see the carrier fall between the high speed and low speed sections. In practice, a 75ms gap before any V.21 transmission is harmless, adds little to the overall length of a call, and ensures the receiving end is ready. */ silence_gen_alter(&t->silence_gen, ms_to_samples(75)); set_tx_handler(s, (span_tx_handler_t *) &silence_gen, &t->silence_gen); set_next_tx_handler(s, (span_tx_handler_t *) &fsk_tx, &t->v21_tx); t->transmit = TRUE; break; case T30_MODEM_V27TER: silence_gen_alter(&t->silence_gen, ms_to_samples(75)); /* For any fast modem, set 200ms of preamble flags */ hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5)); v27ter_tx_restart(&t->v27ter_tx, bit_rate, t->use_tep); v27ter_tx_set_get_bit(&t->v27ter_tx, get_bit_func, get_bit_user_data); set_tx_handler(s, (span_tx_handler_t *) &silence_gen, &t->silence_gen); set_next_tx_handler(s, (span_tx_handler_t *) &v27ter_tx, &t->v27ter_tx); t->transmit = TRUE; break; case T30_MODEM_V29: silence_gen_alter(&t->silence_gen, ms_to_samples(75)); /* For any fast modem, set 200ms of preamble flags */ hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5)); v29_tx_restart(&t->v29_tx, bit_rate, t->use_tep); v29_tx_set_get_bit(&t->v29_tx, get_bit_func, get_bit_user_data); set_tx_handler(s, (span_tx_handler_t *) &silence_gen, &t->silence_gen); set_next_tx_handler(s, (span_tx_handler_t *) &v29_tx, &t->v29_tx); t->transmit = TRUE; break; case T30_MODEM_V17: silence_gen_alter(&t->silence_gen, ms_to_samples(75)); /* For any fast modem, set 200ms of preamble flags */ hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5)); v17_tx_restart(&t->v17_tx, bit_rate, t->use_tep, short_train); v17_tx_set_get_bit(&t->v17_tx, get_bit_func, get_bit_user_data); set_tx_handler(s, (span_tx_handler_t *) &silence_gen, &t->silence_gen); set_next_tx_handler(s, (span_tx_handler_t *) &v17_tx, &t->v17_tx); t->transmit = TRUE; break; case T30_MODEM_DONE: span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); /* Fall through */ default: silence_gen_alter(&t->silence_gen, 0); set_tx_handler(s, (span_tx_handler_t *) &silence_gen, &t->silence_gen); set_next_tx_handler(s, (span_tx_handler_t *) NULL, NULL); t->transmit = FALSE; break; } t->tx_bit_rate = bit_rate; t->current_tx_type = type; }
fax_state_t *fax_init(fax_state_t *s, int calling_party) { if (s == NULL) { if ((s = (fax_state_t *) malloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "FAX"); t30_init(&(s->t30_state), calling_party, fax_set_rx_type, (void *) s, fax_set_tx_type, (void *) s, fax_send_hdlc, (void *) s); t30_set_supported_modems(&(s->t30_state), T30_SUPPORT_V27TER | T30_SUPPORT_V29); hdlc_rx_init(&(s->hdlcrx), FALSE, FALSE, 5, t30_hdlc_accept, &(s->t30_state)); fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &(s->hdlcrx)); fsk_rx_signal_cutoff(&(s->v21rx), -45.5); hdlc_tx_init(&(s->hdlctx), FALSE, 2, FALSE, hdlc_underflow_handler, &(s->t30_state)); s->first_tx_hdlc_frame = TRUE; fsk_tx_init(&(s->v21tx), &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &(s->hdlctx)); v17_rx_init(&(s->v17rx), 14400, t30_non_ecm_put_bit, &(s->t30_state)); v17_tx_init(&(s->v17tx), 14400, s->use_tep, t30_non_ecm_get_bit, &(s->t30_state)); v29_rx_init(&(s->v29rx), 9600, t30_non_ecm_put_bit, &(s->t30_state)); v29_rx_signal_cutoff(&(s->v29rx), -45.5); v29_tx_init(&(s->v29tx), 9600, s->use_tep, t30_non_ecm_get_bit, &(s->t30_state)); v27ter_rx_init(&(s->v27ter_rx), 4800, t30_non_ecm_put_bit, &(s->t30_state)); v27ter_tx_init(&(s->v27ter_tx), 4800, s->use_tep, t30_non_ecm_get_bit, &(s->t30_state)); silence_gen_init(&(s->silence_gen), 0); dc_restore_init(&(s->dc_restore)); t30_restart(&(s->t30_state)); #if defined(LOG_FAX_AUDIO) { char buf[100 + 1]; struct tm *tm; time_t now; time(&now); tm = localtime(&now); sprintf(buf, "/tmp/fax-rx-audio-%x-%02d%02d%02d%02d%02d%02d", s, tm->tm_year%100, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); s->fax_audio_rx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666); sprintf(buf, "/tmp/fax-tx-audio-%x-%02d%02d%02d%02d%02d%02d", s, tm->tm_year%100, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); s->fax_audio_tx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666); } #endif return s; }
static void fax_set_tx_type(void *user_data, int type, int short_train, int use_hdlc) { fax_state_t *s; tone_gen_descriptor_t tone_desc; get_bit_func_t get_bit_func; void *get_bit_user_data; s = (fax_state_t *) user_data; span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); if (s->current_tx_type == type) return; s->first_tx_hdlc_frame = TRUE; if (use_hdlc) { get_bit_func = (get_bit_func_t) hdlc_tx_get_bit; get_bit_user_data = (void *) &(s->hdlctx); } else { get_bit_func = t30_non_ecm_get_bit; get_bit_user_data = (void *) &(s->t30_state); } switch (type) { case T30_MODEM_PAUSE: silence_gen_alter(&(s->silence_gen), ms_to_samples(short_train)); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = NULL; s->transmit = TRUE; break; case T30_MODEM_CNG: /* 0.5s of 1100Hz+-38Hz + 3.0s of silence repeating. Timing +-15% */ make_tone_gen_descriptor(&tone_desc, 1100, -11, 0, 0, 500, 3000, 0, 0, TRUE); tone_gen_init(&(s->tone_gen), &tone_desc); s->tx_handler = (span_tx_handler_t *) &tone_gen; s->tx_user_data = &(s->tone_gen); s->next_tx_handler = NULL; s->transmit = TRUE; break; case T30_MODEM_CED: /* 0.2s of silence, then 2.6s to 4s of 2100Hz+-15Hz tone, then 75ms of silence. The 75ms of silence will be inserted by the pre V.21 pause we use for any switch to V.21. */ silence_gen_alter(&(s->silence_gen), ms_to_samples(200)); make_tone_gen_descriptor(&tone_desc, 2100, -11, 0, 0, 2600, 0, 0, 0, FALSE); tone_gen_init(&(s->tone_gen), &tone_desc); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &tone_gen; s->next_tx_user_data = &(s->tone_gen); s->transmit = TRUE; break; case T30_MODEM_V21: fsk_tx_init(&(s->v21tx), &preset_fsk_specs[FSK_V21CH2], get_bit_func, get_bit_user_data); /* The spec says 1s +-15% of preamble. So, the minimum is 32 octets. */ hdlc_tx_flags(&(s->hdlctx), 32); /* Pause before switching from phase C, as per T.30 5.3.2.2. If we omit this, the receiver might not see the carrier fall between the high speed and low speed sections. In practice, a 75ms gap before any V.21 transmission is harmless, adds little to the overall length of a call, and ensures the receiving end is ready. */ silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &fsk_tx; s->next_tx_user_data = &(s->v21tx); s->transmit = TRUE; break; case T30_MODEM_V27TER_2400: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v27ter_tx_restart(&(s->v27ter_tx), 2400, s->use_tep); v27ter_tx_set_get_bit(&(s->v27ter_tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v27ter_tx; s->next_tx_user_data = &(s->v27ter_tx); hdlc_tx_flags(&(s->hdlctx), 60); s->transmit = TRUE; break; case T30_MODEM_V27TER_4800: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v27ter_tx_restart(&(s->v27ter_tx), 4800, s->use_tep); v27ter_tx_set_get_bit(&(s->v27ter_tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v27ter_tx; s->next_tx_user_data = &(s->v27ter_tx); hdlc_tx_flags(&(s->hdlctx), 120); s->transmit = TRUE; break; case T30_MODEM_V29_7200: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v29_tx_restart(&(s->v29tx), 7200, s->use_tep); v29_tx_set_get_bit(&(s->v29tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v29_tx; s->next_tx_user_data = &(s->v29tx); hdlc_tx_flags(&(s->hdlctx), 180); s->transmit = TRUE; break; case T30_MODEM_V29_9600: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v29_tx_restart(&(s->v29tx), 9600, s->use_tep); v29_tx_set_get_bit(&(s->v29tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v29_tx; s->next_tx_user_data = &(s->v29tx); hdlc_tx_flags(&(s->hdlctx), 240); s->transmit = TRUE; break; case T30_MODEM_V17_7200: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v17_tx_restart(&(s->v17tx), 7200, s->use_tep, short_train); v17_tx_set_get_bit(&(s->v17tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v17_tx; s->next_tx_user_data = &(s->v17tx); hdlc_tx_flags(&(s->hdlctx), 180); s->transmit = TRUE; break; case T30_MODEM_V17_9600: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v17_tx_restart(&(s->v17tx), 9600, s->use_tep, short_train); v17_tx_set_get_bit(&(s->v17tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v17_tx; s->next_tx_user_data = &(s->v17tx); hdlc_tx_flags(&(s->hdlctx), 240); s->transmit = TRUE; break; case T30_MODEM_V17_12000: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v17_tx_restart(&(s->v17tx), 12000, s->use_tep, short_train); v17_tx_set_get_bit(&(s->v17tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v17_tx; s->next_tx_user_data = &(s->v17tx); hdlc_tx_flags(&(s->hdlctx), 300); s->transmit = TRUE; break; case T30_MODEM_V17_14400: silence_gen_alter(&(s->silence_gen), ms_to_samples(75)); v17_tx_restart(&(s->v17tx), 14400, s->use_tep, short_train); v17_tx_set_get_bit(&(s->v17tx), get_bit_func, get_bit_user_data); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = (span_tx_handler_t *) &v17_tx; s->next_tx_user_data = &(s->v17tx); hdlc_tx_flags(&(s->hdlctx), 360); s->transmit = TRUE; break; case T30_MODEM_DONE: span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); /* Fall through */ default: silence_gen_alter(&(s->silence_gen), 0); s->tx_handler = (span_tx_handler_t *) &silence_gen; s->tx_user_data = &(s->silence_gen); s->next_tx_handler = NULL; s->transmit = FALSE; break; } s->current_tx_type = type; }