1 /* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
2 *
3 * Linux ISDN subsystem, audio conversion and compression (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
7 * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14 #include <linux/isdn.h>
15 #include <linux/slab.h>
16 #include "isdn_audio.h"
17 #include "isdn_common.h"
18
19 char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
20
21 /*
22 * Misc. lookup-tables.
23 */
24
25 /* ulaw -> signed 16-bit */
26 static short isdn_audio_ulaw_to_s16[] =
27 {
28 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
29 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
30 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
31 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
32 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
33 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
34 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
35 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
36 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
37 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
38 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
39 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
40 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
41 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
42 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
43 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
44 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
45 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
46 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
47 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
48 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
49 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
50 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
51 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
52 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
53 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
54 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
55 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
56 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
57 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
58 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
59 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
60 };
61
62 /* alaw -> signed 16-bit */
63 static short isdn_audio_alaw_to_s16[] =
64 {
65 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
66 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
67 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
68 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
69 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
70 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
71 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
72 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
73 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
74 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
75 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
76 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
77 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
78 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
79 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
80 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
81 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
82 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
83 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
84 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
85 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
86 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
87 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
88 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
89 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
90 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
91 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
92 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
93 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
94 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
95 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
96 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
97 };
98
99 /* alaw -> ulaw */
100 static char isdn_audio_alaw_to_ulaw[] =
101 {
102 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
103 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
104 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
105 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
106 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
107 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
108 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
109 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
110 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
111 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
112 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
113 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
114 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
115 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
116 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
117 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
118 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
119 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
120 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
121 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
122 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
123 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
124 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
125 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
126 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
127 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
128 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
129 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
130 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
131 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
132 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
133 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
134 };
135
136 /* ulaw -> alaw */
137 static char isdn_audio_ulaw_to_alaw[] =
138 {
139 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
140 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
141 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
142 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
143 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
144 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
145 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
146 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
147 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
148 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
149 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
150 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
151 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
152 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
153 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
154 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
155 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
156 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
157 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
158 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
159 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
160 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
161 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
162 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
163 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
164 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
165 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
166 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
167 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
168 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
169 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
170 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
171 };
172
173 #define NCOEFF 8 /* number of frequencies to be analyzed */
174 #define DTMF_TRESH 4000 /* above this is dtmf */
175 #define SILENCE_TRESH 200 /* below this is silence */
176 #define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
177 #define LOGRP 0
178 #define HIGRP 1
179
180 /* For DTMF recognition:
181 * 2 * cos(2 * PI * k / N) precalculated for all k
182 */
183 static int cos2pik[NCOEFF] =
184 {
185 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
186 };
187
188 static char dtmf_matrix[4][4] =
189 {
190 {'1', '2', '3', 'A'},
191 {'4', '5', '6', 'B'},
192 {'7', '8', '9', 'C'},
193 {'*', '0', '#', 'D'}
194 };
195
196 static inline void
isdn_audio_tlookup(const u_char * table,u_char * buff,unsigned long n)197 isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
198 {
199 #ifdef __i386__
200 unsigned long d0, d1, d2, d3;
201 __asm__ __volatile__(
202 "cld\n"
203 "1:\tlodsb\n\t"
204 "xlatb\n\t"
205 "stosb\n\t"
206 "loop 1b\n\t"
207 : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
208 : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
209 : "memory", "ax");
210 #else
211 while (n--)
212 *buff = table[*(unsigned char *)buff], buff++;
213 #endif
214 }
215
216 void
isdn_audio_ulaw2alaw(unsigned char * buff,unsigned long len)217 isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
218 {
219 isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
220 }
221
222 void
isdn_audio_alaw2ulaw(unsigned char * buff,unsigned long len)223 isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
224 {
225 isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
226 }
227
228 /*
229 * linear <-> adpcm conversion stuff
230 * Most parts from the mgetty-package.
231 * (C) by Gert Doering and Klaus Weidner
232 * Used by permission of Gert Doering
233 */
234
235
236 #define ZEROTRAP /* turn on the trap as per the MIL-STD */
237 #undef ZEROTRAP
238 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
239 #define CLIP 32635
240
241 static unsigned char
isdn_audio_linear2ulaw(int sample)242 isdn_audio_linear2ulaw(int sample)
243 {
244 static int exp_lut[256] =
245 {
246 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
247 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
248 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
249 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
250 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
251 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
252 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
253 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
254 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
255 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
256 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
257 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
258 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
259 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
260 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
261 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
262 };
263 int sign,
264 exponent,
265 mantissa;
266 unsigned char ulawbyte;
267
268 /* Get the sample into sign-magnitude. */
269 sign = (sample >> 8) & 0x80; /* set aside the sign */
270 if (sign != 0)
271 sample = -sample; /* get magnitude */
272 if (sample > CLIP)
273 sample = CLIP; /* clip the magnitude */
274
275 /* Convert from 16 bit linear to ulaw. */
276 sample = sample + BIAS;
277 exponent = exp_lut[(sample >> 7) & 0xFF];
278 mantissa = (sample >> (exponent + 3)) & 0x0F;
279 ulawbyte = ~(sign | (exponent << 4) | mantissa);
280 #ifdef ZEROTRAP
281 /* optional CCITT trap */
282 if (ulawbyte == 0)
283 ulawbyte = 0x02;
284 #endif
285 return (ulawbyte);
286 }
287
288
289 static int Mx[3][8] =
290 {
291 {0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
292 {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
293 {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
294 };
295
296 static int bitmask[9] =
297 {
298 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
299 };
300
301 static int
isdn_audio_get_bits(adpcm_state * s,unsigned char ** in,int * len)302 isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len)
303 {
304 while (s->nleft < s->nbits) {
305 int d = *((*in)++);
306 (*len)--;
307 s->word = (s->word << 8) | d;
308 s->nleft += 8;
309 }
310 s->nleft -= s->nbits;
311 return (s->word >> s->nleft) & bitmask[s->nbits];
312 }
313
314 static void
isdn_audio_put_bits(int data,int nbits,adpcm_state * s,unsigned char ** out,int * len)315 isdn_audio_put_bits(int data, int nbits, adpcm_state * s,
316 unsigned char **out, int *len)
317 {
318 s->word = (s->word << nbits) | (data & bitmask[nbits]);
319 s->nleft += nbits;
320 while (s->nleft >= 8) {
321 int d = (s->word >> (s->nleft - 8));
322 *(out[0]++) = d & 255;
323 (*len)++;
324 s->nleft -= 8;
325 }
326 }
327
328 adpcm_state *
isdn_audio_adpcm_init(adpcm_state * s,int nbits)329 isdn_audio_adpcm_init(adpcm_state * s, int nbits)
330 {
331 if (!s)
332 s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
333 if (s) {
334 s->a = 0;
335 s->d = 5;
336 s->word = 0;
337 s->nleft = 0;
338 s->nbits = nbits;
339 }
340 return s;
341 }
342
343 dtmf_state *
isdn_audio_dtmf_init(dtmf_state * s)344 isdn_audio_dtmf_init(dtmf_state * s)
345 {
346 if (!s)
347 s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
348 if (s) {
349 s->idx = 0;
350 s->last = ' ';
351 }
352 return s;
353 }
354
355 /*
356 * Decompression of adpcm data to a/u-law
357 *
358 */
359
360 int
isdn_audio_adpcm2xlaw(adpcm_state * s,int fmt,unsigned char * in,unsigned char * out,int len)361 isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
362 unsigned char *out, int len)
363 {
364 int a = s->a;
365 int d = s->d;
366 int nbits = s->nbits;
367 int olen = 0;
368
369 while (len) {
370 int e = isdn_audio_get_bits(s, &in, &len);
371 int sign;
372
373 if (nbits == 4 && e == 0)
374 d = 4;
375 sign = (e >> (nbits - 1)) ? -1 : 1;
376 e &= bitmask[nbits - 1];
377 a += sign * ((e << 1) + 1) * d >> 1;
378 if (d & 1)
379 a++;
380 if (fmt)
381 *out++ = isdn_audio_ulaw_to_alaw[
382 isdn_audio_linear2ulaw(a << 2)];
383 else
384 *out++ = isdn_audio_linear2ulaw(a << 2);
385 olen++;
386 d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
387 if (d < 5)
388 d = 5;
389 }
390 s->a = a;
391 s->d = d;
392 return olen;
393 }
394
395 int
isdn_audio_xlaw2adpcm(adpcm_state * s,int fmt,unsigned char * in,unsigned char * out,int len)396 isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
397 unsigned char *out, int len)
398 {
399 int a = s->a;
400 int d = s->d;
401 int nbits = s->nbits;
402 int olen = 0;
403
404 while (len--) {
405 int e = 0,
406 nmax = 1 << (nbits - 1);
407 int sign,
408 delta;
409
410 if (fmt)
411 delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
412 else
413 delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
414 if (delta < 0) {
415 e = nmax;
416 delta = -delta;
417 }
418 while (--nmax && delta > d) {
419 delta -= d;
420 e++;
421 }
422 if (nbits == 4 && ((e & 0x0f) == 0))
423 e = 8;
424 isdn_audio_put_bits(e, nbits, s, &out, &olen);
425 sign = (e >> (nbits - 1)) ? -1 : 1;
426 e &= bitmask[nbits - 1];
427
428 a += sign * ((e << 1) + 1) * d >> 1;
429 if (d & 1)
430 a++;
431 d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
432 if (d < 5)
433 d = 5;
434 }
435 s->a = a;
436 s->d = d;
437 return olen;
438 }
439
440 /*
441 * Goertzel algorithm.
442 * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
443 * for more info.
444 * Result is stored into an sk_buff and queued up for later
445 * evaluation.
446 */
447 static void
isdn_audio_goertzel(int * sample,modem_info * info)448 isdn_audio_goertzel(int *sample, modem_info * info)
449 {
450 int sk,
451 sk1,
452 sk2;
453 int k,
454 n;
455 struct sk_buff *skb;
456 int *result;
457
458 skb = dev_alloc_skb(sizeof(int) * NCOEFF);
459 if (!skb) {
460 printk(KERN_WARNING
461 "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
462 info->line);
463 return;
464 }
465 result = (int *) skb_put(skb, sizeof(int) * NCOEFF);
466 for (k = 0; k < NCOEFF; k++) {
467 sk = sk1 = sk2 = 0;
468 for (n = 0; n < DTMF_NPOINTS; n++) {
469 sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
470 sk2 = sk1;
471 sk1 = sk;
472 }
473 /* Avoid overflows */
474 sk >>= 1;
475 sk2 >>= 1;
476 /* compute |X(k)|**2 */
477 /* report overflows. This should not happen. */
478 /* Comment this out if desired */
479 if (sk < -32768 || sk > 32767)
480 printk(KERN_DEBUG
481 "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
482 if (sk2 < -32768 || sk2 > 32767)
483 printk(KERN_DEBUG
484 "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
485 result[k] =
486 ((sk * sk) >> AMP_BITS) -
487 ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
488 ((sk2 * sk2) >> AMP_BITS);
489 }
490 skb_queue_tail(&info->dtmf_queue, skb);
491 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
492 }
493
494 void
isdn_audio_eval_dtmf(modem_info * info)495 isdn_audio_eval_dtmf(modem_info * info)
496 {
497 struct sk_buff *skb;
498 int *result;
499 dtmf_state *s;
500 int silence;
501 int i;
502 int di;
503 int ch;
504 int grp[2];
505 char what;
506 char *p;
507 int thresh;
508
509 while ((skb = skb_dequeue(&info->dtmf_queue))) {
510 result = (int *) skb->data;
511 s = info->dtmf_state;
512 grp[LOGRP] = grp[HIGRP] = -1;
513 silence = 0;
514 thresh = 0;
515 for (i = 0; i < NCOEFF; i++) {
516 if (result[i] > DTMF_TRESH) {
517 if (result[i] > thresh)
518 thresh = result[i];
519 }
520 else if (result[i] < SILENCE_TRESH)
521 silence++;
522 }
523 if (silence == NCOEFF)
524 what = ' ';
525 else {
526 if (thresh > 0) {
527 thresh = thresh >> 4; /* touchtones must match within 12 dB */
528 for (i = 0; i < NCOEFF; i++) {
529 if (result[i] < thresh)
530 continue; /* ignore */
531 /* good level found. This is allowed only one time per group */
532 if (i < NCOEFF / 2) {
533 /* lowgroup*/
534 if (grp[LOGRP] >= 0) {
535 // Bad. Another tone found. */
536 grp[LOGRP] = -1;
537 break;
538 }
539 else
540 grp[LOGRP] = i;
541 }
542 else { /* higroup */
543 if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
544 grp[HIGRP] = -1;
545 break;
546 }
547 else
548 grp[HIGRP] = i - NCOEFF/2;
549 }
550 }
551 if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
552 what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
553 if (s->last != ' ' && s->last != '.')
554 s->last = what; /* min. 1 non-DTMF between DTMF */
555 } else
556 what = '.';
557 }
558 else
559 what = '.';
560 }
561 if ((what != s->last) && (what != ' ') && (what != '.')) {
562 printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
563 p = skb->data;
564 *p++ = 0x10;
565 *p = what;
566 skb_trim(skb, 2);
567 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
568 ISDN_AUDIO_SKB_LOCK(skb) = 0;
569 di = info->isdn_driver;
570 ch = info->isdn_channel;
571 __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
572 dev->drv[di]->rcvcount[ch] += 2;
573 /* Schedule dequeuing */
574 if ((dev->modempoll) && (info->rcvsched))
575 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
576 wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
577 } else
578 kfree_skb(skb);
579 s->last = what;
580 }
581 }
582
583 /*
584 * Decode DTMF tones, queue result in separate sk_buf for
585 * later examination.
586 * Parameters:
587 * s = pointer to state-struct.
588 * buf = input audio data
589 * len = size of audio data.
590 * fmt = audio data format (0 = ulaw, 1 = alaw)
591 */
592 void
isdn_audio_calc_dtmf(modem_info * info,unsigned char * buf,int len,int fmt)593 isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt)
594 {
595 dtmf_state *s = info->dtmf_state;
596 int i;
597 int c;
598
599 while (len) {
600 c = DTMF_NPOINTS - s->idx;
601 if (c > len)
602 c = len;
603 if (c <= 0)
604 break;
605 for (i = 0; i < c; i++) {
606 if (fmt)
607 s->buf[s->idx++] =
608 isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
609 else
610 s->buf[s->idx++] =
611 isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
612 }
613 if (s->idx == DTMF_NPOINTS) {
614 isdn_audio_goertzel(s->buf, info);
615 s->idx = 0;
616 }
617 len -= c;
618 }
619 }
620
621 silence_state *
isdn_audio_silence_init(silence_state * s)622 isdn_audio_silence_init(silence_state * s)
623 {
624 if (!s)
625 s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
626 if (s) {
627 s->idx = 0;
628 s->state = 0;
629 }
630 return s;
631 }
632
633 void
isdn_audio_calc_silence(modem_info * info,unsigned char * buf,int len,int fmt)634 isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt)
635 {
636 silence_state *s = info->silence_state;
637 int i;
638 signed char c;
639
640 if (!info->emu.vpar[1]) return;
641
642 for (i = 0; i < len; i++) {
643 if (fmt)
644 c = isdn_audio_alaw_to_ulaw[*buf++];
645 else
646 c = *buf++;
647
648 if (c > 0) c -= 128;
649 c = abs(c);
650
651 if (c > (info->emu.vpar[1] * 4)) {
652 s->idx = 0;
653 s->state = 1;
654 } else {
655 if (s->idx < 210000) s->idx++;
656 }
657 }
658 }
659
660 void
isdn_audio_put_dle_code(modem_info * info,u_char code)661 isdn_audio_put_dle_code(modem_info * info, u_char code)
662 {
663 struct sk_buff *skb;
664 int di;
665 int ch;
666 char *p;
667
668 skb = dev_alloc_skb(2);
669 if (!skb) {
670 printk(KERN_WARNING
671 "isdn_audio: Could not alloc skb for ttyI%d\n",
672 info->line);
673 return;
674 }
675 p = (char *) skb_put(skb, 2);
676 p[0] = 0x10;
677 p[1] = code;
678 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
679 ISDN_AUDIO_SKB_LOCK(skb) = 0;
680 di = info->isdn_driver;
681 ch = info->isdn_channel;
682 __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
683 dev->drv[di]->rcvcount[ch] += 2;
684 /* Schedule dequeuing */
685 if ((dev->modempoll) && (info->rcvsched))
686 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
687 wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
688 }
689
690 void
isdn_audio_eval_silence(modem_info * info)691 isdn_audio_eval_silence(modem_info * info)
692 {
693 silence_state *s = info->silence_state;
694 char what;
695
696 what = ' ';
697
698 if (s->idx > (info->emu.vpar[2] * 800)) {
699 s->idx = 0;
700 if (!s->state) { /* silence from beginning of rec */
701 what = 's';
702 } else {
703 what = 'q';
704 }
705 }
706 if ((what == 's') || (what == 'q')) {
707 printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
708 (what=='s') ? "silence":"quiet");
709 isdn_audio_put_dle_code(info, what);
710 }
711 }
712