Wed Jan 8 2020 09:49:50

Asterisk developer's documentation


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  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Spandsp T.38 and G.711 FAX Resource
22  *
23  * \author Matthew Nicholson <mnicholson@digium.com>
24  *
25  * This module registers the Spandsp FAX technology with the res_fax module.
26  */
27 
28 /*** MODULEINFO
29  <depend>spandsp</depend>
30  <depend>res_fax</depend>
31  <support_level>extended</support_level>
32 ***/
33 
34 #include "asterisk.h"
35 
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
37 
38 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
39 #include <spandsp.h>
40 #include <spandsp/version.h>
41 
42 #include "asterisk/logger.h"
43 #include "asterisk/module.h"
44 #include "asterisk/strings.h"
45 #include "asterisk/cli.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/timing.h"
48 #include "asterisk/astobj2.h"
49 #include "asterisk/res_fax.h"
50 
51 #define SPANDSP_FAX_SAMPLES 160
52 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */
53 
54 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
55 static void spandsp_fax_destroy(struct ast_fax_session *s);
56 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
57 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
58 static int spandsp_fax_start(struct ast_fax_session *s);
59 static int spandsp_fax_cancel(struct ast_fax_session *s);
60 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
61 
62 static char *spandsp_fax_cli_show_capabilities(int fd);
63 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
64 static char *spandsp_fax_cli_show_stats(int fd);
65 static char *spandsp_fax_cli_show_settings(int fd);
66 
67 static struct ast_fax_tech spandsp_fax_tech = {
68  .type = "Spandsp",
69  .description = "Spandsp FAX Driver",
70 #if SPANDSP_RELEASE_DATE >= 20090220
71  /* spandsp 0.0.6 */
72  .version = SPANDSP_RELEASE_DATETIME_STRING,
73 #else
74  /* spandsp 0.0.5
75  * TODO: maybe we should determine the version better way
76  */
77  .version = "pre-20090220",
78 #endif
80  .new_session = spandsp_fax_new,
81  .destroy_session = spandsp_fax_destroy,
82  .read = spandsp_fax_read,
83  .write = spandsp_fax_write,
84  .start_session = spandsp_fax_start,
85  .cancel_session = spandsp_fax_cancel,
86  .switch_to_t38 = spandsp_fax_switch_to_t38,
87  .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
88  .cli_show_session = spandsp_fax_cli_show_session,
89  .cli_show_stats = spandsp_fax_cli_show_stats,
90  .cli_show_settings = spandsp_fax_cli_show_settings,
91 };
92 
94  int success;
95  int nofax;
106  int switched;
107 };
108 
109 static struct {
114 
115 struct spandsp_pvt {
116  unsigned int ist38:1;
117  unsigned int isdone:1;
118  fax_state_t fax_state;
119  t38_terminal_state_t t38_state;
120  t30_state_t *t30_state;
121  t38_core_state_t *t38_core_state;
122 
124 
125  struct ast_timer *timer;
127 };
128 
129 static void session_destroy(struct spandsp_pvt *p);
130 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
131 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
132 static void spandsp_log(int level, const char *msg);
133 static int update_stats(struct spandsp_pvt *p, int completion_code);
134 static int spandsp_modems(struct ast_fax_session_details *details);
135 
136 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
137 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
138 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
139 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
140 
141 static void session_destroy(struct spandsp_pvt *p)
142 {
143  struct ast_frame *f;
144 
145  t30_terminate(p->t30_state);
146  p->isdone = 1;
147 
148  ast_timer_close(p->timer);
149  p->timer = NULL;
150  fax_release(&p->fax_state);
151  t38_terminal_release(&p->t38_state);
152 
153  while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
154  ast_frfree(f);
155  }
156 }
157 
158 /*! \brief
159  *
160  */
161 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
162 {
163  struct spandsp_pvt *p = data;
164  struct ast_frame fax_frame = {
166  .subclass.integer = AST_MODEM_T38,
167  .src = "res_fax_spandsp_t38",
168  };
169 
170  struct ast_frame *f = &fax_frame;
171 
172 
173  /* TODO: Asterisk does not provide means of resending the same packet multiple
174  times so count is ignored at the moment */
175 
176  AST_FRAME_SET_BUFFER(f, buf, 0, len);
177 
178  if (!(f = ast_frisolate(f))) {
179  return -1;
180  }
181 
182  /* no need to lock, this all runs in the same thread */
184 
185  return 0;
186 }
187 
188 static int update_stats(struct spandsp_pvt *p, int completion_code)
189 {
190  switch (completion_code) {
191  case T30_ERR_OK:
193  break;
194 
195  /* Link problems */
196  case T30_ERR_CEDTONE: /*! The CED tone exceeded 5s */
197  case T30_ERR_T0_EXPIRED: /*! Timed out waiting for initial communication */
198  case T30_ERR_T1_EXPIRED: /*! Timed out waiting for the first message */
199  case T30_ERR_T3_EXPIRED: /*! Timed out waiting for procedural interrupt */
200  case T30_ERR_HDLC_CARRIER: /*! The HDLC carrier did not stop in a timely manner */
201  case T30_ERR_CANNOT_TRAIN: /*! Failed to train with any of the compatible modems */
203  break;
204 
205  case T30_ERR_OPER_INT_FAIL: /*! Operator intervention failed */
206  case T30_ERR_INCOMPATIBLE: /*! Far end is not compatible */
207  case T30_ERR_RX_INCAPABLE: /*! Far end is not able to receive */
208  case T30_ERR_TX_INCAPABLE: /*! Far end is not able to transmit */
209  case T30_ERR_NORESSUPPORT: /*! Far end cannot receive at the resolution of the image */
210  case T30_ERR_NOSIZESUPPORT: /*! Far end cannot receive at the size of image */
212  break;
213 
214  case T30_ERR_UNEXPECTED: /*! Unexpected message received */
216  break;
217 
218  /* Phase E status values returned to a transmitter */
219  case T30_ERR_TX_BADDCS: /*! Received bad response to DCS or training */
220  case T30_ERR_TX_BADPG: /*! Received a DCN from remote after sending a page */
221  case T30_ERR_TX_ECMPHD: /*! Invalid ECM response received from receiver */
222  case T30_ERR_TX_GOTDCN: /*! Received a DCN while waiting for a DIS */
223  case T30_ERR_TX_INVALRSP: /*! Invalid response after sending a page */
224  case T30_ERR_TX_NODIS: /*! Received other than DIS while waiting for DIS */
225  case T30_ERR_TX_PHBDEAD: /*! Received no response to DCS, training or TCF */
226  case T30_ERR_TX_PHDDEAD: /*! No response after sending a page */
227  case T30_ERR_TX_T5EXP: /*! Timed out waiting for receiver ready (ECM mode) */
229  break;
230 
231  /* Phase E status values returned to a receiver */
232  case T30_ERR_RX_ECMPHD: /*! Invalid ECM response received from transmitter */
233  case T30_ERR_RX_GOTDCS: /*! DCS received while waiting for DTC */
234  case T30_ERR_RX_INVALCMD: /*! Unexpected command after page received */
235  case T30_ERR_RX_NOCARRIER: /*! Carrier lost during fax receive */
236  case T30_ERR_RX_NOEOL: /*! Timed out while waiting for EOL (end Of line) */
238  break;
239  case T30_ERR_RX_NOFAX: /*! Timed out while waiting for first line */
241  break;
242  case T30_ERR_RX_T2EXPDCN: /*! Timer T2 expired while waiting for DCN */
243  case T30_ERR_RX_T2EXPD: /*! Timer T2 expired while waiting for phase D */
244  case T30_ERR_RX_T2EXPFAX: /*! Timer T2 expired while waiting for fax page */
245  case T30_ERR_RX_T2EXPMPS: /*! Timer T2 expired while waiting for next fax page */
246  case T30_ERR_RX_T2EXPRR: /*! Timer T2 expired while waiting for RR command */
247  case T30_ERR_RX_T2EXP: /*! Timer T2 expired while waiting for NSS, DCS or MCF */
248  case T30_ERR_RX_DCNWHY: /*! Unexpected DCN while waiting for DCS or DIS */
249  case T30_ERR_RX_DCNDATA: /*! Unexpected DCN while waiting for image data */
250  case T30_ERR_RX_DCNFAX: /*! Unexpected DCN while waiting for EOM, EOP or MPS */
251  case T30_ERR_RX_DCNPHD: /*! Unexpected DCN after EOM or MPS sequence */
252  case T30_ERR_RX_DCNRRD: /*! Unexpected DCN after RR/RNR sequence */
253  case T30_ERR_RX_DCNNORTN: /*! Unexpected DCN after requested retransmission */
255  break;
256 
257  /* TIFF file problems */
258  case T30_ERR_FILEERROR: /*! TIFF/F file cannot be opened */
259  case T30_ERR_NOPAGE: /*! TIFF/F page not found */
260  case T30_ERR_BADTIFF: /*! TIFF/F format is not compatible */
261  case T30_ERR_BADPAGE: /*! TIFF/F page number tag missing */
262  case T30_ERR_BADTAG: /*! Incorrect values for TIFF/F tags */
263  case T30_ERR_BADTIFFHDR: /*! Bad TIFF/F header - incorrect values in fields */
265  break;
266  case T30_ERR_NOMEM: /*! Cannot allocate memory for more pages */
268  break;
269 
270  /* General problems */
271  case T30_ERR_RETRYDCN: /*! Disconnected after permitted retries */
273  break;
274  case T30_ERR_CALLDROPPED: /*! The call dropped prematurely */
276  break;
277 
278  /* Feature negotiation issues */
279  case T30_ERR_NOPOLL: /*! Poll not accepted */
280  case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
281  case T30_ERR_SUB_UNACCEPTABLE: /*! Far end's sub-address is not acceptable */
282  case T30_ERR_SEP_UNACCEPTABLE: /*! Far end's selective polling address is not acceptable */
283  case T30_ERR_PSA_UNACCEPTABLE: /*! Far end's polled sub-address is not acceptable */
284  case T30_ERR_SID_UNACCEPTABLE: /*! Far end's sender identification is not acceptable */
285  case T30_ERR_PWD_UNACCEPTABLE: /*! Far end's password is not acceptable */
286  case T30_ERR_TSA_UNACCEPTABLE: /*! Far end's transmitting subscriber internet address is not acceptable */
287  case T30_ERR_IRA_UNACCEPTABLE: /*! Far end's internet routing address is not acceptable */
288  case T30_ERR_CIA_UNACCEPTABLE: /*! Far end's calling subscriber internet address is not acceptable */
289  case T30_ERR_ISP_UNACCEPTABLE: /*! Far end's internet selective polling address is not acceptable */
290  case T30_ERR_CSA_UNACCEPTABLE: /*! Far end's called subscriber internet address is not acceptable */
292  break;
293  default:
295  ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
296  return -1;
297  }
298  return 0;
299 }
300 
301 /*! \brief Phase E handler callback.
302  * \param t30_state the span t30 state
303  * \param data this will be the ast_fax_session
304  * \param completion_code the result of the fax session
305  *
306  * This function pulls stats from the spandsp stack and stores them for res_fax
307  * to use later.
308  */
309 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
310 {
311  struct ast_fax_session *s = data;
312  struct spandsp_pvt *p = s->tech_pvt;
313  char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
314  const char *c;
315  t30_stats_t stats;
316 
317  ast_debug(5, "FAX session '%u' entering phase E\n", s->id);
318 
319  p->isdone = 1;
320 
321  update_stats(p, completion_code);
322 
323  t30_get_transfer_statistics(t30_state, &stats);
324 
325  if (completion_code == T30_ERR_OK) {
326  ast_string_field_set(s->details, result, "SUCCESS");
327  } else {
328  ast_string_field_set(s->details, result, "FAILED");
329  ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
330  }
331 
332  ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
333 
334  ast_debug(5, "FAX session '%u' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
335 
336  if ((c = t30_get_tx_ident(t30_state))) {
337  ast_string_field_set(s->details, localstationid, c);
338  }
339 
340  if ((c = t30_get_rx_ident(t30_state))) {
341  ast_string_field_set(s->details, remotestationid, c);
342  }
343 
344 #if SPANDSP_RELEASE_DATE >= 20090220
345  s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
346 #else
347  s->details->pages_transferred = stats.pages_transferred;
348 #endif
349 
350  ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
351 
352  ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
353 
354  t30_get_tx_page_header_info(t30_state, headerinfo);
355  ast_string_field_set(s->details, headerinfo, headerinfo);
356 }
357 
358 /*! \brief Send spandsp log messages to asterisk.
359  * \param level the spandsp logging level
360  * \param msg the log message
361  *
362  * \note This function is a callback function called by spandsp.
363  */
364 static void spandsp_log(int level, const char *msg)
365 {
366  if (level == SPAN_LOG_ERROR) {
367  ast_log(LOG_ERROR, "%s", msg);
368  } else if (level == SPAN_LOG_WARNING) {
369  ast_log(LOG_WARNING, "%s", msg);
370  } else {
371  ast_fax_log(LOG_DEBUG, msg);
372  }
373 }
374 
375 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
376 {
377  int level = SPAN_LOG_WARNING;
378 
379  if (details->option.debug) {
380  level = SPAN_LOG_DEBUG_3;
381  }
382 
383  span_log_set_message_handler(state, spandsp_log);
384  span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
385 }
386 
387 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
388 {
389  if (!ast_strlen_zero(details->localstationid)) {
390  t30_set_tx_ident(t30_state, details->localstationid);
391  }
392 
393  if (!ast_strlen_zero(details->headerinfo)) {
394  t30_set_tx_page_header_info(t30_state, details->headerinfo);
395  }
396 }
397 
398 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
399 {
400  if (details->caps & AST_FAX_TECH_RECEIVE) {
401  t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
402  } else {
403  /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
404  * should be safe because we ensure either RECEIVE or SEND is
405  * indicated in spandsp_fax_new() */
406  t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
407  }
408 }
409 
410 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
411 {
412  t30_set_ecm_capability(t30_state, details->option.ecm);
413  t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
414 }
415 
416 static int spandsp_modems(struct ast_fax_session_details *details)
417 {
418  int modems = 0;
419  if (AST_FAX_MODEM_V17 & details->modems) {
420  modems |= T30_SUPPORT_V17;
421  }
422  if (AST_FAX_MODEM_V27 & details->modems) {
423  modems |= T30_SUPPORT_V27TER;
424  }
425  if (AST_FAX_MODEM_V29 & details->modems) {
426  modems |= T30_SUPPORT_V29;
427  }
428  if (AST_FAX_MODEM_V34 & details->modems) {
429 #if defined(T30_SUPPORT_V34)
430  modems |= T30_SUPPORT_V34;
431 #elif defined(T30_SUPPORT_V34HDX)
432  modems |= T30_SUPPORT_V34HDX;
433 #else
434  ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
435 #endif
436  }
437 
438  return modems;
439 }
440 
441 /*! \brief create an instance of the spandsp tech_pvt for a fax session */
442 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
443 {
444  struct spandsp_pvt *p;
445  int caller_mode;
446 
447  if ((!(p = ast_calloc(1, sizeof(*p))))) {
448  ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
449  goto e_return;
450  }
451 
453 
454  if (s->details->caps & AST_FAX_TECH_RECEIVE) {
455  caller_mode = 0;
456  } else if (s->details->caps & AST_FAX_TECH_SEND) {
457  caller_mode = 1;
458  } else {
459  ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
460  goto e_free;
461  }
462 
463  if (!(p->timer = ast_timer_open())) {
464  ast_log(LOG_ERROR, "Channel '%s' FAX session '%u' failed to create timing source.\n", s->channame, s->id);
465  goto e_free;
466  }
467 
468  s->fd = ast_timer_fd(p->timer);
469 
470  p->stats = &spandsp_global_stats.g711;
471 
473  if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
474  /* audio mode was not requested, start in T.38 mode */
475  p->ist38 = 1;
476  p->stats = &spandsp_global_stats.t38;
477  }
478 
479  /* init t38 stuff */
480  t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, p);
481  set_logging(&p->t38_state.logging, s->details);
482 
483  /* init audio stuff */
484  fax_init(&p->fax_state, caller_mode);
485  set_logging(&p->fax_state.logging, s->details);
486  }
487 
489  return p;
490 
491 e_free:
492  ast_free(p);
493 e_return:
494  return NULL;
495 }
496 
497 /*! \brief Destroy a spandsp fax session.
498  */
499 static void spandsp_fax_destroy(struct ast_fax_session *s)
500 {
501  struct spandsp_pvt *p = s->tech_pvt;
502 
503  session_destroy(p);
504  ast_free(p);
505  s->tech_pvt = NULL;
506  s->fd = -1;
507 }
508 
509 /*! \brief Read a frame from the spandsp fax stack.
510  */
511 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
512 {
513  struct spandsp_pvt *p = s->tech_pvt;
514  uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
515  int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
516  int samples;
517 
518  struct ast_frame fax_frame = {
520  .subclass.codec = AST_FORMAT_SLINEAR,
521  .src = "res_fax_spandsp_g711",
522  };
523 
524  struct ast_frame *f = &fax_frame;
525 
526  if (ast_timer_ack(p->timer, 1) < 0) {
527  ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%u'\n", s->id);
528  return NULL;
529  }
530 
531  /* XXX do we need to lock here? */
532  if (p->isdone) {
534  ast_debug(5, "FAX session '%u' is complete.\n", s->id);
535  return NULL;
536  }
537 
538  if (p->ist38) {
539  t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
540  if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
541  return f;
542  }
543  } else {
544  if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
545  f->samples = samples;
546  AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
547  return ast_frisolate(f);
548  }
549  }
550 
551  return &ast_null_frame;
552 }
553 
554 /*! \brief Write a frame to the spandsp fax stack.
555  * \param s a fax session
556  * \param f the frame to write
557  *
558  * \note res_fax does not currently use the return value of this function.
559  * Also the fax_rx() function never fails.
560  *
561  * \retval 0 success
562  * \retval -1 failure
563  */
564 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
565 {
566  struct spandsp_pvt *p = s->tech_pvt;
567 
568  /* XXX do we need to lock here? */
569  if (s->state == AST_FAX_STATE_COMPLETE) {
570  ast_log(LOG_WARNING, "FAX session '%u' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
571  return -1;
572  }
573 
574  if (p->ist38) {
575  return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
576  } else {
577  return fax_rx(&p->fax_state, f->data.ptr, f->samples);
578  }
579 }
580 
581 /*! \brief */
582 static int spandsp_fax_start(struct ast_fax_session *s)
583 {
584  struct spandsp_pvt *p = s->tech_pvt;
585 
587 
588  if (p->ist38) {
589 #if SPANDSP_RELEASE_DATE >= 20080725
590  /* for spandsp shaphots 0.0.6 and higher */
591  p->t30_state = &p->t38_state.t30;
592  p->t38_core_state = &p->t38_state.t38_fe.t38;
593 #else
594  /* for spandsp releases 0.0.5 */
595  p->t30_state = &p->t38_state.t30_state;
596  p->t38_core_state = &p->t38_state.t38;
597 #endif
598  } else {
599 #if SPANDSP_RELEASE_DATE >= 20080725
600  /* for spandsp shaphots 0.0.6 and higher */
601  p->t30_state = &p->fax_state.t30;
602 #else
603  /* for spandsp release 0.0.5 */
604  p->t30_state = &p->fax_state.t30_state;
605 #endif
606  }
607 
608  set_logging(&p->t30_state->logging, s->details);
609 
610  /* set some parameters */
612  set_file(p->t30_state, s->details);
613  set_ecm(p->t30_state, s->details);
614  t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
615 
616  /* perhaps set_transmit_on_idle() should be called */
617 
618  t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
619 
620  /* set T.38 parameters */
621  if (p->ist38) {
622  set_logging(&p->t38_core_state->logging, s->details);
623 
624  t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
625 
627  t38_set_fill_bit_removal(p->t38_core_state, TRUE);
628  }
629 
631  t38_set_mmr_transcoding(p->t38_core_state, TRUE);
632  }
633 
635  t38_set_jbig_transcoding(p->t38_core_state, TRUE);
636  }
637  } else {
638  /* have the fax stack generate silence if it has no data to send */
639  fax_set_transmit_on_idle(&p->fax_state, 1);
640  }
641 
642 
643  /* start the timer */
645  ast_log(LOG_ERROR, "FAX session '%u' error setting rate on timing source.\n", s->id);
646  return -1;
647  }
648 
650 
651  return 0;
652 }
653 
654 /*! \brief */
655 static int spandsp_fax_cancel(struct ast_fax_session *s)
656 {
657  struct spandsp_pvt *p = s->tech_pvt;
658  t30_terminate(p->t30_state);
659  p->isdone = 1;
660  return 0;
661 }
662 
663 /*! \brief */
665 {
666  struct spandsp_pvt *p = s->tech_pvt;
667 
668  /* prevent the phase E handler from running, this is not a real termination */
669  t30_set_phase_e_handler(p->t30_state, NULL, NULL);
670 
671  t30_terminate(p->t30_state);
672 
673  s->details->option.switch_to_t38 = 1;
675 
676  p->ist38 = 1;
677  p->stats = &spandsp_global_stats.t38;
679 
680  return 0;
681 }
682 
683 /*! \brief */
685 {
686  ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
687  return CLI_SUCCESS;
688 }
689 
690 /*! \brief */
691 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
692 {
693  struct spandsp_pvt *p = s->tech_pvt;
694  t30_stats_t stats;
695 
696  ao2_lock(s);
697  ast_cli(fd, "%-22s : %u\n", "session", s->id);
698  ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
699  ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
701  t30_get_transfer_statistics(p->t30_state, &stats);
702  ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
703  ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
704  ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
705  ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
706 #if SPANDSP_RELEASE_DATE >= 20090220
707  ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
708 #else
709  ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
710 #endif
711  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);
712 
713  ast_cli(fd, "\nData Statistics:\n");
714 #if SPANDSP_RELEASE_DATE >= 20090220
715  ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
716  ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
717 #else
718  ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
719  ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
720 #endif
721  ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
722  ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
723  }
724  ao2_unlock(s);
725  ast_cli(fd, "\n\n");
726  return CLI_SUCCESS;
727 }
728 
729 /*! \brief */
730 static char *spandsp_fax_cli_show_stats(int fd)
731 {
733  ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
734  ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
735  ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
736  ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
737  ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
738  ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
739  ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
740  ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
741  ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
742  ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
743  ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
744  ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
745  ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
746  ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
747 
748  ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
749  ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
750  ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
751  ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
752  ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
753  ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
754  ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
755  ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
756  ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
757  ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
758  ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
759  ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
760  ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
762 
763  return CLI_SUCCESS;
764 }
765 
766 /*! \brief Show res_fax_spandsp settings */
767 static char *spandsp_fax_cli_show_settings(int fd)
768 {
769  /* no settings at the moment */
770  return CLI_SUCCESS;
771 }
772 
773 /*! \brief unload res_fax_spandsp */
774 static int unload_module(void)
775 {
776  ast_fax_tech_unregister(&spandsp_fax_tech);
779 }
780 
781 /*! \brief load res_fax_spandsp */
782 static int load_module(void)
783 {
785  spandsp_fax_tech.module = ast_module_info->self;
786  if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
787  ast_log(LOG_ERROR, "failed to register FAX technology\n");
789  }
790 
791  /* prevent logging to stderr */
792  span_set_message_handler(NULL);
793 
795 }
796 
797 
798 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
799  .load = load_module,
800  .unload = unload_module,
801  );
const ast_string_field result
Definition: res_fax.h:137
static void session_destroy(struct spandsp_pvt *p)
static struct @333 spandsp_global_stats
struct spandsp_fax_stats g711
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
t38_terminal_state_t t38_state
void ast_fax_tech_unregister(struct ast_fax_tech *tech)
unregister a fax technology
Definition: res_fax.c:635
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
struct ast_frame ast_null_frame
Definition: frame.c:131
String manipulation functions.
int seqno
Definition: frame.h:172
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:137
unsigned int id
Definition: res_fax.h:180
void * ptr
Definition: frame.h:160
static int spandsp_fax_start(struct ast_fax_session *s)
uint32_t switch_to_t38
Definition: res_fax.h:154
#define LOG_WARNING
Definition: logger.h:144
static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
const char *const type
Definition: res_fax.h:210
static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
#define AST_MODEM_T38
Definition: frame.h:216
struct ast_timer * timer
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:150
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:123
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:155
#define ao2_unlock(a)
Definition: astobj2.h:497
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
struct ast_frame * ast_frisolate(struct ast_frame *fr)
Makes a frame independent of any static storage.
Definition: frame.c:391
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)
struct spandsp_fax_stats t38
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
#define LOG_DEBUG
Definition: logger.h:122
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
struct spandsp_pvt::frame_queue read_frames
t38_core_state_t * t38_core_state
Utility functions.
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
Definition: frame.h:183
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_module * self
Definition: module.h:227
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Definition: frame.h:204
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
ast_mutex_t lock
Definition: app_meetme.c:964
int datalen
Definition: frame.h:148
struct ast_fax_session_details * details
Definition: res_fax.h:184
#define ao2_lock(a)
Definition: astobj2.h:488
static char * spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
char * channame
Definition: res_fax.h:196
The data communicated between the high level applications and the generic fax function.
Definition: res_fax.h:105
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
struct ast_module * module
Definition: res_fax.h:218
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:93
unsigned int transcoding_jbig
Definition: res_fax.h:94
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:172
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
struct spandsp_fax_stats * stats
union ast_fax_session_details::@203 option
unsigned int pages_transferred
Definition: res_fax.h:139
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:89
struct ast_fax_documents documents
Definition: res_fax.h:114
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:208
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int update_stats(struct spandsp_pvt *p, int completion_code)
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:611
#define ast_free(a)
Definition: astmm.h:97
static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
unsigned int isdone
static struct ast_format f[]
Definition: format_g726.c:181
t30_state_t * t30_state
enum ast_fax_modems modems
Definition: res_fax.h:110
enum ast_fax_state state
Definition: res_fax.h:194
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:680
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:158
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:163
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:367
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.
static char * spandsp_fax_cli_show_stats(int fd)
static void spandsp_log(int level, const char *msg)
Send spandsp log messages to asterisk.
#define CLI_SUCCESS
Definition: cli.h:43
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
#define SPANDSP_FAX_TIMER_RATE
#define SPANDSP_FAX_SAMPLES
#define TRUE
Definition: app_minivm.c:503
The data required to handle a fax session.
Definition: res_fax.h:178
const char * ast_fax_state_to_str(enum ast_fax_state state)
convert an ast_fax_state to a string
Definition: res_fax.c:657
Data structure associated with a single frame of data.
Definition: frame.h:142
enum ast_fax_capabilities caps
Definition: res_fax.h:108
void * tech_pvt
Definition: res_fax.h:192
const ast_string_field resultstr
Definition: res_fax.h:137
enum ast_frame_type frametype
Definition: frame.h:144
const ast_string_field localstationid
Definition: res_fax.h:137
#define ast_mutex_init(pmutex)
Definition: lock.h:152
#define ast_frfree(fr)
Definition: frame.h:583
#define ast_mutex_destroy(a)
Definition: lock.h:154
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:38
Asterisk module definitions.
unsigned int fill_bit_removal
Definition: res_fax.h:92
struct ast_fax_t38_parameters their_t38_parameters
Definition: res_fax.h:170
union ast_frame::@172 data
Timing source management.
Structure for mutex and tracking information.
Definition: lock.h:121
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int samples
Definition: frame.h:150
int ast_fax_tech_register(struct ast_fax_tech *tech)
register a fax technology
Definition: res_fax.c:616
#define ast_mutex_unlock(a)
Definition: lock.h:156
fax_state_t fax_state
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344