Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


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