1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * dtmf.c - DTMF generation and detection.
5  *
6  * Written by Steve Underwood <steveu@coppice.org>
7  *
8  * Copyright (C) 2001-2003, 2005, 2006 Steve Underwood
9  *
10  * All rights reserved.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 2.1,
14  * as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  * $Id: dtmf.c,v 1.43 2008/07/02 14:48:25 steveu Exp $
26  */
27 
28 /*! \file dtmf.h */
29 
30 #if defined(HAVE_CONFIG_H)
31 #include "config.h"
32 #endif
33 
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include "floating_fudge.h"
37 #if defined(HAVE_TGMATH_H)
38 #include <tgmath.h>
39 #endif
40 #if defined(HAVE_MATH_H)
41 #include <math.h>
42 #endif
43 #include <string.h>
44 #include <stdio.h>
45 #include <time.h>
46 #include <fcntl.h>
47 
48 #include "spandsp/telephony.h"
49 #include "spandsp/queue.h"
50 #include "spandsp/complex.h"
51 #include "spandsp/dds.h"
52 #include "spandsp/tone_detect.h"
53 #include "spandsp/tone_generate.h"
54 #include "spandsp/super_tone_rx.h"
55 #include "spandsp/dtmf.h"
56 
57 #define DEFAULT_DTMF_TX_LEVEL       -10
58 #define DEFAULT_DTMF_TX_ON_TIME     50
59 #define DEFAULT_DTMF_TX_OFF_TIME    55
60 
61 #if defined(SPANDSP_USE_FIXED_POINT)
62 #define DTMF_THRESHOLD              10438           /* -42dBm0 */
63 #define DTMF_NORMAL_TWIST           6.309f          /* 8dB */
64 #define DTMF_REVERSE_TWIST          2.512f          /* 4dB */
65 #define DTMF_RELATIVE_PEAK_ROW      6.309f          /* 8dB */
66 #define DTMF_RELATIVE_PEAK_COL      6.309f          /* 8dB */
67 #define DTMF_TO_TOTAL_ENERGY        83.868f         /* -0.85dB */
68 #define DTMF_POWER_OFFSET           68.251f         /* 10*log(256.0*256.0*DTMF_SAMPLES_PER_BLOCK) */
69 #define DTMF_SAMPLES_PER_BLOCK      102
70 #else
71 #define DTMF_THRESHOLD              171032462.0f    /* -42dBm0 [((DTMF_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2 => 171032462.0] */
72 #define DTMF_NORMAL_TWIST           6.309f          /* 8dB [10^(8/10) => 6.309] */
73 #define DTMF_REVERSE_TWIST          2.512f          /* 4dB */
74 #define DTMF_RELATIVE_PEAK_ROW      6.309f          /* 8dB */
75 #define DTMF_RELATIVE_PEAK_COL      6.309f          /* 8dB */
76 #define DTMF_TO_TOTAL_ENERGY        83.868f         /* -0.85dB [DTMF_SAMPLES_PER_BLOCK*10^(-0.85/10.0)] */
77 #define DTMF_POWER_OFFSET           110.395f        /* 10*log(32768.0*32768.0*DTMF_SAMPLES_PER_BLOCK) */
78 #define DTMF_SAMPLES_PER_BLOCK      102
79 #endif
80 
81 static const float dtmf_row[] =
82 {
83      697.0f,  770.0f,  852.0f,  941.0f
84 };
85 static const float dtmf_col[] =
86 {
87     1209.0f, 1336.0f, 1477.0f, 1633.0f
88 };
89 
90 static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
91 
92 static goertzel_descriptor_t dtmf_detect_row[4];
93 static goertzel_descriptor_t dtmf_detect_col[4];
94 
95 static int dtmf_tx_inited = FALSE;
96 static tone_gen_descriptor_t dtmf_digit_tones[16];
97 
dtmf_rx(dtmf_rx_state_t * s,const int16_t amp[],int samples)98 int dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples)
99 {
100 #if defined(SPANDSP_USE_FIXED_POINT)
101     int32_t row_energy[4];
102     int32_t col_energy[4];
103     int16_t xamp;
104     float famp;
105 #else
106     float row_energy[4];
107     float col_energy[4];
108     float xamp;
109     float famp;
110 #endif
111     float v1;
112     int i;
113     int j;
114     int sample;
115     int best_row;
116     int best_col;
117     int limit;
118     uint8_t hit;
119 
120     hit = 0;
121     for (sample = 0;  sample < samples;  sample = limit)
122     {
123         /* The block length is optimised to meet the DTMF specs. */
124         if ((samples - sample) >= (DTMF_SAMPLES_PER_BLOCK - s->current_sample))
125             limit = sample + (DTMF_SAMPLES_PER_BLOCK - s->current_sample);
126         else
127             limit = samples;
128         /* The following unrolled loop takes only 35% (rough estimate) of the
129            time of a rolled loop on the machine on which it was developed */
130         for (j = sample;  j < limit;  j++)
131         {
132             xamp = amp[j];
133             if (s->filter_dialtone)
134             {
135                 famp = xamp;
136                 /* Sharp notches applied at 350Hz and 440Hz - the two common dialtone frequencies.
137                    These are rather high Q, to achieve the required narrowness, without using lots of
138                    sections. */
139                 v1 = 0.98356f*famp + 1.8954426f*s->z350[0] - 0.9691396f*s->z350[1];
140                 famp = v1 - 1.9251480f*s->z350[0] + s->z350[1];
141                 s->z350[1] = s->z350[0];
142                 s->z350[0] = v1;
143 
144                 v1 = 0.98456f*famp + 1.8529543f*s->z440[0] - 0.9691396f*s->z440[1];
145                 famp = v1 - 1.8819938f*s->z440[0] + s->z440[1];
146                 s->z440[1] = s->z440[0];
147                 s->z440[0] = v1;
148                 xamp = famp;
149             }
150             xamp = goertzel_preadjust_amp(xamp);
151 #if defined(SPANDSP_USE_FIXED_POINT)
152             s->energy += ((int32_t) xamp*xamp);
153 #else
154             s->energy += xamp*xamp;
155 #endif
156             goertzel_samplex(&s->row_out[0], xamp);
157             goertzel_samplex(&s->col_out[0], xamp);
158             goertzel_samplex(&s->row_out[1], xamp);
159             goertzel_samplex(&s->col_out[1], xamp);
160             goertzel_samplex(&s->row_out[2], xamp);
161             goertzel_samplex(&s->col_out[2], xamp);
162             goertzel_samplex(&s->row_out[3], xamp);
163             goertzel_samplex(&s->col_out[3], xamp);
164         }
165         s->current_sample += (limit - sample);
166         if (s->current_sample < DTMF_SAMPLES_PER_BLOCK)
167             continue;
168 
169         /* We are at the end of a DTMF detection block */
170         /* Find the peak row and the peak column */
171         row_energy[0] = goertzel_result(&s->row_out[0]);
172         best_row = 0;
173         col_energy[0] = goertzel_result(&s->col_out[0]);
174         best_col = 0;
175         for (i = 1;  i < 4;  i++)
176         {
177             row_energy[i] = goertzel_result(&s->row_out[i]);
178             if (row_energy[i] > row_energy[best_row])
179                 best_row = i;
180             col_energy[i] = goertzel_result(&s->col_out[i]);
181             if (col_energy[i] > col_energy[best_col])
182                 best_col = i;
183         }
184         hit = 0;
185         /* Basic signal level test and the twist test */
186         if (row_energy[best_row] >= s->threshold
187             &&
188             col_energy[best_col] >= s->threshold
189             &&
190             col_energy[best_col] < row_energy[best_row]*s->reverse_twist
191             &&
192             col_energy[best_col]*s->normal_twist > row_energy[best_row])
193         {
194             /* Relative peak test ... */
195             for (i = 0;  i < 4;  i++)
196             {
197                 if ((i != best_col  &&  col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col])
198                     ||
199                     (i != best_row  &&  row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row]))
200                 {
201                     break;
202                 }
203             }
204             /* ... and fraction of total energy test */
205             if (i >= 4
206                 &&
207                 (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->energy)
208             {
209                 /* Got a hit */
210                 hit = dtmf_positions[(best_row << 2) + best_col];
211             }
212         }
213         /* The logic in the next test should ensure the following for different successive hit patterns:
214                 -----ABB = start of digit B.
215                 ----B-BB = start of digit B
216                 ----A-BB = start of digit B
217                 BBBBBABB = still in digit B.
218                 BBBBBB-- = end of digit B
219                 BBBBBBC- = end of digit B
220                 BBBBACBB = B ends, then B starts again.
221                 BBBBBBCC = B ends, then C starts.
222                 BBBBBCDD = B ends, then D starts.
223            This can work with:
224                 - Back to back differing digits. Back-to-back digits should
225                   not happen. The spec. says there should be a gap between digits.
226                   However, many real phones do not impose a gap, and rolling across
227                   the keypad can produce little or no gap.
228                 - It tolerates nasty phones that give a very wobbly start to a digit.
229                 - VoIP can give sample slips. The phase jumps that produces will cause
230                   the block it is in to give no detection. This logic will ride over a
231                   single missed block, and not falsely declare a second digit. If the
232                   hiccup happens in the wrong place on a minimum length digit, however
233                   we would still fail to detect that digit. Could anything be done to
234                   deal with that? Packet loss is clearly a no-go zone.
235                   Note this is only relevant to VoIP using A-law, u-law or similar.
236                   Low bit rate codecs scramble DTMF too much for it to be recognised,
237                   and often slip in units larger than a sample. */
238         if (hit != s->in_digit)
239         {
240             if (s->last_hit != s->in_digit)
241             {
242                 /* We have two successive indications that something has changed. */
243                 /* To declare digit on, the hits must agree. Otherwise we declare tone off. */
244                 hit = (hit  &&  hit == s->last_hit)  ?  hit   :  0;
245                 if (s->realtime_callback)
246                 {
247                     /* Avoid reporting multiple no digit conditions on flaky hits */
248                     if (s->in_digit  ||  hit)
249                     {
250                         i = (s->in_digit  &&  !hit)  ?  -99  :  lrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER);
251                         s->realtime_callback(s->realtime_callback_data, hit, i, 0);
252                     }
253                 }
254                 else
255                 {
256                     if (hit)
257                     {
258                         if (s->current_digits < MAX_DTMF_DIGITS)
259                         {
260                             s->digits[s->current_digits++] = (char) hit;
261                             s->digits[s->current_digits] = '\0';
262                             if (s->digits_callback)
263                             {
264                                 s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
265                                 s->current_digits = 0;
266                             }
267                         }
268                         else
269                         {
270                             s->lost_digits++;
271                         }
272                     }
273                 }
274                 s->in_digit = hit;
275             }
276         }
277         s->last_hit = hit;
278 #if defined(SPANDSP_USE_FIXED_POINT)
279         s->energy = 0;
280 #else
281         s->energy = 0.0f;
282 #endif
283         s->current_sample = 0;
284     }
285     if (s->current_digits  &&  s->digits_callback)
286     {
287         s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
288         s->digits[0] = '\0';
289         s->current_digits = 0;
290     }
291     return 0;
292 }
293 /*- End of function --------------------------------------------------------*/
294 
dtmf_rx_status(dtmf_rx_state_t * s)295 int dtmf_rx_status(dtmf_rx_state_t *s)
296 {
297     if (s->in_digit)
298         return s->in_digit;
299     if (s->last_hit)
300         return 'x';
301     return 0;
302 }
303 /*- End of function --------------------------------------------------------*/
304 
dtmf_rx_get(dtmf_rx_state_t * s,char * buf,int max)305 size_t dtmf_rx_get(dtmf_rx_state_t *s, char *buf, int max)
306 {
307     if (max > s->current_digits)
308         max = s->current_digits;
309     if (max > 0)
310     {
311         memcpy(buf, s->digits, max);
312         memmove(s->digits, s->digits + max, s->current_digits - max);
313         s->current_digits -= max;
314     }
315     buf[max] = '\0';
316     return  max;
317 }
318 /*- End of function --------------------------------------------------------*/
319 
dtmf_rx_set_realtime_callback(dtmf_rx_state_t * s,tone_report_func_t callback,void * user_data)320 void dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s,
321                                    tone_report_func_t callback,
322                                    void *user_data)
323 {
324     s->realtime_callback = callback;
325     s->realtime_callback_data = user_data;
326 }
327 /*- End of function --------------------------------------------------------*/
328 
dtmf_rx_parms(dtmf_rx_state_t * s,int filter_dialtone,int twist,int reverse_twist,int threshold)329 void dtmf_rx_parms(dtmf_rx_state_t *s,
330                    int filter_dialtone,
331                    int twist,
332                    int reverse_twist,
333                    int threshold)
334 {
335     float x;
336 
337     if (filter_dialtone >= 0)
338     {
339         s->z350[0] = 0.0f;
340         s->z350[1] = 0.0f;
341         s->z440[0] = 0.0f;
342         s->z440[1] = 0.0f;
343         s->filter_dialtone = filter_dialtone;
344     }
345     if (twist >= 0)
346         s->normal_twist = powf(10.0f, twist/10.0f);
347     if (reverse_twist >= 0)
348         s->reverse_twist = powf(10.0f, reverse_twist/10.0f);
349     if (threshold > -99)
350     {
351         x = (DTMF_SAMPLES_PER_BLOCK*32768.0f/1.4142f)*powf(10.0f, (threshold - DBM0_MAX_SINE_POWER)/20.0f);
352         s->threshold = x*x;
353     }
354 }
355 /*- End of function --------------------------------------------------------*/
356 
dtmf_rx_init(dtmf_rx_state_t * s,digits_rx_callback_t callback,void * user_data)357 dtmf_rx_state_t *dtmf_rx_init(dtmf_rx_state_t *s,
358                               digits_rx_callback_t callback,
359                               void *user_data)
360 {
361     int i;
362     static int initialised = FALSE;
363 
364     if (s == NULL)
365     {
366         if ((s = (dtmf_rx_state_t *) malloc(sizeof (*s))) == NULL)
367             return  NULL;
368     }
369     s->digits_callback = callback;
370     s->digits_callback_data = user_data;
371     s->realtime_callback = NULL;
372     s->realtime_callback_data = NULL;
373     s->filter_dialtone = FALSE;
374     s->normal_twist = DTMF_NORMAL_TWIST;
375     s->reverse_twist = DTMF_REVERSE_TWIST;
376     s->threshold = DTMF_THRESHOLD;
377 
378     s->in_digit = 0;
379     s->last_hit = 0;
380 
381     if (!initialised)
382     {
383         for (i = 0;  i < 4;  i++)
384         {
385             make_goertzel_descriptor(&dtmf_detect_row[i], dtmf_row[i], DTMF_SAMPLES_PER_BLOCK);
386             make_goertzel_descriptor(&dtmf_detect_col[i], dtmf_col[i], DTMF_SAMPLES_PER_BLOCK);
387         }
388         initialised = TRUE;
389     }
390     for (i = 0;  i < 4;  i++)
391     {
392         goertzel_init(&s->row_out[i], &dtmf_detect_row[i]);
393         goertzel_init(&s->col_out[i], &dtmf_detect_col[i]);
394     }
395 #if defined(SPANDSP_USE_FIXED_POINT)
396     s->energy = 0;
397 #else
398     s->energy = 0.0f;
399 #endif
400     s->current_sample = 0;
401     s->lost_digits = 0;
402     s->current_digits = 0;
403     s->digits[0] = '\0';
404     return s;
405 }
406 /*- End of function --------------------------------------------------------*/
407 
dtmf_rx_free(dtmf_rx_state_t * s)408 int dtmf_rx_free(dtmf_rx_state_t *s)
409 {
410     free(s);
411     return 0;
412 }
413 /*- End of function --------------------------------------------------------*/
414 
dtmf_tx_initialise(void)415 static void dtmf_tx_initialise(void)
416 {
417     int row;
418     int col;
419 
420     if (dtmf_tx_inited)
421         return;
422     for (row = 0;  row < 4;  row++)
423     {
424         for (col = 0;  col < 4;  col++)
425         {
426             make_tone_gen_descriptor(&dtmf_digit_tones[row*4 + col],
427                                      (int) dtmf_row[row],
428                                      DEFAULT_DTMF_TX_LEVEL,
429                                      (int) dtmf_col[col],
430                                      DEFAULT_DTMF_TX_LEVEL,
431                                      DEFAULT_DTMF_TX_ON_TIME,
432                                      DEFAULT_DTMF_TX_OFF_TIME,
433                                      0,
434                                      0,
435                                      FALSE);
436         }
437     }
438     dtmf_tx_inited = TRUE;
439 }
440 /*- End of function --------------------------------------------------------*/
441 
dtmf_tx(dtmf_tx_state_t * s,int16_t amp[],int max_samples)442 int dtmf_tx(dtmf_tx_state_t *s, int16_t amp[], int max_samples)
443 {
444     int len;
445     const char *cp;
446     int digit;
447 
448     len = 0;
449     if (s->tones.current_section >= 0)
450     {
451         /* Deal with the fragment left over from last time */
452         len = tone_gen(&(s->tones), amp, max_samples);
453     }
454     while (len < max_samples  &&  (digit = queue_read_byte(&s->queue.queue)) >= 0)
455     {
456         /* Step to the next digit */
457         if (digit == 0)
458             continue;
459         if ((cp = strchr(dtmf_positions, digit)) == NULL)
460             continue;
461         tone_gen_init(&(s->tones), &dtmf_digit_tones[cp - dtmf_positions]);
462         s->tones.tone[0].gain = s->low_level;
463         s->tones.tone[1].gain = s->high_level;
464         s->tones.duration[0] = s->on_time;
465         s->tones.duration[1] = s->off_time;
466         len += tone_gen(&(s->tones), amp + len, max_samples - len);
467     }
468     return len;
469 }
470 /*- End of function --------------------------------------------------------*/
471 
dtmf_tx_put(dtmf_tx_state_t * s,const char * digits,int len)472 size_t dtmf_tx_put(dtmf_tx_state_t *s, const char *digits, int len)
473 {
474     size_t space;
475 
476     /* This returns the number of characters that would not fit in the buffer.
477        The buffer will only be loaded if the whole string of digits will fit,
478        in which case zero is returned. */
479     if (len < 0)
480     {
481         if ((len = strlen(digits)) == 0)
482             return 0;
483     }
484     if ((space = queue_free_space(&s->queue.queue)) < len)
485         return len - space;
486     if (queue_write(&s->queue.queue, (const uint8_t *) digits, len) >= 0)
487         return 0;
488     return -1;
489 }
490 /*- End of function --------------------------------------------------------*/
491 
dtmf_tx_set_level(dtmf_tx_state_t * s,int level,int twist)492 void dtmf_tx_set_level(dtmf_tx_state_t *s, int level, int twist)
493 {
494     s->low_level = dds_scaling_dbm0f((float) level);
495     s->high_level = dds_scaling_dbm0f((float) (level + twist));
496 }
497 /*- End of function --------------------------------------------------------*/
498 
dtmf_tx_set_timing(dtmf_tx_state_t * s,int on_time,int off_time)499 void dtmf_tx_set_timing(dtmf_tx_state_t *s, int on_time, int off_time)
500 {
501     s->on_time = ((on_time >= 0)  ?  on_time  :  DEFAULT_DTMF_TX_ON_TIME)*SAMPLE_RATE/1000;
502     s->off_time = ((off_time >= 0)  ?  off_time  :  DEFAULT_DTMF_TX_OFF_TIME)*SAMPLE_RATE/1000;
503 }
504 /*- End of function --------------------------------------------------------*/
505 
dtmf_tx_init(dtmf_tx_state_t * s)506 dtmf_tx_state_t *dtmf_tx_init(dtmf_tx_state_t *s)
507 {
508     if (s == NULL)
509     {
510         if ((s = (dtmf_tx_state_t *) malloc(sizeof (*s))) == NULL)
511             return  NULL;
512     }
513     if (!dtmf_tx_inited)
514         dtmf_tx_initialise();
515     tone_gen_init(&(s->tones), &dtmf_digit_tones[0]);
516     dtmf_tx_set_level(s, DEFAULT_DTMF_TX_LEVEL, 0);
517     dtmf_tx_set_timing(s, -1, -1);
518     queue_init(&s->queue.queue, MAX_DTMF_DIGITS, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC);
519     s->tones.current_section = -1;
520     return s;
521 }
522 /*- End of function --------------------------------------------------------*/
523 
dtmf_tx_free(dtmf_tx_state_t * s)524 int dtmf_tx_free(dtmf_tx_state_t *s)
525 {
526     free(s);
527     return 0;
528 }
529 /*- End of function --------------------------------------------------------*/
530 /*- End of file ------------------------------------------------------------*/
531