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