Asterisk - The Open Source Telephony Project  21.4.1
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
107  .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND
108  | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY
109  | AST_FAX_TECH_V21_DETECT,
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;
127  int neg_failed;
128  int failed_to_train;
129  int rx_protocol_error;
130  int tx_protocol_error;
131  int protocol_error;
132  int retries_exceeded;
133  int file_error;
134  int mem_error;
135  int call_dropped;
136  int unknown_error;
137  int switched;
138 };
139 
140 static struct {
142  struct spandsp_fax_stats g711;
143  struct spandsp_fax_stats t38;
144 } spandsp_global_stats;
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 
155  struct spandsp_fax_stats *stats;
156 
157  struct spandsp_fax_gw_stats *t38stats;
158  t38_gateway_state_t t38_gw_state;
159 
160  struct ast_timer *timer;
162 
163  int v21_detected;
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 
211  ast_timer_close(p->timer);
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) {
248  ast_set_flag(f, AST_FAX_FRFLAG_GATEWAY);
249  if (p->ast_t38_state == T38_STATE_NEGOTIATED) {
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 */
257  AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
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:
268  ast_atomic_fetchadd_int(&p->stats->success, 1);
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 */
278  ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
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 */
287  ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
288  break;
289 
290  case T30_ERR_UNEXPECTED: /*! Unexpected message received */
291  ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
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) */
304  ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
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) */
313  ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
314  break;
315  case T30_ERR_RX_NOFAX: /*! Timed out while waiting for first line */
316  ast_atomic_fetchadd_int(&p->stats->nofax, 1);
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 */
330  ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
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 */
340  ast_atomic_fetchadd_int(&p->stats->file_error, 1);
341  break;
342  case T30_ERR_NOMEM: /*! Cannot allocate memory for more pages */
343  ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
344  break;
345 
346  /* General problems */
347  case T30_ERR_RETRYDCN: /*! Disconnected after permitted retries */
348  ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
349  break;
350  case T30_ERR_CALLDROPPED: /*! The call dropped prematurely */
351  ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
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 */
367  ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
368  break;
369  default:
370  ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
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 
570  if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
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  }
575  s->state = AST_FAX_STATE_ACTIVE;
576  return p;
577  }
578 
579  if (s->details->caps & AST_FAX_TECH_GATEWAY) {
580  s->state = AST_FAX_STATE_INITIALIZED;
581  return p;
582  }
583 
584  AST_LIST_HEAD_INIT(&p->read_frames);
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 
604  if (s->details->caps & (AST_FAX_TECH_T38 | AST_FAX_TECH_AUDIO)) {
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 
620  s->state = AST_FAX_STATE_INITIALIZED;
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) {
645  spandsp_v21_cleanup(s);
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) {
678  s->state = AST_FAX_STATE_COMPLETE;
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;
691  AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
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 
773  if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
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 = {
855  .alloc = spandsp_fax_gw_gen_alloc,
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;
873  p->ast_t38_state = ast_channel_get_t38_state(s->chan);
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. */
881  if (p->ast_t38_state == T38_STATE_NEGOTIATING) {
882  p->ast_t38_state = T38_STATE_NEGOTIATED;
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 
890  t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
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,
898  (t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
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 
920  s->state = AST_FAX_STATE_ACTIVE;
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 
968  s->state = AST_FAX_STATE_OPEN;
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 */
997  set_local_info(p->t30_state, s->details);
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 */
1030  if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
1031  ast_log(LOG_ERROR, "FAX session '%u' error setting rate on timing source.\n", s->id);
1032  return -1;
1033  }
1034 
1035  s->state = AST_FAX_STATE_ACTIVE;
1036 
1037  return 0;
1038 }
1039 
1040 /*! \brief */
1041 static int spandsp_fax_cancel(struct ast_fax_session *s)
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 */
1056 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
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;
1066  ast_atomic_fetchadd_int(&p->stats->switched, 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 */
1076 static char *spandsp_fax_cli_show_capabilities(int fd)
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 
1140 static void spandsp_manager_fax_session(struct mansession *s,
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 
1213  ao2_unlock(session);
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 {
1234  ast_mutex_lock(&spandsp_global_stats.lock);
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);
1263  ast_mutex_unlock(&spandsp_global_stats.lock);
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 {
1278  ast_fax_tech_unregister(&spandsp_fax_tech);
1279  ast_mutex_destroy(&spandsp_global_stats.lock);
1280  return AST_MODULE_LOAD_SUCCESS;
1281 }
1282 
1283 /*! \brief load res_fax_spandsp */
1284 static int load_module(void)
1285 {
1286  ast_mutex_init(&spandsp_global_stats.lock);
1287  spandsp_fax_tech.module = ast_module_info->self;
1288  if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
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 );
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
const ast_string_field result
Definition: res_fax.h:142
Main Channel structure associated with a channel.
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
gather data and clean up after gateway ends
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
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.
const ast_string_field headerinfo
Definition: res_fax.h:142
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:2951
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
const char *const type
Definition: res_fax.h:237
T.38 state information.
Definition: res_pjsip_t38.c:59
void ast_fax_tech_unregister(struct ast_fax_tech *tech)
unregister a FAX technology module
Definition: res_fax.c:991
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:878
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:1139
static struct ast_frame * spandsp_fax_read(struct ast_fax_session *s)
Read a frame from the spandsp fax stack.
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
struct ast_channel * chan
Definition: res_fax.h:224
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 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:757
struct ast_frame_subclass subclass
Utility functions.
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
struct ast_module * self
Definition: module.h:356
ast_mutex_t lock
General Asterisk PBX channel definitions.
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
const char * src
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_fax_session_details * details
Definition: res_fax.h:208
In case you didn't read that giant block of text above the mansession_session struct, the 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:1785
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:191
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
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'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.
unsigned int transcoding_mmr
Definition: res_fax.h:98
unsigned int transcoding_jbig
Definition: res_fax.h:99
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
unsigned int pages_transferred
Definition: res_fax.h:144
Support for dynamic strings.
Definition: strings.h:623
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
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)
union ast_frame::@224 data
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
unsigned int flags
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:5144
Support for logging to various files, console and syslog Configuration in file logger.conf.
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
#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:555
static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
Write a frame to the spandsp fax stack.
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.
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
Standard Command Line Interface.
union ast_fax_session_details::@249 option
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
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:10564
The data required to handle a fax session.
Definition: res_fax.h:202
#define AST_MODEM_T38
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
int ast_fax_tech_register(struct ast_fax_tech *tech)
register a FAX technology module
Definition: res_fax.c:973
void * tech_pvt
Definition: res_fax.h:216
const ast_string_field resultstr
Definition: res_fax.h:142
enum ast_frame_type frametype
const ast_string_field localstationid
Definition: res_fax.h:142
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert a ast_fax_state to a string
Definition: res_fax.c:1012
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
#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:941
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'ed dynamic length string.
Definition: strings.h:659
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521