Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/fax_modems.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 * fax_modems.c - the analogue modem set for fax processing | |
| 5 * | |
| 6 * Written by Steve Underwood <steveu@coppice.org> | |
| 7 * | |
| 8 * Copyright (C) 2003, 2005, 2006, 2008 Steve Underwood | |
| 9 * | |
| 10 * All rights reserved. | |
| 11 * | |
| 12 * This program is free software; you can redistribute it and/or modify | |
| 13 * it under the terms of the GNU Lesser General Public License version 2.1, | |
| 14 * as published by the Free Software Foundation. | |
| 15 * | |
| 16 * This program is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 * GNU Lesser General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU Lesser General Public | |
| 22 * License along with this program; if not, write to the Free Software | |
| 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 24 * | |
| 25 * $Id: fax_modems.c,v 1.8 2009/11/02 13:25:20 steveu Exp $ | |
| 26 */ | |
| 27 | |
| 28 /*! \file */ | |
| 29 | |
| 30 #if defined(HAVE_CONFIG_H) | |
| 31 #include "config.h" | |
| 32 #endif | |
| 33 | |
| 34 #include <inttypes.h> | |
| 35 #include <stdlib.h> | |
| 36 #include <stdio.h> | |
| 37 #include <string.h> | |
| 38 #if defined(HAVE_TGMATH_H) | |
| 39 #include <tgmath.h> | |
| 40 #endif | |
| 41 #if defined(HAVE_MATH_H) | |
| 42 #include <math.h> | |
| 43 #endif | |
| 44 #include "floating_fudge.h" | |
| 45 #include <assert.h> | |
| 46 #include <fcntl.h> | |
| 47 #include <time.h> | |
| 48 #if defined(LOG_FAX_AUDIO) | |
| 49 #include <unistd.h> | |
| 50 #endif | |
| 51 | |
| 52 #include "spandsp/telephony.h" | |
| 53 #include "spandsp/logging.h" | |
| 54 #include "spandsp/bit_operations.h" | |
| 55 #include "spandsp/dc_restore.h" | |
| 56 #include "spandsp/queue.h" | |
| 57 #include "spandsp/power_meter.h" | |
| 58 #include "spandsp/complex.h" | |
| 59 #include "spandsp/tone_detect.h" | |
| 60 #include "spandsp/tone_generate.h" | |
| 61 #include "spandsp/async.h" | |
| 62 #include "spandsp/crc.h" | |
| 63 #include "spandsp/hdlc.h" | |
| 64 #include "spandsp/silence_gen.h" | |
| 65 #include "spandsp/fsk.h" | |
| 66 #include "spandsp/v29tx.h" | |
| 67 #include "spandsp/v29rx.h" | |
| 68 #include "spandsp/v27ter_tx.h" | |
| 69 #include "spandsp/v27ter_rx.h" | |
| 70 #include "spandsp/v17tx.h" | |
| 71 #include "spandsp/v17rx.h" | |
| 72 #include "spandsp/super_tone_rx.h" | |
| 73 #include "spandsp/modem_connect_tones.h" | |
| 74 #include "spandsp/fax_modems.h" | |
| 75 | |
| 76 #include "spandsp/private/logging.h" | |
| 77 #include "spandsp/private/silence_gen.h" | |
| 78 #include "spandsp/private/fsk.h" | |
| 79 #include "spandsp/private/v17tx.h" | |
| 80 #include "spandsp/private/v17rx.h" | |
| 81 #include "spandsp/private/v27ter_tx.h" | |
| 82 #include "spandsp/private/v27ter_rx.h" | |
| 83 #include "spandsp/private/v29tx.h" | |
| 84 #include "spandsp/private/v29rx.h" | |
| 85 #include "spandsp/private/modem_connect_tones.h" | |
| 86 #include "spandsp/private/hdlc.h" | |
| 87 #include "spandsp/private/fax_modems.h" | |
| 88 | |
| 89 #define HDLC_FRAMING_OK_THRESHOLD 5 | |
| 90 | |
| 91 SPAN_DECLARE(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len) | |
| 92 { | |
| 93 fax_modems_state_t *s; | |
| 94 | |
| 95 s = (fax_modems_state_t *) user_data; | |
| 96 v17_rx(&s->v17_rx, amp, len); | |
| 97 fsk_rx(&s->v21_rx, amp, len); | |
| 98 if (s->rx_frame_received) | |
| 99 { | |
| 100 /* We have received something, and the fast modem has not trained. We must | |
| 101 be receiving valid V.21 */ | |
| 102 span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx)); | |
| 103 s->rx_handler = (span_rx_handler_t *) &fsk_rx; | |
| 104 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &fsk_rx_fillin; | |
| 105 s->rx_user_data = &s->v21_rx; | |
| 106 } | |
| 107 return 0; | |
| 108 } | |
| 109 /*- End of function --------------------------------------------------------*/ | |
| 110 | |
| 111 SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len) | |
| 112 { | |
| 113 fax_modems_state_t *s; | |
| 114 | |
| 115 s = (fax_modems_state_t *) user_data; | |
| 116 v17_rx_fillin(&s->v17_rx, len); | |
| 117 fsk_rx_fillin(&s->v21_rx, len); | |
| 118 return 0; | |
| 119 } | |
| 120 /*- End of function --------------------------------------------------------*/ | |
| 121 | |
| 122 SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len) | |
| 123 { | |
| 124 fax_modems_state_t *s; | |
| 125 | |
| 126 s = (fax_modems_state_t *) user_data; | |
| 127 v27ter_rx(&s->v27ter_rx, amp, len); | |
| 128 fsk_rx(&s->v21_rx, amp, len); | |
| 129 if (s->rx_frame_received) | |
| 130 { | |
| 131 /* We have received something, and the fast modem has not trained. We must | |
| 132 be receiving valid V.21 */ | |
| 133 span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx)); | |
| 134 s->rx_handler = (span_rx_handler_t *) &fsk_rx; | |
| 135 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &fsk_rx_fillin; | |
| 136 s->rx_user_data = &s->v21_rx; | |
| 137 } | |
| 138 return 0; | |
| 139 } | |
| 140 /*- End of function --------------------------------------------------------*/ | |
| 141 | |
| 142 SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len) | |
| 143 { | |
| 144 fax_modems_state_t *s; | |
| 145 | |
| 146 s = (fax_modems_state_t *) user_data; | |
| 147 v27ter_rx_fillin(&s->v27ter_rx, len); | |
| 148 fsk_rx_fillin(&s->v21_rx, len); | |
| 149 return 0; | |
| 150 } | |
| 151 /*- End of function --------------------------------------------------------*/ | |
| 152 | |
| 153 SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len) | |
| 154 { | |
| 155 fax_modems_state_t *s; | |
| 156 | |
| 157 s = (fax_modems_state_t *) user_data; | |
| 158 v29_rx(&s->v29_rx, amp, len); | |
| 159 fsk_rx(&s->v21_rx, amp, len); | |
| 160 if (s->rx_frame_received) | |
| 161 { | |
| 162 /* We have received something, and the fast modem has not trained. We must | |
| 163 be receiving valid V.21 */ | |
| 164 span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx)); | |
| 165 s->rx_handler = (span_rx_handler_t *) &fsk_rx; | |
| 166 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &fsk_rx_fillin; | |
| 167 s->rx_user_data = &s->v21_rx; | |
| 168 } | |
| 169 return 0; | |
| 170 } | |
| 171 /*- End of function --------------------------------------------------------*/ | |
| 172 | |
| 173 SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len) | |
| 174 { | |
| 175 fax_modems_state_t *s; | |
| 176 | |
| 177 s = (fax_modems_state_t *) user_data; | |
| 178 v29_rx_fillin(&s->v29_rx, len); | |
| 179 fsk_rx_fillin(&s->v21_rx, len); | |
| 180 return 0; | |
| 181 } | |
| 182 /*- End of function --------------------------------------------------------*/ | |
| 183 | |
| 184 static void v21_rx_status_handler(void *user_data, int status) | |
| 185 { | |
| 186 fax_modems_state_t *s; | |
| 187 | |
| 188 s = (fax_modems_state_t *) user_data; | |
| 189 } | |
| 190 /*- End of function --------------------------------------------------------*/ | |
| 191 | |
| 192 static void v17_rx_status_handler(void *user_data, int status) | |
| 193 { | |
| 194 fax_modems_state_t *s; | |
| 195 | |
| 196 s = (fax_modems_state_t *) user_data; | |
| 197 switch (status) | |
| 198 { | |
| 199 case SIG_STATUS_TRAINING_SUCCEEDED: | |
| 200 span_log(&s->logging, SPAN_LOG_FLOW, "Switching to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->v17_rx)); | |
| 201 s->rx_handler = (span_rx_handler_t *) &v17_rx; | |
| 202 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &v17_rx_fillin; | |
| 203 s->rx_user_data = &s->v17_rx; | |
| 204 break; | |
| 205 } | |
| 206 } | |
| 207 /*- End of function --------------------------------------------------------*/ | |
| 208 | |
| 209 static void v27ter_rx_status_handler(void *user_data, int status) | |
| 210 { | |
| 211 fax_modems_state_t *s; | |
| 212 | |
| 213 s = (fax_modems_state_t *) user_data; | |
| 214 switch (status) | |
| 215 { | |
| 216 case SIG_STATUS_TRAINING_SUCCEEDED: | |
| 217 span_log(&s->logging, SPAN_LOG_FLOW, "Switching to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->v27ter_rx)); | |
| 218 s->rx_handler = (span_rx_handler_t *) &v27ter_rx; | |
| 219 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &v27ter_rx_fillin; | |
| 220 s->rx_user_data = &s->v27ter_rx; | |
| 221 break; | |
| 222 } | |
| 223 } | |
| 224 /*- End of function --------------------------------------------------------*/ | |
| 225 | |
| 226 static void v29_rx_status_handler(void *user_data, int status) | |
| 227 { | |
| 228 fax_modems_state_t *s; | |
| 229 | |
| 230 s = (fax_modems_state_t *) user_data; | |
| 231 switch (status) | |
| 232 { | |
| 233 case SIG_STATUS_TRAINING_SUCCEEDED: | |
| 234 span_log(&s->logging, SPAN_LOG_FLOW, "Switching to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->v29_rx)); | |
| 235 s->rx_handler = (span_rx_handler_t *) &v29_rx; | |
| 236 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &v29_rx_fillin; | |
| 237 s->rx_user_data = &s->v29_rx; | |
| 238 break; | |
| 239 } | |
| 240 } | |
| 241 /*- End of function --------------------------------------------------------*/ | |
| 242 | |
| 243 SPAN_DECLARE(void) fax_modems_start_rx_modem(fax_modems_state_t *s, int which) | |
| 244 { | |
| 245 switch (which) | |
| 246 { | |
| 247 case FAX_MODEM_V17_RX: | |
| 248 v17_rx_set_modem_status_handler(&s->v17_rx, v17_rx_status_handler, s); | |
| 249 break; | |
| 250 case FAX_MODEM_V27TER_RX: | |
| 251 v27ter_rx_set_modem_status_handler(&s->v27ter_rx, v27ter_rx_status_handler, s); | |
| 252 break; | |
| 253 case FAX_MODEM_V29_RX: | |
| 254 v29_rx_set_modem_status_handler(&s->v29_rx, v29_rx_status_handler, s); | |
| 255 break; | |
| 256 } | |
| 257 fsk_rx_set_modem_status_handler(&s->v21_rx, v21_rx_status_handler, s); | |
| 258 } | |
| 259 /*- End of function --------------------------------------------------------*/ | |
| 260 | |
| 261 SPAN_DECLARE(void) fax_modems_set_tep_mode(fax_modems_state_t *s, int use_tep) | |
| 262 { | |
| 263 s->use_tep = use_tep; | |
| 264 } | |
| 265 /*- End of function --------------------------------------------------------*/ | |
| 266 | |
| 267 SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, | |
| 268 int use_tep, | |
| 269 hdlc_frame_handler_t hdlc_accept, | |
| 270 hdlc_underflow_handler_t hdlc_tx_underflow, | |
| 271 put_bit_func_t non_ecm_put_bit, | |
| 272 get_bit_func_t non_ecm_get_bit, | |
| 273 tone_report_func_t tone_callback, | |
| 274 void *user_data) | |
| 275 { | |
| 276 if (s == NULL) | |
| 277 { | |
| 278 if ((s = (fax_modems_state_t *) malloc(sizeof(*s))) == NULL) | |
| 279 return NULL; | |
| 280 } | |
| 281 memset(s, 0, sizeof(*s)); | |
| 282 s->use_tep = use_tep; | |
| 283 | |
| 284 hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, user_data); | |
| 285 hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_tx_underflow, user_data); | |
| 286 fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); | |
| 287 fsk_rx_signal_cutoff(&s->v21_rx, -39.09f); | |
| 288 fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); | |
| 289 v17_rx_init(&s->v17_rx, 14400, non_ecm_put_bit, user_data); | |
| 290 v17_tx_init(&s->v17_tx, 14400, s->use_tep, non_ecm_get_bit, user_data); | |
| 291 v29_rx_init(&s->v29_rx, 9600, non_ecm_put_bit, user_data); | |
| 292 v29_rx_signal_cutoff(&s->v29_rx, -45.5f); | |
| 293 v29_tx_init(&s->v29_tx, 9600, s->use_tep, non_ecm_get_bit, user_data); | |
| 294 v27ter_rx_init(&s->v27ter_rx, 4800, non_ecm_put_bit, user_data); | |
| 295 v27ter_tx_init(&s->v27ter_tx, 4800, s->use_tep, non_ecm_get_bit, user_data); | |
| 296 silence_gen_init(&s->silence_gen, 0); | |
| 297 modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG); | |
| 298 if (tone_callback) | |
| 299 { | |
| 300 modem_connect_tones_rx_init(&s->connect_rx, | |
| 301 MODEM_CONNECT_TONES_FAX_CNG, | |
| 302 tone_callback, | |
| 303 user_data); | |
| 304 } | |
| 305 dc_restore_init(&s->dc_restore); | |
| 306 | |
| 307 s->rx_signal_present = FALSE; | |
| 308 s->rx_handler = (span_rx_handler_t *) &span_dummy_rx; | |
| 309 s->rx_fillin_handler = (span_rx_fillin_handler_t *) &span_dummy_rx; | |
| 310 s->rx_user_data = NULL; | |
| 311 s->tx_handler = (span_tx_handler_t *) &silence_gen; | |
| 312 s->tx_user_data = &s->silence_gen; | |
| 313 return s; | |
| 314 } | |
| 315 /*- End of function --------------------------------------------------------*/ | |
| 316 | |
| 317 SPAN_DECLARE(int) fax_modems_release(fax_modems_state_t *s) | |
| 318 { | |
| 319 return 0; | |
| 320 } | |
| 321 /*- End of function --------------------------------------------------------*/ | |
| 322 | |
| 323 SPAN_DECLARE(int) fax_modems_free(fax_modems_state_t *s) | |
| 324 { | |
| 325 if (s) | |
| 326 free(s); | |
| 327 return 0; | |
| 328 } | |
| 329 /*- End of function --------------------------------------------------------*/ | |
| 330 /*- End of file ------------------------------------------------------------*/ |
