Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/modem_connect_tones.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * modem_connect_tones.c - Generation and detection of tones | |
5 * associated with modems calling and answering calls. | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2006 Steve Underwood | |
10 * | |
11 * All rights reserved. | |
12 * | |
13 * This program is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU Lesser General Public License version 2.1, | |
15 * as published by the Free Software Foundation. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU Lesser General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU Lesser General Public | |
23 * License along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 * | |
26 * $Id: modem_connect_tones.c,v 1.41 2009/11/06 19:21:33 steveu Exp $ | |
27 */ | |
28 | |
29 /*! \file */ | |
30 | |
31 /* CNG is 0.5s+-15% of 1100+-38Hz, 3s+-15% off, repeating. | |
32 | |
33 CED is 0.2s silence, 3.3+-0.7s of 2100+-15Hz, and 75+-20ms of silence. | |
34 | |
35 ANS is 3.3+-0.7s of 2100+-15Hz. | |
36 | |
37 ANS/ is 3.3+-0.7s of 2100+-15Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms. | |
38 | |
39 ANSam/ is 2100+-1Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms, and AM with a sinewave of 15+-0.1Hz. | |
40 The modulated envelope ranges in amplitude between (0.8+-0.01) and (1.2+-0.01) times its average | |
41 amplitude. It lasts up to 5s, but will be stopped early if the V.8 protocol proceeds. */ | |
42 | |
43 #if defined(HAVE_CONFIG_H) | |
44 #include "config.h" | |
45 #endif | |
46 | |
47 #include <inttypes.h> | |
48 #include <stdlib.h> | |
49 #include <memory.h> | |
50 #if defined(HAVE_TGMATH_H) | |
51 #include <tgmath.h> | |
52 #endif | |
53 #if defined(HAVE_MATH_H) | |
54 #include <math.h> | |
55 #endif | |
56 #include "floating_fudge.h" | |
57 #include <stdio.h> | |
58 | |
59 #include "spandsp/telephony.h" | |
60 #include "spandsp/fast_convert.h" | |
61 #include "spandsp/logging.h" | |
62 #include "spandsp/complex.h" | |
63 #include "spandsp/dds.h" | |
64 #include "spandsp/tone_detect.h" | |
65 #include "spandsp/tone_generate.h" | |
66 #include "spandsp/super_tone_rx.h" | |
67 #include "spandsp/power_meter.h" | |
68 #include "spandsp/async.h" | |
69 #include "spandsp/fsk.h" | |
70 #include "spandsp/modem_connect_tones.h" | |
71 | |
72 #include "spandsp/private/fsk.h" | |
73 #include "spandsp/private/modem_connect_tones.h" | |
74 | |
75 #define HDLC_FRAMING_OK_THRESHOLD 5 | |
76 | |
77 SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone) | |
78 { | |
79 switch (tone) | |
80 { | |
81 case MODEM_CONNECT_TONES_NONE: | |
82 return "No tone"; | |
83 case MODEM_CONNECT_TONES_FAX_CNG: | |
84 return "FAX CNG"; | |
85 case MODEM_CONNECT_TONES_ANS: | |
86 return "ANS or FAX CED"; | |
87 case MODEM_CONNECT_TONES_ANS_PR: | |
88 return "ANS/"; | |
89 case MODEM_CONNECT_TONES_ANSAM: | |
90 return "ANSam"; | |
91 case MODEM_CONNECT_TONES_ANSAM_PR: | |
92 return "ANSam/"; | |
93 case MODEM_CONNECT_TONES_FAX_PREAMBLE: | |
94 return "FAX preamble"; | |
95 case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: | |
96 return "FAX CED or preamble"; | |
97 } | |
98 return "???"; | |
99 } | |
100 /*- End of function --------------------------------------------------------*/ | |
101 | |
102 SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s, | |
103 int16_t amp[], | |
104 int len) | |
105 { | |
106 int16_t mod; | |
107 int i; | |
108 int xlen; | |
109 | |
110 i = 0; | |
111 switch (s->tone_type) | |
112 { | |
113 case MODEM_CONNECT_TONES_FAX_CNG: | |
114 for ( ; i < len; i++) | |
115 { | |
116 if (s->duration_timer > ms_to_samples(3000)) | |
117 { | |
118 if ((xlen = i + s->duration_timer - ms_to_samples(3000)) > len) | |
119 xlen = len; | |
120 s->duration_timer -= (xlen - i); | |
121 for ( ; i < xlen; i++) | |
122 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
123 } | |
124 if (s->duration_timer > 0) | |
125 { | |
126 if ((xlen = i + s->duration_timer) > len) | |
127 xlen = len; | |
128 s->duration_timer -= (xlen - i); | |
129 memset(amp + i, 0, sizeof(int16_t)*(xlen - i)); | |
130 i = xlen; | |
131 } | |
132 if (s->duration_timer == 0) | |
133 s->duration_timer = ms_to_samples(500 + 3000); | |
134 } | |
135 break; | |
136 case MODEM_CONNECT_TONES_ANS: | |
137 if (s->duration_timer < len) | |
138 len = s->duration_timer; | |
139 if (s->duration_timer > ms_to_samples(2600)) | |
140 { | |
141 /* There is some initial silence to be generated. */ | |
142 if ((i = s->duration_timer - ms_to_samples(2600)) > len) | |
143 i = len; | |
144 memset(amp, 0, sizeof(int16_t)*i); | |
145 } | |
146 for ( ; i < len; i++) | |
147 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
148 s->duration_timer -= len; | |
149 break; | |
150 case MODEM_CONNECT_TONES_ANS_PR: | |
151 if (s->duration_timer < len) | |
152 len = s->duration_timer; | |
153 if (s->duration_timer > ms_to_samples(3300)) | |
154 { | |
155 if ((i = s->duration_timer - ms_to_samples(3300)) > len) | |
156 i = len; | |
157 memset(amp, 0, sizeof(int16_t)*i); | |
158 } | |
159 for ( ; i < len; i++) | |
160 { | |
161 if (--s->hop_timer <= 0) | |
162 { | |
163 s->hop_timer = ms_to_samples(450); | |
164 s->tone_phase += 0x80000000; | |
165 } | |
166 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
167 } | |
168 s->duration_timer -= len; | |
169 break; | |
170 case MODEM_CONNECT_TONES_ANSAM: | |
171 if (s->duration_timer < len) | |
172 len = s->duration_timer; | |
173 if (s->duration_timer > ms_to_samples(5000)) | |
174 { | |
175 if ((i = s->duration_timer - ms_to_samples(5000)) > len) | |
176 i = len; | |
177 memset(amp, 0, sizeof(int16_t)*i); | |
178 } | |
179 for ( ; i < len; i++) | |
180 { | |
181 mod = (int16_t) (s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0)); | |
182 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); | |
183 } | |
184 s->duration_timer -= len; | |
185 break; | |
186 case MODEM_CONNECT_TONES_ANSAM_PR: | |
187 if (s->duration_timer < len) | |
188 len = s->duration_timer; | |
189 if (s->duration_timer > ms_to_samples(5000)) | |
190 { | |
191 if ((i = s->duration_timer - ms_to_samples(5000)) > len) | |
192 i = len; | |
193 memset(amp, 0, sizeof(int16_t)*i); | |
194 } | |
195 for ( ; i < len; i++) | |
196 { | |
197 if (--s->hop_timer <= 0) | |
198 { | |
199 s->hop_timer = ms_to_samples(450); | |
200 s->tone_phase += 0x80000000; | |
201 } | |
202 mod = (int16_t) (s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0)); | |
203 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); | |
204 } | |
205 s->duration_timer -= len; | |
206 break; | |
207 } | |
208 return len; | |
209 } | |
210 /*- End of function --------------------------------------------------------*/ | |
211 | |
212 SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem_connect_tones_tx_state_t *s, | |
213 int tone_type) | |
214 { | |
215 int alloced; | |
216 | |
217 alloced = FALSE; | |
218 if (s == NULL) | |
219 { | |
220 if ((s = (modem_connect_tones_tx_state_t *) malloc(sizeof(*s))) == NULL) | |
221 return NULL; | |
222 alloced = TRUE; | |
223 } | |
224 s->tone_type = tone_type; | |
225 switch (s->tone_type) | |
226 { | |
227 case MODEM_CONNECT_TONES_FAX_CNG: | |
228 /* 0.5s of 1100Hz+-38Hz + 3.0s of silence repeating. Timing +-15% */ | |
229 s->tone_phase_rate = dds_phase_rate(1100.0); | |
230 s->level = dds_scaling_dbm0(-11); | |
231 s->duration_timer = ms_to_samples(500 + 3000); | |
232 s->mod_phase_rate = 0; | |
233 s->tone_phase = 0; | |
234 s->mod_phase = 0; | |
235 s->mod_level = 0; | |
236 s->hop_timer = 0; | |
237 break; | |
238 case MODEM_CONNECT_TONES_ANS: | |
239 case MODEM_CONNECT_TONES_ANSAM: | |
240 /* 0.2s of silence, then 2.6s to 4s of 2100Hz+-15Hz tone, then 75ms of silence. */ | |
241 s->tone_phase_rate = dds_phase_rate(2100.0); | |
242 s->level = dds_scaling_dbm0(-11); | |
243 if (s->tone_type == MODEM_CONNECT_TONES_ANSAM) | |
244 { | |
245 s->mod_phase_rate = dds_phase_rate(15.0); | |
246 s->mod_level = s->level/5; | |
247 s->duration_timer = ms_to_samples(200 + 5000); | |
248 } | |
249 else | |
250 { | |
251 s->mod_phase_rate = 0; | |
252 s->mod_level = 0; | |
253 s->duration_timer = ms_to_samples(200 + 2600); | |
254 } | |
255 s->tone_phase = 0; | |
256 s->mod_phase = 0; | |
257 s->hop_timer = 0; | |
258 break; | |
259 case MODEM_CONNECT_TONES_ANS_PR: | |
260 case MODEM_CONNECT_TONES_ANSAM_PR: | |
261 s->tone_phase_rate = dds_phase_rate(2100.0); | |
262 s->level = dds_scaling_dbm0(-12); | |
263 if (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR) | |
264 { | |
265 s->mod_phase_rate = dds_phase_rate(15.0); | |
266 s->mod_level = s->level/5; | |
267 s->duration_timer = ms_to_samples(200 + 5000); | |
268 } | |
269 else | |
270 { | |
271 s->mod_phase_rate = 0; | |
272 s->mod_level = 0; | |
273 s->duration_timer = ms_to_samples(200 + 3300); | |
274 } | |
275 s->tone_phase = 0; | |
276 s->mod_phase = 0; | |
277 s->hop_timer = ms_to_samples(450); | |
278 break; | |
279 default: | |
280 if (alloced) | |
281 free(s); | |
282 return NULL; | |
283 } | |
284 return s; | |
285 } | |
286 /*- End of function --------------------------------------------------------*/ | |
287 | |
288 SPAN_DECLARE(int) modem_connect_tones_tx_release(modem_connect_tones_tx_state_t *s) | |
289 { | |
290 return 0; | |
291 } | |
292 /*- End of function --------------------------------------------------------*/ | |
293 | |
294 SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s) | |
295 { | |
296 free(s); | |
297 return 0; | |
298 } | |
299 /*- End of function --------------------------------------------------------*/ | |
300 | |
301 static void report_tone_state(modem_connect_tones_rx_state_t *s, int tone, int level) | |
302 { | |
303 if (tone != s->tone_present) | |
304 { | |
305 if (s->tone_callback) | |
306 { | |
307 s->tone_callback(s->callback_data, tone, level, 0); | |
308 } | |
309 else | |
310 { | |
311 if (tone != MODEM_CONNECT_TONES_NONE) | |
312 s->hit = tone; | |
313 } | |
314 s->tone_present = tone; | |
315 } | |
316 } | |
317 /*- End of function --------------------------------------------------------*/ | |
318 | |
319 static void v21_put_bit(void *user_data, int bit) | |
320 { | |
321 modem_connect_tones_rx_state_t *s; | |
322 | |
323 s = (modem_connect_tones_rx_state_t *) user_data; | |
324 if (bit < 0) | |
325 { | |
326 /* Special conditions. */ | |
327 switch (bit) | |
328 { | |
329 case SIG_STATUS_CARRIER_DOWN: | |
330 /* Only declare tone off, if we were the one to declare tone on. */ | |
331 if (s->tone_present == MODEM_CONNECT_TONES_FAX_PREAMBLE) | |
332 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
333 /* Fall through */ | |
334 case SIG_STATUS_CARRIER_UP: | |
335 s->raw_bit_stream = 0; | |
336 s->num_bits = 0; | |
337 s->flags_seen = 0; | |
338 s->framing_ok_announced = FALSE; | |
339 break; | |
340 } | |
341 return; | |
342 } | |
343 /* Look for enough FAX V.21 message preamble (back to back HDLC flag octets) to be sure | |
344 we are really seeing preamble, and declare the signal to be present. Any change from | |
345 preamble declares the signal to not be present, though it will probably be the body | |
346 of the messages following the preamble. */ | |
347 s->raw_bit_stream = (s->raw_bit_stream << 1) | ((bit << 8) & 0x100); | |
348 s->num_bits++; | |
349 if ((s->raw_bit_stream & 0x7F00) == 0x7E00) | |
350 { | |
351 if ((s->raw_bit_stream & 0x8000)) | |
352 { | |
353 /* Hit HDLC abort */ | |
354 s->flags_seen = 0; | |
355 } | |
356 else | |
357 { | |
358 /* Hit HDLC flag */ | |
359 if (s->flags_seen < HDLC_FRAMING_OK_THRESHOLD) | |
360 { | |
361 /* Check the flags are back-to-back when testing for valid preamble. This | |
362 greatly reduces the chances of false preamble detection, and anything | |
363 which doesn't send them back-to-back is badly broken. */ | |
364 if (s->num_bits != 8) | |
365 s->flags_seen = 0; | |
366 if (++s->flags_seen >= HDLC_FRAMING_OK_THRESHOLD && !s->framing_ok_announced) | |
367 { | |
368 report_tone_state(s, MODEM_CONNECT_TONES_FAX_PREAMBLE, lfastrintf(fsk_rx_signal_power(&(s->v21rx)))); | |
369 s->framing_ok_announced = TRUE; | |
370 } | |
371 } | |
372 } | |
373 s->num_bits = 0; | |
374 } | |
375 else | |
376 { | |
377 if (s->flags_seen >= HDLC_FRAMING_OK_THRESHOLD) | |
378 { | |
379 if (s->num_bits == 8) | |
380 { | |
381 s->framing_ok_announced = FALSE; | |
382 s->flags_seen = 0; | |
383 } | |
384 } | |
385 } | |
386 } | |
387 /*- End of function --------------------------------------------------------*/ | |
388 | |
389 SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s, | |
390 const int16_t amp[], | |
391 int len) | |
392 { | |
393 int i; | |
394 int16_t notched; | |
395 float v1; | |
396 float famp; | |
397 float filtered; | |
398 | |
399 switch (s->tone_type) | |
400 { | |
401 case MODEM_CONNECT_TONES_FAX_CNG: | |
402 for (i = 0; i < len; i++) | |
403 { | |
404 famp = amp[i]; | |
405 /* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth | |
406 criteria. */ | |
407 v1 = 0.792928f*famp + 1.0018744927985f*s->znotch_1 - 0.54196833412465f*s->znotch_2; | |
408 famp = v1 - 1.2994747954630f*s->znotch_1 + s->znotch_2; | |
409 s->znotch_2 = s->znotch_1; | |
410 s->znotch_1 = v1; | |
411 notched = (int16_t) lfastrintf(famp); | |
412 | |
413 /* Estimate the overall energy in the channel, and the energy in | |
414 the notch (i.e. overall channel energy - tone energy => noise). | |
415 Use abs instead of multiply for speed (is it really faster?). */ | |
416 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
417 s->notch_level += ((abs(notched) - s->notch_level) >> 5); | |
418 if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) | |
419 { | |
420 /* There is adequate energy in the channel, and it is mostly at 1100Hz. */ | |
421 if (s->tone_present != MODEM_CONNECT_TONES_FAX_CNG) | |
422 { | |
423 if (++s->tone_cycle_duration >= ms_to_samples(415)) | |
424 report_tone_state(s, MODEM_CONNECT_TONES_FAX_CNG, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); | |
425 } | |
426 } | |
427 else | |
428 { | |
429 /* If the signal looks wrong, even for a moment, we consider this the | |
430 end of the tone. */ | |
431 if (s->tone_present == MODEM_CONNECT_TONES_FAX_CNG) | |
432 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
433 s->tone_cycle_duration = 0; | |
434 } | |
435 } | |
436 break; | |
437 case MODEM_CONNECT_TONES_FAX_PREAMBLE: | |
438 /* Ignore any CED tone, and just look for V.21 preamble. */ | |
439 fsk_rx(&(s->v21rx), amp, len); | |
440 break; | |
441 case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: | |
442 /* Also look for V.21 preamble. A lot of machines don't send the 2100Hz burst. It | |
443 might also not be seen all the way through the channel, due to switching delays. */ | |
444 fsk_rx(&(s->v21rx), amp, len); | |
445 /* Now fall through and look for a 2100Hz tone */ | |
446 case MODEM_CONNECT_TONES_ANS: | |
447 for (i = 0; i < len; i++) | |
448 { | |
449 famp = amp[i]; | |
450 /* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */ | |
451 v1 = fabs(famp) + 1.996667f*s->z15hz_1 - 0.9968004f*s->z15hz_2; | |
452 filtered = 0.001599787f*(v1 - s->z15hz_2); | |
453 s->z15hz_2 = s->z15hz_1; | |
454 s->z15hz_1 = v1; | |
455 s->am_level += abs(lfastrintf(filtered)) - (s->am_level >> 8); | |
456 //printf("%9.1f %10.4f %9d %9d\n", famp, filtered, s->am_level, s->channel_level); | |
457 /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth | |
458 criteria. */ | |
459 /* This is actually centred at 2095Hz, but gets the balance we want, due | |
460 to the asymmetric walls of the notch */ | |
461 v1 = 0.76000f*famp - 0.1183852f*s->znotch_1 - 0.5104039f*s->znotch_2; | |
462 famp = v1 + 0.1567596f*s->znotch_1 + s->znotch_2; | |
463 s->znotch_2 = s->znotch_1; | |
464 s->znotch_1 = v1; | |
465 notched = (int16_t) lfastrintf(famp); | |
466 /* Estimate the overall energy in the channel, and the energy in | |
467 the notch (i.e. overall channel energy - tone energy => noise). | |
468 Use abs instead of multiply for speed (is it really faster?). | |
469 Damp the overall energy a little more for a stable result. | |
470 Damp the notch energy a little less, so we don't damp out the | |
471 blip every time the phase reverses. */ | |
472 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
473 s->notch_level += ((abs(notched) - s->notch_level) >> 4); | |
474 /* This should cut off at about -43dBm0 */ | |
475 if (s->channel_level <= 70) | |
476 { | |
477 /* If the energy level is low, even for a moment, we consider this the | |
478 end of the tone. */ | |
479 if (s->tone_present != MODEM_CONNECT_TONES_NONE) | |
480 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
481 s->tone_cycle_duration = 0; | |
482 s->good_cycles = 0; | |
483 s->tone_on = FALSE; | |
484 continue; | |
485 } | |
486 /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ | |
487 s->tone_cycle_duration++; | |
488 if (s->notch_level*6 < s->channel_level) | |
489 { | |
490 /* The notch test says yes, so we have the tone. */ | |
491 /* We should get a kick from the notch filter every 450+-25ms, as the phase reverses, for an | |
492 EC disable tone. For a simple answer tone, the tone should persist unbroken for longer. */ | |
493 if (!s->tone_on) | |
494 { | |
495 if (s->tone_cycle_duration >= ms_to_samples(450 - 25)) | |
496 { | |
497 if (++s->good_cycles == 3) | |
498 { | |
499 report_tone_state(s, | |
500 (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANS_PR, | |
501 lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); | |
502 } | |
503 } | |
504 else | |
505 { | |
506 s->good_cycles = 0; | |
507 } | |
508 /* Cycles are timed from rising edge to rising edge */ | |
509 s->tone_cycle_duration = 0; | |
510 } | |
511 else | |
512 { | |
513 if (s->tone_cycle_duration >= ms_to_samples(450 + 100)) | |
514 { | |
515 if (s->tone_present == MODEM_CONNECT_TONES_NONE) | |
516 { | |
517 report_tone_state(s, | |
518 (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM : MODEM_CONNECT_TONES_ANS, | |
519 lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); | |
520 } | |
521 s->good_cycles = 0; | |
522 s->tone_cycle_duration = ms_to_samples(450 + 100); | |
523 } | |
524 } | |
525 s->tone_on = TRUE; | |
526 } | |
527 else if (s->notch_level*5 > s->channel_level) | |
528 { | |
529 if (s->tone_present == MODEM_CONNECT_TONES_ANS) | |
530 { | |
531 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
532 s->good_cycles = 0; | |
533 } | |
534 else | |
535 { | |
536 if (s->tone_cycle_duration >= ms_to_samples(450 + 25)) | |
537 { | |
538 /* The change came too late for a cycle of ANS_PR tone */ | |
539 if (s->tone_present == MODEM_CONNECT_TONES_ANS_PR || s->tone_present == MODEM_CONNECT_TONES_ANSAM_PR) | |
540 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
541 s->good_cycles = 0; | |
542 } | |
543 } | |
544 s->tone_on = FALSE; | |
545 } | |
546 } | |
547 break; | |
548 } | |
549 return 0; | |
550 } | |
551 /*- End of function --------------------------------------------------------*/ | |
552 | |
553 SPAN_DECLARE(int) modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s) | |
554 { | |
555 int x; | |
556 | |
557 x = s->hit; | |
558 s->hit = MODEM_CONNECT_TONES_NONE; | |
559 return x; | |
560 } | |
561 /*- End of function --------------------------------------------------------*/ | |
562 | |
563 SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem_connect_tones_rx_state_t *s, | |
564 int tone_type, | |
565 tone_report_func_t tone_callback, | |
566 void *user_data) | |
567 { | |
568 if (s == NULL) | |
569 { | |
570 if ((s = (modem_connect_tones_rx_state_t *) malloc(sizeof(*s))) == NULL) | |
571 return NULL; | |
572 } | |
573 | |
574 s->tone_type = tone_type; | |
575 switch (s->tone_type) | |
576 { | |
577 case MODEM_CONNECT_TONES_FAX_PREAMBLE: | |
578 case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: | |
579 fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, s); | |
580 fsk_rx_signal_cutoff(&(s->v21rx), -45.5f); | |
581 break; | |
582 case MODEM_CONNECT_TONES_ANS_PR: | |
583 case MODEM_CONNECT_TONES_ANSAM: | |
584 case MODEM_CONNECT_TONES_ANSAM_PR: | |
585 /* Treat these all the same for receive purposes */ | |
586 s->tone_type = MODEM_CONNECT_TONES_ANS; | |
587 break; | |
588 } | |
589 s->channel_level = 0; | |
590 s->notch_level = 0; | |
591 s->am_level = 0; | |
592 s->tone_present = MODEM_CONNECT_TONES_NONE; | |
593 s->tone_cycle_duration = 0; | |
594 s->good_cycles = 0; | |
595 s->hit = MODEM_CONNECT_TONES_NONE; | |
596 s->tone_on = FALSE; | |
597 s->tone_callback = tone_callback; | |
598 s->callback_data = user_data; | |
599 s->znotch_1 = 0.0f; | |
600 s->znotch_2 = 0.0f; | |
601 s->z15hz_1 = 0.0f; | |
602 s->z15hz_2 = 0.0f; | |
603 s->num_bits = 0; | |
604 s->flags_seen = 0; | |
605 s->framing_ok_announced = FALSE; | |
606 s->raw_bit_stream = 0; | |
607 return s; | |
608 } | |
609 /*- End of function --------------------------------------------------------*/ | |
610 | |
611 SPAN_DECLARE(int) modem_connect_tones_rx_release(modem_connect_tones_rx_state_t *s) | |
612 { | |
613 return 0; | |
614 } | |
615 /*- End of function --------------------------------------------------------*/ | |
616 | |
617 SPAN_DECLARE(int) modem_connect_tones_rx_free(modem_connect_tones_rx_state_t *s) | |
618 { | |
619 free(s); | |
620 return 0; | |
621 } | |
622 /*- End of function --------------------------------------------------------*/ | |
623 /*- End of file ------------------------------------------------------------*/ |