1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * dtmf_rx_tests.c - Test the DTMF detector against the spec., whatever the spec.
5  *                   may be :)
6  *
7  * Written by Steve Underwood <steveu@coppice.org>
8  *
9  * Copyright (C) 2001, 2006 Steve Underwood
10  *
11  * All rights reserved.
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2, as
15  * published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26 
27 /*
28  * These tests include conversion to and from A-law. I assume the
29  * distortion this produces is comparable to u-law, so it should be
30  * a fair test.
31  *
32  * These tests mirror those on the CM7291 test tape from Mitel.
33  * Many of these tests are highly questionable, but they are a
34  * well accepted industry standard.
35  *
36  * However standard these tests might be, Mitel appears to have stopped
37  * selling copies of their tape.
38  *
39  * For the talk-off test the Bellcore tapes may be used. However, they are
40  * copyright material, so the test data files produced from the Bellcore
41  * tapes cannot be distributed as a part of this package.
42  *
43  */
44 
45 /*! \page dtmf_rx_tests_page DTMF receiver tests
46 \section dtmf_rx_tests_page_sec_1 What does it do?
47 
48 The DTMF detection test suite performs similar tests to the Mitel test tape,
49 traditionally used for testing DTMF receivers. Mitel seem to have discontinued
50 this product, but all it not lost.
51 
52 The first side of the Mitel tape consists of a number of tone and tone+noise
53 based tests. The test suite synthesizes equivalent test data. Being digitally
54 generated, this data is rather more predictable than the test data on the nasty
55 old stretchy cassette tapes which Mitel sold.
56 
57 The second side of the Mitel tape contains fragments of real speech from real
58 phone calls captured from the North American telephone network. These are
59 considered troublesome for DTMF detectors. A good detector is expected to
60 achieve a reasonably low number of false detections on this data. Fresh clean
61 copies of this seem to be unobtainable. However, Bellcore produce a much more
62 aggressive set of three cassette tapes. All six side (about 30 minutes each) are
63 filled with much tougher fragments of real speech from the North American
64 telephone network. If you can do well in this test, nobody cares about your
65 results against the Mitel test tape.
66 
67 A fresh set of tapes was purchased for these tests, and digitised, producing 6
68 wave files of 16 bit signed PCM data, sampled at 8kHz. They were transcribed
69 using a speed adjustable cassette player. The test tone at the start of the
70 tapes is pretty accurate, and the new tapes should not have had much opportunity
71 to stretch. It is believed these transcriptions are about as good as the source
72 material permits.
73 
74 PLEASE NOTE
75 
76 These transcriptions may be freely used by anyone who has a legitimate copy of
77 the original tapes. However, if you don't have a legitimate copy of those tapes,
78 you also have no right to use this data. The original tapes are the copyright
79 material of BellCore, and they charge over US$200 for a set. I doubt they sell
80 enough copies to consider this much of a business. However, it is their data,
81 and it is their right to do as they wish with it. Currently I see no indication
82 they wish to give it away for free.
83 */
84 
85 #if defined(HAVE_CONFIG_H)
86 #include "config.h"
87 #endif
88 
89 #include <stdlib.h>
90 #include <string.h>
91 #include <stdio.h>
92 #include <fcntl.h>
93 #include <unistd.h>
94 #include <time.h>
95 #include <sndfile.h>
96 
97 #include "spandsp.h"
98 #include "spandsp-sim.h"
99 
100 /* Basic DTMF specs:
101  *
102  * Minimum tone on = 40ms
103  * Minimum tone off = 50ms
104  * Maximum digit rate = 10 per second
105  * Normal twist <= 8dB accepted
106  * Reverse twist <= 4dB accepted
107  * S/N >= 15dB will detect OK
108  * Attenuation <= 26dB will detect OK
109  * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
110  */
111 
112 #define DEFAULT_DTMF_TX_LEVEL       -10
113 #define DEFAULT_DTMF_TX_ON_TIME     50
114 #define DEFAULT_DTMF_TX_OFF_TIME    50
115 
116 #define SAMPLES_PER_CHUNK           160
117 
118 #define ALL_POSSIBLE_DIGITS         "123A456B789C*0#D"
119 
120 #define MITEL_DIR                   "../test-data/mitel/"
121 #define BELLCORE_DIR                "../test-data/bellcore/"
122 
123 const char *bellcore_files[] =
124 {
125     MITEL_DIR    "mitel-cm7291-talkoff.wav",
126     BELLCORE_DIR "tr-tsy-00763-1.wav",
127     BELLCORE_DIR "tr-tsy-00763-2.wav",
128     BELLCORE_DIR "tr-tsy-00763-3.wav",
129     BELLCORE_DIR "tr-tsy-00763-4.wav",
130     BELLCORE_DIR "tr-tsy-00763-5.wav",
131     BELLCORE_DIR "tr-tsy-00763-6.wav",
132     ""
133 };
134 
135 static tone_gen_descriptor_t my_dtmf_digit_tones[16];
136 
137 float dtmf_row[] =
138 {
139      697.0f,  770.0f,  852.0f,  941.0f
140 };
141 float dtmf_col[] =
142 {
143     1209.0f, 1336.0f, 1477.0f, 1633.0f
144 };
145 
146 char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
147 
148 bool callback_hit;
149 bool callback_ok;
150 int callback_roll;
151 int step;
152 
153 float max_forward_twist;
154 float max_reverse_twist;
155 
156 bool use_dialtone_filter = false;
157 
158 char *decode_test_file = NULL;
159 
160 static int16_t amp[1000000];
161 static int16_t amp2[1000000];
162 
163 codec_munge_state_t *munge = NULL;
164 
my_dtmf_gen_init(float low_fudge,int low_level,float high_fudge,int high_level,int duration,int gap)165 static void my_dtmf_gen_init(float low_fudge,
166                              int low_level,
167                              float high_fudge,
168                              int high_level,
169                              int duration,
170                              int gap)
171 {
172     int row;
173     int col;
174 
175     for (row = 0;  row < 4;  row++)
176     {
177         for (col = 0;  col < 4;  col++)
178         {
179             tone_gen_descriptor_init(&my_dtmf_digit_tones[row*4 + col],
180                                      dtmf_row[row]*(1.0f + low_fudge),
181                                      low_level,
182                                      dtmf_col[col]*(1.0f + high_fudge),
183                                      high_level,
184                                      duration,
185                                      gap,
186                                      0,
187                                      0,
188                                      false);
189         }
190     }
191 }
192 /*- End of function --------------------------------------------------------*/
193 
my_dtmf_generate(int16_t amp[],const char * digits)194 static int my_dtmf_generate(int16_t amp[], const char *digits)
195 {
196     int len;
197     char *cp;
198     tone_gen_state_t tone;
199 
200     len = 0;
201     while (*digits)
202     {
203         cp = strchr(dtmf_positions, *digits);
204         if (cp)
205         {
206             tone_gen_init(&tone, &my_dtmf_digit_tones[cp - dtmf_positions]);
207             len += tone_gen(&tone, amp + len, 1000);
208         }
209         digits++;
210     }
211     return len;
212 }
213 /*- End of function --------------------------------------------------------*/
214 
digit_delivery(void * data,const char * digits,int len)215 static void digit_delivery(void *data, const char *digits, int len)
216 {
217     int i;
218     int seg;
219     const char *s = ALL_POSSIBLE_DIGITS;
220     const char *t;
221 
222     callback_hit = true;
223     if (data == (void *) 0x12345678)
224     {
225         t = s + callback_roll;
226         seg = 16 - callback_roll;
227         for (i = 0;  i < len;  i += seg, seg = 16)
228         {
229             if (i + seg > len)
230                 seg = len - i;
231             if (memcmp(digits + i, t, seg))
232             {
233                 callback_ok = false;
234                 printf("Fail at %d %d\n", i, seg);
235                 break;
236             }
237             t = s;
238             callback_roll = (callback_roll + seg)%16;
239         }
240     }
241     else
242     {
243         callback_ok = false;
244     }
245 }
246 /*- End of function --------------------------------------------------------*/
247 
digit_status(void * data,int signal,int level,int delay)248 static void digit_status(void *data, int signal, int level, int delay)
249 {
250     const char *s = ALL_POSSIBLE_DIGITS;
251     int len;
252     static int last_step = 0;
253     static int first = true;
254 
255     //printf("Digit status %d %d %d\n", signal, level, delay);
256     callback_hit = true;
257     len = step - last_step;
258     if (data == (void *) 0x12345678)
259     {
260         if (len < 320  ||  len > 480)
261         {
262             if (first)
263             {
264                 /* At the beginning the apparent duration is expected to be wrong */
265                 first = false;
266             }
267             else
268             {
269                 printf("Failed for signal %s length %d at %d\n", (callback_roll & 1)  ?  "on"  :  "off", len, step);
270                 callback_ok = false;
271             }
272         }
273         if (callback_roll & 1)
274         {
275             if (signal != 0)
276             {
277                 printf("Failed for signal 0x%X instead of 0\n", signal);
278                 callback_ok = false;
279             }
280         }
281         else
282         {
283             if (signal != s[callback_roll >> 1])
284             {
285                 printf("Failed for signal 0x%X instead of 0x%X\n", signal, s[callback_roll >> 1]);
286                 callback_ok = false;
287             }
288             if (level < DEFAULT_DTMF_TX_LEVEL + 3 - 1  ||  level > DEFAULT_DTMF_TX_LEVEL + 3 + 1)
289             {
290                 printf("Failed for level %d instead of %d\n", level, DEFAULT_DTMF_TX_LEVEL + 3);
291                 callback_ok = false;
292             }
293         }
294         if (++callback_roll >= 32)
295             callback_roll = 0;
296     }
297     else
298     {
299         callback_ok = false;
300     }
301     last_step = step;
302 }
303 /*- End of function --------------------------------------------------------*/
304 
mitel_cm7291_side_1_tests(void)305 static void mitel_cm7291_side_1_tests(void)
306 {
307     int i;
308     int j;
309     int len;
310     int sample;
311     const char *s;
312     char digit[2];
313     char buf[128 + 1];
314     int actual;
315     int nplus;
316     int nminus;
317     float rrb;
318     float rcfo;
319     dtmf_rx_state_t *dtmf_state;
320     awgn_state_t noise_source;
321     logging_state_t *logging;
322 
323     dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
324     if (use_dialtone_filter  ||  max_forward_twist >= 0.0f  ||  max_reverse_twist >= 0.0f)
325         dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f);
326     logging = dtmf_rx_get_logging_state(dtmf_state);
327     span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
328     span_log_set_tag(logging, "DTMF-rx");
329 
330     /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step,
331        which has no meaning here. */
332     printf("Test 1: Calibration\n");
333     printf("    Passed\n");
334 
335     /* Test 2: Decode check
336        This is a sanity check, that all digits are reliably detected
337        under ideal conditions.  Each possible digit repeated 10 times,
338        with 50ms bursts. The level of each tone is about 6dB down from clip.
339        6dB down actually causes trouble with G.726, so we use 7dB down. */
340     printf("Test 2: Decode check\n");
341     my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50);
342     s = ALL_POSSIBLE_DIGITS;
343     digit[1] = '\0';
344     while (*s)
345     {
346         digit[0] = *s++;
347         for (i = 0;  i < 10;  i++)
348         {
349             len = my_dtmf_generate(amp, digit);
350             codec_munge(munge, amp, len);
351             dtmf_rx(dtmf_state, amp, len);
352 
353             actual = dtmf_rx_get(dtmf_state, buf, 128);
354 
355             if (actual != 1  ||  buf[0] != digit[0])
356             {
357                 printf("    Sent     '%s'\n", digit);
358                 printf("    Received '%s'\n", buf);
359                 printf("    Failed\n");
360                 exit(2);
361             }
362         }
363     }
364     printf("    Passed\n");
365 
366     /* Test 3: Recognition bandwidth and channel centre frequency check.
367        Use only the diagonal pairs of tones (digits 1, 5, 9 and D). Each
368        tone pair requires four test to complete the check, making 16
369        sections overall. Each section contains 40 pulses of
370        50ms duration, with an amplitude of -20dB from clip per
371        frequency.
372 
373        Four sections covering the tests for one tone (1 digit) are:
374        a. H frequency at 0% deviation from center, L frequency at +0.1%.
375           L frequency is then increments in +01.% steps up to +4%. The
376           number of tone bursts is noted and designated N+.
377        b. H frequency at 0% deviation, L frequency at -0.1%. L frequency
378           is then incremental in -0.1% steps, up to -4%. The number of
379           tone bursts is noted and designated N-.
380        c. The test in (a) is repeated with the L frequency at 0% and the
381           H frequency varied up to +4%.
382        d. The test in (b) is repeated with the L frequency and 0% and the
383           H frequency varied to -4%.
384 
385        Receiver Recognition Bandwidth (RRB) is calculated as follows:
386             RRB% = (N+ + N-)/10
387        Receiver Center Frequency Offset (RCFO) is calculated as follows:
388             RCFO% = X + (N+ - N-)/20
389 
390        Note that this test doesn't test what it says it is testing at all,
391        and the results are quite inaccurate, if not a downright lie! However,
392        it follows the Mitel procedure, so how can it be bad? :)
393     */
394     printf("Test 3: Recognition bandwidth and channel centre frequency check\n");
395     s = "159D";
396     digit[1] = '\0';
397     while (*s)
398     {
399         digit[0] = *s++;
400         for (nplus = 0, i = 1;  i <= 60;  i++)
401         {
402             my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50);
403             len = my_dtmf_generate(amp, digit);
404             codec_munge(munge, amp, len);
405             dtmf_rx(dtmf_state, amp, len);
406             nplus += dtmf_rx_get(dtmf_state, buf, 128);
407         }
408         for (nminus = 0, i = -1;  i >= -60;  i--)
409         {
410             my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50);
411             len = my_dtmf_generate(amp, digit);
412             codec_munge(munge, amp, len);
413             dtmf_rx(dtmf_state, amp, len);
414             nminus += dtmf_rx_get(dtmf_state, buf, 128);
415         }
416         rrb = (float) (nplus + nminus)/10.0f;
417         rcfo = (float) (nplus - nminus)/10.0f;
418         printf("    %c (low)  rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
419                digit[0],
420                rrb,
421                rcfo,
422                (float) nminus/10.0f,
423                (float) nplus/10.0f);
424         if (rrb < 3.0f + rcfo  ||  rrb >= 15.0f + rcfo)
425         {
426             printf("    Failed\n");
427             exit(2);
428         }
429 
430         for (nplus = 0, i = 1;  i <= 60;  i++)
431         {
432             my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50);
433             len = my_dtmf_generate(amp, digit);
434             codec_munge(munge, amp, len);
435             dtmf_rx(dtmf_state, amp, len);
436             nplus += dtmf_rx_get(dtmf_state, buf, 128);
437         }
438         for (nminus = 0, i = -1;  i >= -60;  i--)
439         {
440             my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50);
441             len = my_dtmf_generate(amp, digit);
442             codec_munge(munge, amp, len);
443             dtmf_rx(dtmf_state, amp, len);
444             nminus += dtmf_rx_get(dtmf_state, buf, 128);
445         }
446         rrb = (float) (nplus + nminus)/10.0f;
447         rcfo = (float) (nplus - nminus)/10.0f;
448         printf("    %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
449                digit[0],
450                rrb,
451                rcfo,
452                (float) nminus/10.0f,
453                (float) nplus/10.0f);
454         if (rrb < 3.0f + rcfo  ||  rrb >= 15.0f + rcfo)
455         {
456             printf("    Failed\n");
457             exit(2);
458         }
459     }
460     printf("    Passed\n");
461 
462     /* Test 4: Acceptable amplitude ratio (twist).
463        Use only the diagonal pairs of tones (digits 1, 5, 9 and D).
464        There are eight sections to the test. Each section contains 200
465        pulses with a 50ms duration for each pulse. Initially the amplitude
466        of both tones is 6dB down from clip. The two sections to test one
467        tone pair are:
468 
469        a. Standard Twist: H tone amplitude is maintained at -6dB from clip,
470           L tone amplitude is attenuated gradually until the amplitude ratio
471           L/H is -20dB. Note the number of responses from the receiver.
472        b. Reverse Twist: L tone amplitude is maintained at -6dB from clip,
473           H tone amplitude is attenuated gradually until the amplitude ratio
474           is 20dB. Note the number of responses from the receiver.
475 
476        All tone bursts are of 50ms duration.
477 
478        The Acceptable Amplitude Ratio in dB is equal to the number of
479        responses registered in (a) or (b), divided by 10.
480 
481        TODO: This is supposed to work in 1/10dB steps, but here I used 1dB
482              steps, as the current tone generator has its amplitude set in
483              1dB steps.
484     */
485     printf("Test 4: Acceptable amplitude ratio (twist)\n");
486     s = "159D";
487     digit[1] = '\0';
488     while (*s)
489     {
490         digit[0] = *s++;
491         for (nplus = 0, i = -30;  i >= -230;  i--)
492         {
493             my_dtmf_gen_init(0.0f, -3, 0.0f, i/10, 50, 50);
494 
495             len = my_dtmf_generate(amp, digit);
496             codec_munge(munge, amp, len);
497             dtmf_rx(dtmf_state, amp, len);
498             nplus += dtmf_rx_get(dtmf_state, buf, 128);
499         }
500         printf("    %c normal twist  = %.2fdB\n", digit[0], (float) nplus/10.0);
501         if (nplus < 80)
502         {
503             printf("    Failed\n");
504             exit(2);
505         }
506         for (nminus = 0, i = -30;  i >= -230;  i--)
507         {
508             my_dtmf_gen_init(0.0f, i/10, 0.0f, -3, 50, 50);
509 
510             len = my_dtmf_generate(amp, digit);
511             codec_munge(munge, amp, len);
512             dtmf_rx(dtmf_state, amp, len);
513             nminus += dtmf_rx_get(dtmf_state, buf, 128);
514         }
515         printf("    %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0);
516         if (nminus < 40)
517         {
518             printf("    Failed\n");
519             exit(2);
520         }
521     }
522     printf("    Passed\n");
523 
524     /* Test 5: Dynamic range
525        This test utilizes tone pair L1 H1 (digit 1). Thirty-five tone pair
526        pulses are transmitted, with both frequencies stating at -6dB from
527        clip. The amplitude of each is gradually attenuated by -35dB at a
528        rate of 1dB per pulse. The Dynamic Range in dB is equal to the
529        number of responses from the receiver during the test.
530 
531        Well not really, but that is the Mitel test. Lets sweep a bit further,
532        and see what the real range is */
533     printf("Test 5: Dynamic range\n");
534     for (nplus = 0, i = +3;  i >= -50;  i--)
535     {
536         my_dtmf_gen_init(0.0f, i, 0.0f, i, 50, 50);
537 
538         len = my_dtmf_generate(amp, "1");
539         codec_munge(munge, amp, len);
540         dtmf_rx(dtmf_state, amp, len);
541         nplus += dtmf_rx_get(dtmf_state, buf, 128);
542     }
543     printf("    Dynamic range = %ddB\n", nplus);
544     /* We ought to set some pass/fail condition, even if Mitel did not. If
545        we don't, regression testing is weakened. */
546     if (nplus < 35)
547     {
548         printf("    Failed\n");
549         exit(2);
550     }
551     printf("    Passed\n");
552 
553     /* Test 6: Guard time
554        This test utilizes tone pair L1 H1 (digit 1). Four hundred pulses
555        are transmitted at an amplitude of -6dB from clip per frequency.
556        Pulse duration starts at 49ms and is gradually reduced to 10ms.
557        Guard time in ms is equal to (500 - number of responses)/10.
558 
559        That is the Mitel test, and we will follow it. Its totally bogus,
560        though. Just what the heck is a pass or fail here? */
561 
562     printf("Test 6: Guard time\n");
563     for (nplus = 0, i = 490;  i >= 100;  i--)
564     {
565         my_dtmf_gen_init(0.0f, -3, 0.0f, -3, i/10, 50);
566 
567         len = my_dtmf_generate(amp, "1");
568         codec_munge(munge, amp, len);
569         dtmf_rx(dtmf_state, amp, len);
570         nplus += dtmf_rx_get(dtmf_state, buf, 128);
571     }
572     printf("    Guard time = %dms\n", (500 - nplus)/10);
573     printf("    Passed\n");
574 
575     /* Test 7: Acceptable signal to noise ratio
576        This test utilizes tone pair L1 H1, transmitted on a noise background.
577        The test consists of three sections in which the tone pair is
578        transmitted 1000 times at an amplitude -6dB from clip per frequency,
579        but with a different white noise level for each section. The first
580        level is -24dBV, the second -18dBV and the third -12dBV.. The
581        acceptable signal to noise ratio is the lowest ratio of signal
582        to noise in the test where the receiver responds to all 1000 pulses.
583 
584        Well, that is the Mitel test, but it doesn't tell you what the
585        decoder can really do. Lets do a more comprehensive test */
586 
587     printf("Test 7: Acceptable signal to noise ratio\n");
588     my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50);
589 
590     for (j = -13;  j > -50;  j--)
591     {
592         awgn_init_dbm0(&noise_source, 1234567, (float) j);
593         for (i = 0;  i < 1000;  i++)
594         {
595             len = my_dtmf_generate(amp, "1");
596 
597             // TODO: Clip
598             for (sample = 0;  sample < len;  sample++)
599                 amp[sample] = sat_add16(amp[sample], awgn(&noise_source));
600 
601             codec_munge(munge, amp, len);
602             dtmf_rx(dtmf_state, amp, len);
603 
604             if (dtmf_rx_get(dtmf_state, buf, 128) != 1)
605                 break;
606         }
607         if (i == 1000)
608             break;
609     }
610     printf("    Acceptable S/N ratio is %ddB\n", -4 - j);
611     if (-4 - j > 26)
612     {
613         printf("    Failed\n");
614         exit(2);
615     }
616     dtmf_rx_free(dtmf_state);
617     printf("    Passed\n");
618 }
619 /*- End of function --------------------------------------------------------*/
620 
mitel_cm7291_side_2_and_bellcore_tests(void)621 static void mitel_cm7291_side_2_and_bellcore_tests(void)
622 {
623     int i;
624     int j;
625     int len;
626     int hits;
627     int hit_types[256];
628     char buf[128 + 1];
629     SNDFILE *inhandle;
630     int frames;
631     dtmf_rx_state_t *dtmf_state;
632     logging_state_t *logging;
633 
634     dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
635     if (use_dialtone_filter  ||  max_forward_twist >= 0.0f  ||  max_reverse_twist >= 0.0f)
636         dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f);
637     logging = dtmf_rx_get_logging_state(dtmf_state);
638     span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
639     span_log_set_tag(logging, "DTMF-rx");
640 
641     /* The remainder of the Mitel tape is the talk-off test */
642     /* Here we use the Bellcore test tapes (much tougher), in six
643       files - 1 from each side of the original 3 cassette tapes */
644     /* Bellcore say you should get no more than 470 false detections with
645        a good receiver. Dialogic claim 20. Of course, we can do better than
646        that, eh? */
647     printf("Test 8: Talk-off test\n");
648     memset(hit_types, '\0', sizeof(hit_types));
649     for (j = 0;  bellcore_files[j][0];  j++)
650     {
651         if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL)
652         {
653             printf("    Cannot open speech file '%s'\n", bellcore_files[j]);
654             exit(2);
655         }
656         hits = 0;
657         while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE)))
658         {
659             dtmf_rx(dtmf_state, amp, frames);
660             len = dtmf_rx_get(dtmf_state, buf, 128);
661             if (len > 0)
662             {
663                 for (i = 0;  i < len;  i++)
664                     hit_types[(int) buf[i]]++;
665                 hits += len;
666             }
667         }
668         if (sf_close_telephony(inhandle))
669         {
670             printf("    Cannot close speech file '%s'\n", bellcore_files[j]);
671             exit(2);
672         }
673         printf("    File %d gave %d false hits.\n", j + 1, hits);
674     }
675     for (i = 0, j = 0;  i < 256;  i++)
676     {
677         if (hit_types[i])
678         {
679             printf("    Digit %c had %d false hits.\n", i, hit_types[i]);
680             j += hit_types[i];
681         }
682     }
683     printf("    %d false hits in total.\n", j);
684     if (j > 470)
685     {
686         printf("    Failed\n");
687         exit(2);
688     }
689     printf("    Passed\n");
690     dtmf_rx_free(dtmf_state);
691 }
692 /*- End of function --------------------------------------------------------*/
693 
dial_tone_tolerance_tests(void)694 static void dial_tone_tolerance_tests(void)
695 {
696     int i;
697     int j;
698     int len;
699     int sample;
700     char buf[128 + 1];
701     dtmf_rx_state_t *dtmf_state;
702     tone_gen_descriptor_t dial_tone_desc;
703     tone_gen_state_t dial_tone;
704     logging_state_t *logging;
705 
706     dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
707     if (use_dialtone_filter  ||  max_forward_twist >= 0.0f  ||  max_reverse_twist >= 0.0f)
708         dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f);
709     logging = dtmf_rx_get_logging_state(dtmf_state);
710     span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
711     span_log_set_tag(logging, "DTMF-rx");
712 
713     /* Test dial tone tolerance */
714     printf("Test: Dial tone tolerance.\n");
715     my_dtmf_gen_init(0.0f, -15, 0.0f, -15, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME);
716 
717     for (j = -30;  j < -3;  j++)
718     {
719         tone_gen_descriptor_init(&dial_tone_desc, 350, j, 440, j, 1, 0, 0, 0, true);
720         tone_gen_init(&dial_tone, &dial_tone_desc);
721         for (i = 0;  i < 10;  i++)
722         {
723             len = my_dtmf_generate(amp, ALL_POSSIBLE_DIGITS);
724             tone_gen(&dial_tone, amp2, len);
725 
726             for (sample = 0;  sample < len;  sample++)
727                 amp[sample] = sat_add16(amp[sample], amp2[sample]);
728             codec_munge(munge, amp, len);
729             dtmf_rx(dtmf_state, amp, len);
730 
731             if (dtmf_rx_get(dtmf_state, buf, 128) != strlen(ALL_POSSIBLE_DIGITS))
732                 break;
733         }
734         if (i != 10)
735             break;
736     }
737     printf("    Acceptable signal to dial tone ratio is %ddB\n", -15 - j);
738     if ((use_dialtone_filter  &&  (-15 - j) > -12)
739         ||
740         (!use_dialtone_filter  &&  (-15 - j) > 10))
741     {
742         printf("    Failed\n");
743         exit(2);
744     }
745     printf("    Passed\n");
746     dtmf_rx_free(dtmf_state);
747 }
748 /*- End of function --------------------------------------------------------*/
749 
callback_function_tests(void)750 static void callback_function_tests(void)
751 {
752     int i;
753     int j;
754     int len;
755     int sample;
756     dtmf_rx_state_t *dtmf_state;
757     logging_state_t *logging;
758 
759     /* Test the callback mode for delivering detected digits */
760     printf("Test: Callback digit delivery mode.\n");
761     callback_hit = false;
762     callback_ok = true;
763     callback_roll = 0;
764     dtmf_state = dtmf_rx_init(NULL, digit_delivery, (void *) 0x12345678);
765     if (use_dialtone_filter  ||  max_forward_twist >= 0.0f  ||  max_reverse_twist >= 0.0f)
766         dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f);
767     logging = dtmf_rx_get_logging_state(dtmf_state);
768     span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
769     span_log_set_tag(logging, "DTMF-rx");
770 
771     my_dtmf_gen_init(0.0f, DEFAULT_DTMF_TX_LEVEL, 0.0f, DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME);
772     for (i = 1;  i < 10;  i++)
773     {
774         len = 0;
775         for (j = 0;  j < i;  j++)
776             len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS);
777         dtmf_rx(dtmf_state, amp, len);
778         if (!callback_hit  ||  !callback_ok)
779             break;
780     }
781     if (!callback_hit  ||  !callback_ok)
782     {
783         printf("    Failed\n");
784         exit(2);
785     }
786     printf("    Passed\n");
787 
788     /* Test the realtime callback mode for reporting detected digits */
789     printf("Test: Realtime callback digit delivery mode.\n");
790     callback_hit = false;
791     callback_ok = true;
792     callback_roll = 0;
793     dtmf_rx_init(dtmf_state, NULL, NULL);
794     dtmf_rx_set_realtime_callback(dtmf_state, digit_status, (void *) 0x12345678);
795     if (use_dialtone_filter  ||  max_forward_twist >= 0.0f  ||  max_reverse_twist >= 0.0f)
796         dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f);
797     logging = dtmf_rx_get_logging_state(dtmf_state);
798     span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
799     span_log_set_tag(logging, "DTMF-rx");
800 
801     my_dtmf_gen_init(0.0f, DEFAULT_DTMF_TX_LEVEL, 0.0f, DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME);
802     step = 0;
803     for (i = 1;  i < 10;  i++)
804     {
805         len = 0;
806         for (j = 0;  j < i;  j++)
807             len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS);
808         for (sample = 0, j = SAMPLES_PER_CHUNK;  sample < len;  sample += SAMPLES_PER_CHUNK, j = ((len - sample) >= SAMPLES_PER_CHUNK)  ?  SAMPLES_PER_CHUNK  :  (len - sample))
809         {
810             dtmf_rx(dtmf_state, &amp[sample], j);
811             if (!callback_ok)
812                 break;
813             step += j;
814         }
815         if (!callback_hit  ||  !callback_ok)
816             break;
817     }
818     if (!callback_hit  ||  !callback_ok)
819     {
820         printf("    Failed\n");
821         exit(2);
822     }
823     dtmf_rx_free(dtmf_state);
824 }
825 /*- End of function --------------------------------------------------------*/
826 
decode_test(const char * test_file)827 static void decode_test(const char *test_file)
828 {
829     int16_t amp[SAMPLES_PER_CHUNK];
830     SNDFILE *inhandle;
831     dtmf_rx_state_t *dtmf_state;
832     char buf[128 + 1];
833     int actual;
834     int samples;
835     int total;
836     logging_state_t *logging;
837 
838     dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
839     if (use_dialtone_filter  ||  max_forward_twist >= 0.0f  ||  max_reverse_twist >= 0.0f)
840         dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f);
841     logging = dtmf_rx_get_logging_state(dtmf_state);
842     span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
843     span_log_set_tag(logging, "DTMF-rx");
844 
845     /* We will decode the audio from a file. */
846 
847     if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
848     {
849         fprintf(stderr, "    Cannot open audio file '%s'\n", decode_test_file);
850         exit(2);
851     }
852 
853     total = 0;
854     while ((samples = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK)) > 0)
855     {
856         codec_munge(munge, amp, samples);
857         dtmf_rx(dtmf_state, amp, samples);
858         //printf("Status 0x%X\n", dtmf_rx_status(dtmf_state));
859         if ((actual = dtmf_rx_get(dtmf_state, buf, 128)) > 0)
860             printf("Received '%s'\n", buf);
861         total += actual;
862     }
863     printf("%d digits received\n", total);
864 }
865 /*- End of function --------------------------------------------------------*/
866 
main(int argc,char * argv[])867 int main(int argc, char *argv[])
868 {
869     int duration;
870     time_t now;
871     int channel_codec;
872     int opt;
873 
874     use_dialtone_filter = false;
875     channel_codec = MUNGE_CODEC_NONE;
876     decode_test_file = NULL;
877     max_forward_twist = -1.0f;
878     max_reverse_twist = -1.0f;
879     while ((opt = getopt(argc, argv, "c:d:F:fR:")) != -1)
880     {
881         switch (opt)
882         {
883         case 'c':
884             channel_codec = atoi(optarg);
885             break;
886         case 'd':
887             decode_test_file = optarg;
888             break;
889         case 'F':
890             max_forward_twist = atof(optarg);
891             break;
892         case 'f':
893             use_dialtone_filter = true;
894             break;
895         case 'R':
896             max_reverse_twist = atof(optarg);
897             break;
898         default:
899             //usage();
900             exit(2);
901             break;
902         }
903     }
904     munge = codec_munge_init(channel_codec, 0);
905 
906     if (decode_test_file)
907     {
908         decode_test(decode_test_file);
909     }
910     else
911     {
912         time(&now);
913         mitel_cm7291_side_1_tests();
914         mitel_cm7291_side_2_and_bellcore_tests();
915         dial_tone_tolerance_tests();
916         callback_function_tests();
917         printf("    Passed\n");
918         duration = time(NULL) - now;
919         printf("Tests passed in %ds\n", duration);
920     }
921 
922     codec_munge_free(munge);
923     return 0;
924 }
925 /*- End of function --------------------------------------------------------*/
926 /*- End of file ------------------------------------------------------------*/
927