dtmf_rx_tests.c 31 KB

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