aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/mISDN/dsp_dtmf.c
diff options
context:
space:
mode:
authorKarsten Keil <kkeil@suse.de>2008-07-26 19:56:38 -0400
committerKarsten Keil <kkeil@suse.de>2008-07-26 19:56:38 -0400
commit960366cf8dbb3359afaca30cf7fdbf69a6d6dda7 (patch)
tree261bc6e6584caf44d8d1fa319e6228431ac3b91d /drivers/isdn/mISDN/dsp_dtmf.c
parent1b2b03f8e514e4f68e293846ba511a948b80243c (diff)
Add mISDN DSP
Enable support for digital audio processing capability. This module may be used for special applications that require cross connecting of bchannels, conferencing, dtmf decoding echo cancelation, tone generation, and Blowfish encryption and decryption. It may use hardware features if available. Signed-off-by: Karsten Keil <kkeil@suse.de>
Diffstat (limited to 'drivers/isdn/mISDN/dsp_dtmf.c')
-rw-r--r--drivers/isdn/mISDN/dsp_dtmf.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c
new file mode 100644
index 000000000000..efc371c1f0dc
--- /dev/null
+++ b/drivers/isdn/mISDN/dsp_dtmf.c
@@ -0,0 +1,303 @@
1/*
2 * DTMF decoder.
3 *
4 * Copyright by Andreas Eversberg (jolly@eversberg.eu)
5 * based on different decoders such as ISDN4Linux
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/mISDNif.h>
13#include <linux/mISDNdsp.h>
14#include "core.h"
15#include "dsp.h"
16
17#define NCOEFF 8 /* number of frequencies to be analyzed */
18
19/* For DTMF recognition:
20 * 2 * cos(2 * PI * k / N) precalculated for all k
21 */
22static u64 cos2pik[NCOEFF] =
23{
24 /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
25 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
26};
27
28/* digit matrix */
29static char dtmf_matrix[4][4] =
30{
31 {'1', '2', '3', 'A'},
32 {'4', '5', '6', 'B'},
33 {'7', '8', '9', 'C'},
34 {'*', '0', '#', 'D'}
35};
36
37/* dtmf detection using goertzel algorithm
38 * init function
39 */
40void dsp_dtmf_goertzel_init(struct dsp *dsp)
41{
42 dsp->dtmf.size = 0;
43 dsp->dtmf.lastwhat = '\0';
44 dsp->dtmf.lastdigit = '\0';
45 dsp->dtmf.count = 0;
46}
47
48/* check for hardware or software features
49 */
50void dsp_dtmf_hardware(struct dsp *dsp)
51{
52 int hardware = 1;
53
54 if (!dsp->features.hfc_dtmf)
55 hardware = 0;
56
57 /* check for volume change */
58 if (dsp->tx_volume) {
59 if (dsp_debug & DEBUG_DSP_DTMF)
60 printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
61 "because tx_volume is changed\n",
62 __func__, dsp->name);
63 hardware = 0;
64 }
65 if (dsp->rx_volume) {
66 if (dsp_debug & DEBUG_DSP_DTMF)
67 printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
68 "because rx_volume is changed\n",
69 __func__, dsp->name);
70 hardware = 0;
71 }
72 /* check if encryption is enabled */
73 if (dsp->bf_enable) {
74 if (dsp_debug & DEBUG_DSP_DTMF)
75 printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
76 "because encryption is enabled\n",
77 __func__, dsp->name);
78 hardware = 0;
79 }
80 /* check if pipeline exists */
81 if (dsp->pipeline.inuse) {
82 if (dsp_debug & DEBUG_DSP_DTMF)
83 printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
84 "because pipeline exists.\n",
85 __func__, dsp->name);
86 hardware = 0;
87 }
88
89 dsp->dtmf.hardware = hardware;
90 dsp->dtmf.software = !hardware;
91}
92
93
94/*************************************************************
95 * calculate the coefficients of the given sample and decode *
96 *************************************************************/
97
98/* the given sample is decoded. if the sample is not long enough for a
99 * complete frame, the decoding is finished and continued with the next
100 * call of this function.
101 *
102 * the algorithm is very good for detection with a minimum of errors. i
103 * tested it allot. it even works with very short tones (40ms). the only
104 * disadvantage is, that it doesn't work good with different volumes of both
105 * tones. this will happen, if accoustically coupled dialers are used.
106 * it sometimes detects tones during speach, which is normal for decoders.
107 * use sequences to given commands during calls.
108 *
109 * dtmf - points to a structure of the current dtmf state
110 * spl and len - the sample
111 * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
112 */
113
114u8
115*dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt)
116{
117 u8 what;
118 int size;
119 signed short *buf;
120 s32 sk, sk1, sk2;
121 int k, n, i;
122 s32 *hfccoeff;
123 s32 result[NCOEFF], tresh, treshl;
124 int lowgroup, highgroup;
125 s64 cos2pik_;
126
127 dsp->dtmf.digits[0] = '\0';
128
129 /* Note: The function will loop until the buffer has not enough samples
130 * left to decode a full frame.
131 */
132again:
133 /* convert samples */
134 size = dsp->dtmf.size;
135 buf = dsp->dtmf.buffer;
136 switch (fmt) {
137 case 0: /* alaw */
138 case 1: /* ulaw */
139 while (size < DSP_DTMF_NPOINTS && len) {
140 buf[size++] = dsp_audio_law_to_s32[*data++];
141 len--;
142 }
143 break;
144
145 case 2: /* HFC coefficients */
146 default:
147 if (len < 64) {
148 if (len > 0)
149 printk(KERN_ERR "%s: coefficients have invalid "
150 "size. (is=%d < must=%d)\n",
151 __func__, len, 64);
152 return dsp->dtmf.digits;
153 }
154 hfccoeff = (s32 *)data;
155 for (k = 0; k < NCOEFF; k++) {
156 sk2 = (*hfccoeff++)>>4;
157 sk = (*hfccoeff++)>>4;
158 if (sk > 32767 || sk < -32767 || sk2 > 32767
159 || sk2 < -32767)
160 printk(KERN_WARNING
161 "DTMF-Detection overflow\n");
162 /* compute |X(k)|**2 */
163 result[k] =
164 (sk * sk) -
165 (((cos2pik[k] * sk) >> 15) * sk2) +
166 (sk2 * sk2);
167 }
168 data += 64;
169 len -= 64;
170 goto coefficients;
171 break;
172 }
173 dsp->dtmf.size = size;
174
175 if (size < DSP_DTMF_NPOINTS)
176 return dsp->dtmf.digits;
177
178 dsp->dtmf.size = 0;
179
180 /* now we have a full buffer of signed long samples - we do goertzel */
181 for (k = 0; k < NCOEFF; k++) {
182 sk = 0;
183 sk1 = 0;
184 sk2 = 0;
185 buf = dsp->dtmf.buffer;
186 cos2pik_ = cos2pik[k];
187 for (n = 0; n < DSP_DTMF_NPOINTS; n++) {
188 sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++);
189 sk2 = sk1;
190 sk1 = sk;
191 }
192 sk >>= 8;
193 sk2 >>= 8;
194 if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
195 printk(KERN_WARNING "DTMF-Detection overflow\n");
196 /* compute |X(k)|**2 */
197 result[k] =
198 (sk * sk) -
199 (((cos2pik[k] * sk) >> 15) * sk2) +
200 (sk2 * sk2);
201 }
202
203 /* our (squared) coefficients have been calculated, we need to process
204 * them.
205 */
206coefficients:
207 tresh = 0;
208 for (i = 0; i < NCOEFF; i++) {
209 if (result[i] < 0)
210 result[i] = 0;
211 if (result[i] > dsp->dtmf.treshold) {
212 if (result[i] > tresh)
213 tresh = result[i];
214 }
215 }
216
217 if (tresh == 0) {
218 what = 0;
219 goto storedigit;
220 }
221
222 if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
223 printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
224 " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
225 result[0]/10000, result[1]/10000, result[2]/10000,
226 result[3]/10000, result[4]/10000, result[5]/10000,
227 result[6]/10000, result[7]/10000, tresh/10000,
228 result[0]/(tresh/100), result[1]/(tresh/100),
229 result[2]/(tresh/100), result[3]/(tresh/100),
230 result[4]/(tresh/100), result[5]/(tresh/100),
231 result[6]/(tresh/100), result[7]/(tresh/100));
232
233 /* calc digit (lowgroup/highgroup) */
234 lowgroup = -1;
235 highgroup = -1;
236 treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */
237 tresh = tresh >> 2; /* touchtones must match within 6 dB */
238 for (i = 0; i < NCOEFF; i++) {
239 if (result[i] < treshl)
240 continue; /* ignore */
241 if (result[i] < tresh) {
242 lowgroup = -1;
243 highgroup = -1;
244 break; /* noise inbetween */
245 }
246 /* good level found. This is allowed only one time per group */
247 if (i < NCOEFF/2) {
248 /* lowgroup */
249 if (lowgroup >= 0) {
250 /* Bad. Another tone found. */
251 lowgroup = -1;
252 break;
253 } else
254 lowgroup = i;
255 } else {
256 /* higroup */
257 if (highgroup >= 0) {
258 /* Bad. Another tone found. */
259 highgroup = -1;
260 break;
261 } else
262 highgroup = i-(NCOEFF/2);
263 }
264 }
265
266 /* get digit or null */
267 what = 0;
268 if (lowgroup >= 0 && highgroup >= 0)
269 what = dtmf_matrix[lowgroup][highgroup];
270
271storedigit:
272 if (what && (dsp_debug & DEBUG_DSP_DTMF))
273 printk(KERN_DEBUG "DTMF what: %c\n", what);
274
275 if (dsp->dtmf.lastwhat != what)
276 dsp->dtmf.count = 0;
277
278 /* the tone (or no tone) must remain 3 times without change */
279 if (dsp->dtmf.count == 2) {
280 if (dsp->dtmf.lastdigit != what) {
281 dsp->dtmf.lastdigit = what;
282 if (what) {
283 if (dsp_debug & DEBUG_DSP_DTMF)
284 printk(KERN_DEBUG "DTMF digit: %c\n",
285 what);
286 if ((strlen(dsp->dtmf.digits)+1)
287 < sizeof(dsp->dtmf.digits)) {
288 dsp->dtmf.digits[strlen(
289 dsp->dtmf.digits)+1] = '\0';
290 dsp->dtmf.digits[strlen(
291 dsp->dtmf.digits)] = what;
292 }
293 }
294 }
295 } else
296 dsp->dtmf.count++;
297
298 dsp->dtmf.lastwhat = what;
299
300 goto again;
301}
302
303