Asterisk - The Open Source Telephony Project  GIT-master-0190e70
app_fax.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Simple fax applications
5  *
6  * 2007-2008, Dmitry Andrianov <asterisk@dima.spb.ru>
7  *
8  * Code based on original implementation by Steve Underwood <steveu@coppice.org>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  *
13  */
14 
15 /*** MODULEINFO
16  <defaultenabled>no</defaultenabled>
17  <depend>spandsp</depend>
18  <conflict>res_fax</conflict>
19  <support_level>deprecated</support_level>
20  <replacement>res_fax</replacement>
21 ***/
22 
23 /* Needed for spandsp headers */
24 #define ASTMM_LIBC ASTMM_IGNORE
25 #include "asterisk.h"
26 
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <inttypes.h>
31 #include <pthread.h>
32 #include <errno.h>
33 #include <tiffio.h>
34 
35 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
36 #include <spandsp.h>
37 #include <spandsp/version.h>
38 
39 #include "asterisk/lock.h"
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/app.h"
45 #include "asterisk/dsp.h"
46 #include "asterisk/module.h"
47 #include "asterisk/stasis.h"
49 #include "asterisk/format_cache.h"
50 
51 /*** DOCUMENTATION
52  <application name="SendFAX" language="en_US" module="app_fax">
53  <synopsis>
54  Send a Fax
55  </synopsis>
56  <syntax>
57  <parameter name="filename" required="true">
58  <para>Filename of TIFF file to fax</para>
59  </parameter>
60  <parameter name="a" required="false">
61  <para>Makes the application behave as the answering machine</para>
62  <para>(Default behavior is as calling machine)</para>
63  </parameter>
64  </syntax>
65  <description>
66  <para>Send a given TIFF file to the channel as a FAX.</para>
67  <para>This application sets the following channel variables:</para>
68  <variablelist>
69  <variable name="LOCALSTATIONID">
70  <para>To identify itself to the remote end</para>
71  </variable>
72  <variable name="LOCALHEADERINFO">
73  <para>To generate a header line on each page</para>
74  </variable>
75  <variable name="FAXSTATUS">
76  <value name="SUCCESS"/>
77  <value name="FAILED"/>
78  </variable>
79  <variable name="FAXERROR">
80  <para>Cause of failure</para>
81  </variable>
82  <variable name="REMOTESTATIONID">
83  <para>The CSID of the remote side</para>
84  </variable>
85  <variable name="FAXPAGES">
86  <para>Number of pages sent</para>
87  </variable>
88  <variable name="FAXBITRATE">
89  <para>Transmission rate</para>
90  </variable>
91  <variable name="FAXRESOLUTION">
92  <para>Resolution of sent fax</para>
93  </variable>
94  </variablelist>
95  </description>
96  </application>
97  <application name="ReceiveFAX" language="en_US" module="app_fax">
98  <synopsis>
99  Receive a Fax
100  </synopsis>
101  <syntax>
102  <parameter name="filename" required="true">
103  <para>Filename of TIFF file save incoming fax</para>
104  </parameter>
105  <parameter name="c" required="false">
106  <para>Makes the application behave as the calling machine</para>
107  <para>(Default behavior is as answering machine)</para>
108  </parameter>
109  </syntax>
110  <description>
111  <para>Receives a FAX from the channel into the given filename
112  overwriting the file if it already exists.</para>
113  <para>File created will be in TIFF format.</para>
114 
115  <para>This application sets the following channel variables:</para>
116  <variablelist>
117  <variable name="LOCALSTATIONID">
118  <para>To identify itself to the remote end</para>
119  </variable>
120  <variable name="LOCALHEADERINFO">
121  <para>To generate a header line on each page</para>
122  </variable>
123  <variable name="FAXSTATUS">
124  <value name="SUCCESS"/>
125  <value name="FAILED"/>
126  </variable>
127  <variable name="FAXERROR">
128  <para>Cause of failure</para>
129  </variable>
130  <variable name="REMOTESTATIONID">
131  <para>The CSID of the remote side</para>
132  </variable>
133  <variable name="FAXPAGES">
134  <para>Number of pages sent</para>
135  </variable>
136  <variable name="FAXBITRATE">
137  <para>Transmission rate</para>
138  </variable>
139  <variable name="FAXRESOLUTION">
140  <para>Resolution of sent fax</para>
141  </variable>
142  </variablelist>
143  </description>
144  </application>
145 
146  ***/
147 
148 static const char app_sndfax_name[] = "SendFAX";
149 static const char app_rcvfax_name[] = "ReceiveFAX";
150 
151 #define MAX_SAMPLES 240
152 
153 /* Watchdog. I have seen situations when remote fax disconnects (because of poor line
154  quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
155  To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
156  We also terminate application when more than 30 minutes passed regardless of
157  state changes. This is just a precaution measure - no fax should take that long */
158 
159 #define WATCHDOG_TOTAL_TIMEOUT 30 * 60
160 #define WATCHDOG_STATE_TIMEOUT 5 * 60
161 
162 typedef struct {
163  struct ast_channel *chan;
164  enum ast_t38_state t38state; /* T38 state of the channel */
165  int direction; /* Fax direction: 0 - receiving, 1 - sending */
167  char *file_name;
168  struct ast_control_t38_parameters t38parameters;
169  volatile int finished;
170 } fax_session;
171 
172 static void span_message(int level, const char *msg)
173 {
174  if (level == SPAN_LOG_ERROR) {
175  ast_log(LOG_ERROR, "%s", msg);
176  } else if (level == SPAN_LOG_WARNING) {
177  ast_log(LOG_WARNING, "%s", msg);
178  } else {
179  ast_debug(1, "%s", msg);
180  }
181 }
182 
183 static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
184 {
185  struct ast_channel *chan = (struct ast_channel *) user_data;
186 
187  struct ast_frame outf = {
189  .subclass.integer = AST_MODEM_T38,
190  .src = __FUNCTION__,
191  };
192 
193  /* TODO: Asterisk does not provide means of resending the same packet multiple
194  times so count is ignored at the moment */
195 
196  AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
197 
198  if (ast_write(chan, &outf) < 0) {
199  ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
200  return -1;
201  }
202 
203  return 0;
204 }
205 
206 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
207 {
208  RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
209  RAII_VAR(struct ast_json *, json_filenames, NULL, ast_json_unref);
211  const char *local_ident;
212  const char *far_ident;
213  char buf[20];
214  fax_session *s = (fax_session *) user_data;
215  t30_stats_t stat;
216  int pages_transferred;
217 
218  ast_debug(1, "Fax phase E handler. result=%d\n", result);
219 
220  t30_get_transfer_statistics(f, &stat);
221 
222  s = (fax_session *) user_data;
223 
224  if (result != T30_ERR_OK) {
225  s->finished = -1;
226 
227  /* FAXSTATUS is already set to FAILED */
228  pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
229 
230  ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
231 
232  return;
233  }
234 
235  s->finished = 1;
236 
237  local_ident = S_OR(t30_get_tx_ident(f), "");
238  far_ident = S_OR(t30_get_rx_ident(f), "");
239  pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
240  pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
241  pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
242 #if SPANDSP_RELEASE_DATE >= 20090220
243  pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
244 #else
245  pages_transferred = stat.pages_transferred;
246 #endif
247  snprintf(buf, sizeof(buf), "%d", pages_transferred);
248  pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
249  snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
250  pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
251  snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
252  pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);
253 
254  ast_debug(1, "Fax transmitted successfully.\n");
255  ast_debug(1, " Remote station ID: %s\n", far_ident);
256  ast_debug(1, " Pages transferred: %d\n", pages_transferred);
257  ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
258  ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
259 
260  json_filenames = ast_json_pack("[s]", s->file_name);
261  if (!json_filenames) {
262  return;
263  }
264  ast_json_ref(json_filenames);
265  json_object = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: i, s: o}",
266  "type", s->direction ? "send" : "receive",
267  "remote_station_id", AST_JSON_UTF8_VALIDATE(far_ident),
268  "local_station_id", AST_JSON_UTF8_VALIDATE(local_ident),
269  "fax_pages", pages_transferred,
270  "fax_resolution", stat.y_resolution,
271  "fax_bitrate", stat.bit_rate,
272  "filenames", json_filenames);
274  if (!message) {
275  return;
276  }
278 }
279 
280 /* === Helper functions to configure fax === */
281 
282 /* Setup SPAN logging according to Asterisk debug level */
283 static int set_logging(logging_state_t *state)
284 {
285  int level = SPAN_LOG_WARNING + option_debug;
286 
287  span_log_set_message_handler(state, span_message);
288  span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
289 
290  return 0;
291 }
292 
293 static void set_local_info(t30_state_t *state, fax_session *s)
294 {
295  const char *x;
296 
297  x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
298  if (!ast_strlen_zero(x))
299  t30_set_tx_ident(state, x);
300 
301  x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
302  if (!ast_strlen_zero(x))
303  t30_set_tx_page_header_info(state, x);
304 }
305 
306 static void set_file(t30_state_t *state, fax_session *s)
307 {
308  if (s->direction)
309  t30_set_tx_file(state, s->file_name, -1, -1);
310  else
311  t30_set_rx_file(state, s->file_name, -1);
312 }
313 
314 static void set_ecm(t30_state_t *state, int ecm)
315 {
316  t30_set_ecm_capability(state, ecm);
317  t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
318 }
319 
320 /* === Generator === */
321 
322 /* This function is only needed to return passed params so
323  generator_activate will save it to channel's generatordata */
324 static void *fax_generator_alloc(struct ast_channel *chan, void *params)
325 {
326  return params;
327 }
328 
329 static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
330 {
331  fax_state_t *fax = (fax_state_t*) data;
332  uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
333  int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
334 
335  struct ast_frame outf = {
337  .subclass.format = ast_format_slin,
338  .src = __FUNCTION__,
339  };
340 
341  if (samples > MAX_SAMPLES) {
342  ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
343  samples = MAX_SAMPLES;
344  }
345 
346  if ((len = fax_tx(fax, buf, samples)) > 0) {
347  outf.samples = len;
348  AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
349 
350  if (ast_write(chan, &outf) < 0) {
351  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
352  return -1;
353  }
354  }
355 
356  return 0;
357 }
358 
359 static struct ast_generator generator = {
361  .generate = fax_generator_generate,
362 };
363 
364 
365 /* === Transmission === */
366 
368 {
369  int res = -1;
370  struct ast_format *original_read_fmt;
371  struct ast_format *original_write_fmt = NULL;
372  fax_state_t fax;
373  t30_state_t *t30state;
374  struct ast_frame *inf = NULL;
375  int last_state = 0;
376  struct timeval now, start, state_change;
378  struct ast_control_t38_parameters t38_parameters = { .version = 0,
379  .max_ifp = 800,
380  .rate = AST_T38_RATE_14400,
381  .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
382  .fill_bit_removal = 1,
383 /*
384  * spandsp has API calls to support MMR and JBIG transcoding, but they aren't
385  * implemented quite yet... so don't offer them to the remote endpoint
386  * .transcoding_mmr = 1,
387  * .transcoding_jbig = 1,
388 */
389  };
390 
391  /* if in called party mode, try to use T.38 */
392  if (s->caller_mode == FALSE) {
393  /* check if we are already in T.38 mode (unlikely), or if we can request
394  * a switch... if so, request it now and wait for the result, rather
395  * than starting an audio FAX session that will have to be cancelled
396  */
397  if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
398  return 1;
399  } else if ((t38_state != T38_STATE_UNAVAILABLE) &&
401  (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
402  /* wait up to five seconds for negotiation to complete */
403  unsigned int timeout = 5000;
404  int ms;
405 
406  ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan));
407  while (timeout > 0) {
408  ms = ast_waitfor(s->chan, 1000);
409  if (ms < 0) {
410  ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
411  return -1;
412  }
413  if (!ms) {
414  /* nothing happened */
415  if (timeout > 0) {
416  timeout -= 1000;
417  continue;
418  } else {
419  ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan));
420  break;
421  }
422  }
423  if (!(inf = ast_read(s->chan))) {
424  return -1;
425  }
426  if ((inf->frametype == AST_FRAME_CONTROL) &&
428  (inf->datalen == sizeof(t38_parameters))) {
429  struct ast_control_t38_parameters *parameters = inf->data.ptr;
430 
431  switch (parameters->request_response) {
432  case AST_T38_NEGOTIATED:
433  ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan));
434  res = 1;
435  break;
436  case AST_T38_REFUSED:
437  ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan));
438  break;
439  default:
440  ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan));
441  break;
442  }
443  ast_frfree(inf);
444  if (res == 1) {
445  return 1;
446  } else {
447  break;
448  }
449  }
450  ast_frfree(inf);
451  }
452  }
453  }
454 
455 #if SPANDSP_RELEASE_DATE >= 20080725
456  /* for spandsp shaphots 0.0.6 and higher */
457  t30state = &fax.t30;
458 #else
459  /* for spandsp release 0.0.5 */
460  t30state = &fax.t30_state;
461 #endif
462 
463  original_read_fmt = ao2_bump(ast_channel_readformat(s->chan));
465  if (res < 0) {
466  ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
467  goto done;
468  }
469 
470  original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan));
472  if (res < 0) {
473  ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
474  goto done;
475  }
476 
477  /* Initialize T30 terminal */
478  fax_init(&fax, s->caller_mode);
479 
480  /* Setup logging */
481  set_logging(&fax.logging);
482  set_logging(&t30state->logging);
483 
484  /* Configure terminal */
485  set_local_info(t30state, s);
486  set_file(t30state, s);
487  set_ecm(t30state, TRUE);
488 
489  fax_set_transmit_on_idle(&fax, TRUE);
490 
491  t30_set_phase_e_handler(t30state, phase_e_handler, s);
492 
493  start = state_change = ast_tvnow();
494 
495  ast_activate_generator(s->chan, &generator, &fax);
496 
497  while (!s->finished) {
498  inf = NULL;
499 
500  if ((res = ast_waitfor(s->chan, 25)) < 0) {
501  ast_debug(1, "Error waiting for a frame\n");
502  break;
503  }
504 
505  /* Watchdog */
506  now = ast_tvnow();
507  if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
508  ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
509  res = -1;
510  break;
511  }
512 
513  if (!res) {
514  /* There was timeout waiting for a frame. Loop around and wait again */
515  continue;
516  }
517 
518  /* There is a frame available. Get it */
519  res = 0;
520 
521  if (!(inf = ast_read(s->chan))) {
522  ast_debug(1, "Channel hangup\n");
523  res = -1;
524  break;
525  }
526 
527  ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen);
528 
529  /* Check the frame type. Format also must be checked because there is a chance
530  that a frame in old format was already queued before we set channel format
531  to slinear so it will still be received by ast_read */
532  if (inf->frametype == AST_FRAME_VOICE &&
534  if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
535  /* I know fax_rx never returns errors. The check here is for good style only */
536  ast_log(LOG_WARNING, "fax_rx returned error\n");
537  res = -1;
538  break;
539  }
540  if (last_state != t30state->state) {
541  state_change = ast_tvnow();
542  last_state = t30state->state;
543  }
544  } else if ((inf->frametype == AST_FRAME_CONTROL) &&
546  struct ast_control_t38_parameters *parameters = inf->data.ptr;
547 
548  if (parameters->request_response == AST_T38_NEGOTIATED) {
549  /* T38 switchover completed */
550  s->t38parameters = *parameters;
551  ast_debug(1, "T38 negotiated, finishing audio loop\n");
552  res = 1;
553  break;
554  } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
555  t38_parameters.request_response = AST_T38_NEGOTIATED;
556  ast_debug(1, "T38 request received, accepting\n");
557  /* Complete T38 switchover */
558  ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
559  /* Do not break audio loop, wait until channel driver finally acks switchover
560  * with AST_T38_NEGOTIATED
561  */
562  }
563  }
564 
565  ast_frfree(inf);
566  inf = NULL;
567  }
568 
569  ast_debug(1, "Loop finished, res=%d\n", res);
570 
571  if (inf)
572  ast_frfree(inf);
573 
575 
576  /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
577  by t30_terminate, display diagnostics and set status variables although no transmittion
578  has taken place yet. */
579  if (res > 0) {
580  t30_set_phase_e_handler(t30state, NULL, NULL);
581  }
582 
583  t30_terminate(t30state);
584  fax_release(&fax);
585 
586 done:
587  if (original_write_fmt) {
588  if (ast_set_write_format(s->chan, original_write_fmt) < 0)
589  ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan));
590  ao2_ref(original_write_fmt, -1);
591  }
592 
593  if (original_read_fmt) {
594  if (ast_set_read_format(s->chan, original_read_fmt) < 0)
595  ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan));
596  ao2_ref(original_read_fmt, -1);
597  }
598 
599  return res;
600 
601 }
602 
603 static int transmit_t38(fax_session *s)
604 {
605  int res = 0;
606  t38_terminal_state_t t38;
607  struct ast_frame *inf = NULL;
608  int last_state = 0;
609  struct timeval now, start, state_change, last_frame;
610  t30_state_t *t30state;
611  t38_core_state_t *t38state;
612 
613 #if SPANDSP_RELEASE_DATE >= 20080725
614  /* for spandsp shaphots 0.0.6 and higher */
615  t30state = &t38.t30;
616  t38state = &t38.t38_fe.t38;
617 #else
618  /* for spandsp releases 0.0.5 */
619  t30state = &t38.t30_state;
620  t38state = &t38.t38;
621 #endif
622 
623  /* Initialize terminal */
624  memset(&t38, 0, sizeof(t38));
625  if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
626  ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
627  res = -1;
628  goto disable_t38;
629  }
630 
631  t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
632 
634  t38_set_fill_bit_removal(t38state, TRUE);
635  }
637  t38_set_mmr_transcoding(t38state, TRUE);
638  }
640  t38_set_jbig_transcoding(t38state, TRUE);
641  }
642 
643  /* Setup logging */
644  set_logging(&t38.logging);
645  set_logging(&t30state->logging);
646  set_logging(&t38state->logging);
647 
648  /* Configure terminal */
649  set_local_info(t30state, s);
650  set_file(t30state, s);
651  set_ecm(t30state, TRUE);
652 
653  t30_set_phase_e_handler(t30state, phase_e_handler, s);
654 
655  now = start = state_change = ast_tvnow();
656 
657  while (!s->finished) {
658  inf = NULL;
659 
660  if ((res = ast_waitfor(s->chan, 25)) < 0) {
661  ast_debug(1, "Error waiting for a frame\n");
662  break;
663  }
664 
665  last_frame = now;
666 
667  /* Watchdog */
668  now = ast_tvnow();
669  if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
670  ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
671  res = -1;
672  break;
673  }
674 
675  t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
676 
677  if (!res) {
678  /* There was timeout waiting for a frame. Loop around and wait again */
679  continue;
680  }
681 
682  /* There is a frame available. Get it */
683  res = 0;
684 
685  if (!(inf = ast_read(s->chan))) {
686  ast_debug(1, "Channel hangup\n");
687  res = -1;
688  break;
689  }
690 
691  ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen);
692 
693  if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) {
694  t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
695  if (last_state != t30state->state) {
696  state_change = ast_tvnow();
697  last_state = t30state->state;
698  }
700  struct ast_control_t38_parameters *parameters = inf->data.ptr;
701  if (parameters->request_response == AST_T38_TERMINATED) {
702  ast_debug(1, "T38 down, finishing\n");
703  break;
704  }
705  }
706 
707  ast_frfree(inf);
708  inf = NULL;
709  }
710 
711  ast_debug(1, "Loop finished, res=%d\n", res);
712 
713  if (inf)
714  ast_frfree(inf);
715 
716  t30_terminate(t30state);
717  t38_terminal_release(&t38);
718 
720  /* if we are not the caller, it's our job to shut down the T.38
721  * session when the FAX transmisson is complete.
722  */
723  if ((s->caller_mode == FALSE) &&
726 
727  if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
728  /* wait up to five seconds for negotiation to complete */
729  unsigned int timeout = 5000;
730  int ms;
731 
732  ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan));
733  while (timeout > 0) {
734  ms = ast_waitfor(s->chan, 1000);
735  if (ms < 0) {
736  ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
737  return -1;
738  }
739  if (!ms) {
740  /* nothing happened */
741  if (timeout > 0) {
742  timeout -= 1000;
743  continue;
744  } else {
745  ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan));
746  break;
747  }
748  }
749  if (!(inf = ast_read(s->chan))) {
750  return -1;
751  }
752  if ((inf->frametype == AST_FRAME_CONTROL) &&
754  (inf->datalen == sizeof(t38_parameters))) {
755  struct ast_control_t38_parameters *parameters = inf->data.ptr;
756 
757  switch (parameters->request_response) {
758  case AST_T38_TERMINATED:
759  ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan));
760  break;
761  case AST_T38_REFUSED:
762  ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan));
763  break;
764  default:
765  ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan));
766  break;
767  }
768  ast_frfree(inf);
769  break;
770  }
771  ast_frfree(inf);
772  }
773  }
774  }
775 
776  return res;
777 }
778 
779 static int transmit(fax_session *s)
780 {
781  int res = 0;
782 
783  /* Clear all channel variables which to be set by the application.
784  Pre-set status to error so in case of any problems we can just leave */
785  pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED");
786  pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems");
787 
788  pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
789  pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
790  pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0");
791  pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
792  pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL);
793 
794  if (ast_channel_state(s->chan) != AST_STATE_UP) {
795  /* Shouldn't need this, but checking to see if channel is already answered
796  * Theoretically asterisk should already have answered before running the app */
797  res = ast_answer(s->chan);
798  if (res) {
799  ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(s->chan));
800  return res;
801  }
802  }
803 
805  if (s->t38state != T38_STATE_NEGOTIATED) {
806  /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */
807  pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio");
808  res = transmit_audio(s);
809  if (res > 0) {
810  /* transmit_audio reports switchover to T38. Update t38state */
812  if (s->t38state != T38_STATE_NEGOTIATED) {
813  ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
814  }
815  }
816  }
817 
818  if (s->t38state == T38_STATE_NEGOTIATED) {
819  pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38");
820  res = transmit_t38(s);
821  }
822 
823  if (res) {
824  ast_log(LOG_WARNING, "Transmission error\n");
825  res = -1;
826  } else if (s->finished < 0) {
827  ast_log(LOG_WARNING, "Transmission failed\n");
828  } else if (s->finished > 0) {
829  ast_debug(1, "Transmission finished Ok\n");
830  }
831 
832  return res;
833 }
834 
835 /* === Application functions === */
836 
837 static int sndfax_exec(struct ast_channel *chan, const char *data)
838 {
839  int res = 0;
840  char *parse;
841  fax_session session = { 0, };
842  char restore_digit_detect = 0;
843 
845  AST_APP_ARG(file_name);
847  );
848 
849  if (chan == NULL) {
850  ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
851  return -1;
852  }
853 
854  /* The next few lines of code parse out the filename and header from the input string */
855  if (ast_strlen_zero(data)) {
856  /* No data implies no filename or anything is present */
857  ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
858  return -1;
859  }
860 
861  parse = ast_strdupa(data);
862  AST_STANDARD_APP_ARGS(args, parse);
863 
864  session.caller_mode = TRUE;
865 
866  if (args.options) {
867  if (strchr(args.options, 'a'))
868  session.caller_mode = FALSE;
869  }
870 
871  /* Done parsing */
872  session.direction = 1;
873  session.file_name = args.file_name;
874  session.chan = chan;
875  session.finished = 0;
876 
877  /* get current digit detection mode, then disable digit detection if enabled */
878  {
879  int dummy = sizeof(restore_digit_detect);
880 
881  ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
882  }
883 
884  if (restore_digit_detect) {
885  char new_digit_detect = 0;
886 
887  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
888  }
889 
890  /* disable FAX tone detection if enabled */
891  {
892  char new_fax_detect = 0;
893 
894  ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
895  }
896 
897  res = transmit(&session);
898 
899  if (restore_digit_detect) {
900  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
901  }
902 
903  return res;
904 }
905 
906 static int rcvfax_exec(struct ast_channel *chan, const char *data)
907 {
908  int res = 0;
909  char *parse;
911  char restore_digit_detect = 0;
912 
914  AST_APP_ARG(file_name);
916  );
917 
918  if (chan == NULL) {
919  ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
920  return -1;
921  }
922 
923  /* The next few lines of code parse out the filename and header from the input string */
924  if (ast_strlen_zero(data)) {
925  /* No data implies no filename or anything is present */
926  ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
927  return -1;
928  }
929 
930  parse = ast_strdupa(data);
931  AST_STANDARD_APP_ARGS(args, parse);
932 
933  session.caller_mode = FALSE;
934 
935  if (args.options) {
936  if (strchr(args.options, 'c'))
937  session.caller_mode = TRUE;
938  }
939 
940  /* Done parsing */
941  session.direction = 0;
942  session.file_name = args.file_name;
943  session.chan = chan;
944  session.finished = 0;
945 
946  /* get current digit detection mode, then disable digit detection if enabled */
947  {
948  int dummy = sizeof(restore_digit_detect);
949 
950  ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
951  }
952 
953  if (restore_digit_detect) {
954  char new_digit_detect = 0;
955 
956  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
957  }
958 
959  /* disable FAX tone detection if enabled */
960  {
961  char new_fax_detect = 0;
962 
963  ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
964  }
965 
966  res = transmit(&session);
967 
968  if (restore_digit_detect) {
969  ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
970  }
971 
972  return res;
973 }
974 
975 static int unload_module(void)
976 {
977  int res;
978 
981 
982  return res;
983 }
984 
985 static int load_module(void)
986 {
987  int res ;
988 
991 
992  /* The default SPAN message handler prints to stderr. It is something we do not want */
993  span_set_message_handler(NULL);
994 
995  return res;
996 }
997 
998 
999 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
1000  .support_level = AST_MODULE_SUPPORT_DEPRECATED,
1001  .load = load_module,
1002  .unload = unload_module,
1003 );
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:2818
Main Channel structure associated with a channel.
static int unload_module(void)
Definition: app_fax.c:975
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define FALSE
Definition: app_minivm.c:521
char * file_name
Definition: app_fax.c:167
static void set_ecm(t30_state_t *state, int ecm)
Definition: app_fax.c:314
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:227
short int16_t
Definition: db.h:59
int option_debug
Definition: options.c:69
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2946
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
static void set_local_info(t30_state_t *state, fax_session *s)
Definition: app_fax.c:293
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block)
Checks the value of an option.
Definition: channel.c:7405
static const char app_sndfax_name[]
Definition: app_fax.c:148
Convenient Signal Processing routines.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define LOG_WARNING
Definition: logger.h:274
static int set_logging(logging_state_t *state)
Definition: app_fax.c:283
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:64
union ast_frame::@257 data
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
static int load_module(void)
Definition: app_fax.c:985
struct ast_control_t38_parameters t38parameters
Definition: app_fax.c:168
static int timeout
Definition: cdr_mysql.c:86
T.38 state information.
Definition: res_pjsip_t38.c:59
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4271
enum ast_control_t38 request_response
static void phase_e_handler(t30_state_t *f, void *user_data, int result)
Definition: app_fax.c:206
int caller_mode
Definition: app_fax.c:166
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4667
Definition of a media format.
Definition: format.c:43
ast_t38_state
Possible T38 states on channels.
Definition: channel.h:879
static const char app_rcvfax_name[]
Definition: app_fax.c:149
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
t38state
T38 States for a call.
Definition: sip.h:665
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
const char * args
#define NULL
Definition: resample.c:96
struct spandsp_fax_stats t38
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7385
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static void * fax_generator_alloc(struct ast_channel *chan, void *params)
Definition: app_fax.c:324
static void span_message(int level, const char *msg)
Definition: app_fax.c:172
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
struct ast_channel * chan
Definition: app_fax.c:163
int done
Definition: test_amihooks.c:48
#define ao2_bump(obj)
Definition: astobj2.h:491
static void set_file(t30_state_t *state, fax_session *s)
Definition: app_fax.c:306
int direction
Definition: app_fax.c:165
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
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
General Asterisk PBX channel definitions.
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5748
#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:851
static int disable_t38(struct ast_channel *chan)
Definition: res_fax.c:1527
static struct ast_mansession session
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5789
static int rcvfax_exec(struct ast_channel *chan, const char *data)
Definition: app_fax.c:906
Core PBX routines and definitions.
volatile int finished
Definition: app_fax.c:169
static int sndfax_exec(struct ast_channel *chan, const char *data)
Definition: app_fax.c:837
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define AST_OPTION_DIGIT_DETECT
#define MAX_SAMPLES
Definition: app_fax.c:151
static int transmit_t38(fax_session *s)
Definition: app_fax.c:603
#define LOG_ERROR
Definition: logger.h:285
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
static struct ast_generator generator
Definition: app_fax.c:359
static int transmit_audio(fax_session *s)
Definition: app_fax.c:367
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
#define ast_strlen_zero(a)
Definition: muted.c:73
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1507
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:5088
static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_fax.c:329
Support for logging to various files, console and syslog Configuration in file logger.conf.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2888
#define AST_OPTION_FAX_DETECT
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3157
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
#define TRUE
Definition: app_minivm.c:518
#define ast_frfree(fr)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2800
static PGresult * result
Definition: cel_pgsql.c:88
enum ast_t38_state t38state
Definition: app_fax.c:164
#define AST_MODEM_T38
Data structure associated with a single frame of data.
static int transmit(fax_session *s)
Definition: app_fax.c:779
Abstract JSON element (object, array, string, int, ...).
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
Definition: app_fax.c:183
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:78
enum ast_frame_type frametype
static struct test_options options
struct ast_format * format
#define WATCHDOG_STATE_TIMEOUT
Definition: app_fax.c:160
#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.
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
struct stasis_message_type * ast_channel_fax_type(void)
Message type for a fax operation.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define AST_JSON_UTF8_VALIDATE(str)
Check str for UTF-8 and replace with an empty string if fails the check.
Definition: json.h:224
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
Media Format Cache API.
#define AST_APP_ARG(name)
Define an application argument.
#define WATCHDOG_TOTAL_TIMEOUT
Definition: app_fax.c:159