Mercurial > hg > audiostuff
view spandsp-0.0.6pre17/tests/v22bis_tests.c @ 6:22a74b01a099 default tip
implement more meaningful test program
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:14:50 +0200 |
parents | 26cd8f1ef0b1 |
children |
line wrap: on
line source
/* * SpanDSP - a series of DSP components for telephony * * v22bis_tests.c * * Written by Steve Underwood <steveu@coppice.org> * * Copyright (C) 2004 Steve Underwood * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: v22bis_tests.c,v 1.63 2009/07/09 13:52:09 steveu Exp $ */ /*! \page v22bis_tests_page V.22bis modem tests \section v22bis_tests_page_sec_1 What does it do? These tests connect two V.22bis modems back to back, through a telephone line model. BER testing is then used to evaluate performance under various line conditions. If the appropriate GUI environment exists, the tests are built such that a visual display of modem status is maintained. \section v22bis_tests_page_sec_2 How is it used? */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) #define ENABLE_GUI #endif #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sndfile.h> #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES #include "spandsp.h" #include "spandsp-sim.h" #if defined(ENABLE_GUI) #include "modem_monitor.h" #endif #define BLOCK_LEN 160 #define OUT_FILE_NAME "v22bis.wav" char *decode_test_file = NULL; int use_gui = FALSE; int rx_bits = 0; both_ways_line_model_state_t *model; typedef struct { v22bis_state_t *v22bis; bert_state_t bert_tx; bert_state_t bert_rx; bert_results_t latest_results; #if defined(ENABLE_GUI) qam_monitor_t *qam_monitor; #endif float smooth_power; int symbol_no; } endpoint_t; endpoint_t endpoint[2]; static void reporter(void *user_data, int reason, bert_results_t *results) { endpoint_t *s; s = (endpoint_t *) user_data; switch (reason) { case BERT_REPORT_REGULAR: fprintf(stderr, "V.22bis rx %p BERT report regular - %d bits, %d bad bits, %d resyncs\n", user_data, results->total_bits, results->bad_bits, results->resyncs); memcpy(&s->latest_results, results, sizeof(s->latest_results)); break; default: fprintf(stderr, "V.22bis rx %p BERT report %s\n", user_data, bert_event_to_str(reason)); break; } } /*- End of function --------------------------------------------------------*/ static void v22bis_putbit(void *user_data, int bit) { endpoint_t *s; int i; int len; int bit_rate; complexf_t *coeffs; s = (endpoint_t *) user_data; if (bit < 0) { /* Special conditions */ printf("V.22bis rx %p status is %s (%d)\n", user_data, signal_status_to_str(bit), bit); switch (bit) { case SIG_STATUS_TRAINING_SUCCEEDED: bit_rate = v22bis_current_bit_rate(s->v22bis); printf("Negotiated bit rate: %d\n", bit_rate); len = v22bis_rx_equalizer_state(s->v22bis, &coeffs); printf("Equalizer:\n"); for (i = 0; i < len; i++) printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); break; } return; } if (decode_test_file) printf("Rx bit %p-%d - %d\n", user_data, rx_bits++, bit); else bert_put_bit(&s->bert_rx, bit); } /*- End of function --------------------------------------------------------*/ static int v22bis_getbit(void *user_data) { endpoint_t *s; int bit; s = (endpoint_t *) user_data; bit = bert_get_bit(&s->bert_tx); return bit; } /*- End of function --------------------------------------------------------*/ static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol) { int i; int len; complexf_t *coeffs; float fpower; endpoint_t *s; s = (endpoint_t *) user_data; if (constel) { #if defined(ENABLE_GUI) if (use_gui) { qam_monitor_update_constel(s->qam_monitor, constel); qam_monitor_update_carrier_tracking(s->qam_monitor, v22bis_rx_carrier_frequency(s->v22bis)); qam_monitor_update_symbol_tracking(s->qam_monitor, v22bis_rx_symbol_timing_correction(s->v22bis)); } #endif fpower = (constel->re - target->re)*(constel->re - target->re) + (constel->im - target->im)*(constel->im - target->im); s->smooth_power = 0.95f*s->smooth_power + 0.05f*fpower; printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %8.4f\n", s->symbol_no, constel->re, constel->im, target->re, target->im, symbol, fpower, s->smooth_power, v22bis_rx_signal_power(s->v22bis)); s->symbol_no++; } else { printf("Gardner step %d\n", symbol); len = v22bis_rx_equalizer_state(s->v22bis, &coeffs); printf("Equalizer A:\n"); for (i = 0; i < len; i++) printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); #if defined(ENABLE_GUI) if (use_gui) qam_monitor_update_equalizer(s->qam_monitor, coeffs, len); #endif } } /*- End of function --------------------------------------------------------*/ int main(int argc, char *argv[]) { int16_t amp[2][BLOCK_LEN]; int16_t model_amp[2][BLOCK_LEN]; int16_t out_amp[2*BLOCK_LEN]; SNDFILE *inhandle; SNDFILE *outhandle; int outframes; int samples; int samples2; int i; int j; int test_bps; int line_model_no; int bits_per_test; int noise_level; int signal_level; int log_audio; int channel_codec; int opt; channel_codec = MUNGE_CODEC_NONE; test_bps = 2400; line_model_no = 0; decode_test_file = NULL; noise_level = -70; signal_level = -13; bits_per_test = 50000; log_audio = FALSE; while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:s:")) != -1) { switch (opt) { case 'b': test_bps = atoi(optarg); if (test_bps != 2400 && test_bps != 1200) { fprintf(stderr, "Invalid bit rate specified\n"); exit(2); } break; case 'B': bits_per_test = atoi(optarg); break; case 'c': channel_codec = atoi(optarg); break; case 'd': decode_test_file = optarg; break; case 'g': #if defined(ENABLE_GUI) use_gui = TRUE; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'l': log_audio = TRUE; break; case 'm': line_model_no = atoi(optarg); break; case 'n': noise_level = atoi(optarg); break; case 's': signal_level = atoi(optarg); break; default: //usage(); exit(2); break; } } inhandle = NULL; if (decode_test_file) { /* We will decode the audio from a file. */ if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) { fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); exit(2); } } outhandle = NULL; if (log_audio) { if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL) { fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); exit(2); } } memset(endpoint, 0, sizeof(endpoint)); for (i = 0; i < 2; i++) { endpoint[i].v22bis = v22bis_init(NULL, test_bps, V22BIS_GUARD_TONE_1800HZ, (i == 0), v22bis_getbit, &endpoint[i], v22bis_putbit, &endpoint[i]); v22bis_tx_power(endpoint[i].v22bis, signal_level); /* Move the carrier off a bit */ endpoint[i].v22bis->tx.carrier_phase_rate = dds_phase_ratef((i == 0) ? 1207.0f : 2407.0f); v22bis_rx_set_qam_report_handler(endpoint[i].v22bis, qam_report, (void *) &endpoint[i]); span_log_set_level(&endpoint[i].v22bis->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); span_log_set_tag(&endpoint[i].v22bis->logging, (i == 0) ? "caller" : "answerer"); endpoint[i].smooth_power = 0.0f; endpoint[i].symbol_no = 0; bert_init(&endpoint[i].bert_tx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_init(&endpoint[i].bert_rx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&endpoint[i].bert_rx, 10000, reporter, &endpoint[i]); } #if defined(ENABLE_GUI) if (use_gui) { endpoint[0].qam_monitor = qam_monitor_init(6.0f, "Calling modem"); endpoint[1].qam_monitor = qam_monitor_init(6.0f, "Answering modem"); } #endif if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, (float) noise_level, channel_codec, 0)) == NULL) { fprintf(stderr, " Failed to create line model\n"); exit(2); } samples = 0; for (;;) { for (i = 0; i < 2; i++) { samples = v22bis_tx(endpoint[i].v22bis, amp[i], BLOCK_LEN); #if defined(ENABLE_GUI) if (use_gui) qam_monitor_update_audio_level(endpoint[i].qam_monitor, amp[i], samples); #endif if (samples == 0) { /* Note that we might get a few bad bits as the carrier shuts down. */ bert_result(&endpoint[i].bert_rx, &endpoint[i].latest_results); bert_init(&endpoint[i].bert_tx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_init(&endpoint[i].bert_rx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&endpoint[i].bert_rx, 10000, reporter, &endpoint[i]); printf("Restarting on zero output\n"); v22bis_restart(endpoint[i].v22bis, test_bps); } } #if 1 both_ways_line_model(model, model_amp[0], amp[0], model_amp[1], amp[1], samples); #else vec_copyi16(model_amp[0], amp[0], samples); vec_copyi16(model_amp[1], amp[1], samples); #endif if (decode_test_file) { samples2 = sf_readf_short(inhandle, model_amp[0], samples); if (samples2 != samples) break; } for (i = 0; i < 2; i++) { span_log_bump_samples(&endpoint[i].v22bis->logging, samples); v22bis_rx(endpoint[i ^ 1].v22bis, model_amp[i], samples); for (j = 0; j < samples; j++) out_amp[2*j + i] = model_amp[i][j]; for ( ; j < BLOCK_LEN; j++) out_amp[2*j + i] = 0; } if (log_audio) { outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN); if (outframes != BLOCK_LEN) { fprintf(stderr, " Error writing audio file\n"); exit(2); } } } #if defined(ENABLE_GUI) if (use_gui) qam_wait_to_end(endpoint[0].qam_monitor); #endif if (decode_test_file) { if (sf_close(inhandle)) { fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); exit(2); } } if (log_audio) { if (sf_close(outhandle) != 0) { fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); exit(2); } } return 0; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/