blob: 78ce422147137c97a17391bfbdcfdd65ca2baa5b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "isdn_audio.h"
17#include "isdn_common.h"
18
19char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
20
21/*
22 * Misc. lookup-tables.
23 */
24
25/* ulaw -> signed 16-bit */
26static 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 */
63static 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 */
100static 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 */
137static 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 */
183static int cos2pik[NCOEFF] =
184{
185 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
186};
187
188static 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
196static inline void
197isdn_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"
Joe Perches475be4d2012-02-19 19:52:38 -0800207 : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
208 : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
209 : "memory", "ax");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210#else
211 while (n--)
212 *buff = table[*(unsigned char *)buff], buff++;
213#endif
214}
215
216void
217isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
218{
219 isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
220}
221
222void
223isdn_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
241static unsigned char
242isdn_audio_linear2ulaw(int sample)
243{
244 static int exp_lut[256] =
Joe Perches475be4d2012-02-19 19:52:38 -0800245 {
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 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 int sign,
Joe Perches475be4d2012-02-19 19:52:38 -0800264 exponent,
265 mantissa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 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
289static 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
296static int bitmask[9] =
297{
298 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
299};
300
301static int
Joe Perches475be4d2012-02-19 19:52:38 -0800302isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
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
314static void
Joe Perches475be4d2012-02-19 19:52:38 -0800315isdn_audio_put_bits(int data, int nbits, adpcm_state *s,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 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
328adpcm_state *
Joe Perches475be4d2012-02-19 19:52:38 -0800329isdn_audio_adpcm_init(adpcm_state *s, int nbits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
331 if (!s)
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800332 s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 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
343dtmf_state *
Joe Perches475be4d2012-02-19 19:52:38 -0800344isdn_audio_dtmf_init(dtmf_state *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 if (!s)
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800347 s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 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
360int
Joe Perches475be4d2012-02-19 19:52:38 -0800361isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 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[
Joe Perches475be4d2012-02-19 19:52:38 -0800382 isdn_audio_linear2ulaw(a << 2)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 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
395int
Joe Perches475be4d2012-02-19 19:52:38 -0800396isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 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,
Joe Perches475be4d2012-02-19 19:52:38 -0800406 nmax = 1 << (nbits - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 int sign,
Joe Perches475be4d2012-02-19 19:52:38 -0800408 delta;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
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.
Joe Perches475be4d2012-02-19 19:52:38 -0800442 * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 * for more info.
444 * Result is stored into an sk_buff and queued up for later
445 * evaluation.
446 */
447static void
Joe Perches475be4d2012-02-19 19:52:38 -0800448isdn_audio_goertzel(int *sample, modem_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 int sk,
Joe Perches475be4d2012-02-19 19:52:38 -0800451 sk1,
452 sk2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 int k,
Joe Perches475be4d2012-02-19 19:52:38 -0800454 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 struct sk_buff *skb;
456 int *result;
457
458 skb = dev_alloc_skb(sizeof(int) * NCOEFF);
459 if (!skb) {
460 printk(KERN_WARNING
Joe Perches475be4d2012-02-19 19:52:38 -0800461 "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 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] =
Joe Perches475be4d2012-02-19 19:52:38 -0800486 ((sk * sk) >> AMP_BITS) -
487 ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
488 ((sk2 * sk2) >> AMP_BITS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 }
490 skb_queue_tail(&info->dtmf_queue, skb);
491 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
492}
493
494void
Joe Perches475be4d2012-02-19 19:52:38 -0800495isdn_audio_eval_dtmf(modem_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
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 */
592void
Joe Perches475be4d2012-02-19 19:52:38 -0800593isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
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++] =
Joe Perches475be4d2012-02-19 19:52:38 -0800608 isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 else
610 s->buf[s->idx++] =
Joe Perches475be4d2012-02-19 19:52:38 -0800611 isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
613 if (s->idx == DTMF_NPOINTS) {
614 isdn_audio_goertzel(s->buf, info);
615 s->idx = 0;
616 }
617 len -= c;
618 }
619}
620
621silence_state *
Joe Perches475be4d2012-02-19 19:52:38 -0800622isdn_audio_silence_init(silence_state *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
624 if (!s)
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800625 s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (s) {
627 s->idx = 0;
628 s->state = 0;
629 }
630 return s;
631}
632
633void
Joe Perches475be4d2012-02-19 19:52:38 -0800634isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
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)
Joe Perches475be4d2012-02-19 19:52:38 -0800644 c = isdn_audio_alaw_to_ulaw[*buf++];
645 else
646 c = *buf++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 if (c > 0) c -= 128;
649 c = abs(c);
650
Joe Perches475be4d2012-02-19 19:52:38 -0800651 if (c > (info->emu.vpar[1] * 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 s->idx = 0;
Joe Perches475be4d2012-02-19 19:52:38 -0800653 s->state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 } else {
Joe Perches475be4d2012-02-19 19:52:38 -0800655 if (s->idx < 210000) s->idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 }
657 }
658}
659
660void
Joe Perches475be4d2012-02-19 19:52:38 -0800661isdn_audio_put_dle_code(modem_info *info, u_char code)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
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
Joe Perches475be4d2012-02-19 19:52:38 -0800671 "isdn_audio: Could not alloc skb for ttyI%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 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
690void
Joe Perches475be4d2012-02-19 19:52:38 -0800691isdn_audio_eval_silence(modem_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 silence_state *s = info->silence_state;
694 char what;
695
696 what = ' ';
697
Joe Perches475be4d2012-02-19 19:52:38 -0800698 if (s->idx > (info->emu.vpar[2] * 800)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 s->idx = 0;
Joe Perches475be4d2012-02-19 19:52:38 -0800700 if (!s->state) { /* silence from beginning of rec */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 what = 's';
702 } else {
703 what = 'q';
704 }
705 }
Joe Perches475be4d2012-02-19 19:52:38 -0800706 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}