Mercurial > hg > audiostuff
diff spandsp-0.0.3/spandsp-0.0.3/tests/dtmf_rx_tests.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.3/spandsp-0.0.3/tests/dtmf_rx_tests.c Fri Jun 25 16:00:21 2010 +0200 @@ -0,0 +1,894 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * dtmf_rx_tests.c - Test the DTMF detector against the spec., whatever the spec. + * may be :) + * + * Written by Steve Underwood <steveu@coppice.org> + * + * Copyright (C) 2001, 2006 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: dtmf_rx_tests.c,v 1.23 2006/11/19 14:07:26 steveu Exp $ + */ + +/* + * These tests include conversion to and from A-law. I assume the + * distortion this produces is comparable to u-law, so it should be + * a fair test. + * + * These tests mirror those on the CM7291 test tape from Mitel. + * Many of these tests are highly questionable, but they are a + * well accepted industry standard. + * + * However standard these tests might be, Mitel appears to have stopped + * selling copies of their tape. + * + * For the talk-off test the Bellcore tapes may be used. However, they are + * copyright material, so the test data files produced from the Bellcore + * tapes cannot be distributed as a part of this package. + * + */ + +/*! \page dtmf_rx_tests_page DTMF receiver tests +\section dtmf_rx_tests_page_sec_1 What does it do? + +The DTMF detection test suite performs similar tests to the Mitel test tape, +traditionally used for testing DTMF receivers. Mitel seem to have discontinued +this product, but all it not lost. + +The first side of the Mitel tape consists of a number of tone and tone+noise +based tests. The test suite synthesizes equivalent test data. Being digitally +generated, this data is rather more predictable than the test data on the nasty +old stretchy cassette tapes which Mitel sold. + +The second side of the Mitel tape contains fragments of real speech from real +phone calls captured from the North American telephone network. These are +considered troublesome for DTMF detectors. A good detector is expected to +achieve a reasonably low number of false detections on this data. Fresh clean +copies of this seem to be unobtainable. However, Bellcore produce a much more +aggressive set of three cassette tapes. All six side (about 30 minutes each) are +filled with much tougher fragments of real speech from the North American +telephone network. If you can do well in this test, nobody cares about your +results against the Mitel test tape. + +A fresh set of tapes was purchased for these tests, and digitised, producing 6 +wave files of 16 bit signed PCM data, sampled at 8kHz. They were transcribed +using a speed adjustable cassette player. The test tone at the start of the +tapes is pretty accurate, and the new tapes should not have had much opportunity +to stretch. It is believed these transcriptions are about as good as the source +material permits. + +PLEASE NOTE + +These transcriptions may be freely used by anyone who has a legitimate copy of +the original tapes. However, if you don't have a legitimate copy of those tapes, +you also have no right to use this data. The original tapes are the copyright +material of BellCore, and they charge over US$200 for a set. I doubt they sell +enough copies to consider this much of a business. However, it is their data, +and it is their right to do as they wish with it. Currently I see no indication +they wish to give it away for free. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#if defined(HAVE_TGMATH_H) +#include <tgmath.h> +#endif +#if defined(HAVE_MATH_H) +#include <math.h> +#endif +#include <stdio.h> +#include <time.h> +#include <fcntl.h> +#include <audiofile.h> +#include <tiffio.h> + +#include "spandsp.h" + +#include "test_utils.h" + +/* Basic DTMF specs: + * + * Minimum tone on = 40ms + * Minimum tone off = 50ms + * Maximum digit rate = 10 per second + * Normal twist <= 8dB accepted + * Reverse twist <= 4dB accepted + * S/N >= 15dB will detect OK + * Attenuation <= 26dB will detect OK + * Frequency tolerance +- 1.5% will detect, +-3.5% will reject + */ + +#define DTMF_DURATION 380 +#define DTMF_PAUSE 400 +#define DTMF_CYCLE (DTMF_DURATION + DTMF_PAUSE) + +#define ALL_POSSIBLE_DIGITS "123A456B789C*0#D" + +#define MITEL_DIR "../itutests/mitel/" +#define BELLCORE_DIR "../itutests/bellcore/" + +const char *bellcore_files[] = +{ + MITEL_DIR "mitel-cm7291-talkoff.wav", + BELLCORE_DIR "tr-tsy-00763-1.wav", + BELLCORE_DIR "tr-tsy-00763-2.wav", + BELLCORE_DIR "tr-tsy-00763-3.wav", + BELLCORE_DIR "tr-tsy-00763-4.wav", + BELLCORE_DIR "tr-tsy-00763-5.wav", + BELLCORE_DIR "tr-tsy-00763-6.wav", + "" +}; + +static tone_gen_descriptor_t my_dtmf_digit_tones[16]; + +float dtmf_row[] = +{ + 697.0f, 770.0f, 852.0f, 941.0f +}; +float dtmf_col[] = +{ + 1209.0f, 1336.0f, 1477.0f, 1633.0f +}; + +char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; + +int callback_hit; +int callback_ok; +int callback_roll; +int step; + +int use_dialtone_filter = FALSE; + +char *decode_test_file = NULL; + +static int16_t amp[1000000]; +static int16_t amp2[1000000]; + +codec_munge_state_t *munge = NULL; + +static void my_dtmf_gen_init(float low_fudge, + int low_level, + float high_fudge, + int high_level, + int duration, + int gap) +{ + int row; + int col; + + for (row = 0; row < 4; row++) + { + for (col = 0; col < 4; col++) + { + make_tone_gen_descriptor(&my_dtmf_digit_tones[row*4 + col], + dtmf_row[row]*(1.0f + low_fudge), + low_level, + dtmf_col[col]*(1.0f + high_fudge), + high_level, + duration, + gap, + 0, + 0, + FALSE); + } + } +} +/*- End of function --------------------------------------------------------*/ + +static int my_dtmf_generate(int16_t amp[], const char *digits) +{ + int len; + char *cp; + tone_gen_state_t tone; + + len = 0; + while (*digits) + { + cp = strchr(dtmf_positions, *digits); + if (cp) + { + tone_gen_init(&tone, &my_dtmf_digit_tones[cp - dtmf_positions]); + len += tone_gen(&tone, amp + len, 1000); + } + digits++; + } + return len; +} +/*- End of function --------------------------------------------------------*/ + +static void digit_delivery(void *data, const char *digits, int len) +{ + int i; + int seg; + const char *s = ALL_POSSIBLE_DIGITS; + const char *t; + + callback_hit = TRUE; + if (data == (void *) 0x12345678) + { + t = s + callback_roll; + seg = 16 - callback_roll; + for (i = 0; i < len; i += seg, seg = 16) + { + if (i + seg > len) + seg = len - i; + if (memcmp(digits + i, t, seg)) + { + callback_ok = FALSE; + printf("Fail at %d %d\n", i, seg); + break; + } + t = s; + callback_roll = (callback_roll + seg)%16; + } + } + else + { + callback_ok = FALSE; + } +} +/*- End of function --------------------------------------------------------*/ + +static void digit_status(void *data, int signal) +{ + const char *s = ALL_POSSIBLE_DIGITS; + int len; + static int last_step = 0; + static int first = TRUE; + + callback_hit = TRUE; + len = step - last_step; + if (data == (void *) 0x12345678) + { + if (len < 320 || len > 480) + { + if (first) + { + /* At the beginning the apparent duration is expected to be wrong */ + first = FALSE; + } + else + { + printf("Failed for signal %s length %d at %d\n", (callback_roll & 1) ? "on" : "off", len, step); + callback_ok = FALSE; + } + } + if (callback_roll & 1) + { + if (signal != 0) + { + printf("Failed for signal 0x%X instead of 0\n", signal); + callback_ok = FALSE; + } + } + else + { + if (signal != s[callback_roll >> 1]) + { + printf("Failed for signal 0x%X instead of 0x%X\n", signal, s[callback_roll >> 1]); + callback_ok = FALSE; + } + } + if (++callback_roll >= 32) + callback_roll = 0; + } + else + { + callback_ok = FALSE; + } + last_step = step; +} +/*- End of function --------------------------------------------------------*/ + +static void mitel_cm7291_side_1_tests(void) +{ + int i; + int j; + int len; + int sample; + const char *s; + char digit[2]; + char buf[128 + 1]; + int actual; + int nplus; + int nminus; + float rrb; + float rcfo; + dtmf_rx_state_t dtmf_state; + awgn_state_t noise_source; + + dtmf_rx_init(&dtmf_state, NULL, NULL); + if (use_dialtone_filter) + dtmf_rx_parms(&dtmf_state, TRUE, -1, -1); + + /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step, + which has no meaning here. */ + printf("Test 1: Calibration\n"); + printf(" Passed\n"); + + /* Test 2: Decode check + This is a sanity check, that all digits are reliably detected + under ideal conditions. Each possible digit repeated 10 times, + with 50ms bursts. The level of each tone is about 6dB down from clip. + 6dB down actually causes trouble with G.726, so we use 7dB down. */ + printf("Test 2: Decode check\n"); + my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50); + s = ALL_POSSIBLE_DIGITS; + digit[1] = '\0'; + while (*s) + { + digit[0] = *s++; + for (i = 0; i < 10; i++) + { + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + + actual = dtmf_rx_get(&dtmf_state, buf, 128); + + if (actual != 1 || buf[0] != digit[0]) + { + printf(" Sent '%s'\n", digit); + printf(" Received '%s'\n", buf); + printf(" Failed\n"); + exit(2); + } + } + } + printf(" Passed\n"); + + /* Test 3: Recognition bandwidth and channel centre frequency check. + Use only the diagonal pairs of tones (digits 1, 5, 9 and D). Each + tone pair requires four test to complete the check, making 16 + sections overall. Each section contains 40 pulses of + 50ms duration, with an amplitude of -20dB from clip per + frequency. + + Four sections covering the tests for one tone (1 digit) are: + a. H frequency at 0% deviation from center, L frequency at +0.1%. + L frequency is then increments in +01.% steps up to +4%. The + number of tone bursts is noted and designated N+. + b. H frequency at 0% deviation, L frequency at -0.1%. L frequency + is then incremental in -0.1% steps, up to -4%. The number of + tone bursts is noted and designated N-. + c. The test in (a) is repeated with the L frequency at 0% and the + H frequency varied up to +4%. + d. The test in (b) is repeated with the L frequency and 0% and the + H frequency varied to -4%. + + Receiver Recognition Bandwidth (RRB) is calculated as follows: + RRB% = (N+ + N-)/10 + Receiver Center Frequency Offset (RCFO) is calculated as follows: + RCFO% = X + (N+ - N-)/20 + + Note that this test doesn't test what it says it is testing at all, + and the results are quite inaccurate, if not a downright lie! However, + it follows the Mitel procedure, so how can it be bad? :) + */ + printf("Test 3: Recognition bandwidth and channel centre frequency check\n"); + s = "159D"; + digit[1] = '\0'; + while (*s) + { + digit[0] = *s++; + for (nplus = 0, i = 1; i <= 60; i++) + { + my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50); + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nplus += dtmf_rx_get(&dtmf_state, buf, 128); + } + for (nminus = 0, i = -1; i >= -60; i--) + { + my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50); + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nminus += dtmf_rx_get(&dtmf_state, buf, 128); + } + rrb = (float) (nplus + nminus)/10.0f; + rcfo = (float) (nplus - nminus)/10.0f; + printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", + digit[0], + rrb, + rcfo, + (float) nminus/10.0f, + (float) nplus/10.0f); + if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo) + { + printf(" Failed\n"); + exit(2); + } + + for (nplus = 0, i = 1; i <= 60; i++) + { + my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50); + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nplus += dtmf_rx_get(&dtmf_state, buf, 128); + } + for (nminus = 0, i = -1; i >= -60; i--) + { + my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50); + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nminus += dtmf_rx_get(&dtmf_state, buf, 128); + } + rrb = (float) (nplus + nminus)/10.0f; + rcfo = (float) (nplus - nminus)/10.0f; + printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", + digit[0], + rrb, + rcfo, + (float) nminus/10.0f, + (float) nplus/10.0f); + if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo) + { + printf(" Failed\n"); + exit(2); + } + } + printf(" Passed\n"); + + /* Test 4: Acceptable amplitude ratio (twist). + Use only the diagonal pairs of tones (digits 1, 5, 9 and D). + There are eight sections to the test. Each section contains 200 + pulses with a 50ms duration for each pulse. Initially the amplitude + of both tones is 6dB down from clip. The two sections to test one + tone pair are: + + a. Standard Twist: H tone amplitude is maintained at -6dB from clip, + L tone amplitude is attenuated gradually until the amplitude ratio + L/H is -20dB. Note the number of responses from the receiver. + b. Reverse Twist: L tone amplitude is maintained at -6dB from clip, + H tone amplitude is attenuated gradually until the amplitude ratio + is 20dB. Note the number of responses from the receiver. + + All tone bursts are of 50ms duration. + + The Acceptable Amplitude Ratio in dB is equal to the number of + responses registered in (a) or (b), divided by 10. + + TODO: This is supposed to work in 1/10dB steps, but here I used 1dB + steps, as the current tone generator has its amplitude set in + 1dB steps. + */ + printf("Test 4: Acceptable amplitude ratio (twist)\n"); + s = "159D"; + digit[1] = '\0'; + while (*s) + { + digit[0] = *s++; + for (nplus = 0, i = -30; i >= -230; i--) + { + my_dtmf_gen_init(0.0f, -3, 0.0f, i/10, 50, 50); + + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nplus += dtmf_rx_get(&dtmf_state, buf, 128); + } + printf(" %c normal twist = %.2fdB\n", digit[0], (float) nplus/10.0); + if (nplus < 80) + { + printf(" Failed\n"); + exit(2); + } + for (nminus = 0, i = -30; i >= -230; i--) + { + my_dtmf_gen_init(0.0f, i/10, 0.0f, -3, 50, 50); + + len = my_dtmf_generate(amp, digit); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nminus += dtmf_rx_get(&dtmf_state, buf, 128); + } + printf(" %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0); + if (nminus < 40) + { + printf(" Failed\n"); + exit(2); + } + } + printf(" Passed\n"); + + /* Test 5: Dynamic range + This test utilizes tone pair L1 H1 (digit 1). Thirty-five tone pair + pulses are transmitted, with both frequencies stating at -6dB from + clip. The amplitude of each is gradually attenuated by -35dB at a + rate of 1dB per pulse. The Dynamic Range in dB is equal to the + number of responses from the receiver during the test. + + Well not really, but that is the Mitel test. Lets sweep a bit further, + and see what the real range is */ + printf("Test 5: Dynamic range\n"); + for (nplus = 0, i = +3; i >= -50; i--) + { + my_dtmf_gen_init(0.0f, i, 0.0f, i, 50, 50); + + len = my_dtmf_generate(amp, "1"); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nplus += dtmf_rx_get(&dtmf_state, buf, 128); + } + printf(" Dynamic range = %ddB\n", nplus); + printf(" Passed\n"); + + /* Test 6: Guard time + This test utilizes tone pair L1 H1 (digit 1). Four hundred pulses + are transmitted at an amplitude of -6dB from clip per frequency. + Pulse duration starts at 49ms and is gradually reduced to 10ms. + Guard time in ms is equal to (500 - number of responses)/10. + + That is the Mitel test, and we will follow it. Its totally bogus, + though. Just what the heck is a pass or fail here? */ + + printf("Test 6: Guard time\n"); + for (nplus = 0, i = 490; i >= 100; i--) + { + my_dtmf_gen_init(0.0f, -3, 0.0f, -3, i/10, 50); + + len = my_dtmf_generate(amp, "1"); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + nplus += dtmf_rx_get(&dtmf_state, buf, 128); + } + printf(" Guard time = %dms\n", (500 - nplus)/10); + printf(" Passed\n"); + + /* Test 7: Acceptable signal to noise ratio + This test utilizes tone pair L1 H1, transmitted on a noise background. + The test consists of three sections in which the tone pair is + transmitted 1000 times at an amplitude -6dB from clip per frequency, + but with a different white noise level for each section. The first + level is -24dBV, the second -18dBV and the third -12dBV.. The + acceptable signal to noise ratio is the lowest ratio of signal + to noise in the test where the receiver responds to all 1000 pulses. + + Well, that is the Mitel test, but it doesn't tell you what the + decoder can really do. Lets do a more comprehensive test */ + + printf("Test 7: Acceptable signal to noise ratio\n"); + my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50); + + for (j = -13; j > -50; j--) + { + awgn_init_dbm0(&noise_source, 1234567, (float) j); + for (i = 0; i < 1000; i++) + { + len = my_dtmf_generate(amp, "1"); + + // TODO: Clip + for (sample = 0; sample < len; sample++) + amp[sample] = saturate(amp[sample] + awgn(&noise_source)); + + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + + if (dtmf_rx_get(&dtmf_state, buf, 128) != 1) + break; + } + if (i == 1000) + break; + } + printf(" Acceptable S/N ratio is %ddB\n", -4 - j); + if (-4 - j > 26) + { + printf(" Failed\n"); + exit(2); + } + printf(" Passed\n"); +} +/*- End of function --------------------------------------------------------*/ + +static void mitel_cm7291_side_2_and_bellcore_tests(void) +{ + int i; + int j; + int len; + int hits; + int hit_types[256]; + char buf[128 + 1]; + AFfilehandle inhandle; + int frames; + float x; + dtmf_rx_state_t dtmf_state; + + dtmf_rx_init(&dtmf_state, NULL, NULL); + if (use_dialtone_filter) + dtmf_rx_parms(&dtmf_state, TRUE, -1, -1); + + /* The remainder of the Mitel tape is the talk-off test */ + /* Here we use the Bellcore test tapes (much tougher), in six + wave files - 1 from each side of the original 3 cassette tapes */ + /* Bellcore say you should get no more than 470 false detections with + a good receiver. Dialogic claim 20. Of course, we can do better than + that, eh? */ + printf("Test 8: Talk-off test\n"); + memset(hit_types, '\0', sizeof(hit_types)); + for (j = 0; bellcore_files[j][0]; j++) + { + if ((inhandle = afOpenFile(bellcore_files[j], "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open speech file '%s'\n", bellcore_files[j]); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in speech file '%s'\n", bellcore_files[j]); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in speech file '%s'\n", bellcore_files[j]); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in speech file '%s'\n", bellcore_files[j]); + exit(2); + } + hits = 0; + while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, SAMPLE_RATE))) + { + dtmf_rx(&dtmf_state, amp, frames); + len = dtmf_rx_get(&dtmf_state, buf, 128); + if (len > 0) + { + for (i = 0; i < len; i++) + hit_types[(int) buf[i]]++; + hits += len; + } + } + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close speech file '%s'\n", bellcore_files[j]); + exit(2); + } + printf(" File %d gave %d false hits.\n", j + 1, hits); + } + for (i = 0, j = 0; i < 256; i++) + { + if (hit_types[i]) + { + printf(" Digit %c had %d false hits\n", i, hit_types[i]); + j += hit_types[i]; + } + } + printf(" %d hits in total\n", j); + if (j > 470) + { + printf(" Failed\n"); + exit(2); + } + printf(" Passed\n"); +} +/*- End of function --------------------------------------------------------*/ + +static void dial_tone_tolerance_tests(void) +{ + int i; + int j; + int len; + int sample; + char buf[128 + 1]; + dtmf_rx_state_t dtmf_state; + tone_gen_descriptor_t dial_tone_desc; + tone_gen_state_t dial_tone; + + dtmf_rx_init(&dtmf_state, NULL, NULL); + if (use_dialtone_filter) + dtmf_rx_parms(&dtmf_state, TRUE, -1, -1); + + /* Test dial tone tolerance */ + printf("Test: Dial tone tolerance.\n"); + my_dtmf_gen_init(0.0f, -15, 0.0f, -15, 50, 50); + + for (j = -30; j < -3; j++) + { + make_tone_gen_descriptor(&dial_tone_desc, 350, j, 440, j, 1, 0, 0, 0, TRUE); + tone_gen_init(&dial_tone, &dial_tone_desc); + for (i = 0; i < 10; i++) + { + len = my_dtmf_generate(amp, ALL_POSSIBLE_DIGITS); + tone_gen(&dial_tone, amp2, len); + + for (sample = 0; sample < len; sample++) + amp[sample] = saturate(amp[sample] + amp2[sample]); + codec_munge(munge, amp, len); + dtmf_rx(&dtmf_state, amp, len); + + if (dtmf_rx_get(&dtmf_state, buf, 128) != strlen(ALL_POSSIBLE_DIGITS)) + break; + } + if (i != 10) + break; + } + printf(" Acceptable signal to dial tone ratio is %ddB\n", -15 - j); + if ((use_dialtone_filter && (-15 - j) > -12) + || + (!use_dialtone_filter && (-15 - j) > 10)) + { + printf(" Failed\n"); + exit(2); + } + printf(" Passed\n"); +} +/*- End of function --------------------------------------------------------*/ + +static void callback_function_tests(void) +{ + int i; + int j; + int len; + int sample; + dtmf_rx_state_t dtmf_state; + + /* Test the callback mode for delivering detected digits */ + printf("Test: Callback digit delivery mode.\n"); + callback_hit = FALSE; + callback_ok = TRUE; + callback_roll = 0; + dtmf_rx_init(&dtmf_state, digit_delivery, (void *) 0x12345678); + if (use_dialtone_filter) + dtmf_rx_parms(&dtmf_state, TRUE, -1, -1); + my_dtmf_gen_init(0.0f, -10, 0.0f, -10, 50, 50); + for (i = 1; i < 10; i++) + { + len = 0; + for (j = 0; j < i; j++) + len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS); + dtmf_rx(&dtmf_state, amp, len); + if (!callback_hit || !callback_ok) + break; + } + if (!callback_hit || !callback_ok) + { + printf(" Failed\n"); + exit(2); + } + printf(" Passed\n"); + + /* Test the realtime callback mode for reporting detected digits */ + printf("Test: Realtime callback digit delivery mode.\n"); + callback_hit = FALSE; + callback_ok = TRUE; + callback_roll = 0; + dtmf_rx_init(&dtmf_state, NULL, NULL); + dtmf_rx_set_realtime_callback(&dtmf_state, digit_status, (void *) 0x12345678); + if (use_dialtone_filter) + dtmf_rx_parms(&dtmf_state, TRUE, -1, -1); + my_dtmf_gen_init(0.0f, -10, 0.0f, -10, 50, 50); + step = 0; + for (i = 1; i < 10; i++) + { + len = 0; + for (j = 0; j < i; j++) + len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS); + for (sample = 0, j = 160; sample < len; sample += 160, j = ((len - sample) >= 160) ? 160 : (len - sample)) + { + dtmf_rx(&dtmf_state, &[sample], j); + if (!callback_ok) + break; + step += j; + } + if (!callback_hit || !callback_ok) + break; + } + if (!callback_hit || !callback_ok) + { + printf(" Failed\n"); + exit(2); + } +} +/*- End of function --------------------------------------------------------*/ + +static void decode_test(const char *test_file) +{ + int16_t amp[160]; + AFfilehandle inhandle; + dtmf_rx_state_t dtmf_state; + char buf[128 + 1]; + int actual; + int samples; + int total; + + dtmf_rx_init(&dtmf_state, NULL, NULL); + if (use_dialtone_filter) + dtmf_rx_parms(&dtmf_state, TRUE, -1, -1); + + /* We will decode the audio from a wave file. */ + + if ((inhandle = afOpenFile(decode_test_file, "r", NULL)) == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot open wave file '%s'\n", decode_test_file); + exit(2); + } + + total = 0; + while ((samples = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, 160)) > 0) + { + codec_munge(munge, amp, samples); + dtmf_rx(&dtmf_state, amp, samples); + if ((actual = dtmf_rx_get(&dtmf_state, buf, 128)) > 0) + printf("Received '%s'\n", buf); + total += actual; + } + printf("%d digits received\n", total); +} +/*- End of function --------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + int duration; + int i; + time_t now; + int channel_codec; + + use_dialtone_filter = FALSE; + channel_codec = MUNGE_CODEC_NONE; + decode_test_file = NULL; + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-c") == 0) + { + channel_codec = atoi(argv[++i]); + continue; + } + if (strcmp(argv[i], "-d") == 0) + { + decode_test_file = argv[++i]; + continue; + } + if (strcmp(argv[i], "-f") == 0) + { + use_dialtone_filter = TRUE; + continue; + } + } + munge = codec_munge_init(channel_codec); + + if (decode_test_file) + { + decode_test(decode_test_file); + } + else + { + time(&now); + mitel_cm7291_side_1_tests(); + mitel_cm7291_side_2_and_bellcore_tests(); + dial_tone_tolerance_tests(); + callback_function_tests(); + printf(" Passed\n"); + duration = time(NULL) - now; + printf("Tests passed in %ds\n", duration); + } + + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/