FreeSWITCH API Documentation  1.7.0
libteletone_detect.c
Go to the documentation of this file.
1 /*
2  * libteletone
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is tone_detect.c - General telephony tone detection, and specific detection of DTMF.
18  *
19  *
20  * The Initial Developer of the Original Code is
21  * Stephen Underwood <steveu@coppice.org>
22  * Portions created by the Initial Developer are Copyright (C)
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Contributor(s):
26  *
27  * The the original interface designed by Steve Underwood was preserved to retain
28  *the optimizations when considering DTMF tones though the names were changed in the interest
29  * of namespace.
30  *
31  * Much less efficient expansion interface was added to allow for the detection of
32  * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
33  * (controlled by compile time constant TELETONE_MAX_TONES)
34  *
35  * Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
36  *
37  *
38  * libteletone_detect.c Tone Detection Code
39  *
40  *
41  *********************************************************************************
42  *
43  * Derived from tone_detect.c - General telephony tone detection, and specific
44  * detection of DTMF.
45  *
46  * Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
47  *
48  * Despite my general liking of the GPL, I place this code in the
49  * public domain for the benefit of all mankind - even the slimy
50  * ones who might try to proprietize my work and use it to my
51  * detriment.
52  *
53  *
54  * Exception:
55  * The author hereby grants the use of this source code under the
56  * following license if and only if the source code is distributed
57  * as part of the OpenZAP or FreeTDM library. Any use or distribution of this
58  * source code outside the scope of the OpenZAP or FreeTDM library will nullify the
59  * following license and reinact the MPL 1.1 as stated above.
60  *
61  * Copyright (c) 2007, Anthony Minessale II
62  * All rights reserved.
63  *
64  * Redistribution and use in source and binary forms, with or without
65  * modification, are permitted provided that the following conditions
66  * are met:
67  *
68  * * Redistributions of source code must retain the above copyright
69  * notice, this list of conditions and the following disclaimer.
70  *
71  * * Redistributions in binary form must reproduce the above copyright
72  * notice, this list of conditions and the following disclaimer in the
73  * documentation and/or other materials provided with the distribution.
74  *
75  * * Neither the name of the original author; nor the names of any contributors
76  * may be used to endorse or promote products derived from this software
77  * without specific prior written permission.
78  *
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
81  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
82  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
83  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
84  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
85  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
86  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
87  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
88  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
89  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
90  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91  */
92 
93 #include <libteletone_detect.h>
94 
95 #ifndef _MSC_VER
96 #include <stdint.h>
97 #endif
98 #include <string.h>
99 #include <stdio.h>
100 #include <time.h>
101 #include <fcntl.h>
102 
103 #define LOW_ENG 10000000
104 #define ZC 2
109 
110 static float dtmf_row[] = {697.0f, 770.0f, 852.0f, 941.0f};
111 static float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f};
112 
113 static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
114 
116  goertzel_state->v2 = goertzel_state->v3 = 0.0;
117  goertzel_state->fac = tdesc->fac;
118 }
119 
121  int16_t sample_buffer[],
122  int samples)
123 {
124  int i;
125  float v1;
126 
127  for (i = 0; i < samples; i++) {
128  v1 = goertzel_state->v2;
129  goertzel_state->v2 = goertzel_state->v3;
130  goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]);
131  }
132 }
133 #ifdef _MSC_VER
134 #pragma warning(disable:4244)
135 #endif
136 
137 #define teletone_goertzel_result(gs) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
138 
139 TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
140 {
141  int i;
142  float theta;
143 
144  if (!sample_rate) {
145  sample_rate = 8000;
146  }
147 
148  dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
149 
150  for (i = 0; i < GRID_FACTOR; i++) {
151  theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate));
152  dtmf_detect_row[i].fac = (float)(2.0*cos(theta));
153 
154  theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate));
155  dtmf_detect_col[i].fac = (float)(2.0*cos(theta));
156 
157  theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate));
158  dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta));
159 
160  theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate));
161  dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta));
162 
163  goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
164  goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
165  goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
166  goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
167 
168  dtmf_detect_state->energy = 0.0;
169  }
170  dtmf_detect_state->current_sample = 0;
171  dtmf_detect_state->detected_digits = 0;
172  dtmf_detect_state->lost_digits = 0;
173  dtmf_detect_state->digit = 0;
174  dtmf_detect_state->dur = 0;
175 }
176 
178 {
179  float theta = 0;
180  int x = 0;
181 
182  if (!mt->sample_rate) {
183  mt->sample_rate = 8000;
184  }
185 
186  if (!mt->min_samples) {
187  mt->min_samples = 102;
188  }
189 
190  mt->min_samples *= (mt->sample_rate / 8000);
191 
192  if (!mt->positive_factor) {
193  mt->positive_factor = 2;
194  }
195 
196  if(!mt->negative_factor) {
197  mt->negative_factor = 10;
198  }
199 
200  if (!mt->hit_factor) {
201  mt->hit_factor = 2;
202  }
203 
204  for(x = 0; x < TELETONE_MAX_TONES; x++) {
205  if ((int) map->freqs[x] == 0) {
206  break;
207  }
208  mt->tone_count++;
209  theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate));
210  mt->tdd[x].fac = (float)(2.0 * cos(theta));
211  goertzel_init (&mt->gs[x], &mt->tdd[x]);
212  goertzel_init (&mt->gs2[x], &mt->tdd[x]);
213  }
214 
215 }
216 
218  int16_t sample_buffer[],
219  int samples)
220 {
221  int sample, limit = 0, j, x = 0;
222  float v1, famp;
223  float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0};
224  int gtest = 0, see_hit = 0;
225 
226  for (sample = 0; sample >= 0 && sample < samples; sample = limit) {
227  mt->total_samples++;
228 
229  if ((samples - sample) >= (mt->min_samples - mt->current_sample)) {
230  limit = sample + (mt->min_samples - mt->current_sample);
231  } else {
232  limit = samples;
233  }
234  if (limit < 0 || limit > samples) {
235  limit = samples;
236  }
237 
238  for (j = sample; j < limit; j++) {
239  famp = sample_buffer[j];
240 
241  mt->energy += famp*famp;
242 
243  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
244  v1 = mt->gs[x].v2;
245  mt->gs[x].v2 = mt->gs[x].v3;
246  mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp);
247 
248  v1 = mt->gs2[x].v2;
249  mt->gs2[x].v2 = mt->gs2[x].v3;
250  mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp);
251  }
252  }
253 
254  mt->current_sample += (limit - sample);
255  if (mt->current_sample < mt->min_samples) {
256  continue;
257  }
258 
259  eng_sum = 0;
260  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
261  eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x]));
262  eng_sum += eng_all[x];
263  }
264 
265  gtest = 0;
266  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
267  gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0;
268  }
269 
270  if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) {
271  if(mt->negatives) {
272  mt->negatives--;
273  }
274  mt->positives++;
275 
276  if(mt->positives >= mt->positive_factor) {
277  mt->hits++;
278  }
279  if (mt->hits >= mt->hit_factor) {
280  see_hit++;
281  mt->positives = mt->negatives = mt->hits = 0;
282  }
283  } else {
284  mt->negatives++;
285  if(mt->positives) {
286  mt->positives--;
287  }
288  if(mt->negatives > mt->negative_factor) {
289  mt->positives = mt->hits = 0;
290  }
291  }
292 
293  /* Reinitialise the detector for the next block */
294  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
295  goertzel_init (&mt->gs[x], &mt->tdd[x]);
296  goertzel_init (&mt->gs2[x], &mt->tdd[x]);
297  }
298 
299  mt->energy = 0.0;
300  mt->current_sample = 0;
301  }
302 
303  return see_hit;
304 }
305 
306 
308  int16_t sample_buffer[],
309  int samples)
310 {
311  float row_energy[GRID_FACTOR];
312  float col_energy[GRID_FACTOR];
313  float famp;
314  float v1;
315  int i;
316  int j;
317  int sample;
318  int best_row;
319  int best_col;
320  char hit;
321  int limit;
322  teletone_hit_type_t r = 0;
323 
324  hit = 0;
325  for (sample = 0; sample < samples; sample = limit) {
326  /* BLOCK_LEN is optimised to meet the DTMF specs. */
327  if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) {
328  limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample);
329  } else {
330  limit = samples;
331  }
332 
333  for (j = sample; j < limit; j++) {
334  int x = 0;
335  famp = sample_buffer[j];
336 
337  dtmf_detect_state->energy += famp*famp;
338 
339  for(x = 0; x < GRID_FACTOR; x++) {
340  v1 = dtmf_detect_state->row_out[x].v2;
341  dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3;
342  dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp);
343 
344  v1 = dtmf_detect_state->col_out[x].v2;
345  dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3;
346  dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp);
347 
348  v1 = dtmf_detect_state->col_out2nd[x].v2;
349  dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3;
350  dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp);
351 
352  v1 = dtmf_detect_state->row_out2nd[x].v2;
353  dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3;
354  dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp);
355  }
356 
357  }
358 
359  if (dtmf_detect_state->zc > 0) {
360  if (dtmf_detect_state->energy < LOW_ENG && dtmf_detect_state->lenergy < LOW_ENG) {
361  if (!--dtmf_detect_state->zc) {
362  /* Reinitialise the detector for the next block */
363  dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
364  for (i = 0; i < GRID_FACTOR; i++) {
365  goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
366  goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
367  goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
368  goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
369  }
370  dtmf_detect_state->dur -= samples;
371  return TT_HIT_END;
372  }
373  }
374 
375  dtmf_detect_state->dur += samples;
376  dtmf_detect_state->lenergy = dtmf_detect_state->energy;
377  dtmf_detect_state->energy = 0.0;
378  dtmf_detect_state->current_sample = 0;
379  return TT_HIT_MIDDLE;
380  } else if (dtmf_detect_state->digit) {
381  return TT_HIT_END;
382  }
383 
384 
385  dtmf_detect_state->current_sample += (limit - sample);
386  if (dtmf_detect_state->current_sample < BLOCK_LEN) {
387  continue;
388  }
389  /* We are at the end of a DTMF detection block */
390  /* Find the peak row and the peak column */
391  row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]);
392  col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]);
393 
394  for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) {
395  row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]);
396  if (row_energy[i] > row_energy[best_row]) {
397  best_row = i;
398  }
399  col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]);
400  if (col_energy[i] > col_energy[best_col]) {
401  best_col = i;
402  }
403  }
404  hit = 0;
405  /* Basic signal level test and the twist test */
406  if (row_energy[best_row] >= DTMF_THRESHOLD &&
407  col_energy[best_col] >= DTMF_THRESHOLD &&
408  col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
409  col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
410  /* Relative peak test */
411  for (i = 0; i < GRID_FACTOR; i++) {
412  if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
413  (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
414  break;
415  }
416  }
417  /* ... and second harmonic test */
418  if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy &&
419  teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
420  teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
421  hit = dtmf_positions[(best_row << 2) + best_col];
422  /* Look for two successive similar results */
423  /* The logic in the next test is:
424  We need two successive identical clean detects, with
425  something different preceeding it. This can work with
426  back to back differing digits. More importantly, it
427  can work with nasty phones that give a very wobbly start
428  to a digit. */
429  if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
430  dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
431  dtmf_detect_state->detected_digits++;
432  if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
433  dtmf_detect_state->digit = hit;
434  } else {
435  dtmf_detect_state->lost_digits++;
436  }
437 
438  if (!dtmf_detect_state->zc) {
439  dtmf_detect_state->zc = ZC;
440  dtmf_detect_state->dur = 0;
441  r = TT_HIT_BEGIN;
442  break;
443  }
444 
445  }
446  }
447  }
448 
449  dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
450  dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
451  dtmf_detect_state->hit3 = hit;
452 
453  dtmf_detect_state->energy = 0.0;
454  dtmf_detect_state->current_sample = 0;
455 
456  }
457 
458  return r;
459 }
460 
461 
462 TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
463 {
464  if (!dtmf_detect_state->digit) {
465  return 0;
466  }
467 
468  *buf = dtmf_detect_state->digit;
469 
470  *dur = dtmf_detect_state->dur;
471 
472  if (!dtmf_detect_state->zc) {
473  dtmf_detect_state->dur = 0;
474  dtmf_detect_state->digit = 0;
475  }
476 
477  return 1;
478 }
479 
480 /* For Emacs:
481  * Local Variables:
482  * mode:c
483  * indent-tabs-mode:t
484  * tab-width:4
485  * c-basic-offset:4
486  * End:
487  * For VIM:
488  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
489  */
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]
#define DTMF_THRESHOLD
#define TELETONE_MAX_TONES
Definition: libteletone.h:81
A container for a single multi-tone detection TELETONE_MAX_TONES dictates the maximum simultaneous to...
#define ZC
#define LOW_ENG
An abstraction to store a tone mapping.
Definition: libteletone.h:93
teletone_hit_type_t
Tone Detection Routines.
#define GRID_FACTOR
static float dtmf_col[]
A container for a DTMF detection state.
A continer for the elements of a Goertzel Algorithm (The names are from his formula) ...
#define TELETONE_API(type)
Definition: libteletone.h:133
#define DTMF_RELATIVE_PEAK_COL
void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
Initilize a multi-frequency tone detector.
static float dtmf_row[]
#define BLOCK_LEN
#define TELETONE_MAX_DTMF_DIGITS
Definition: libteletone.h:80
static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR]
switch_byte_t switch_byte_t * buf
teletone_hit_type_t teletone_dtmf_detect(teletone_dtmf_detect_state_t *dtmf_detect_state, int16_t sample_buffer[], int samples)
Check a sample buffer for the presence of DTMF digits.
#define M_TWO_PI
static char dtmf_positions[]
int teletone_dtmf_get(teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
retrieve any collected digits into a string buffer
#define DTMF_RELATIVE_PEAK_ROW
#define DTMF_NORMAL_TWIST
int teletone_multi_tone_detect(teletone_multi_tone_t *mt, int16_t sample_buffer[], int samples)
Check a sample buffer for the presence of the mulit-frequency tone described by mt.
An abstraction to store the coefficient of a tone frequency.
#define teletone_goertzel_result(gs)
static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR]
static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc)
#define DTMF_2ND_HARMONIC_COL
static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR]
#define DTMF_2ND_HARMONIC_ROW
#define DTMF_REVERSE_TWIST
void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state, int16_t sample_buffer[], int samples)
Step through the Goertzel Algorithm for each sample in a buffer.
void teletone_dtmf_detect_init(teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
Initilize a DTMF detection state object.