FreeSWITCH API Documentation  1.7.0
Macros | Functions | Variables
libteletone_detect.c File Reference
#include <libteletone_detect.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
+ Include dependency graph for libteletone_detect.c:

Go to the source code of this file.

Macros

#define LOW_ENG   10000000
 
#define ZC   2
 
#define teletone_goertzel_result(gs)   (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
 

Functions

static void goertzel_init (teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc)
 
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. More...
 
void teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
 Initilize a DTMF detection state object. More...
 
void teletone_multi_tone_init (teletone_multi_tone_t *mt, teletone_tone_map_t *map)
 Initilize a multi-frequency tone detector. More...
 
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. More...
 
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. More...
 
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 More...
 

Variables

static
teletone_detection_descriptor_t 
dtmf_detect_row [GRID_FACTOR]
 
static
teletone_detection_descriptor_t 
dtmf_detect_col [GRID_FACTOR]
 
static
teletone_detection_descriptor_t 
dtmf_detect_row_2nd [GRID_FACTOR]
 
static
teletone_detection_descriptor_t 
dtmf_detect_col_2nd [GRID_FACTOR]
 
static float dtmf_row [] = {697.0f, 770.0f, 852.0f, 941.0f}
 
static float dtmf_col [] = {1209.0f, 1336.0f, 1477.0f, 1633.0f}
 
static char dtmf_positions [] = "123A" "456B" "789C" "*0#D"
 

Macro Definition Documentation

#define LOW_ENG   10000000

Definition at line 103 of file libteletone_detect.c.

Referenced by teletone_dtmf_detect().

#define teletone_goertzel_result (   gs)    (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))

Definition at line 137 of file libteletone_detect.c.

Referenced by teletone_dtmf_detect(), and teletone_multi_tone_detect().

#define ZC   2

Definition at line 104 of file libteletone_detect.c.

Referenced by teletone_dtmf_detect().

Function Documentation

static void goertzel_init ( teletone_goertzel_state_t goertzel_state,
teletone_detection_descriptor_t tdesc 
)
static
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.

Parameters
dtmf_detect_statethe detection state object to check
sample_bufferan array aof 16 bit signed linear samples
samplesthe number of samples present in sample_buffer
Returns
true when DTMF was detected or false when it is not

Definition at line 307 of file libteletone_detect.c.

References BLOCK_LEN, DTMF_2ND_HARMONIC_COL, DTMF_2ND_HARMONIC_ROW, DTMF_NORMAL_TWIST, dtmf_positions, DTMF_RELATIVE_PEAK_COL, DTMF_RELATIVE_PEAK_ROW, DTMF_REVERSE_TWIST, DTMF_THRESHOLD, goertzel_init(), GRID_FACTOR, LOW_ENG, teletone_goertzel_result, TELETONE_MAX_DTMF_DIGITS, TT_HIT_BEGIN, TT_HIT_END, TT_HIT_MIDDLE, and ZC.

Referenced by inband_dtmf_callback().

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 }
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]
#define DTMF_THRESHOLD
teletone_goertzel_state_t row_out[GRID_FACTOR]
#define ZC
#define LOW_ENG
teletone_hit_type_t
#define GRID_FACTOR
#define DTMF_RELATIVE_PEAK_COL
teletone_goertzel_state_t row_out2nd[GRID_FACTOR]
teletone_goertzel_state_t col_out2nd[GRID_FACTOR]
#define BLOCK_LEN
#define TELETONE_MAX_DTMF_DIGITS
Definition: libteletone.h:80
static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR]
static char dtmf_positions[]
#define DTMF_RELATIVE_PEAK_ROW
#define DTMF_NORMAL_TWIST
#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]
teletone_goertzel_state_t col_out[GRID_FACTOR]
#define DTMF_2ND_HARMONIC_ROW
#define DTMF_REVERSE_TWIST
void teletone_dtmf_detect_init ( teletone_dtmf_detect_state_t dtmf_detect_state,
int  sample_rate 
)

Initilize a DTMF detection state object.

Parameters
dtmf_detect_statethe DTMF detection state to initilize
sample_ratethe desired sample rate

Definition at line 139 of file libteletone_detect.c.

References dtmf_col, dtmf_row, teletone_detection_descriptor_t::fac, goertzel_init(), GRID_FACTOR, and M_TWO_PI.

Referenced by switch_ivr_inband_dtmf_session().

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 }
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]
teletone_goertzel_state_t row_out[GRID_FACTOR]
#define GRID_FACTOR
static float dtmf_col[]
teletone_goertzel_state_t row_out2nd[GRID_FACTOR]
static float dtmf_row[]
teletone_goertzel_state_t col_out2nd[GRID_FACTOR]
static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR]
#define M_TWO_PI
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)
static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR]
teletone_goertzel_state_t col_out[GRID_FACTOR]
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

Parameters
dtmf_detect_statethe detection state object to check
bufthe string buffer to write to
maxthe maximum length of buf
Returns
the number of characters written to buf

Definition at line 462 of file libteletone_detect.c.

Referenced by inband_dtmf_callback().

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 }
switch_byte_t switch_byte_t * buf
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.

Parameters
goertzel_statethe goertzel state to step the samples through
sample_bufferan array aof 16 bit signed linear samples
samplesthe number of samples present in sample_buffer

Definition at line 120 of file libteletone_detect.c.

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 }
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.

Parameters
mtthe multi-frequency tone descriptor
sample_bufferan array aof 16 bit signed linear samples
samplesthe number of samples present in sample_buffer
Returns
true when the tone was detected or false when it is not

Definition at line 217 of file libteletone_detect.c.

References goertzel_init(), teletone_goertzel_result, and TELETONE_MAX_TONES.

Referenced by tone_detect_callback().

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 }
#define TELETONE_MAX_TONES
Definition: libteletone.h:81
teletone_goertzel_state_t gs[TELETONE_MAX_TONES]
teletone_goertzel_state_t gs2[TELETONE_MAX_TONES]
#define teletone_goertzel_result(gs)
static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc)
teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES]
void teletone_multi_tone_init ( teletone_multi_tone_t mt,
teletone_tone_map_t map 
)

Initilize a multi-frequency tone detector.

Parameters
mtthe multi-frequency tone descriptor
mapa representation of the multi-frequency tone

Definition at line 177 of file libteletone_detect.c.

References goertzel_init(), M_TWO_PI, and TELETONE_MAX_TONES.

Referenced by switch_ivr_tone_detect_session().

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 }
#define TELETONE_MAX_TONES
Definition: libteletone.h:81
teletone_goertzel_state_t gs[TELETONE_MAX_TONES]
teletone_process_t freqs[TELETONE_MAX_TONES]
Definition: libteletone.h:95
teletone_goertzel_state_t gs2[TELETONE_MAX_TONES]
#define M_TWO_PI
static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc)
teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES]

Variable Documentation

float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f}
static

Definition at line 111 of file libteletone_detect.c.

Referenced by teletone_dtmf_detect_init().

Definition at line 106 of file libteletone_detect.c.

teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR]
static

Definition at line 108 of file libteletone_detect.c.

Definition at line 105 of file libteletone_detect.c.

teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR]
static

Definition at line 107 of file libteletone_detect.c.

char dtmf_positions[] = "123A" "456B" "789C" "*0#D"
static

Definition at line 113 of file libteletone_detect.c.

Referenced by teletone_dtmf_detect().

float dtmf_row[] = {697.0f, 770.0f, 852.0f, 941.0f}
static

Definition at line 110 of file libteletone_detect.c.

Referenced by teletone_dtmf_detect_init().