Asterisk - The Open Source Telephony Project  GIT-master-a24979a
res_fax_spandsp.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009-2010, Digium, Inc.
5  *
6  * Matthew Nicholson <mnicholson@digium.com>
7  *
8  * Initial T.38-gateway code
9  * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
10  * Created by Nethemba s.r.o. http://www.nethemba.com
11  * Sponsored by IPEX a.s. http://www.ipex.cz
12  *
13  * T.38-gateway integration into asterisk app_fax and rework
14  * 2008, Gregory Hinton Nietsky <gregory@dnstelecom.co.za>
15  * dns Telecom http://www.dnstelecom.co.za
16  *
17  * Modified to make T.38-gateway compatible with Asterisk 1.6.2
18  * 2010, Anton Verevkin <mymail@verevkin.it>
19  * ViaNetTV http://www.vianettv.com
20  *
21  * Modified to make T.38-gateway work
22  * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
23  *
24  * See http://www.asterisk.org for more information about
25  * the Asterisk project. Please do not directly contact
26  * any of the maintainers of this project for assistance;
27  * the project provides a web site, mailing lists and IRC
28  * channels for your use.
29  *
30  * This program is free software, distributed under the terms of
31  * the GNU General Public License Version 2. See the LICENSE file
32  * at the top of the source tree.
33  */
34 
35 /*! \file
36  *
37  * \brief Spandsp T.38 and G.711 FAX Resource
38  *
39  * \author Matthew Nicholson <mnicholson@digium.com>
40  * \author Gregory H. Nietsky <gregory@distrotech.co.za>
41  *
42  * This module registers the Spandsp FAX technology with the res_fax module.
43  */
44 
45 /*** MODULEINFO
46  <depend>spandsp</depend>
47  <depend>res_fax</depend>
48  <support_level>extended</support_level>
49 ***/
50 
51 /* Needed for spandsp headers */
52 #define ASTMM_LIBC ASTMM_IGNORE
53 #include "asterisk.h"
54 
55 #include "asterisk/logger.h"
56 #include "asterisk/module.h"
57 #include "asterisk/strings.h"
58 #include "asterisk/cli.h"
59 #include "asterisk/utils.h"
60 #include "asterisk/timing.h"
61 #include "asterisk/astobj2.h"
62 #include "asterisk/res_fax.h"
63 #include "asterisk/channel.h"
64 #include "asterisk/format_cache.h"
65 
66 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
67 #include <spandsp.h>
68 #include <spandsp/version.h>
69 
70 #define SPANDSP_FAX_SAMPLES 160
71 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */
72 #define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
73 
74 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
75 static void spandsp_fax_destroy(struct ast_fax_session *s);
76 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
77 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
78 static int spandsp_fax_start(struct ast_fax_session *s);
79 static int spandsp_fax_cancel(struct ast_fax_session *s);
80 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
81 static int spandsp_fax_gateway_start(struct ast_fax_session *s);
82 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
83 static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
84 static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
85 static void spandsp_v21_cleanup(struct ast_fax_session *s);
86 static void spandsp_v21_tone(void *data, int code, int level, int delay);
87 
88 static char *spandsp_fax_cli_show_capabilities(int fd);
89 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
90 static void spandsp_manager_fax_session(struct mansession *s,
91  const char *id_text, struct ast_fax_session *session);
92 static char *spandsp_fax_cli_show_stats(int fd);
93 static char *spandsp_fax_cli_show_settings(int fd);
94 
95 static struct ast_fax_tech spandsp_fax_tech = {
96  .type = "Spandsp",
97  .description = "Spandsp FAX Driver",
98 #if SPANDSP_RELEASE_DATE >= 20090220
99  /* spandsp 0.0.6 */
100  .version = SPANDSP_RELEASE_DATETIME_STRING,
101 #else
102  /* spandsp 0.0.5
103  * TODO: maybe we should determine the version better way
104  */
105  .version = "pre-20090220",
106 #endif
110  .new_session = spandsp_fax_new,
111  .destroy_session = spandsp_fax_destroy,
112  .read = spandsp_fax_read,
113  .write = spandsp_fax_write,
114  .start_session = spandsp_fax_start,
115  .cancel_session = spandsp_fax_cancel,
116  .switch_to_t38 = spandsp_fax_switch_to_t38,
117  .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
118  .cli_show_session = spandsp_fax_cli_show_session,
119  .manager_fax_session = spandsp_manager_fax_session,
120  .cli_show_stats = spandsp_fax_cli_show_stats,
121  .cli_show_settings = spandsp_fax_cli_show_settings,
122 };
123 
125  int success;
126  int nofax;
137  int switched;
138 };
139 
140 static struct {
142  struct spandsp_fax_stats g711;
143  struct spandsp_fax_stats t38;
145 
146 struct spandsp_pvt {
147  unsigned int ist38:1;
148  unsigned int isdone:1;
150  fax_state_t fax_state;
151  t38_terminal_state_t t38_state;
152  t30_state_t *t30_state;
153  t38_core_state_t *t38_core_state;
154 
156 
157  struct spandsp_fax_gw_stats *t38stats;
158  t38_gateway_state_t t38_gw_state;
159 
160  struct ast_timer *timer;
162 
164  modem_connect_tones_rx_state_t *tone_state;
165 };
166 
167 static int spandsp_v21_new(struct spandsp_pvt *p);
168 static void session_destroy(struct spandsp_pvt *p);
169 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
170 static int update_stats(struct spandsp_pvt *p, int completion_code);
171 static int spandsp_modems(struct ast_fax_session_details *details);
172 #if SPANDSP_RELEASE_DATE >= 20120902
173 /* for spandsp shaphots 3.0.0 and higher */
174 static void t30_phase_e_handler(void *data, int completion_code);
175 static void spandsp_log(void *user_data, int level, const char *msg);
176 #else
177 /* for spandsp release 0.0.6 */
178 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
179 static void spandsp_log(int level, const char *msg);
180 #endif
181 
182 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
183 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
184 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
185 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
186 
187 static void session_destroy(struct spandsp_pvt *p)
188 {
189  struct ast_frame *f;
190  t30_state_t *t30_to_terminate;
191 
192  if (p->t30_state) {
193  t30_to_terminate = p->t30_state;
194  } else if (p->ist38) {
195 #if SPANDSP_RELEASE_DATE >= 20080725
196  t30_to_terminate = &p->t38_state.t30;
197 #else
198  t30_to_terminate = &p->t38_state.t30_state;
199 #endif
200  } else {
201 #if SPANDSP_RELEASE_DATE >= 20080725
202  t30_to_terminate = &p->fax_state.t30;
203 #else
204  t30_to_terminate = &p->fax_state.t30_state;
205 #endif
206  }
207 
208  t30_terminate(t30_to_terminate);
209  p->isdone = 1;
210 
212  p->timer = NULL;
213  fax_release(&p->fax_state);
214  t38_terminal_release(&p->t38_state);
215 
216  while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
217  ast_frfree(f);
218  }
219 }
220 
221 /*! \brief
222  *
223  */
224 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
225 {
226  int res = -1;
227  struct ast_fax_session *s = data;
228  struct spandsp_pvt *p = s->tech_pvt;
229  struct ast_frame fax_frame = {
231  .subclass.integer = AST_MODEM_T38,
232  .src = "res_fax_spandsp_t38",
233  };
234 
235  struct ast_frame *f = &fax_frame;
236 
237 
238  /* TODO: Asterisk does not provide means of resending the same packet multiple
239  times so count is ignored at the moment */
240 
241  AST_FRAME_SET_BUFFER(f, buf, 0, len);
242 
243  if (!(f = ast_frisolate(f))) {
244  return res;
245  }
246 
247  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
250  res = ast_write(s->chan, f);
251  } else {
252  res = ast_queue_frame(s->chan, f);
253  }
254  ast_frfree(f);
255  } else {
256  /* no need to lock, this all runs in the same thread */
258  res = 0;
259  }
260 
261  return res;
262 }
263 
264 static int update_stats(struct spandsp_pvt *p, int completion_code)
265 {
266  switch (completion_code) {
267  case T30_ERR_OK:
269  break;
270 
271  /* Link problems */
272  case T30_ERR_CEDTONE: /*! The CED tone exceeded 5s */
273  case T30_ERR_T0_EXPIRED: /*! Timed out waiting for initial communication */
274  case T30_ERR_T1_EXPIRED: /*! Timed out waiting for the first message */
275  case T30_ERR_T3_EXPIRED: /*! Timed out waiting for procedural interrupt */
276  case T30_ERR_HDLC_CARRIER: /*! The HDLC carrier did not stop in a timely manner */
277  case T30_ERR_CANNOT_TRAIN: /*! Failed to train with any of the compatible modems */
279  break;
280 
281  case T30_ERR_OPER_INT_FAIL: /*! Operator intervention failed */
282  case T30_ERR_INCOMPATIBLE: /*! Far end is not compatible */
283  case T30_ERR_RX_INCAPABLE: /*! Far end is not able to receive */
284  case T30_ERR_TX_INCAPABLE: /*! Far end is not able to transmit */
285  case T30_ERR_NORESSUPPORT: /*! Far end cannot receive at the resolution of the image */
286  case T30_ERR_NOSIZESUPPORT: /*! Far end cannot receive at the size of image */
288  break;
289 
290  case T30_ERR_UNEXPECTED: /*! Unexpected message received */
292  break;
293 
294  /* Phase E status values returned to a transmitter */
295  case T30_ERR_TX_BADDCS: /*! Received bad response to DCS or training */
296  case T30_ERR_TX_BADPG: /*! Received a DCN from remote after sending a page */
297  case T30_ERR_TX_ECMPHD: /*! Invalid ECM response received from receiver */
298  case T30_ERR_TX_GOTDCN: /*! Received a DCN while waiting for a DIS */
299  case T30_ERR_TX_INVALRSP: /*! Invalid response after sending a page */
300  case T30_ERR_TX_NODIS: /*! Received other than DIS while waiting for DIS */
301  case T30_ERR_TX_PHBDEAD: /*! Received no response to DCS, training or TCF */
302  case T30_ERR_TX_PHDDEAD: /*! No response after sending a page */
303  case T30_ERR_TX_T5EXP: /*! Timed out waiting for receiver ready (ECM mode) */
305  break;
306 
307  /* Phase E status values returned to a receiver */
308  case T30_ERR_RX_ECMPHD: /*! Invalid ECM response received from transmitter */
309  case T30_ERR_RX_GOTDCS: /*! DCS received while waiting for DTC */
310  case T30_ERR_RX_INVALCMD: /*! Unexpected command after page received */
311  case T30_ERR_RX_NOCARRIER: /*! Carrier lost during fax receive */
312  case T30_ERR_RX_NOEOL: /*! Timed out while waiting for EOL (end Of line) */
314  break;
315  case T30_ERR_RX_NOFAX: /*! Timed out while waiting for first line */
317  break;
318  case T30_ERR_RX_T2EXPDCN: /*! Timer T2 expired while waiting for DCN */
319  case T30_ERR_RX_T2EXPD: /*! Timer T2 expired while waiting for phase D */
320  case T30_ERR_RX_T2EXPFAX: /*! Timer T2 expired while waiting for fax page */
321  case T30_ERR_RX_T2EXPMPS: /*! Timer T2 expired while waiting for next fax page */
322  case T30_ERR_RX_T2EXPRR: /*! Timer T2 expired while waiting for RR command */
323  case T30_ERR_RX_T2EXP: /*! Timer T2 expired while waiting for NSS, DCS or MCF */
324  case T30_ERR_RX_DCNWHY: /*! Unexpected DCN while waiting for DCS or DIS */
325  case T30_ERR_RX_DCNDATA: /*! Unexpected DCN while waiting for image data */
326  case T30_ERR_RX_DCNFAX: /*! Unexpected DCN while waiting for EOM, EOP or MPS */
327  case T30_ERR_RX_DCNPHD: /*! Unexpected DCN after EOM or MPS sequence */
328  case T30_ERR_RX_DCNRRD: /*! Unexpected DCN after RR/RNR sequence */
329  case T30_ERR_RX_DCNNORTN: /*! Unexpected DCN after requested retransmission */
331  break;
332 
333  /* TIFF file problems */
334  case T30_ERR_FILEERROR: /*! TIFF/F file cannot be opened */
335  case T30_ERR_NOPAGE: /*! TIFF/F page not found */
336  case T30_ERR_BADTIFF: /*! TIFF/F format is not compatible */
337  case T30_ERR_BADPAGE: /*! TIFF/F page number tag missing */
338  case T30_ERR_BADTAG: /*! Incorrect values for TIFF/F tags */
339  case T30_ERR_BADTIFFHDR: /*! Bad TIFF/F header - incorrect values in fields */
341  break;
342  case T30_ERR_NOMEM: /*! Cannot allocate memory for more pages */
344  break;
345 
346  /* General problems */
347  case T30_ERR_RETRYDCN: /*! Disconnected after permitted retries */
349  break;
350  case T30_ERR_CALLDROPPED: /*! The call dropped prematurely */
352  break;
353 
354  /* Feature negotiation issues */
355  case T30_ERR_NOPOLL: /*! Poll not accepted */
356  case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
357  case T30_ERR_SUB_UNACCEPTABLE: /*! Far end's sub-address is not acceptable */
358  case T30_ERR_SEP_UNACCEPTABLE: /*! Far end's selective polling address is not acceptable */
359  case T30_ERR_PSA_UNACCEPTABLE: /*! Far end's polled sub-address is not acceptable */
360  case T30_ERR_SID_UNACCEPTABLE: /*! Far end's sender identification is not acceptable */
361  case T30_ERR_PWD_UNACCEPTABLE: /*! Far end's password is not acceptable */
362  case T30_ERR_TSA_UNACCEPTABLE: /*! Far end's transmitting subscriber internet address is not acceptable */
363  case T30_ERR_IRA_UNACCEPTABLE: /*! Far end's internet routing address is not acceptable */
364  case T30_ERR_CIA_UNACCEPTABLE: /*! Far end's calling subscriber internet address is not acceptable */
365  case T30_ERR_ISP_UNACCEPTABLE: /*! Far end's internet selective polling address is not acceptable */
366  case T30_ERR_CSA_UNACCEPTABLE: /*! Far end's called subscriber internet address is not acceptable */
368  break;
369  default:
371  ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
372  return -1;
373  }
374  return 0;
375 }
376 
377 /*! \brief Phase E handler callback.
378  * \param t30_state the span t30 state
379  * \param data this will be the ast_fax_session
380  * \param completion_code the result of the fax session
381  *
382  * This function pulls stats from the spandsp stack and stores them for res_fax
383  * to use later.
384  */
385 #if SPANDSP_RELEASE_DATE >= 20120902
386 /* for spandsp shaphots 3.0.0 and higher */
387 static void t30_phase_e_handler(void *data, int completion_code)
388 #else
389 /* for spandsp release 0.0.6 */
390 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
391 #endif
392 {
393  struct ast_fax_session *s = data;
394  struct spandsp_pvt *p = s->tech_pvt;
395  char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
396  const char *c;
397  t30_stats_t stats;
398 #if SPANDSP_RELEASE_DATE >= 20120902
399  /* for spandsp shaphots 3.0.0 and higher */
400  t30_state_t *t30_state = p->t30_state;
401 #endif
402 
403  ast_debug(5, "FAX session '%u' entering phase E\n", s->id);
404 
405  p->isdone = 1;
406 
407  update_stats(p, completion_code);
408 
409  t30_get_transfer_statistics(t30_state, &stats);
410 
411  if (completion_code == T30_ERR_OK) {
412  ast_string_field_set(s->details, result, "SUCCESS");
413  } else {
414  ast_string_field_set(s->details, result, "FAILED");
415  ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
416  }
417 
418  ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
419 
420  ast_debug(5, "FAX session '%u' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
421 
422  if ((c = t30_get_tx_ident(t30_state))) {
423  ast_string_field_set(s->details, localstationid, c);
424  }
425 
426  if ((c = t30_get_rx_ident(t30_state))) {
427  ast_string_field_set(s->details, remotestationid, c);
428  }
429 
430 #if SPANDSP_RELEASE_DATE >= 20090220
431  s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
432 #else
433  s->details->pages_transferred = stats.pages_transferred;
434 #endif
435 
436  ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
437 
438  ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
439 
440  t30_get_tx_page_header_info(t30_state, headerinfo);
441  ast_string_field_set(s->details, headerinfo, headerinfo);
442 }
443 
444 /*! \brief Send spandsp log messages to asterisk.
445  * \param level the spandsp logging level
446  * \param msg the log message
447  *
448  * \note This function is a callback function called by spandsp.
449  */
450 #if SPANDSP_RELEASE_DATE >= 20120902
451 /* for spandsp shaphots 3.0.0 and higher */
452 static void spandsp_log(void *user_data, int level, const char *msg)
453 #else
454 /* for spandsp release 0.0.6 */
455 static void spandsp_log(int level, const char *msg)
456 #endif
457 {
458  if (level == SPAN_LOG_ERROR) {
459  ast_log(LOG_ERROR, "%s", msg);
460  } else if (level == SPAN_LOG_WARNING) {
461  ast_log(LOG_WARNING, "%s", msg);
462  } else {
463  ast_fax_log(LOG_DEBUG, msg);
464  }
465 }
466 
467 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
468 {
469  int level = SPAN_LOG_WARNING;
470 
471  if (details->option.debug) {
472  level = SPAN_LOG_DEBUG_3;
473  }
474 
475 #if SPANDSP_RELEASE_DATE >= 20120902
476  /* for spandsp shaphots 3.0.0 and higher */
477  span_log_set_message_handler(state, spandsp_log, NULL);
478 #else
479  /* for spandsp release 0.0.6 */
480  span_log_set_message_handler(state, spandsp_log);
481 #endif
482  span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
483 }
484 
485 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
486 {
487  if (!ast_strlen_zero(details->localstationid)) {
488  t30_set_tx_ident(t30_state, details->localstationid);
489  }
490 
491  if (!ast_strlen_zero(details->headerinfo)) {
492  t30_set_tx_page_header_info(t30_state, details->headerinfo);
493  }
494 }
495 
496 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
497 {
498  if (details->caps & AST_FAX_TECH_RECEIVE) {
499  t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
500  } else {
501  /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
502  * should be safe because we ensure either RECEIVE or SEND is
503  * indicated in spandsp_fax_new() */
504  t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
505  }
506 }
507 
508 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
509 {
510  t30_set_ecm_capability(t30_state, details->option.ecm);
511 #if SPANDSP_RELEASE_DATE >= 20120902
512  /* for spandsp shaphots 3.0.0 and higher */
513  t30_set_supported_compressions(t30_state, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6);
514 #else
515  /* for spandsp release 0.0.6 */
516  t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
517 #endif
518 }
519 
520 static int spandsp_v21_new(struct spandsp_pvt *p)
521 {
522  /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
523  * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
524  * doesn't seem to work right all the time.
525  */
526  p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
527  if (!p->tone_state) {
528  return -1;
529  }
530 
531  return 0;
532 }
533 
534 static int spandsp_modems(struct ast_fax_session_details *details)
535 {
536  int modems = 0;
537  if (AST_FAX_MODEM_V17 & details->modems) {
538  modems |= T30_SUPPORT_V17;
539  }
540  if (AST_FAX_MODEM_V27TER & details->modems) {
541  modems |= T30_SUPPORT_V27TER;
542  }
543  if (AST_FAX_MODEM_V29 & details->modems) {
544  modems |= T30_SUPPORT_V29;
545  }
546  if (AST_FAX_MODEM_V34 & details->modems) {
547 #if defined(T30_SUPPORT_V34)
548  modems |= T30_SUPPORT_V34;
549 #elif defined(T30_SUPPORT_V34HDX)
550  modems |= T30_SUPPORT_V34HDX;
551 #else
552  ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
553 #endif
554  }
555 
556  return modems;
557 }
558 
559 /*! \brief create an instance of the spandsp tech_pvt for a fax session */
560 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
561 {
562  struct spandsp_pvt *p;
563  int caller_mode;
564 
565  if ((!(p = ast_calloc(1, sizeof(*p))))) {
566  ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
567  goto e_return;
568  }
569 
571  if (spandsp_v21_new(p)) {
572  ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
573  goto e_return;
574  }
576  return p;
577  }
578 
579  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
581  return p;
582  }
583 
585 
586  if (s->details->caps & AST_FAX_TECH_RECEIVE) {
587  caller_mode = 0;
588  } else if (s->details->caps & AST_FAX_TECH_SEND) {
589  caller_mode = 1;
590  } else {
591  ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
592  goto e_free;
593  }
594 
595  if (!(p->timer = ast_timer_open())) {
596  ast_log(LOG_ERROR, "Channel '%s' FAX session '%u' failed to create timing source.\n", s->channame, s->id);
597  goto e_free;
598  }
599 
600  s->fd = ast_timer_fd(p->timer);
601 
602  p->stats = &spandsp_global_stats.g711;
603 
605  if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
606  /* audio mode was not requested, start in T.38 mode */
607  p->ist38 = 1;
608  p->stats = &spandsp_global_stats.t38;
609  }
610 
611  /* init t38 stuff */
612  t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
613  set_logging(&p->t38_state.logging, s->details);
614 
615  /* init audio stuff */
616  fax_init(&p->fax_state, caller_mode);
617  set_logging(&p->fax_state.logging, s->details);
618  }
619 
621  return p;
622 
623 e_free:
624  ast_free(p);
625 e_return:
626  return NULL;
627 }
628 
629 static void spandsp_v21_cleanup(struct ast_fax_session *s)
630 {
631  struct spandsp_pvt *p = s->tech_pvt;
632 
633  modem_connect_tones_rx_free(p->tone_state);
634 }
635 
636 /*! \brief Destroy a spandsp fax session.
637  */
638 static void spandsp_fax_destroy(struct ast_fax_session *s)
639 {
640  struct spandsp_pvt *p = s->tech_pvt;
641 
642  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
644  } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
646  } else {
647  session_destroy(p);
648  }
649 
650  ast_free(p);
651  s->tech_pvt = NULL;
652  s->fd = -1;
653 }
654 
655 /*! \brief Read a frame from the spandsp fax stack.
656  */
657 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
658 {
659  struct spandsp_pvt *p = s->tech_pvt;
660  uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
661  int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
662  int samples;
663 
664  struct ast_frame fax_frame = {
666  .src = "res_fax_spandsp_g711",
667  .subclass.format = ast_format_slin,
668  };
669  struct ast_frame *f = &fax_frame;
670 
671  if (ast_timer_ack(p->timer, 1) < 0) {
672  ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%u'\n", s->id);
673  return NULL;
674  }
675 
676  /* XXX do we need to lock here? */
677  if (p->isdone) {
679  ast_debug(5, "FAX session '%u' is complete.\n", s->id);
680  return NULL;
681  }
682 
683  if (p->ist38) {
684  t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
685  if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
686  return f;
687  }
688  } else {
689  if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
690  f->samples = samples;
692  return ast_frisolate(f);
693  }
694  }
695 
696  return &ast_null_frame;
697 }
698 
699 static void spandsp_v21_tone(void *data, int code, int level, int delay)
700 {
701  struct spandsp_pvt *p = data;
702 
703  if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
704  p->v21_detected = 1;
705  }
706 }
707 
708 static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f)
709 {
710  struct spandsp_pvt *p = s->tech_pvt;
711  int16_t *slndata;
712  g711_state_t *decoder;
713 
714  if (p->v21_detected) {
715  return 0;
716  }
717 
718  /*invalid frame*/
719  if (!f->data.ptr || !f->datalen) {
720  return -1;
721  }
722 
723  ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format=%s }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, ast_format_get_name(f->subclass.format));
724 
725  /* slinear frame can be passed to spandsp */
727  modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
728 
729  /* alaw/ulaw frame must be converted to slinear before passing to spandsp */
732  if (!(slndata = ast_malloc(sizeof(*slndata) * f->samples))) {
733  return -1;
734  }
735  decoder = g711_init(NULL, (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL ? G711_ALAW : G711_ULAW));
736  g711_decode(decoder, slndata, f->data.ptr, f->samples);
737  ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", ast_format_get_name(f->subclass.format));
738  modem_connect_tones_rx(p->tone_state, slndata, f->samples);
739  g711_release(decoder);
740 #if SPANDSP_RELEASE_DATE >= 20090220
741  g711_free(decoder);
742 #endif
743  ast_free(slndata);
744 
745  /* frame in other formats cannot be passed to spandsp, it could cause segfault */
746  } else {
747  ast_log(LOG_WARNING, "Frame format %s not supported, v.21 detection skipped\n", ast_format_get_name(f->subclass.format));
748  return -1;
749  }
750 
751  if (p->v21_detected) {
752  s->details->option.v21_detected = 1;
753  ast_debug(5, "v.21 detected\n");
754  }
755 
756  return 0;
757 }
758 
759 /*! \brief Write a frame to the spandsp fax stack.
760  * \param s a fax session
761  * \param f the frame to write
762  *
763  * \note res_fax does not currently use the return value of this function.
764  * Also the fax_rx() function never fails.
765  *
766  * \retval 0 success
767  * \retval -1 failure
768  */
769 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
770 {
771  struct spandsp_pvt *p = s->tech_pvt;
772 
774  return spandsp_v21_detect(s, f);
775  }
776 
777  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
778  return spandsp_fax_gateway_process(s, f);
779  }
780 
781  /* XXX do we need to lock here? */
782  if (s->state == AST_FAX_STATE_COMPLETE) {
783  ast_log(LOG_WARNING, "FAX session '%u' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
784  return -1;
785  }
786 
787  if (p->ist38) {
788  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
789  } else {
790  return fax_rx(&p->fax_state, f->data.ptr, f->samples);
791  }
792 }
793 
794 /*! \brief generate T.30 packets sent to the T.30 leg of gateway
795  * \param chan T.30 channel
796  * \param data fax session structure
797  * \param len not used
798  * \param samples no of samples generated
799  * \return -1 on failure or 0 on sucess*/
800 static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
801 {
802  int res = -1;
803  struct ast_fax_session *s = data;
804  struct spandsp_pvt *p = s->tech_pvt;
805  uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
806  struct ast_frame *f;
807  struct ast_frame t30_frame = {
809  .subclass.format = ast_format_slin,
810  .src = "res_fax_spandsp_g711",
811  .samples = samples,
812  .flags = AST_FAX_FRFLAG_GATEWAY,
813  };
814 
815  AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
816 
817  if (!(f = ast_frisolate(&t30_frame))) {
818  return p->isdone ? -1 : res;
819  }
820 
821  /* generate a T.30 packet */
822  if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
823  f->datalen = f->samples * sizeof(int16_t);
824  res = ast_write(chan, f);
825  }
826  ast_frfree(f);
827  return p->isdone ? -1 : res;
828 }
829 
830 /*! \brief simple routine to allocate data to generator
831  * \param chan channel
832  * \param params generator data
833  * \return data to use in generator call*/
834 static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params)
835 {
836  ao2_ref(params, +1);
837  return params;
838 }
839 
840 static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data)
841 {
842  ao2_ref(data, -1);
843 }
844 
845 /*! \brief activate a spandsp gateway based on the information in the given fax session
846  * \param s fax session
847  * \return -1 on error 0 on sucess*/
849 {
850  struct spandsp_pvt *p = s->tech_pvt;
851  struct ast_fax_t38_parameters *t38_param;
852  int i;
853  RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
854  static struct ast_generator t30_gen = {
856  .release = spandsp_fax_gw_gen_release,
857  .generate = spandsp_fax_gw_t30_gen,
858  };
859 
860 #if SPANDSP_RELEASE_DATE >= 20081012
861  /* for spandsp shaphots 0.0.6 and higher */
862  p->t38_core_state=&p->t38_gw_state.t38x.t38;
863 #else
864  /* for spandsp release 0.0.5 */
865  p->t38_core_state=&p->t38_gw_state.t38;
866 #endif
867 
868  if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
869  return -1;
870  }
871 
872  p->ist38 = 1;
874  peer = ast_channel_bridge_peer(s->chan);
875  if (!peer) {
876  return -1;
877  }
878 
879  /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
880  * gateway is started. We treat both states the same. */
883  }
884 
885  ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
886 
887  set_logging(&p->t38_gw_state.logging, s->details);
888  set_logging(&p->t38_core_state->logging, s->details);
889 
891  t38_set_t38_version(p->t38_core_state, t38_param->version);
892  t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
893  t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
894  t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
895  t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
896  t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
897  t38_set_data_rate_management_method(p->t38_core_state,
899 
900  t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
901  t38_set_sequence_number_handling(p->t38_core_state, TRUE);
902 
903 
904  t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details));
905 
906  /* engage udptl nat on other side of T38 line
907  * (Asterisk changes media ports thus we send a few packets to reinitialize
908  * pinholes in NATs and FWs
909  */
910  for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
911 #if SPANDSP_RELEASE_DATE >= 20091228
912  t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
913 #elif SPANDSP_RELEASE_DATE >= 20081012
914  t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
915 #else
916  t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
917 #endif
918  }
919 
921 
922  return 0;
923 }
924 
925 /*! \brief process a frame from the bridge
926  * \param s fax session
927  * \param f frame to process
928  * \return 1 on sucess 0 on incorrect packet*/
929 static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
930 {
931  struct spandsp_pvt *p = s->tech_pvt;
932 
933  /*invalid frame*/
934  if (!f->data.ptr || !f->datalen) {
935  return -1;
936  }
937 
938  /* Process a IFP packet */
939  if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
940  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
941  } else if ((f->frametype == AST_FRAME_VOICE) &&
943  return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
944  }
945 
946  return -1;
947 }
948 
949 /*! \brief gather data and clean up after gateway ends
950  * \param s fax session*/
952 {
953  struct spandsp_pvt *p = s->tech_pvt;
954  t38_stats_t t38_stats;
955 
956  t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
957 
958  s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
959  s->details->pages_transferred = t38_stats.pages_transferred;
960  ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
961 }
962 
963 /*! \brief */
964 static int spandsp_fax_start(struct ast_fax_session *s)
965 {
966  struct spandsp_pvt *p = s->tech_pvt;
967 
969 
970  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
971  return spandsp_fax_gateway_start(s);
972  }
973 
974  if (p->ist38) {
975 #if SPANDSP_RELEASE_DATE >= 20080725
976  /* for spandsp shaphots 0.0.6 and higher */
977  p->t30_state = &p->t38_state.t30;
978  p->t38_core_state = &p->t38_state.t38_fe.t38;
979 #else
980  /* for spandsp releases 0.0.5 */
981  p->t30_state = &p->t38_state.t30_state;
982  p->t38_core_state = &p->t38_state.t38;
983 #endif
984  } else {
985 #if SPANDSP_RELEASE_DATE >= 20080725
986  /* for spandsp shaphots 0.0.6 and higher */
987  p->t30_state = &p->fax_state.t30;
988 #else
989  /* for spandsp release 0.0.5 */
990  p->t30_state = &p->fax_state.t30_state;
991 #endif
992  }
993 
994  set_logging(&p->t30_state->logging, s->details);
995 
996  /* set some parameters */
998  set_file(p->t30_state, s->details);
999  set_ecm(p->t30_state, s->details);
1000  t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
1001 
1002  /* perhaps set_transmit_on_idle() should be called */
1003 
1004  t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
1005 
1006  /* set T.38 parameters */
1007  if (p->ist38) {
1008  set_logging(&p->t38_core_state->logging, s->details);
1009 
1010  t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
1011 
1013  t38_set_fill_bit_removal(p->t38_core_state, TRUE);
1014  }
1015 
1017  t38_set_mmr_transcoding(p->t38_core_state, TRUE);
1018  }
1019 
1021  t38_set_jbig_transcoding(p->t38_core_state, TRUE);
1022  }
1023  } else {
1024  /* have the fax stack generate silence if it has no data to send */
1025  fax_set_transmit_on_idle(&p->fax_state, 1);
1026  }
1027 
1028 
1029  /* start the timer */
1031  ast_log(LOG_ERROR, "FAX session '%u' error setting rate on timing source.\n", s->id);
1032  return -1;
1033  }
1034 
1036 
1037  return 0;
1038 }
1039 
1040 /*! \brief */
1042 {
1043  struct spandsp_pvt *p = s->tech_pvt;
1044 
1045  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
1046  p->isdone = 1;
1047  return 0;
1048  }
1049 
1050  t30_terminate(p->t30_state);
1051  p->isdone = 1;
1052  return 0;
1053 }
1054 
1055 /*! \brief */
1057 {
1058  struct spandsp_pvt *p = s->tech_pvt;
1059 
1060  /* prevent the phase E handler from running, this is not a real termination */
1061  t30_set_phase_e_handler(p->t30_state, NULL, NULL);
1062 
1063  t30_terminate(p->t30_state);
1064 
1065  s->details->option.switch_to_t38 = 1;
1067 
1068  p->ist38 = 1;
1069  p->stats = &spandsp_global_stats.t38;
1070  spandsp_fax_start(s);
1071 
1072  return 0;
1073 }
1074 
1075 /*! \brief */
1077 {
1078  ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
1079  return CLI_SUCCESS;
1080 }
1081 
1082 /*! \brief */
1083 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
1084 {
1085  ao2_lock(s);
1086  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
1087  struct spandsp_pvt *p = s->tech_pvt;
1088 
1089  ast_cli(fd, "%-22s : %u\n", "session", s->id);
1090  ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
1091  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1092  if (s->state != AST_FAX_STATE_UNINITIALIZED) {
1093  t38_stats_t stats;
1094  t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
1095  ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1096  ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1097  ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1098  }
1099  } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
1100  ast_cli(fd, "%-22s : %u\n", "session", s->id);
1101  ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
1102  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1103  } else {
1104  struct spandsp_pvt *p = s->tech_pvt;
1105 
1106  ast_cli(fd, "%-22s : %u\n", "session", s->id);
1107  ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
1108  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
1109  if (s->state != AST_FAX_STATE_UNINITIALIZED) {
1110  t30_stats_t stats;
1111  t30_get_transfer_statistics(p->t30_state, &stats);
1112  ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
1113  ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
1114  ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
1115  ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
1116 #if SPANDSP_RELEASE_DATE >= 20090220
1117  ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1118 #else
1119  ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
1120 #endif
1121  ast_cli(fd, "%-22s : %s\n", "File Name", s->details->caps & AST_FAX_TECH_RECEIVE ? p->t30_state->rx_file : p->t30_state->tx_file);
1122 
1123  ast_cli(fd, "\nData Statistics:\n");
1124 #if SPANDSP_RELEASE_DATE >= 20090220
1125  ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
1126  ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
1127 #else
1128  ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1129  ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1130 #endif
1131  ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
1132  ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
1133  }
1134  }
1135  ao2_unlock(s);
1136  ast_cli(fd, "\n\n");
1137  return CLI_SUCCESS;
1138 }
1139 
1141  const char *id_text, struct ast_fax_session *session)
1142 {
1143  struct ast_str *message_string;
1144  struct spandsp_pvt *span_pvt = session->tech_pvt;
1145  int res;
1146 
1147  message_string = ast_str_create(128);
1148 
1149  if (!message_string) {
1150  return;
1151  }
1152 
1153  ao2_lock(session);
1154  res = ast_str_append(&message_string, 0, "SessionNumber: %u\r\n", session->id);
1155  res |= ast_str_append(&message_string, 0, "Operation: %s\r\n", ast_fax_session_operation_str(session));
1156  res |= ast_str_append(&message_string, 0, "State: %s\r\n", ast_fax_state_to_str(session->state));
1157 
1158  if (session->details->caps & AST_FAX_TECH_GATEWAY) {
1159  t38_stats_t stats;
1160 
1161  if (session->state == AST_FAX_STATE_UNINITIALIZED) {
1162  goto skip_cap_additions;
1163  }
1164 
1165  t38_gateway_get_transfer_statistics(&span_pvt->t38_gw_state, &stats);
1166  res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
1167  stats.error_correcting_mode ? "yes" : "no");
1168  res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
1169  stats.bit_rate);
1170  res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1171  stats.pages_transferred + 1);
1172  } else if (!(session->details->caps & AST_FAX_TECH_V21_DETECT)) { /* caps is SEND/RECEIVE */
1173  t30_stats_t stats;
1174 
1175  if (session->state == AST_FAX_STATE_UNINITIALIZED) {
1176  goto skip_cap_additions;
1177  }
1178 
1179  t30_get_transfer_statistics(span_pvt->t30_state, &stats);
1180  res |= ast_str_append(&message_string, 0, "ErrorCorrectionMode: %s\r\n",
1181  stats.error_correcting_mode ? "Yes" : "No");
1182  res |= ast_str_append(&message_string, 0, "DataRate: %d\r\n",
1183  stats.bit_rate);
1184  res |= ast_str_append(&message_string, 0, "ImageResolution: %dx%d\r\n",
1185  stats.x_resolution, stats.y_resolution);
1186 #if SPANDSP_RELEASE_DATE >= 20090220
1187  res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1188  ((session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
1189 #else
1190  res |= ast_str_append(&message_string, 0, "PageNumber: %d\r\n",
1191  stats.pages_transferred + 1);
1192 #endif
1193  res |= ast_str_append(&message_string, 0, "FileName: %s\r\n",
1194  session->details->caps & AST_FAX_TECH_RECEIVE ? span_pvt->t30_state->rx_file :
1195  span_pvt->t30_state->tx_file);
1196 #if SPANDSP_RELEASE_DATE >= 20090220
1197  res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
1198  stats.pages_tx);
1199  res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
1200  stats.pages_rx);
1201 #else
1202  res |= ast_str_append(&message_string, 0, "PagesTransmitted: %d\r\n",
1203  (session->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
1204  res |= ast_str_append(&message_string, 0, "PagesReceived: %d\r\n",
1205  (session->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
1206 #endif
1207  res |= ast_str_append(&message_string, 0, "TotalBadLines: %d\r\n",
1208  stats.bad_rows);
1209  }
1210 
1211 skip_cap_additions:
1212 
1214 
1215  if (res < 0) {
1216  /* One or more of the ast_str_append attempts failed, cancel the message */
1217  ast_free(message_string);
1218  return;
1219  }
1220 
1221  astman_append(s, "Event: FAXSession\r\n"
1222  "%s"
1223  "%s"
1224  "\r\n",
1225  id_text,
1226  ast_str_buffer(message_string));
1227 
1228  ast_free(message_string);
1229 }
1230 
1231 /*! \brief */
1232 static char *spandsp_fax_cli_show_stats(int fd)
1233 {
1235  ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
1236  ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
1237  ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
1238  ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
1239  ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
1240  ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
1241  ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
1242  ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
1243  ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
1244  ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
1245  ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
1246  ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
1247  ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
1248  ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
1249 
1250  ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
1251  ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
1252  ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
1253  ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
1254  ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
1255  ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
1256  ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
1257  ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
1258  ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
1259  ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
1260  ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
1261  ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
1262  ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
1264 
1265  return CLI_SUCCESS;
1266 }
1267 
1268 /*! \brief Show res_fax_spandsp settings */
1269 static char *spandsp_fax_cli_show_settings(int fd)
1270 {
1271  /* no settings at the moment */
1272  return CLI_SUCCESS;
1273 }
1274 
1275 /*! \brief unload res_fax_spandsp */
1276 static int unload_module(void)
1277 {
1280  return AST_MODULE_LOAD_SUCCESS;
1281 }
1282 
1283 /*! \brief load res_fax_spandsp */
1284 static int load_module(void)
1285 {
1289  ast_log(LOG_ERROR, "failed to register FAX technology\n");
1290  return AST_MODULE_LOAD_DECLINE;
1291  }
1292 
1293  /* prevent logging to stderr */
1294 #if SPANDSP_RELEASE_DATE >= 20120902
1295  /* for spandsp shaphots 3.0.0 and higher */
1296  span_set_message_handler(NULL, NULL);
1297 #else
1298  /* for spandsp release 0.0.6 */
1299  span_set_message_handler(NULL);
1300 #endif
1301 
1302  return AST_MODULE_LOAD_SUCCESS;
1303 }
1304 
1305 
1306 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
1307  .support_level = AST_MODULE_SUPPORT_EXTENDED,
1308  .load = load_module,
1309  .unload = unload_module,
1310  .enhances = "res_fax",
1311 );
#define TRUE
Definition: app_minivm.c:524
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static PGresult * result
Definition: cel_pgsql.c:84
General Asterisk PBX channel definitions.
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2952
static enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
Retrieves the current T38 state of a channel.
Definition: channel.h:2850
ast_t38_state
Possible T38 states on channels.
Definition: channel.h:878
@ T38_STATE_NEGOTIATED
Definition: channel.h:883
@ T38_STATE_NEGOTIATING
Definition: channel.h:881
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1133
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5179
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition: channel.c:10750
Standard Command Line Interface.
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
short int16_t
Definition: db.h:59
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition: format.h:36
Media Format Cache API.
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define AST_MODEM_T38
#define ast_frfree(fr)
@ AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_VOICE
@ AST_FRAME_MODEM
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define LOG_ERROR
#define LOG_WARNING
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
#define ast_mutex_init(pmutex)
Definition: lock.h:184
#define ast_mutex_unlock(a)
Definition: lock.h:188
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
#define ast_mutex_destroy(a)
Definition: lock.h:186
#define ast_mutex_lock(a)
Definition: lock.h:187
Asterisk module definitions.
@ AST_MODFLAG_DEFAULT
Definition: module.h:315
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
void ast_fax_tech_unregister(struct ast_fax_tech *tech)
unregister a fax technology
Definition: res_fax.c:991
@ AST_FAX_OPTFLAG_FALSE
Definition: res_fax.h:85
@ AST_FAX_OPTFLAG_TRUE
Definition: res_fax.h:87
const char * ast_fax_session_operation_str(struct ast_fax_session *s)
get string representation of a FAX session's operation
Definition: res_fax.c:4253
@ AST_FAX_TECH_T38
Definition: res_fax.h:43
@ AST_FAX_TECH_AUDIO
Definition: res_fax.h:41
@ AST_FAX_TECH_RECEIVE
Definition: res_fax.h:39
@ AST_FAX_TECH_V21_DETECT
Definition: res_fax.h:49
@ AST_FAX_TECH_SEND
Definition: res_fax.h:37
@ AST_FAX_TECH_GATEWAY
Definition: res_fax.h:47
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert an ast_fax_state to a string
Definition: res_fax.c:1012
#define AST_FAX_FRFLAG_GATEWAY
Definition: res_fax.h:232
int ast_fax_tech_register(struct ast_fax_tech *tech)
register a fax technology
Definition: res_fax.c:973
@ AST_FAX_STATE_INITIALIZED
Definition: res_fax.h:69
@ AST_FAX_STATE_ACTIVE
Definition: res_fax.h:73
@ AST_FAX_STATE_COMPLETE
Definition: res_fax.h:75
@ AST_FAX_STATE_OPEN
Definition: res_fax.h:71
@ AST_FAX_STATE_UNINITIALIZED
Definition: res_fax.h:67
@ AST_FAX_MODEM_V17
Definition: res_fax.h:55
@ AST_FAX_MODEM_V29
Definition: res_fax.h:59
@ AST_FAX_MODEM_V27TER
Definition: res_fax.h:57
@ AST_FAX_MODEM_V34
Definition: res_fax.h:61
void ast_fax_log(int level, const char *file, const int line, const char *function, const char *msg)
Log message at FAX or recommended level.
Definition: res_fax.c:1035
static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
Phase E handler callback.
static void spandsp_log(int level, const char *msg)
Send spandsp log messages to asterisk.
static char * spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
static struct ast_fax_tech spandsp_fax_tech
#define SPANDSP_FAX_SAMPLES
static void session_destroy(struct spandsp_pvt *p)
struct spandsp_fax_stats g711
static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
static void spandsp_v21_tone(void *data, int code, int level, int delay)
static void spandsp_manager_fax_session(struct mansession *s, const char *id_text, struct ast_fax_session *session)
static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
static char * spandsp_fax_cli_show_stats(int fd)
static void * spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
create an instance of the spandsp tech_pvt for a fax session
static int spandsp_modems(struct ast_fax_session_details *details)
static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
static struct ast_frame * spandsp_fax_read(struct ast_fax_session *s)
Read a frame from the spandsp fax stack.
static struct @464 spandsp_global_stats
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
process a frame from the bridge
static char * spandsp_fax_cli_show_capabilities(int fd)
static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
#define SPANDSP_FAX_TIMER_RATE
static int spandsp_fax_cancel(struct ast_fax_session *s)
static int load_module(void)
load res_fax_spandsp
static int spandsp_v21_new(struct spandsp_pvt *p)
#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY
static int spandsp_fax_gateway_start(struct ast_fax_session *s)
activate a spandsp gateway based on the information in the given fax session
static char * spandsp_fax_cli_show_settings(int fd)
Show res_fax_spandsp settings.
static int unload_module(void)
unload res_fax_spandsp
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
gather data and clean up after gateway ends
static void * spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params)
simple routine to allocate data to generator
static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data)
static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f)
static void spandsp_v21_cleanup(struct ast_fax_session *s)
ast_mutex_t lock
static int update_stats(struct spandsp_pvt *p, int completion_code)
static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
static int spandsp_fax_start(struct ast_fax_session *s)
struct spandsp_fax_stats t38
static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
Write a frame to the spandsp fax stack.
static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
generate T.30 packets sent to the T.30 leg of gateway
static void spandsp_fax_destroy(struct ast_fax_session *s)
Destroy a spandsp fax session.
#define NULL
Definition: resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
Main Channel structure associated with a channel.
The data communicated between the high level applications and the generic fax function.
Definition: res_fax.h:110
const ast_string_field localstationid
Definition: res_fax.h:142
struct ast_fax_t38_parameters their_t38_parameters
Definition: res_fax.h:177
struct ast_fax_documents documents
Definition: res_fax.h:119
const ast_string_field result
Definition: res_fax.h:142
enum ast_fax_modems modems
Definition: res_fax.h:115
union ast_fax_session_details::@281 option
const ast_string_field headerinfo
Definition: res_fax.h:142
struct ast_fax_t38_parameters our_t38_parameters
Definition: res_fax.h:175
uint32_t switch_to_t38
Definition: res_fax.h:159
const ast_string_field resultstr
Definition: res_fax.h:142
unsigned int pages_transferred
Definition: res_fax.h:144
enum ast_fax_capabilities caps
Definition: res_fax.h:113
The data required to handle a fax session.
Definition: res_fax.h:202
void * tech_pvt
Definition: res_fax.h:216
struct ast_channel * chan
Definition: res_fax.h:224
char * channame
Definition: res_fax.h:220
unsigned int id
Definition: res_fax.h:204
enum ast_fax_state state
Definition: res_fax.h:218
struct ast_fax_session_details * details
Definition: res_fax.h:208
unsigned int transcoding_jbig
Definition: res_fax.h:99
unsigned int version
Definition: res_fax.h:93
unsigned int max_ifp
Definition: res_fax.h:94
unsigned int transcoding_mmr
Definition: res_fax.h:98
enum ast_control_t38_rate_management rate_management
Definition: res_fax.h:96
unsigned int fill_bit_removal
Definition: res_fax.h:97
used to register a FAX technology module with res_fax
Definition: res_fax.h:235
struct ast_module * module
Definition: res_fax.h:245
const char *const type
Definition: res_fax.h:237
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@254 data
enum ast_frame_type frametype
unsigned int flags
const char * src
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:226
struct ast_module * self
Definition: module.h:342
Structure for mutex and tracking information.
Definition: lock.h:135
Support for dynamic strings.
Definition: strings.h:604
void * data
Definition: timing.c:55
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1632
struct spandsp_fax_stats * stats
t38_core_state_t * t38_core_state
struct spandsp_pvt::frame_queue read_frames
struct spandsp_fax_gw_stats * t38stats
fax_state_t fax_state
modem_connect_tones_rx_state_t * tone_state
struct ast_timer * timer
unsigned int ist38
t38_terminal_state_t t38_state
t38_gateway_state_t t38_gw_state
t30_state_t * t30_state
enum ast_t38_state ast_t38_state
unsigned int isdone
static struct test_val c
Timing source management.
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:936
#define ast_set_flag(p, flag)
Definition: utils.h:70