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