Beispiel #1
0
static int t38_tests(int use_gui, int test_sending, int model_no, int speed_pattern_no)
{
    t38_terminal_state_t *t38_state;
    int fast_send;
    int fast_send_tcf;
    int fast_blocks;
    uint8_t fast_buf[1000];
    int msg_len;
    uint8_t msg[1024];
    int t38_version;
    int without_pacing;
    int use_tep;
    int seq_no;
    double tx_when;
    double rx_when;
    t30_state_t *t30;
    t38_core_state_t *t38_core;
    logging_state_t *logging;
    int i;

    t38_version = 1;
    without_pacing = FALSE;
    use_tep = FALSE;

    srand48(0x1234567);
    if ((path_a_to_b = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((path_b_to_a = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((t31_state = t31_init(NULL, at_tx_handler, NULL, modem_call_control, NULL, t31_tx_packet_handler, NULL)) == NULL)
    {
        fprintf(stderr, "    Cannot start the T.31 T.38 modem\n");
        exit(2);
    }
    logging = t31_get_logging_state(t31_state);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.31");

    t38_core = t31_get_t38_core_state(t31_state);
    logging = t38_core_get_logging_state(t38_core);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.31");

    span_log_set_level(&t31_state->at_state.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&t31_state->at_state.logging, "T.31");

    t31_set_mode(t31_state, TRUE);
    t38_set_t38_version(t38_core, t38_version);

    if (test_sending)
    {
        if ((t38_state = t38_terminal_init(NULL, FALSE, t38_tx_packet_handler, t31_state)) == NULL)
        {
            fprintf(stderr, "Cannot start the T.38 channel\n");
            exit(2);
        }
        t30 = t38_terminal_get_t30_state(t38_state);
        t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1);
        fax_test_seq = fax_send_test_seq;
        countdown = 0;
    }
    else
    {
        if ((t38_state = t38_terminal_init(NULL, TRUE, t38_tx_packet_handler, t31_state)) == NULL)
        {
            fprintf(stderr, "Cannot start the T.38 channel\n");
            exit(2);
        }
        t30 = t38_terminal_get_t30_state(t38_state);
        t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1);
        fax_test_seq = fax_receive_test_seq;
        countdown = 250;
    }

    t30 = t38_terminal_get_t30_state(t38_state);
    t38_core = t38_terminal_get_t38_core_state(t38_state);
    t38_set_t38_version(t38_core, t38_version);
    t38_terminal_set_config(t38_state, without_pacing);
    t38_terminal_set_tep_mode(t38_state, use_tep);

    t30_set_tx_ident(t30, "11111111");
    t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
    //t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) 'A');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) 'A');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) 'A');

    logging = t38_terminal_get_logging_state(t38_state);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38");

    t38_core = t38_terminal_get_t38_core_state(t38_state);
    span_log_set_level(&t38_core->logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&t38_core->logging, "T.38");

    logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38");

    fast_send = FALSE;
    fast_send_tcf = TRUE;
    fast_blocks = 0;
    kick = TRUE;
#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    while (!done)
    {
        logging = t38_terminal_get_logging_state(t38_state);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t38_core = t38_terminal_get_t38_core_state(t38_state);
        logging = t38_core_get_logging_state(t38_core);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t30 = t38_terminal_get_t30_state(t38_state);
        logging = t30_get_logging_state(t30);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

        logging = t31_get_logging_state(t31_state);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t38_core = t31_get_t38_core_state(t31_state);
        logging = t38_core_get_logging_state(t38_core);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&t31_state->at_state.logging, SAMPLES_PER_CHUNK);

        t38_terminal_send_timeout(t38_state, SAMPLES_PER_CHUNK);
        t31_t38_send_timeout(t31_state, SAMPLES_PER_CHUNK);

        when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

        if (kick)
        {
            kick = FALSE;
            if (fax_test_seq[test_seq_ptr].command > (const char *) 2)
            {
                if (fax_test_seq[test_seq_ptr].command[0])
                {
                    printf("%s\n", fax_test_seq[test_seq_ptr].command);
                    t31_at_rx(t31_state, fax_test_seq[test_seq_ptr].command, fax_test_seq[test_seq_ptr].len_command);
                }
            }
            else
            {
                if (fax_test_seq[test_seq_ptr].command == (const char *) 2)
                {
                    printf("Fast send TCF\n");
                    fast_send = TRUE;
                    fast_send_tcf = TRUE;
                    fast_blocks = 100;
                }
                else
                {
                    printf("Fast send image\n");
                    fast_send = TRUE;
                    fast_send_tcf = FALSE;
                    fast_blocks = 100;
                }
            }
        }
        if (fast_send)
        {
            /* Send fast modem data */
            if (fast_send_tcf)
            {
                memset(fast_buf, 0, 36);
            }
            else
            {
                if (fast_blocks == 1)
                {
                    /* Create the end of page condition */
                    for (i = 0;  i < 36;  i += 2)
                    {
                        fast_buf[i] = 0x00;
                        fast_buf[i + 1] = 0x80;
                    }
                }
                else
                {
                    /* Create a chunk of white page */
                    for (i = 0;  i < 36;  i += 4)
                    {
                        fast_buf[i] = 0x00;
                        fast_buf[i + 1] = 0x80;
                        fast_buf[i + 2] = 0xB2;
                        fast_buf[i + 3] = 0x01;
                    }
                }
            }
            if (fast_blocks == 1)
            {
                /* Insert EOLs */
                fast_buf[35] = ETX;
                fast_buf[34] = DLE;
                fast_buf[31] =
                fast_buf[28] =
                fast_buf[25] =
                fast_buf[22] =
                fast_buf[19] =
                fast_buf[16] = 1;
            }
            t31_at_rx(t31_state, (char *) fast_buf, 36);
            if (--fast_blocks == 0)
                fast_send = FALSE;
        }
        if (countdown)
        {
            if (answered)
            {
                countdown = 0;
                t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED);
            }
            else if (--countdown == 0)
            {
                t31_call_event(t31_state, AT_CALL_EVENT_ALERTING);
                countdown = 250;
            }
        }
        while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core = t31_get_t38_core_state(t31_state);
            t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
        }
        while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core = t38_terminal_get_t38_core_state(t38_state);
            t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
    }
    t38_terminal_release(t38_state);
    return 0;
}
Beispiel #2
0
int main(int argc, char *argv[])
{
    int16_t silence[SAMPLES_PER_CHUNK];
    int16_t t30_amp_a[SAMPLES_PER_CHUNK];
    int16_t t38_amp_a[SAMPLES_PER_CHUNK];
    int16_t t38_amp_b[SAMPLES_PER_CHUNK];
    int16_t t30_amp_b[SAMPLES_PER_CHUNK];
    int16_t out_amp[SAMPLES_PER_CHUNK*4];
    int t30_len_a;
    int t38_len_a;
    int t38_len_b;
    int t30_len_b;
    int log_audio;
    int msg_len;
    uint8_t msg[1024];
    int outframes;
    AFfilesetup filesetup;
    AFfilehandle wave_handle;
    int use_ecm;
    int use_tep;
    int use_transmit_on_idle;
    int t38_version;
    const char *input_file_name;
    int i;
    int seq_no;
    int model_no;
    int speed_pattern_no;
    double tx_when;
    double rx_when;
    int use_gui;
    int opt;

    log_audio = FALSE;
    use_ecm = FALSE;
    t38_version = 1;
    input_file_name = INPUT_FILE_NAME;
    simulate_incrementing_repeats = FALSE;
    model_no = 0;
    speed_pattern_no = 1;
    use_gui = FALSE;
    use_tep = FALSE;
    use_transmit_on_idle = TRUE;
    while ((opt = getopt(argc, argv, "egi:Ilm:s:tv:")) != -1)
    {
        switch (opt)
        {
        case 'e':
            use_ecm = TRUE;
            break;
        case 'g':
            use_gui = TRUE;
            break;
        case 'i':
            input_file_name = optarg;
            break;
        case 'I':
            simulate_incrementing_repeats = TRUE;
            break;
        case 'l':
            log_audio = TRUE;
            break;
        case 'm':
            model_no = optarg[0] - 'A' + 1;
            break;
        case 's':
            speed_pattern_no = atoi(optarg);
            break;
        case 't':
            use_tep = TRUE;
            break;
        case 'v':
            t38_version = atoi(optarg);
            break;
        }
    }

    printf("Using T.38 version %d\n", t38_version);
    if (use_ecm)
        printf("Using ECM\n");

    filesetup = AF_NULL_FILESETUP;
    wave_handle = AF_NULL_FILEHANDLE;
    if (log_audio)
    {
        if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP)
        {
            fprintf(stderr, "    Failed to create file setup\n");
            exit(2);
        }
        afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
        afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
        afInitFileFormat(filesetup, AF_FILE_WAVE);
        afInitChannels(filesetup, AF_DEFAULT_TRACK, 4);
        if ((wave_handle = afOpenFile(OUTPUT_FILE_NAME_WAVE, "w", filesetup)) == AF_NULL_FILEHANDLE)
        {
            fprintf(stderr, "    Cannot create wave file '%s'\n", OUTPUT_FILE_NAME_WAVE);
            exit(2);
        }
    }
    memset(silence, 0, sizeof(silence));
 
    srand48(0x1234567);
    if ((path_a_to_b = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((path_b_to_a = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }

    if (fax_init(&fax_state_a, TRUE) == NULL)
    {
        fprintf(stderr, "Cannot start FAX\n");
        exit(2);
    }
    fax_set_transmit_on_idle(&fax_state_a, use_transmit_on_idle);
    fax_set_tep_mode(&fax_state_a, use_tep);
    //t30_set_supported_modems(&(fax_state_a.t30_state), T30_SUPPORT_V27TER | T30_SUPPORT_V29);
    t30_set_local_ident(&fax_state_a.t30_state, "11111111");
    t30_set_tx_file(&fax_state_a.t30_state, input_file_name, -1, -1);
    t30_set_phase_b_handler(&fax_state_a.t30_state, phase_b_handler, (void *) (intptr_t) 'A');
    t30_set_phase_d_handler(&fax_state_a.t30_state, phase_d_handler, (void *) (intptr_t) 'A');
    t30_set_phase_e_handler(&fax_state_a.t30_state, phase_e_handler, (void *) (intptr_t) 'A');
    t30_set_local_nsf(&fax_state_a.t30_state, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_ecm_capability(&fax_state_a.t30_state, use_ecm);
    if (use_ecm)
        t30_set_supported_compressions(&fax_state_a.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
    span_log_set_level(&fax_state_a.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&fax_state_a.logging, "FAX-A ");
    span_log_set_level(&fax_state_a.t30_state.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&fax_state_a.t30_state.logging, "FAX-A ");
    memset(t30_amp_a, 0, sizeof(t30_amp_a));

    if (t38_gateway_init(&t38_state_a, tx_packet_handler_a, &t38_state_b) == NULL)
    {
        fprintf(stderr, "Cannot start the T.38 channel\n");
        exit(2);
    }
    t38_gateway_set_transmit_on_idle(&t38_state_a, use_transmit_on_idle);
    //t38_gateway_set_supported_modems(&t38_state_a, T30_SUPPORT_V27TER | T30_SUPPORT_V29);
    //t38_gateway_set_nsx_suppression(&t38_state_a, FALSE);
    t38_set_t38_version(&t38_state_a.t38, t38_version);
    t38_gateway_set_ecm_capability(&t38_state_a, use_ecm);
    span_log_set_level(&t38_state_a.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&t38_state_a.logging, "T.38-A");
    span_log_set_level(&t38_state_a.t38.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&t38_state_a.t38.logging, "T.38-A");
    memset(t38_amp_a, 0, sizeof(t38_amp_a));

    if (t38_gateway_init(&t38_state_b, tx_packet_handler_b, &t38_state_a) == NULL)
    {
        fprintf(stderr, "Cannot start the T.38 channel\n");
        exit(2);
    }
    t38_gateway_set_transmit_on_idle(&t38_state_b, use_transmit_on_idle);
    //t38_gateway_set_supported_modems(&t38_state_b, T30_SUPPORT_V27TER | T30_SUPPORT_V29);
    //t38_gateway_set_nsx_suppression(&t38_state_b, FALSE);
    t38_set_t38_version(&t38_state_b.t38, t38_version);
    t38_gateway_set_ecm_capability(&t38_state_b, use_ecm);
    span_log_set_level(&t38_state_b.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&t38_state_b.logging, "T.38-B");
    span_log_set_level(&t38_state_b.t38.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&t38_state_b.t38.logging, "T.38-B");
    memset(t38_amp_b, 0, sizeof(t38_amp_b));

    if (fax_init(&fax_state_b, FALSE) == NULL)
    {
        fprintf(stderr, "Cannot start FAX\n");
        exit(2);
    }
    fax_set_transmit_on_idle(&fax_state_b, use_transmit_on_idle);
    fax_set_tep_mode(&fax_state_b, use_tep);
    t30_set_local_ident(&fax_state_b.t30_state, "22222222");
    t30_set_rx_file(&fax_state_b.t30_state, OUTPUT_FILE_NAME, -1);
    t30_set_phase_b_handler(&fax_state_b.t30_state, phase_b_handler, (void *) (intptr_t) 'B');
    t30_set_phase_d_handler(&fax_state_b.t30_state, phase_d_handler, (void *) (intptr_t) 'B');
    t30_set_phase_e_handler(&fax_state_b.t30_state, phase_e_handler, (void *) (intptr_t) 'B');
    t30_set_local_nsf(&fax_state_b.t30_state, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_ecm_capability(&fax_state_b.t30_state, use_ecm);
    if (use_ecm)
        t30_set_supported_compressions(&fax_state_b.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
    span_log_set_level(&fax_state_b.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&fax_state_b.logging, "FAX-B ");
    span_log_set_level(&fax_state_b.t30_state.logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(&fax_state_b.t30_state.logging, "FAX-B ");
    memset(t30_amp_b, 0, sizeof(t30_amp_b));

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    for (;;)
    {
        span_log_bump_samples(&fax_state_a.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&fax_state_a.t30_state.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&t38_state_a.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&t38_state_a.t38.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&t38_state_b.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&t38_state_b.t38.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&fax_state_b.logging, SAMPLES_PER_CHUNK);
        span_log_bump_samples(&fax_state_b.t30_state.logging, SAMPLES_PER_CHUNK);
        memset(out_amp, 0, sizeof(out_amp));

        t30_len_a = fax_tx(&fax_state_a, t30_amp_a, SAMPLES_PER_CHUNK);
        if (!use_transmit_on_idle)
        {
            /* The receive side always expects a full block of samples, but the
               transmit side may not be sending any when it doesn't need to. We
               may need to pad with some silence. */
            if (t30_len_a < SAMPLES_PER_CHUNK)
            {
                memset(t30_amp_a + t30_len_a, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len_a));
                t30_len_a = SAMPLES_PER_CHUNK;
            }
        }
        if (log_audio)
        {
            for (i = 0;  i < t30_len_a;  i++)
                out_amp[i*4] = t30_amp_a[i];
        }
        if (t38_gateway_rx(&t38_state_a, t30_amp_a, t30_len_a))
            break;

        t38_len_a = t38_gateway_tx(&t38_state_a, t38_amp_a, SAMPLES_PER_CHUNK);
        if (!use_transmit_on_idle)
        {
            if (t38_len_a < SAMPLES_PER_CHUNK)
            {
                memset(t38_amp_a + t38_len_a, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len_a));
                t38_len_a = SAMPLES_PER_CHUNK;
            }
        }
        if (log_audio)
        {
            for (i = 0;  i < t38_len_a;  i++)
                out_amp[i*4 + 1] = t38_amp_a[i];
        }
        if (fax_rx(&fax_state_a, t38_amp_a, SAMPLES_PER_CHUNK))
            break;

        t30_len_b = fax_tx(&fax_state_b, t30_amp_b, SAMPLES_PER_CHUNK);
        if (!use_transmit_on_idle)
        {
            /* The receive side always expects a full block of samples, but the
               transmit side may not be sending any when it doesn't need to. We
               may need to pad with some silence. */
            if (t30_len_b < SAMPLES_PER_CHUNK)
            {
                memset(t30_amp_b + t30_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len_b));
                t30_len_b = SAMPLES_PER_CHUNK;
            }
        }
        if (log_audio)
        {
            for (i = 0;  i < t30_len_b;  i++)
                out_amp[i*4 + 3] = t30_amp_b[i];
        }
        if (t38_gateway_rx(&t38_state_b, t30_amp_b, t30_len_b))
            break;

        t38_len_b = t38_gateway_tx(&t38_state_b, t38_amp_b, SAMPLES_PER_CHUNK);
        if (!use_transmit_on_idle)
        {
            if (t38_len_b < SAMPLES_PER_CHUNK)
            {
                memset(t38_amp_b + t38_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len_b));
                t38_len_b = SAMPLES_PER_CHUNK;
            }
        }
        if (log_audio)
        {
            for (i = 0;  i < t38_len_b;  i++)
                out_amp[i*4 + 2] = t38_amp_b[i];
        }
        if (fax_rx(&fax_state_b, t38_amp_b, SAMPLES_PER_CHUNK))
            break;

        when += 0.02;

        while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core_rx_ifp_packet(&t38_state_b.t38, msg, msg_len, seq_no);
        }
        while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core_rx_ifp_packet(&t38_state_a.t38, msg, msg_len, seq_no);
        }
        if (log_audio)
        {
            outframes = afWriteFrames(wave_handle, AF_DEFAULT_TRACK, out_amp, SAMPLES_PER_CHUNK);
            if (outframes != SAMPLES_PER_CHUNK)
                break;
        }

        if (done[0]  &&  done[1])
            break;
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
    }
    if (log_audio)
    {
        if (afCloseFile(wave_handle) != 0)
        {
            fprintf(stderr, "    Cannot close wave file '%s'\n", OUTPUT_FILE_NAME_WAVE);
            exit(2);
        }
        afFreeFileSetup(filesetup);
    }
    if (!succeeded[0]  ||  !succeeded[1])
    {
        printf("Tests failed\n");
        exit(2);
    }
    printf("Tests passed\n");
    return  0;
}
static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int test_sending, int g1050_model_no, int g1050_speed_pattern_no)
{
    t38_terminal_state_t *t38_state;
    fax_state_t *fax_state;
    uint8_t msg[1024];
    char buf[1024];
    int len;
    int msg_len;
    int t30_len;
    int t31_len;
    int t38_version;
    int without_pacing;
    int use_tep;
    int seq_no;
    double tx_when;
    double rx_when;
    t30_state_t *t30;
    t38_core_state_t *t38_core;
    logging_state_t *logging;
    int k;
    int outframes;
    int ret;
    int16_t t30_amp[SAMPLES_PER_CHUNK];
    int16_t t31_amp[SAMPLES_PER_CHUNK];
    int16_t silence[SAMPLES_PER_CHUNK];
    int16_t out_amp[2*SAMPLES_PER_CHUNK];
    SNDFILE *wave_handle;
    SNDFILE *in_handle;
    at_state_t *at_state;
#if defined(WIN32)
	DWORD read_bytes;
	OVERLAPPED o;
#endif

    /* Test the T.31 modem against the full FAX machine in spandsp */
    
    /* Set up the test environment */
    t38_version = 1;
    without_pacing = FALSE;
    use_tep = FALSE;

    wave_handle = NULL;
    if (log_audio)
    {
        if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
            exit(2);
        }
    }

    in_handle = NULL;
    if (decode_test_file)
    {
        if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", decode_test_file);
            exit(2);
        }
    }

    srand48(0x1234567);
    if ((path_a_to_b = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((path_b_to_a = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }

    t38_state = NULL;
    fax_state = NULL;
    if (test_sending)
    {
        if (t38_mode)
        {
            if ((t38_state = t38_terminal_init(NULL, FALSE, t38_tx_packet_handler, t31_state)) == NULL)
            {
                fprintf(stderr, "Cannot start the T.38 channel\n");
                exit(2);
            }
            t30 = t38_terminal_get_t30_state(t38_state);
        }
        else
        {
            fax_state = fax_init(NULL, FALSE);
            t30 = fax_get_t30_state(fax_state);
        }
        t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1);
        countdown = 0;
    }
    else
    {
        if (t38_mode)
        {
            if ((t38_state = t38_terminal_init(NULL, TRUE, t38_tx_packet_handler, t31_state)) == NULL)
            {
                fprintf(stderr, "Cannot start the T.38 channel\n");
                exit(2);
            }
            t30 = t38_terminal_get_t30_state(t38_state);
        }
        else
        {
            fax_state = fax_init(NULL, TRUE);
            t30 = fax_get_t30_state(fax_state);
        }
        t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1);
        countdown = 250;
    }

    t30_set_ecm_capability(t30, use_ecm);

    if (t38_mode)
    {
        t38_core = t38_terminal_get_t38_core_state(t38_state);
        t38_set_t38_version(t38_core, t38_version);
        t38_terminal_set_config(t38_state, without_pacing);
        t38_terminal_set_tep_mode(t38_state, use_tep);
    }

    t30_set_tx_ident(t30, "11111111");
    t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
    //t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) 'A');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) 'A');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) 'A');

    if (t38_mode)
        logging = t38_terminal_get_logging_state(t38_state);
    else
        logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, (t38_mode)  ?  "T.38"  :  "FAX");

    if (t38_mode)
    {
        t38_core = t38_terminal_get_t38_core_state(t38_state);
        logging = t38_core_get_logging_state(t38_core);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "T.38");

        logging = t30_get_logging_state(t30);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "T.38");
    }
    else
    {
        logging = fax_get_logging_state(fax_state);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "FAX");
    }

    memset(silence, 0, sizeof(silence));
    memset(t30_amp, 0, sizeof(t30_amp));

    /* Now set up and run the T.31 modem */
    if ((t31_state = t31_init(NULL, at_tx_handler, &modem[0], t31_call_control, &modem[0], t31_tx_packet_handler, NULL)) == NULL)
    {
        fprintf(stderr, "    Cannot start the T.31 modem\n");
        exit(2);
    }
    at_state = t31_get_at_state(t31_state);

    logging = t31_get_logging_state(t31_state);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.31");

    logging = at_get_logging_state(at_state);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.31");

    if (t38_mode)
    {
        t38_core = t31_get_t38_core_state(t31_state);
        logging = t38_core_get_logging_state(t38_core);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "T.31");

        t31_set_mode(t31_state, TRUE);
        t38_set_t38_version(t38_core, t38_version);
    }

    at_reset_call_info(at_state);
    at_set_call_info(at_state, "DATE", "1231");
    at_set_call_info(at_state, "TIME", "1200");
    at_set_call_info(at_state, "NAME", "Name");
    at_set_call_info(at_state, "NMBR", "123456789");
    at_set_call_info(at_state, "ANID", "987654321");
    at_set_call_info(at_state, "USER", "User");
    at_set_call_info(at_state, "CDID", "234567890");
    at_set_call_info(at_state, "NDID", "345678901");

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif

    while (!done)
    {
        /* Deal with call setup, through the AT interface. */ 
        if (test_sending)
        {
        }
        else
        {
            if (answered == 0)
            {
                if (--countdown == 0)
                {
                    t31_call_event(t31_state, AT_CALL_EVENT_ALERTING);
                    countdown = 250;
                }
            }
            else if (answered == 1)
            {
printf("ZZZ\n");
                answered = 2;
                t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED);
            }
        }

        ret = modem_wait_sock(modem[0].master, 20, MODEM_POLL_READ);
        if ((ret & MODEM_POLL_READ))
        {
#if defined(WIN32)
			o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

			/* Initialize the rest of the OVERLAPPED structure to zero. */
			o.Internal = 0;
			o.InternalHigh = 0;
			o.Offset = 0;
			o.OffsetHigh = 0;
			assert(o.hEvent);
			if (!ReadFile(modem->master, buf, avail, &read_bytes, &o))
				GetOverlappedResult(modem->master, &o, &read_bytes, TRUE);
			CloseHandle (o.hEvent);
			if ((len = read_bytes))
#else
            if ((len = read(modem[0].master, buf, 1024)))
#endif
{
int i;

printf("YYY %d - ", len);
for (i = 0;  i < len;  i++)
    printf(" 0x%02x", buf[i] & 0xFF);
printf("\n");
                t31_at_rx(t31_state, buf, len);
}
        }

        if (answered == 2)
        {
            if (t38_mode)
            {
                while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
                {
#if defined(ENABLE_GUI)
                    if (use_gui)
                        media_monitor_rx(seq_no, tx_when, rx_when);
#endif
                    t38_core = t31_get_t38_core_state(t31_state);
                    t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
                }
                while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
                {
#if defined(ENABLE_GUI)
                    if (use_gui)
                        media_monitor_rx(seq_no, tx_when, rx_when);
#endif
                    t38_core = t38_terminal_get_t38_core_state(t38_state);
                    t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
                }
#if defined(ENABLE_GUI)
                if (use_gui)
                    media_monitor_update_display();
#endif
                /* Bump the G.1050 models along */
                when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

                /* Bump things along on the t38_terminal side */
                span_log_bump_samples(t38_terminal_get_logging_state(t38_state), SAMPLES_PER_CHUNK);
                t38_core = t38_terminal_get_t38_core_state(t38_state);
                span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK);

                t38_terminal_send_timeout(t38_state, SAMPLES_PER_CHUNK);
                t31_t38_send_timeout(t31_state, SAMPLES_PER_CHUNK);
            }
            else
            {
                t30_len = fax_tx(fax_state, t30_amp, SAMPLES_PER_CHUNK);
                /* The receive side always expects a full block of samples, but the
                   transmit side may not be sending any when it doesn't need to. We
                   may need to pad with some silence. */
                if (t30_len < SAMPLES_PER_CHUNK)
                {
                    memset(t30_amp + t30_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len));
                    t30_len = SAMPLES_PER_CHUNK;
                }
                if (log_audio)
                {
                    for (k = 0;  k < t30_len;  k++)
                        out_amp[2*k] = t30_amp[k];
                }
                if (t31_rx(t31_state, t30_amp, t30_len))
                    break;
                t31_len = t31_tx(t31_state, t31_amp, SAMPLES_PER_CHUNK);
                if (t31_len < SAMPLES_PER_CHUNK)
                {
                    memset(t31_amp + t31_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t31_len));
                    t31_len = SAMPLES_PER_CHUNK;
                }
                if (log_audio)
                {
                    for (k = 0;  k < t31_len;  k++)
                        out_amp[2*k + 1] = t31_amp[k];
                }
                if (fax_rx(fax_state, t31_amp, SAMPLES_PER_CHUNK))
                    break;

                if (log_audio)
                {
                    outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
                    if (outframes != SAMPLES_PER_CHUNK)
                        break;
                }

                /* Bump things along on the FAX machine side */
                span_log_bump_samples(fax_get_logging_state(fax_state), SAMPLES_PER_CHUNK);
            }
            /* Bump things along on the FAX machine side */
            span_log_bump_samples(t30_get_logging_state(t30), SAMPLES_PER_CHUNK);

            /* Bump things along on the T.31 modem side */
            t38_core = t31_get_t38_core_state(t31_state);
            span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK);
            span_log_bump_samples(t31_get_logging_state(t31_state), SAMPLES_PER_CHUNK);
            span_log_bump_samples(at_get_logging_state(t31_get_at_state(t31_state)), SAMPLES_PER_CHUNK);
        }
    }

    if (t38_mode)
        t38_terminal_release(t38_state);

    if (decode_test_file)
    {
        if (sf_close_telephony(in_handle))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", decode_test_file);
            exit(2);
        }
    }
    if (log_audio)
    {
        if (sf_close_telephony(wave_handle))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
            exit(2);
        }
    }

    if (!done)
    {
        printf("Tests failed\n");
        return 2;
    }

    return 0;
}
Beispiel #4
0
int main(int argc, char *argv[])
{
    int16_t silence[SAMPLES_PER_CHUNK];
    int16_t t30_amp[2][SAMPLES_PER_CHUNK];
    int16_t t38_amp[2][SAMPLES_PER_CHUNK];
    int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK];
    int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK];
    int16_t out_amp[SAMPLES_PER_CHUNK*4];
    int16_t *fax_rx_buf[2];
    int16_t *fax_tx_buf[2];
    int16_t *t38_gateway_rx_buf[2];
    int16_t *t38_gateway_tx_buf[2];
    int t30_len[2];
    int t38_len[2];
    int hist_ptr;
    int log_audio;
    int msg_len;
    uint8_t msg[1024];
    int outframes;
    SNDFILE *wave_handle;
    SNDFILE *input_wave_handle;
    int use_ecm;
    int use_tep;
    int feedback_audio;
    int use_transmit_on_idle;
    int t38_version;
    const char *input_tiff_file_name;
    const char *decode_file_name;
    int i;
    int j;
    int seq_no;
    int g1050_model_no;
    int g1050_speed_pattern_no;
    int t38_transport;
    double tx_when;
    double rx_when;
    int supported_modems;
    int remove_fill_bits;
    int opt;
    int start_page;
    int end_page;
    int drop_frame;
    int drop_frame_rate;
    float signal_scaling;
    int signal_level;
    int noise_level;
    int code_to_look_up;
    int scan_line_time;
    t38_stats_t t38_stats;
    t30_stats_t t30_stats;
    logging_state_t *logging;
    int expected_pages;
    char *page_header_info;
    char *page_header_tz;
    const char *tag;
    char buf[132 + 1];
#if defined(ENABLE_GUI)
    int use_gui;
#endif

#if defined(ENABLE_GUI)
    use_gui = FALSE;
#endif
    log_audio = FALSE;
    use_ecm = FALSE;
    t38_version = 1;
    input_tiff_file_name = INPUT_TIFF_FILE_NAME;
    t38_simulate_incrementing_repeats = FALSE;
    g1050_model_no = 0;
    g1050_speed_pattern_no = 1;
    remove_fill_bits = FALSE;
    use_tep = FALSE;
    feedback_audio = FALSE;
    use_transmit_on_idle = TRUE;
    supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
    page_header_info = NULL;
    page_header_tz = NULL;
    drop_frame = 0;
    drop_frame_rate = 0;
    start_page = -1;
    end_page = -1;
    signal_level = 0;
    noise_level = -99;
    scan_line_time = 0;
    decode_file_name = NULL;
    code_to_look_up = -1;
    t38_transport = T38_TRANSPORT_UDPTL;
    while ((opt = getopt(argc, argv, "c:d:D:efFgH:i:Ilm:M:n:p:s:tT:u:v:z:")) != -1)
    {
        switch (opt)
        {
        case 'c':
            code_to_look_up = atoi(optarg);
            break;
        case 'd':
            decode_file_name = optarg;
            break;
        case 'D':
            drop_frame_rate =
            drop_frame = atoi(optarg);
            break;
        case 'e':
            use_ecm = TRUE;
            break;
        case 'f':
            feedback_audio = TRUE;
            break;
        case 'F':
            remove_fill_bits = TRUE;
            break;
        case 'g':
#if defined(ENABLE_GUI)
            use_gui = TRUE;
#else
            fprintf(stderr, "Graphical monitoring not available\n");
            exit(2);
#endif
            break;
        case 'H':
            page_header_info = optarg;
            break;
        case 'i':
            input_tiff_file_name = optarg;
            break;
        case 'I':
            t38_simulate_incrementing_repeats = TRUE;
            break;
        case 'l':
            log_audio = TRUE;
            break;
        case 'm':
            supported_modems = atoi(optarg);
            break;
        case 'M':
            g1050_model_no = optarg[0] - 'A' + 1;
            break;
        case 'n':
            noise_level = atoi(optarg);
            break;
        case 'p':
            for (i = 0;  i < 2;  i++)
            {
                switch (optarg[i])
                {
                case 'A':
                    mode[i] = AUDIO_FAX;
                    break;
                case 'G':
                    mode[i] = T38_GATEWAY_FAX;
                    break;
                case 'T':
                    mode[i] = T38_TERMINAL_FAX;
                    break;
                default:
                    fprintf(stderr, "Unknown FAX path element %c\n", optarg[i]);
                    exit(2);
                }
            }
            if ((mode[0] == AUDIO_FAX  &&  mode[1] != AUDIO_FAX)
                ||
                (mode[0] != AUDIO_FAX  &&  mode[1] == AUDIO_FAX))
            {
                fprintf(stderr, "Invalid FAX path %s\n", optarg);
                exit(2);
            }
            break;
        case 's':
            g1050_speed_pattern_no = atoi(optarg);
            break;
#if 0
        case 's':
            signal_level = atoi(optarg);
            break;
#endif
        case 'S':
            scan_line_time = atoi(optarg);
            break;
        case 't':
            use_tep = TRUE;
            break;
        case 'T':
            start_page = 0;
            end_page = atoi(optarg);
            break;
        case 'u':
            if (strcasecmp(optarg, "udptl") == 0)
                t38_transport = T38_TRANSPORT_UDPTL;
            else if (strcasecmp(optarg, "rtp") == 0)
                t38_transport = T38_TRANSPORT_RTP;
            else if (strcasecmp(optarg, "tcp") == 0)
                t38_transport = T38_TRANSPORT_TCP;
            else if (strcasecmp(optarg, "tcp-tpkt") == 0)
                t38_transport = T38_TRANSPORT_TCP_TPKT;
            else
            {
                fprintf(stderr, "Unknown T.38 transport mode\n");
                exit(2);
            }
            break;
        case 'v':
            t38_version = atoi(optarg);
            break;
        case 'z':
            page_header_tz = optarg;
            break;
        default:
            //usage();
            exit(2);
            break;
        }
    }

    if (code_to_look_up >= 0)
    {
        printf("Result code %d is %s\n", code_to_look_up, t30_completion_code_to_str(code_to_look_up));
        exit(0);
    }

    printf("Using T.38 version %d\n", t38_version);
    if (use_ecm)
        printf("Using ECM\n");

    wave_handle = NULL;
    if (log_audio)
    {
        if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 4)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
            exit(2);
        }
    }
    memset(silence, 0, sizeof(silence));
 
    srand48(0x1234567);
    /* Set up the nodes */
    input_wave_handle = NULL;
    if (mode[0] == T38_TERMINAL_FAX)
    {
    }
    else
    {
        if (decode_file_name)
        {
            if ((input_wave_handle = sf_open_telephony_read(decode_file_name, 1)) == NULL)
            {
                fprintf(stderr, "    Cannot open audio file '%s'\n", decode_file_name);
                exit(2);
            }
        }
    }

    for (i = 0;  i < 2;  i++)
    {
        tag = (i == 0)  ?  "A"  :  "B";

        memset(&expected_rx_info[i], 0, sizeof(expected_rx_info[i]));
        if (mode[i] == T38_TERMINAL_FAX)
        {
            if ((t38_state[i] = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
            {
                fprintf(stderr, "Cannot start the T.38 terminal instance\n");
                exit(2);
            }
            t30_state[i] = t38_terminal_get_t30_state(t38_state[i]);
            t38_core_state[i] = t38_terminal_get_t38_core_state(t38_state[i]);

            logging = t38_terminal_get_logging_state(t38_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = t38_core_get_logging_state(t38_core_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = t30_get_logging_state(t30_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);
        }
        else
        {
            if ((fax_state[i] = fax_init(NULL, (i == 0))) == NULL)
            {
                fprintf(stderr, "Cannot start FAX instance\n");
                exit(2);
            }
            t30_state[i] = fax_get_t30_state(fax_state[i]);

            logging = fax_get_logging_state(fax_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = fax_modems_get_logging_state(&fax_state[i]->modems);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = t30_get_logging_state(t30_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            if (mode[i] == T38_GATEWAY_FAX)
            {
                if ((t38_gateway_state[i] = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
                {
                    fprintf(stderr, "Cannot start the T.38 gateway instancel\n");
                    exit(2);
                }
                t38_core_state[i] = t38_gateway_get_t38_core_state(t38_gateway_state[i]);

                logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
                span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
                span_log_set_tag(logging, tag);

                logging = fax_modems_get_logging_state(&t38_gateway_state[i]->audio.modems);
                span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
                span_log_set_tag(logging, tag);

                logging = t38_core_get_logging_state(t38_core_state[i]);
                span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
                span_log_set_tag(logging, tag);

                fax_rx_buf[i] = t38_amp[i];
                fax_tx_buf[i] = t30_amp[i];
                t38_gateway_rx_buf[i] = t30_amp[i];
                t38_gateway_tx_buf[i] = t38_amp[i];
            }
            else
            {
                fax_rx_buf[i] = t30_amp[i];
                fax_tx_buf[i] = t30_amp[i ^ 1];
                t38_gateway_rx_buf[i] = NULL;
                t38_gateway_tx_buf[i] = NULL;
            }
            awgn_state[i] = NULL;
            signal_scaling = 1.0f;
            if (noise_level > -99)
            {
                awgn_state[i] = awgn_init_dbm0(NULL, 1234567, noise_level);
                signal_scaling = powf(10.0f, signal_level/20.0f);
                printf("Signal scaling %f\n", signal_scaling);
            }
        }
        set_t30_callbacks(t30_state[i], i);
    }
    /* Set up the channels */
    for (i = 0;  i < 2;  i++)
    {
        if ((g1050_path[i] = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
        {
            fprintf(stderr, "Failed to start IP network path model\n");
            exit(2);
        }
        memset(audio_buffer[2*i], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
        memset(audio_buffer[2*i + 1], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
        memset(t30_amp[i], 0, sizeof(t30_amp[i]));
        memset(t38_amp[i], 0, sizeof(t38_amp[i]));
    }
    memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
    memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));

    for (i = 0;  i < 2;  i++)
    {
        j = i + 1;
        sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j);
        t30_set_tx_ident(t30_state[i], buf);
        strcpy(expected_rx_info[i ^ 1].ident, buf);
        sprintf(buf, "Sub-address %d", j);
        t30_set_tx_sub_address(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].sub_address, buf);
        sprintf(buf, "Sender ID %d", j);
        t30_set_tx_sender_ident(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].sender_ident, buf);
        sprintf(buf, "Password %d", j);
        t30_set_tx_password(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].password, buf);
        sprintf(buf, "Polled sub-add %d", j);
        t30_set_tx_polled_sub_address(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].polled_sub_address, buf);
        sprintf(buf, "Select poll add %d", j);
        t30_set_tx_selective_polling_address(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].selective_polling_address, buf);
        t30_set_tx_page_header_info(t30_state[i], page_header_info);
        if (page_header_tz)
            t30_set_tx_page_header_tz(t30_state[i], page_header_tz);

        if ((i & 1) == 1)
        {
            t30_set_tx_nsf(t30_state[i], (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
            expected_rx_info[i ^ 1].nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00";
            expected_rx_info[i ^ 1].nsf_len = 12;
        }

        t30_set_supported_modems(t30_state[i], supported_modems);
        t30_set_supported_t30_features(t30_state[i],
                                       T30_SUPPORT_IDENTIFICATION
                                     | T30_SUPPORT_SELECTIVE_POLLING
                                     | T30_SUPPORT_SUB_ADDRESSING);
        t30_set_supported_image_sizes(t30_state[i],
                                      T30_SUPPORT_US_LETTER_LENGTH
                                    | T30_SUPPORT_US_LEGAL_LENGTH
                                    | T30_SUPPORT_UNLIMITED_LENGTH
                                    | T30_SUPPORT_215MM_WIDTH
                                    | T30_SUPPORT_255MM_WIDTH
                                    | T30_SUPPORT_303MM_WIDTH);
        t30_set_supported_resolutions(t30_state[i],
                                      T30_SUPPORT_STANDARD_RESOLUTION
                                    | T30_SUPPORT_FINE_RESOLUTION
                                    | T30_SUPPORT_SUPERFINE_RESOLUTION
                                    | T30_SUPPORT_R8_RESOLUTION
                                    | T30_SUPPORT_R16_RESOLUTION
                                    | T30_SUPPORT_300_300_RESOLUTION
                                    | T30_SUPPORT_400_400_RESOLUTION
                                    | T30_SUPPORT_600_600_RESOLUTION
                                    | T30_SUPPORT_1200_1200_RESOLUTION
                                    | T30_SUPPORT_300_600_RESOLUTION
                                    | T30_SUPPORT_400_800_RESOLUTION
                                    | T30_SUPPORT_600_1200_RESOLUTION);
        t30_set_ecm_capability(t30_state[i], use_ecm);
        if (use_ecm)
        {
            t30_set_supported_compressions(t30_state[i],
                                           T30_SUPPORT_T4_1D_COMPRESSION
                                         | T30_SUPPORT_T4_2D_COMPRESSION
                                         | T30_SUPPORT_T6_COMPRESSION
                                         | T30_SUPPORT_T81_COMPRESSION
                                         | T30_SUPPORT_T85_COMPRESSION
                                         | T30_SUPPORT_T85_L0_COMPRESSION);
        }
        else
        {
            t30_set_supported_compressions(t30_state[i],
                                           T30_SUPPORT_T4_1D_COMPRESSION
                                         | T30_SUPPORT_T4_2D_COMPRESSION);
        }
        t30_set_minimum_scan_line_time(t30_state[i], scan_line_time);

        if (mode[i] == T38_GATEWAY_FAX)
        {
            t38_gateway_set_transmit_on_idle(t38_gateway_state[i], use_transmit_on_idle);
            t38_gateway_set_supported_modems(t38_gateway_state[i], supported_modems);
            //t38_gateway_set_nsx_suppression(t38_state[i], NULL, 0, NULL, 0);
            t38_gateway_set_fill_bit_removal(t38_gateway_state[i], remove_fill_bits);
            t38_gateway_set_real_time_frame_handler(t38_gateway_state[i], real_time_gateway_frame_handler, (void *) (intptr_t) i);
            t38_gateway_set_ecm_capability(t38_gateway_state[i], use_ecm);
        }
        if (mode[i] != AUDIO_FAX)
        {
            t38_set_t38_version(t38_core_state[i], t38_version);
        }

        if (mode[i] == T38_TERMINAL_FAX)
        {
            //t30_set_iaf_mode(t30_state[i], T30_IAF_MODE_NO_FILL_BITS);
            switch (t38_transport)
            {
            case T38_TRANSPORT_UDPTL:
            case T38_TRANSPORT_RTP:
                t38_terminal_set_fill_bit_removal(t38_state[i], remove_fill_bits);
                t38_terminal_set_tep_mode(t38_state[i], use_tep);
                break;
            case T38_TRANSPORT_TCP:
            case T38_TRANSPORT_TCP_TPKT:
                t38_terminal_set_fill_bit_removal(t38_state[i], TRUE);
                t38_terminal_set_config(t38_state[i], T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS);
                t38_terminal_set_tep_mode(t38_state[i], FALSE);
                break;
            }
        }
        else
        {
            fax_set_transmit_on_idle(fax_state[i], use_transmit_on_idle);
            fax_set_tep_mode(fax_state[i], use_tep);
        }
    }

    t30_set_tx_file(t30_state[0], input_tiff_file_name, start_page, end_page);
    t30_set_rx_file(t30_state[1], OUTPUT_TIFF_FILE_NAME, -1);

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    hist_ptr = 0;
    for (;;)
    {
        memset(out_amp, 0, sizeof(out_amp));

        for (i = 0;  i < 2;  i++)
        {
            /* Update T.30 timing */
            logging = t30_get_logging_state(t30_state[i]);
            span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

            if (mode[i] == T38_TERMINAL_FAX)
            {
                /* Update T.38 termination timing */
                logging = t38_terminal_get_logging_state(t38_state[i]);
                span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
                logging = t38_core_get_logging_state(t38_core_state[i]);
                span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

                completed[i] = t38_terminal_send_timeout(t38_state[i], SAMPLES_PER_CHUNK);
            }
            else
            {
                /* Update audio FAX timing */
                logging = fax_get_logging_state(fax_state[i]);
                span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

                fax_rx(fax_state[i], fax_rx_buf[i], SAMPLES_PER_CHUNK);
                if (!t30_call_active(t30_state[i]))
                {
                    completed[i] = TRUE;
                    continue;
                }

                if (i == 0  &&  input_wave_handle)
                {
                    t30_len[i] = sf_readf_short(input_wave_handle, fax_tx_buf[i], SAMPLES_PER_CHUNK);
                    if (t30_len[i] == 0)
                        break;
                }
                else
                {
                    t30_len[i] = fax_tx(fax_state[i], fax_tx_buf[i], SAMPLES_PER_CHUNK);
                    if (!use_transmit_on_idle)
                    {
                        /* The receive side always expects a full block of samples, but the
                           transmit side may not be sending any when it doesn't need to. We
                           may need to pad with some silence. */
                        if (t30_len[i] < SAMPLES_PER_CHUNK)
                        {
                            memset(t30_amp[i] + t30_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len[i]));
                            t30_len[i] = SAMPLES_PER_CHUNK;
                        }
                    }
                    if (awgn_state[i])
                    {
                        for (j = 0;  j < t30_len[i];  j++)
                            fax_tx_buf[i][j] = ((int16_t) (fax_tx_buf[i][j]*signal_scaling)) + awgn(awgn_state[i]);
                    }
                }
                if (log_audio)
                {
                    for (j = 0;  j < t30_len[i];  j++)
                        out_amp[4*j + 2*i] = t30_amp[i][j];
                }
                if (feedback_audio)
                {
                    for (j = 0;  j < t30_len[i];  j++)
                        t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
                    memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
                }

                if (mode[i] == T38_GATEWAY_FAX)
                {
                    /* Update T.38 gateway timing */
                    logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
                    span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
                    logging = t38_core_get_logging_state(t38_core_state[i]);
                    span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

                    if (drop_frame_rate  &&  --drop_frame == 0)
                    {
                        drop_frame = drop_frame_rate;
                        if (t38_gateway_rx_fillin(t38_gateway_state[i], SAMPLES_PER_CHUNK))
                            break;
                    }
                    else
                    {
                        if (t38_gateway_rx(t38_gateway_state[i], t38_gateway_rx_buf[i], SAMPLES_PER_CHUNK))
                            break;
                    }

                    t38_len[i] = t38_gateway_tx(t38_gateway_state[i], t38_gateway_tx_buf[i], SAMPLES_PER_CHUNK);
                    if (!use_transmit_on_idle)
                    {
                        if (t38_len[i] < SAMPLES_PER_CHUNK)
                        {
                            memset(t38_amp[i] + t38_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len[i]));
                            t38_len[i] = SAMPLES_PER_CHUNK;
                        }
                    }
                    if (feedback_audio)
                    {
                        for (j = 0;  j < t30_len[i];  j++)
                            t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
                        memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
                    }

                    if (log_audio)
                    {
                        for (j = 0;  j < t38_len[i];  j++)
                            out_amp[4*j + 2*i + 1] = t38_amp[i][j];
                    }
                }
            }
            if (mode[i] != AUDIO_FAX)
            {
                while ((msg_len = g1050_get(g1050_path[i], msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
                {
#if defined(ENABLE_GUI)
                    if (use_gui)
                        media_monitor_rx(seq_no, tx_when, rx_when);
#endif
                   t38_core_rx_ifp_packet(t38_core_state[i ^ 1], msg, msg_len, seq_no);
                }
            }
        }
        if (log_audio)
        {
            outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
            if (outframes != SAMPLES_PER_CHUNK)
                break;
        }

        when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

        if (completed[0]  &&  completed[1])
            break;
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
        if (++hist_ptr > 3)
            hist_ptr = 0;
    }
Beispiel #5
0
static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, int g1050_model_no, int g1050_speed_pattern_no)
{
    t38_terminal_state_t *t38_state;
    fax_state_t *fax_state;
    int fast_send;
    int fast_send_tcf;
    int fast_blocks;
    int msg_len;
    int t30_len;
    int t31_len;
    int t38_version;
    int without_pacing;
    int use_tep;
    int seq_no;
    int i;
    int k;
    int outframes;
    uint8_t fast_buf[1000];
    uint8_t msg[1024];
    double tx_when;
    double rx_when;
    t30_state_t *t30;
    t38_core_state_t *t38_core;
    logging_state_t *logging;
    int16_t t30_amp[SAMPLES_PER_CHUNK];
    int16_t t31_amp[SAMPLES_PER_CHUNK];
    int16_t silence[SAMPLES_PER_CHUNK];
    int16_t out_amp[2*SAMPLES_PER_CHUNK];
    SNDFILE *wave_handle;
    SNDFILE *in_handle;

    /* Test the T.31 modem against the full FAX machine in spandsp */

    /* Set up the test environment */
    t38_version = 1;
    without_pacing = false;
    use_tep = false;

    wave_handle = NULL;
    if (log_audio)
    {
        if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
            exit(2);
        }
    }

    in_handle = NULL;
    if (decode_test_file)
    {
        if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", decode_test_file);
            exit(2);
        }
    }

    srand48(0x1234567);
    if ((path_a_to_b = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((path_b_to_a = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }

    t38_state = NULL;
    fax_state = NULL;
    if (test_sending)
    {
        if (t38_mode)
        {
            if ((t38_state = t38_terminal_init(NULL, false, t38_tx_packet_handler, t31_state)) == NULL)
            {
                fprintf(stderr, "Cannot start the T.38 channel\n");
                exit(2);
            }
            t30 = t38_terminal_get_t30_state(t38_state);
        }
        else
        {
            fax_state = fax_init(NULL, false);
            t30 = fax_get_t30_state(fax_state);
        }
        t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1);
        fax_test_seq = fax_send_test_seq;
        countdown = 0;
    }
    else
    {
        if (t38_mode)
        {
            if ((t38_state = t38_terminal_init(NULL, true, t38_tx_packet_handler, t31_state)) == NULL)
            {
                fprintf(stderr, "Cannot start the T.38 channel\n");
                exit(2);
            }
            t30 = t38_terminal_get_t30_state(t38_state);
        }
        else
        {
            fax_state = fax_init(NULL, true);
            t30 = fax_get_t30_state(fax_state);
        }
        t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1);
        fax_test_seq = fax_receive_test_seq;
        countdown = 250;
    }

    if (t38_mode)
    {
        t38_core = t38_terminal_get_t38_core_state(t38_state);
        t38_set_t38_version(t38_core, t38_version);
        t38_terminal_set_config(t38_state, without_pacing);
        t38_terminal_set_tep_mode(t38_state, use_tep);
    }

    t30_set_tx_ident(t30, "11111111");
    t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
    //t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) 'A');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) 'A');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) 'A');

    if (t38_mode)
        logging = t38_terminal_get_logging_state(t38_state);
    else
        logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, (t38_mode)  ?  "T.38"  :  "FAX");

    if (t38_mode)
    {
        t38_core = t38_terminal_get_t38_core_state(t38_state);
        span_log_set_level(&t38_core->logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(&t38_core->logging, "T.38");

        logging = t30_get_logging_state(t30);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "T.38");
    }
    else
    {
        logging = fax_get_logging_state(fax_state);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "FAX");
    }

    memset(silence, 0, sizeof(silence));
    memset(t30_amp, 0, sizeof(t30_amp));

    /* Now set up and run the T.31 modem */
    if ((t31_state = t31_init(NULL, at_tx_handler, NULL, modem_call_control, NULL, t31_tx_packet_handler, NULL)) == NULL)
    {
        fprintf(stderr, "    Cannot start the T.31 modem\n");
        exit(2);
    }
    logging = t31_get_logging_state(t31_state);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.31");

    logging = at_get_logging_state(t31_get_at_state(t31_state));
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.31");

    if (t38_mode)
    {
        t38_core = t31_get_t38_core_state(t31_state);
        logging = t38_core_get_logging_state(t38_core);
        span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
        span_log_set_tag(logging, "T.31");

        t31_set_mode(t31_state, true);
        t38_set_t38_version(t38_core, t38_version);
    }

    fast_send = false;
    fast_send_tcf = true;
    fast_blocks = 0;
    kick = true;
#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    while (!done)
    {
        if (countdown)
        {
            /* Deal with call setup, through the AT interface. */
            if (answered)
            {
                countdown = 0;
                t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED);
            }
            else if (--countdown == 0)
            {
                t31_call_event(t31_state, AT_CALL_EVENT_ALERTING);
                countdown = 250;
            }
        }

        if (kick)
        {
            /* Work through the script */
            kick = false;
            if (fax_test_seq[test_seq_ptr].command > (const char *) 2)
            {
                if (fax_test_seq[test_seq_ptr].command[0])
                {
                    printf("%s\n", fax_test_seq[test_seq_ptr].command);
                    t31_at_rx(t31_state, fax_test_seq[test_seq_ptr].command, fax_test_seq[test_seq_ptr].len_command);
                }
            }
            else
            {
                if (fax_test_seq[test_seq_ptr].command == (const char *) 2)
                {
                    printf("Fast send TCF\n");
                    fast_send = true;
                    fast_send_tcf = true;
                    fast_blocks = 100;
                }
                else
                {
                    printf("Fast send image\n");
                    fast_send = true;
                    fast_send_tcf = false;
                    fast_blocks = 100;
                }
            }
        }
        if (fast_send)
        {
            /* Send fast modem data */
            if (fast_send_tcf)
            {
                /* If we are sending TCF, its simply zeros */
                memset(fast_buf, 0, 36);
                if (fast_blocks == 1)
                {
                    /* Tell the modem this is the end of the TCF data */
                    fast_buf[34] = DLE;
                    fast_buf[35] = ETX;
                }
            }
            else
            {
                /* If we are sending image data, we need to make it look like genuine image data,
                   with proper EOL and RTC markers. */
                if (fast_blocks > 1)
                {
                    /* Create a chunk of white page, 1728 pixels wide. */
                    for (i = 0;  i < 36;  i += 4)
                    {
                        fast_buf[i] = 0x00;
                        fast_buf[i + 1] = 0x80;
                        fast_buf[i + 2] = 0xB2;
                        fast_buf[i + 3] = 0x01;
                    }
                }
                else
                {
                    /* Create the end of page condition. */
                    for (i = 0;  i < 36;  i += 3)
                    {
                        fast_buf[i] = 0x00;
                        fast_buf[i + 1] = 0x08;
                        fast_buf[i + 2] = 0x80;
                    }
                    /* Tell the modem this is the end of the image data. */
                    fast_buf[34] = DLE;
                    fast_buf[35] = ETX;
                }
            }
            t31_at_rx(t31_state, (char *) fast_buf, 36);
            if (--fast_blocks == 0)
                fast_send = false;
        }

        if (t38_mode)
        {
            while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
            {
#if defined(ENABLE_GUI)
                if (use_gui)
                    media_monitor_rx(seq_no, tx_when, rx_when);
#endif
                t38_core = t31_get_t38_core_state(t31_state);
                t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
            }
            while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
            {
#if defined(ENABLE_GUI)
                if (use_gui)
                    media_monitor_rx(seq_no, tx_when, rx_when);
#endif
                t38_core = t38_terminal_get_t38_core_state(t38_state);
                t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
            }
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_update_display();
#endif
            /* Bump the G.1050 models along */
            when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

            /* Bump things along on the t38_terminal side */
            span_log_bump_samples(t38_terminal_get_logging_state(t38_state), SAMPLES_PER_CHUNK);
            t38_core = t38_terminal_get_t38_core_state(t38_state);
            span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK);

            t38_terminal_send_timeout(t38_state, SAMPLES_PER_CHUNK);
            t31_t38_send_timeout(t31_state, SAMPLES_PER_CHUNK);
        }
        else
        {
            t30_len = fax_tx(fax_state, t30_amp, SAMPLES_PER_CHUNK);
            /* The receive side always expects a full block of samples, but the
               transmit side may not be sending any when it doesn't need to. We
               may need to pad with some silence. */
            if (t30_len < SAMPLES_PER_CHUNK)
            {
                memset(t30_amp + t30_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len));
                t30_len = SAMPLES_PER_CHUNK;
            }
            if (log_audio)
            {
                for (k = 0;  k < t30_len;  k++)
                    out_amp[2*k] = t30_amp[k];
            }
            if (t31_rx(t31_state, t30_amp, t30_len))
                break;
            t31_len = t31_tx(t31_state, t31_amp, SAMPLES_PER_CHUNK);
            if (t31_len < SAMPLES_PER_CHUNK)
            {
                memset(t31_amp + t31_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t31_len));
                t31_len = SAMPLES_PER_CHUNK;
            }
            if (log_audio)
            {
                for (k = 0;  k < t31_len;  k++)
                    out_amp[2*k + 1] = t31_amp[k];
            }
            if (fax_rx(fax_state, t31_amp, SAMPLES_PER_CHUNK))
                break;

            if (log_audio)
            {
                outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
                if (outframes != SAMPLES_PER_CHUNK)
                    break;
            }

            /* Bump things along on the FAX machine side */
            span_log_bump_samples(fax_get_logging_state(fax_state), SAMPLES_PER_CHUNK);
        }

        /* Bump things along on the FAX machine side */
        span_log_bump_samples(t30_get_logging_state(t30), SAMPLES_PER_CHUNK);

        /* Bump things along on the T.31 modem side */
        t38_core = t31_get_t38_core_state(t31_state);
        span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK);
        span_log_bump_samples(t31_get_logging_state(t31_state), SAMPLES_PER_CHUNK);
        span_log_bump_samples(at_get_logging_state(t31_get_at_state(t31_state)), SAMPLES_PER_CHUNK);
    }

    if (t38_mode)
        t38_terminal_release(t38_state);

    if (decode_test_file)
    {
        if (sf_close_telephony(in_handle))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", decode_test_file);
            exit(2);
        }
    }
    if (log_audio)
    {
        if (sf_close_telephony(wave_handle))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
            exit(2);
        }
    }

    if (!done  ||  !sequence_terminated)
    {
        printf("Tests failed\n");
        return -1;
    }

    return 0;
}
int main(int argc, char *argv[])
{
    rfc2198_sim_state_t *s;
    double *packet_arrival_times;
    int packets_per_sec;
    int num_packets;
    int model_no;
    int speed_pattern_no;
    int use_gui;
    int simulation_time;
    int i;
    int len;
    uint8_t put_pkt[256];
    uint8_t get_pkt[256];
    int put_pkt_len;
    int get_pkt_len;
    int get_seq_no;
    double get_departure_time;
    double get_arrival_time;
    int packets_put;
    int packets_really_put;
    int packets_got;
    int oos_packets_got;
    int missing_packets_got;
    int highest_seq_no_got;
    int opt;
    FILE *out_file;

    model_no = MODEL_NO;
    speed_pattern_no = SPEED_PATTERN_NO;
    simulation_time = SIMULATION_TIME;
    use_gui = FALSE;
    while ((opt = getopt(argc, argv, "gm:s:t:")) != -1)
    {
        switch (opt)
        {
        case 'g':
#if defined(ENABLE_GUI)
            use_gui = TRUE;
#else
            fprintf(stderr, "Graphical monitoring not available\n");
            exit(2);
#endif
            break;
        case 'm':
            model_no = optarg[0] - 'A' + 1;
            if (model_no < 0  ||  model_no > 8)
            {
                fprintf(stderr, "Bad model ID '%s'\n", optarg);
                exit(2);
            }
            break;
        case 's':
            speed_pattern_no = atoi(optarg);
            if (speed_pattern_no < 1  ||  speed_pattern_no > 133)
            {
                fprintf(stderr, "Bad link speed pattern %s\n", optarg);
                exit(2);
            }
            break;
        case 't':
            simulation_time = atoi(optarg);
            break;
        default:
            //usage();
            exit(2);
            break;
        }
    }
    argc -= optind;
    argv += optind;

    if ((out_file = fopen("rfc2198_sim_tests.txt", "w")) == NULL)
    {
        fprintf(stderr, "Can't open %s\n", "rfc2198_sim_tests.txt");
        return 2;
    }
    packets_per_sec = 1000/PACKET_INTERVAL;
    num_packets = packets_per_sec*simulation_time;

    if ((packet_arrival_times = calloc(num_packets, sizeof(double))) == NULL)
    {
        fprintf(stderr, "Can't allocate the data buffers\n");
        return 2;
    }
    for (i = 0;  i < num_packets;  i++)
        packet_arrival_times[i] = 0.0;

    /* If we don't initialise this random number generator it gives endless zeros on some systems. */
    /* Use a fixed seed to produce identical results in successive runs of the simulation, for debug purposes. */
    srand48(0x1234567);

    if ((s = rfc2198_sim_init(model_no, speed_pattern_no, PACKET_SIZE, packets_per_sec, 3)) == NULL)
    {
        fprintf(stderr, "Failed to start the G.1050 model\n");
        exit(2);
    }
    //rfc2198_sim_dump_parms(model_no, speed_pattern_no);

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif

    for (i = 0;  i < 256;  i++)
        put_pkt[i] = i;
    put_pkt_len = 256;
    get_pkt_len = -1;
    get_seq_no = -1;
    get_arrival_time = -1;
    packets_put = 0;
    packets_really_put = 0;
    packets_got = 0;
    oos_packets_got = 0;
    missing_packets_got = 0;
    highest_seq_no_got = -1;
    for (i = 0;  i < num_packets;  i++)
    {
        if ((len = rfc2198_sim_put(s, put_pkt, put_pkt_len, i, (double) i*0.001*PACKET_INTERVAL)) > 0)
            packets_really_put++;
        packets_put++;
#if 0        
        if (i == 5)
            rfc2198_sim_queue_dump(s);
#endif
        if (i >= 5)
        {
            do
            {
                get_pkt_len = rfc2198_sim_get(s, get_pkt, 256, (double) i*0.001*PACKET_INTERVAL, &get_seq_no, &get_departure_time, &get_arrival_time);
                if (get_pkt_len >= 0)
                {
#if defined(ENABLE_GUI)
                    if (use_gui)
                        media_monitor_rx(get_seq_no, get_departure_time, get_arrival_time);
#endif
                    packets_got++;
                    if (get_seq_no < highest_seq_no_got)
                        oos_packets_got++;
                    else if (get_seq_no > highest_seq_no_got + 1)
                        missing_packets_got += (get_seq_no - highest_seq_no_got - 1);
                    if (get_seq_no > highest_seq_no_got)
                        highest_seq_no_got = get_seq_no;
                    fprintf(out_file, "%d, %.3f, %.8f\n", get_seq_no, get_seq_no*0.001*PACKET_INTERVAL, get_arrival_time);
                }
            }
            while (get_pkt_len >= 0);
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
    }
    /* Clear out anything remaining in the queue, by jumping forwards in time */
    do
    {
        get_pkt_len = rfc2198_sim_get(s, get_pkt, 256, (double) i*0.001*PACKET_INTERVAL + 5.0, &get_seq_no, &get_departure_time, &get_arrival_time);
        if (get_pkt_len >= 0)
        {
            packets_got++;
            fprintf(out_file, "%d, %.3f, %.8f\n", get_seq_no, get_seq_no*0.001*PACKET_INTERVAL, get_arrival_time);
        }
    }
    while (get_pkt_len >= 0);

    fclose(out_file);

    printf("Put %d packets. Really put %d packets. Got %d packets.\n", packets_put, packets_really_put, packets_got);
    printf("%d OOS packets, %d missing packets\n", oos_packets_got, missing_packets_got - oos_packets_got);
    printf("%d packets queued, %d received\n", packets_really_put, packets_got);
    printf("%.3f%% of packets lost before redundancy\n", 100.0*(packets_put - packets_really_put)/packets_put);
    printf("%.3f%% of packets lost after redundancy\n", 100.0*(packets_put - packets_got)/packets_put);
    return 0;
}
int main(int argc, char *argv[])
{
    int16_t t38_amp_b[SAMPLES_PER_CHUNK];
    int16_t t30_amp_b[SAMPLES_PER_CHUNK];
    int16_t out_amp[2*SAMPLES_PER_CHUNK];
    int t38_len_b;
    int t30_len_b;
    int msg_len;
    uint8_t msg[1024];
    int log_audio;
    int outframes;
    SNDFILE *wave_handle;
    int t38_version;
    int use_ecm;
    int use_tep;
    int feedback_audio;
    int use_transmit_on_idle;
    const char *input_file_name;
    int i;
    int seq_no;
    int g1050_model_no;
    int g1050_speed_pattern_no;
    double tx_when;
    double rx_when;
    int use_gui;
    int supported_modems;
    int opt;
    t30_state_t *t30;
    t38_core_state_t *t38_core;
    logging_state_t *logging;

    log_audio = false;
    t38_version = 1;
    use_ecm = false;
    input_file_name = INPUT_FILE_NAME;
    simulate_incrementing_repeats = false;
    g1050_model_no = 0;
    g1050_speed_pattern_no = 1;
    use_gui = false;
    use_tep = false;
    feedback_audio = false;
    use_transmit_on_idle = true;
    supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
    while ((opt = getopt(argc, argv, "efgi:Ilm:M:s:tv:")) != -1)
    {
        switch (opt)
        {
        case 'e':
            use_ecm = true;
            break;
        case 'f':
            feedback_audio = true;
            break;
        case 'g':
#if defined(ENABLE_GUI)
            use_gui = true;
#else
            fprintf(stderr, "Graphical monitoring not available\n");
            exit(2);
#endif
            break;
        case 'i':
            input_file_name = optarg;
            break;
        case 'I':
            simulate_incrementing_repeats = true;
            break;
        case 'l':
            log_audio = true;
            break;
        case 'm':
            supported_modems = atoi(optarg);
            break;
        case 'M':
            g1050_model_no = optarg[0] - 'A' + 1;
            break;
        case 's':
            g1050_speed_pattern_no = atoi(optarg);
            break;
        case 't':
            use_tep = true;
            break;
        case 'v':
            t38_version = atoi(optarg);
            break;
        default:
            //usage();
            exit(2);
            break;
        }
    }

    printf("Using T.38 version %d\n", t38_version);
    if (use_ecm)
        printf("Using ECM\n");

    wave_handle = NULL;
    if (log_audio)
    {
        if ((wave_handle = sf_open_telephony_write(OUTPUT_FILE_NAME_WAVE, 2)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", OUTPUT_FILE_NAME_WAVE);
            exit(2);
        }
    }

    srand48(0x1234567);
    if ((path_a_to_b = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((path_b_to_a = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }

    if ((t38_state_a = t38_terminal_init(NULL, true, tx_packet_handler_a, &t38_state_b)) == NULL)
    {
        fprintf(stderr, "Cannot start the T.38 channel\n");
        exit(2);
    }
    t30 = t38_terminal_get_t30_state(t38_state_a);
    t38_core = t38_terminal_get_t38_core_state(t38_state_a);
    t38_set_t38_version(t38_core, t38_version);

    logging = t38_terminal_get_logging_state(t38_state_a);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-A");

    logging = t38_core_get_logging_state(t38_core);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-A");

    logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-A");

    t30_set_supported_modems(t30, supported_modems);
    t30_set_tx_ident(t30, "11111111");
    t30_set_tx_file(t30, input_file_name, -1, -1);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'A');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A');
    t30_set_ecm_capability(t30, use_ecm);
    if (use_ecm)
        t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);

    if ((t38_state_b = t38_gateway_init(NULL, tx_packet_handler_b, &t38_state_a)) == NULL)
    {
        fprintf(stderr, "Cannot start the T.38 channel\n");
        exit(2);
    }
    t38_core = t38_gateway_get_t38_core_state(t38_state_b);
    t38_gateway_set_transmit_on_idle(t38_state_b, use_transmit_on_idle);
    t38_set_t38_version(t38_core, t38_version);
    t38_gateway_set_ecm_capability(t38_state_b, use_ecm);

    logging = t38_gateway_get_logging_state(t38_state_b);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-B");

    logging = t38_core_get_logging_state(t38_core);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-B");

    memset(t38_amp_b, 0, sizeof(t38_amp_b));

    if ((fax_state_b = fax_init(NULL, false)) == NULL)
    {
        fprintf(stderr, "Cannot start FAX\n");
        exit(2);
    }
    t30 = fax_get_t30_state(fax_state_b);
    fax_set_transmit_on_idle(fax_state_b, use_transmit_on_idle);
    fax_set_tep_mode(fax_state_b, use_tep);
    t30_set_supported_modems(t30, supported_modems);
    t30_set_tx_ident(t30, "22222222");
    t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'B');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'B');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'B');
    t30_set_ecm_capability(t30, use_ecm);
    if (use_ecm)
        t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);

    logging = fax_get_logging_state(fax_state_b);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "FAX-B ");

    logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "FAX-B ");

    memset(t30_amp_b, 0, sizeof(t30_amp_b));

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    for (;;)
    {
        logging = t38_terminal_get_logging_state(t38_state_a);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t38_core = t38_terminal_get_t38_core_state(t38_state_a);
        logging = t38_core_get_logging_state(t38_core);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t30 = t38_terminal_get_t30_state(t38_state_a);
        logging = t30_get_logging_state(t30);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        logging = t38_gateway_get_logging_state(t38_state_b);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t38_core = t38_gateway_get_t38_core_state(t38_state_b);
        logging = t38_core_get_logging_state(t38_core);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        logging = fax_get_logging_state(fax_state_b);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t30 = fax_get_t30_state(fax_state_b);
        logging = t30_get_logging_state(t30);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        memset(out_amp, 0, sizeof(out_amp));

        t38_terminal_send_timeout(t38_state_a, SAMPLES_PER_CHUNK);

        t30_len_b = fax_tx(fax_state_b, t30_amp_b, SAMPLES_PER_CHUNK);
        if (!use_transmit_on_idle)
        {
            /* The receive side always expects a full block of samples, but the
               transmit side may not be sending any when it doesn't need to. We
               may need to pad with some silence. */
            if (t30_len_b < SAMPLES_PER_CHUNK)
            {
                memset(t30_amp_b + t30_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len_b));
                t30_len_b = SAMPLES_PER_CHUNK;
            }
        }
        if (feedback_audio)
        {
            for (i = 0;  i < t30_len_b;  i++)
                t30_amp_b[i] += t38_amp_b[i] >> 1;
        }
        if (log_audio)
        {
            for (i = 0;  i < t30_len_b;  i++)
                out_amp[2*i + 1] = t30_amp_b[i];
        }
        if (t38_gateway_rx(t38_state_b, t30_amp_b, t30_len_b))
            break;
    
        t38_len_b = t38_gateway_tx(t38_state_b, t38_amp_b, SAMPLES_PER_CHUNK);
        if (!use_transmit_on_idle)
        {
            if (t38_len_b < SAMPLES_PER_CHUNK)
            {
                memset(t38_amp_b + t38_len_b, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len_b));
                t38_len_b = SAMPLES_PER_CHUNK;
            }
        }
        if (log_audio)
        {
            for (i = 0;  i < t38_len_b;  i++)
                out_amp[2*i] = t38_amp_b[i];
        }
        if (fax_rx(fax_state_b, t38_amp_b, SAMPLES_PER_CHUNK))
            break;

        when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

        while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core = t38_gateway_get_t38_core_state(t38_state_b);
            t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
        }
        while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core = t38_terminal_get_t38_core_state(t38_state_a);
            t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
        }
        if (log_audio)
        {
            outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
            if (outframes != SAMPLES_PER_CHUNK)
                break;
        }

        if (done[0]  &&  done[1])
            break;
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
    }
    t38_terminal_release(t38_state_a);
    fax_release(fax_state_b);
    if (log_audio)
    {
        if (sf_close(wave_handle) != 0)
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", OUTPUT_FILE_NAME_WAVE);
            exit(2);
        }
    }
    if (!succeeded[0]  ||  !succeeded[1])
    {
        printf("Tests failed\n");
        exit(2);
    }
    printf("Tests passed\n");
    return 0;
}
int main(int argc, char *argv[])
{
    int msg_len;
    uint8_t msg[1024];
    int t38_version;
    int seq_no;
    int use_ecm;
    int without_pacing;
    int use_tep;
    int model_no;
    int speed_pattern_no;
    const char *input_file_name;
    double tx_when;
    double rx_when;
    int use_gui;
    int supported_modems;
    int opt;
    t30_state_t *t30;
    t38_core_state_t *t38_core;
    logging_state_t *logging;

    t38_version = 1;
    without_pacing = FALSE;
    use_tep = FALSE;
    input_file_name = INPUT_FILE_NAME;
    use_ecm = FALSE;
    simulate_incrementing_repeats = FALSE;
    model_no = 0;
    speed_pattern_no = 1;
    use_gui = FALSE;
    supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
    while ((opt = getopt(argc, argv, "efgi:Im:M:ps:tv:")) != -1)
    {
        switch (opt)
        {
        case 'e':
            use_ecm = TRUE;
            break;
        case 'g':
#if defined(ENABLE_GUI)
            use_gui = TRUE;
#else
            fprintf(stderr, "Graphical monitoring not available\n");
            exit(2);
#endif
            break;
        case 'i':
            input_file_name = optarg;
            break;
        case 'I':
            simulate_incrementing_repeats = TRUE;
            break;
        case 'm':
            supported_modems = atoi(optarg);
            break;
        case 'M':
            model_no = optarg[0] - 'A' + 1;
            break;
        case 'p':
            without_pacing = TRUE;
            break;
        case 's':
            speed_pattern_no = atoi(optarg);
            break;
        case 't':
            use_tep = TRUE;
            break;
        case 'v':
            t38_version = atoi(optarg);
            break;
        default:
            //usage();
            exit(2);
            break;
        }
    }

    printf("Using T.38 version %d\n", t38_version);
    if (use_ecm)
        printf("Using ECM\n");

    srand48(0x1234567);
    if ((path_a_to_b = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }
    if ((path_b_to_a = g1050_init(model_no, speed_pattern_no, 100, 33)) == NULL)
    {
        fprintf(stderr, "Failed to start IP network path model\n");
        exit(2);
    }

    if ((t38_state_a = t38_terminal_init(NULL, TRUE, tx_packet_handler_a, t38_state_b)) == NULL)
    {
        fprintf(stderr, "Cannot start the T.38 channel\n");
        exit(2);
    }
    t30 = t38_terminal_get_t30_state(t38_state_a);
    t38_core = t38_terminal_get_t38_core_state(t38_state_a);
    t38_set_t38_version(t38_core, t38_version);
    t38_terminal_set_config(t38_state_a, without_pacing);
    t38_terminal_set_tep_mode(t38_state_a, use_tep);
    
    logging = t38_terminal_get_logging_state(t38_state_a);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-A");

    logging = t38_core_get_logging_state(t38_core);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-A");

    logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-A");

    t30_set_supported_modems(t30, supported_modems);
    t30_set_tx_ident(t30, "11111111");
    t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_tx_file(t30, input_file_name, -1, -1);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'A');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A');
    t30_set_ecm_capability(t30, use_ecm);
    if (use_ecm)
        t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);

    if ((t38_state_b = t38_terminal_init(NULL, FALSE, tx_packet_handler_b, t38_state_a)) == NULL)
    {
        fprintf(stderr, "Cannot start the T.38 channel\n");
        exit(2);
    }
    t30 = t38_terminal_get_t30_state(t38_state_b);
    t38_core = t38_terminal_get_t38_core_state(t38_state_b);
    t38_set_t38_version(t38_core, t38_version);
    t38_terminal_set_config(t38_state_b, without_pacing);
    t38_terminal_set_tep_mode(t38_state_b, use_tep);

    logging = t38_terminal_get_logging_state(t38_state_b);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-B");

    logging = t38_core_get_logging_state(t38_core);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-B");

    logging = t30_get_logging_state(t30);
    span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
    span_log_set_tag(logging, "T.38-B");

    t30_set_supported_modems(t30, supported_modems);
    t30_set_tx_ident(t30, "22222222");
    t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
    t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1);
    t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'B');
    t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'B');
    t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'B');
    t30_set_ecm_capability(t30, use_ecm);
    if (use_ecm)
        t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    for (;;)
    {
        logging = t38_terminal_get_logging_state(t38_state_a);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t38_core = t38_terminal_get_t38_core_state(t38_state_a);
        logging = t38_core_get_logging_state(t38_core);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t30 = t38_terminal_get_t30_state(t38_state_a);
        logging = t30_get_logging_state(t30);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        logging = t38_terminal_get_logging_state(t38_state_b);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t38_core = t38_terminal_get_t38_core_state(t38_state_b);
        logging = t38_core_get_logging_state(t38_core);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
        t30 = t38_terminal_get_t30_state(t38_state_b);
        logging = t30_get_logging_state(t30);
        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

        done[0] = t38_terminal_send_timeout(t38_state_a, SAMPLES_PER_CHUNK);
        done[1] = t38_terminal_send_timeout(t38_state_b, SAMPLES_PER_CHUNK);

        when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

        while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core = t38_terminal_get_t38_core_state(t38_state_b);
            t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
        }
        while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
        {
#if defined(ENABLE_GUI)
            if (use_gui)
                media_monitor_rx(seq_no, tx_when, rx_when);
#endif
            t38_core = t38_terminal_get_t38_core_state(t38_state_a);
            t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no);
        }
        if (done[0]  &&  done[1])
            break;
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
    }
    t38_terminal_release(t38_state_a);
    t38_terminal_release(t38_state_b);
    if (!succeeded[0]  ||  !succeeded[1])
    {
        printf("Tests failed\n");
        exit(2);
    }
    printf("Tests passed\n");
    return  0;
}