[Pkg-voip-commits] r5934 - in /asterisk-spandsp-plugins/trunk: app_fax.c debian/ debian/asterisk-app-fax.install debian/changelog debian/control debian/patches/app_fax_14 debian/patches/series debian/rules
tzafrir-guest at alioth.debian.org
tzafrir-guest at alioth.debian.org
Sat Jul 12 10:56:43 UTC 2008
Author: tzafrir-guest
Date: Sat Jul 12 10:56:43 2008
New Revision: 5934
URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=5934
Log:
* replacing app_rxfax and app_txfax (which are not maintained)
with a backport of app_fax from Asterisk 1.6.
* Converting the package to native for now, until there's a host for
a backport of app_fax from Asterisk 1.6.
* Big note: The syntax of the dialplan aplications has changed.
* This backport includes compatibility RxFax and TxFax applications that
will work fir simple cases.
* Removing T.38 support. This may badly break the transmit path.
* Moving to quilt.
* Depending on asterisk >= 1.4.20 because of the location of asterisk.h .
If you want to build with older asterisk, change "asterisk.h" to
<asterisk/asterisk.h> .
* Newer spandsp dependency as it probably won't build with older ones.
* Added target get-orig-svn to grab a newer source from Digium's SVN.
Added:
asterisk-spandsp-plugins/trunk/app_fax.c
asterisk-spandsp-plugins/trunk/debian/patches/app_fax_14
asterisk-spandsp-plugins/trunk/debian/patches/series
Modified:
asterisk-spandsp-plugins/trunk/debian/ (props changed)
asterisk-spandsp-plugins/trunk/debian/asterisk-app-fax.install
asterisk-spandsp-plugins/trunk/debian/changelog
asterisk-spandsp-plugins/trunk/debian/control
asterisk-spandsp-plugins/trunk/debian/rules
Added: asterisk-spandsp-plugins/trunk/app_fax.c
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/app_fax.c?rev=5934&op=file
==============================================================================
--- asterisk-spandsp-plugins/trunk/app_fax.c (added)
+++ asterisk-spandsp-plugins/trunk/app_fax.c Sat Jul 12 10:56:43 2008
@@ -1,0 +1,741 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Simple fax applications
+ *
+ * 2007-2008, Dmitry Andrianov <asterisk at dima.spb.ru>
+ *
+ * Code based on original implementation by Steve Underwood <steveu at coppice.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ *
+ */
+
+/*** MODULEINFO
+ <depend>spandsp</depend>
+***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <errno.h>
+#include <tiffio.h>
+
+#include <spandsp.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/app.h"
+#include "asterisk/dsp.h"
+#include "asterisk/module.h"
+#include "asterisk/manager.h"
+
+static char *app_sndfax_name = "SendFAX";
+static char *app_sndfax_synopsis = "Send a FAX";
+static char *app_sndfax_desc =
+" SendFAX(filename[|options]):\n"
+"Send a given TIFF file to the channel as a FAX.\n"
+"The option string may contain zero or more of the following characters:\n"
+" 'a' -- makes the application behave as an answering machine\n"
+" The default behaviour is to behave as a calling machine.\n"
+"\n"
+"This application uses following variables:\n"
+" LOCALSTATIONID to identify itself to the remote end.\n"
+" LOCALHEADERINFO to generate a header line on each page.\n"
+"\n"
+"This application sets the following channel variables upon completion:\n"
+" FAXSTATUS - status of operation:\n"
+" SUCCESS | FAILED\n"
+" FAXERROR - Error when FAILED\n"
+" REMOTESTATIONID - CSID of the remote side.\n"
+" FAXPAGES - number of pages sent.\n"
+" FAXBITRATE - transmition rate.\n"
+" FAXRESOLUTION - resolution.\n"
+"\n"
+"Returns -1 in case of user hang up or any channel error.\n"
+"Returns 0 on success.\n";
+
+static char *app_rcvfax_name = "ReceiveFAX";
+static char *app_rcvfax_synopsis = "Receive a FAX";
+static char *app_rcvfax_desc =
+" ReceiveFAX(filename[|options]):\n"
+"Receives a fax from the channel into the given filename overwriting\n"
+"the file if it already exists. File created will have TIFF format.\n"
+"The option string may contain zero or more of the following characters:\n"
+" 'c' -- makes the application behave as a calling machine\n"
+" The default behaviour is to behave as an answering machine.\n"
+"\n"
+"This application uses following variables:\n"
+" LOCALSTATIONID to identify itself to the remote end.\n"
+" LOCALHEADERINFO to generate a header line on each page.\n"
+"\n"
+"This application sets the following channel variables upon completion:\n"
+" FAXSTATUS - status of operation:\n"
+" SUCCESS | FAILED\n"
+" FAXERROR - Error when FAILED\n"
+" REMOTESTATIONID - CSID of the remote side.\n"
+" FAXPAGES - number of pages sent.\n"
+" FAXBITRATE - transmition rate.\n"
+" FAXRESOLUTION - resolution.\n"
+"\n"
+"Returns -1 in case of user hang up or any channel error.\n"
+"Returns 0 on success.\n";
+
+#define MAX_SAMPLES 240
+
+/* Watchdog. I have seen situations when remote fax disconnects (because of poor line
+ quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
+ To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
+ We also terminate application when more than 30 minutes passed regardless of
+ state changes. This is just a precaution measure - no fax should take that long */
+
+#define WATCHDOG_TOTAL_TIMEOUT 30 * 60
+#define WATCHDOG_STATE_TIMEOUT 5 * 60
+
+typedef struct {
+ struct ast_channel *chan;
+ enum ast_t38_state t38state; /* T38 state of the channel */
+ int direction; /* Fax direction: 0 - receiving, 1 - sending */
+ int caller_mode;
+ char *file_name;
+
+ volatile int finished;
+} fax_session;
+
+static void span_message(int level, const char *msg)
+{
+ if (level == SPAN_LOG_ERROR) {
+ ast_log(LOG_ERROR, "%s", msg);
+ } else if (level == SPAN_LOG_WARNING) {
+ ast_log(LOG_WARNING, "%s", msg);
+ } else {
+ ast_log(LOG_DEBUG, "%s", msg);
+ }
+}
+
+static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
+{
+ struct ast_channel *chan = (struct ast_channel *) user_data;
+
+ struct ast_frame outf = {
+ .frametype = AST_FRAME_MODEM,
+ .subclass = AST_MODEM_T38,
+ .src = __FUNCTION__,
+ };
+
+ /* TODO: Asterisk does not provide means of resending the same packet multiple
+ times so count is ignored at the moment */
+
+ AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
+
+ if (ast_write(chan, &outf) < 0) {
+ ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void phase_e_handler(t30_state_t *f, void *user_data, int result)
+{
+ const char *local_ident;
+ const char *far_ident;
+ char buf[20];
+ fax_session *s = (fax_session *) user_data;
+ t30_stats_t stat;
+
+ ast_debug(1, "Fax phase E handler. result=%d\n", result);
+
+ t30_get_transfer_statistics(f, &stat);
+
+ s = (fax_session *) user_data;
+
+ if (result != T30_ERR_OK) {
+ s->finished = -1;
+
+ /* FAXSTATUS is already set to FAILED */
+ pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
+
+ ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
+
+ return;
+ }
+
+ s->finished = 1;
+
+ local_ident = t30_get_tx_ident(f);
+ far_ident = t30_get_rx_ident(f);
+ pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
+ pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
+ pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
+ snprintf(buf, sizeof(buf), "%d", stat.pages_transferred);
+ pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
+ snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
+ pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
+ snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
+ pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);
+
+ ast_debug(1, "Fax transmitted successfully.\n");
+ ast_debug(1, " Remote station ID: %s\n", far_ident);
+ ast_debug(1, " Pages transferred: %d\n", stat.pages_transferred);
+ ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
+ ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
+
+ manager_event(EVENT_FLAG_CALL,
+ s->direction ? "FaxSent" : "FaxReceived",
+ "Channel: %s\r\n"
+ "Exten: %s\r\n"
+ "CallerID: %s\r\n"
+ "RemoteStationID: %s\r\n"
+ "LocalStationID: %s\r\n"
+ "PagesTransferred: %d\r\n"
+ "Resolution: %d\r\n"
+ "TransferRate: %d\r\n"
+ "FileName: %s\r\n",
+ s->chan->name,
+ s->chan->exten,
+ S_OR(s->chan->cid.cid_num, ""),
+ far_ident,
+ local_ident,
+ stat.pages_transferred,
+ stat.y_resolution,
+ stat.bit_rate,
+ s->file_name);
+}
+
+/* === Helper functions to configure fax === */
+
+/* Setup SPAN logging according to Asterisk debug level */
+static int set_logging(logging_state_t *state)
+{
+ int level = SPAN_LOG_WARNING + option_debug;
+
+ span_log_set_message_handler(state, span_message);
+ span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
+
+ return 0;
+}
+
+static void set_local_info(t30_state_t *state, fax_session *s)
+{
+ const char *x;
+
+ x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
+ if (!ast_strlen_zero(x))
+ t30_set_tx_ident(state, x);
+
+ x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
+ if (!ast_strlen_zero(x))
+ t30_set_tx_page_header_info(state, x);
+}
+
+static void set_file(t30_state_t *state, fax_session *s)
+{
+ if (s->direction)
+ t30_set_tx_file(state, s->file_name, -1, -1);
+ else
+ t30_set_rx_file(state, s->file_name, -1);
+}
+
+static void set_ecm(t30_state_t *state, int ecm)
+{
+ t30_set_ecm_capability(state, ecm);
+ t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
+}
+
+/* === Generator === */
+
+/* This function is only needed to return passed params so
+ generator_activate will save it to channel's generatordata */
+static void *fax_generator_alloc(struct ast_channel *chan, void *params)
+{
+ return params;
+}
+
+static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
+{
+ fax_state_t *fax = (fax_state_t*) data;
+ uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
+ int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
+
+ struct ast_frame outf = {
+ .frametype = AST_FRAME_VOICE,
+ .subclass = AST_FORMAT_SLINEAR,
+ .src = __FUNCTION__,
+ };
+
+ if (samples > MAX_SAMPLES) {
+ ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
+ samples = MAX_SAMPLES;
+ }
+
+ if ((len = fax_tx(fax, buf, samples)) > 0) {
+ outf.samples = len;
+ AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
+
+ if (ast_write(chan, &outf) < 0) {
+ ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+struct ast_generator generator = {
+ alloc: fax_generator_alloc,
+ generate: fax_generator_generate,
+};
+
+
+/* === Transmission === */
+
+static int transmit_audio(fax_session *s)
+{
+ int res = -1;
+ int original_read_fmt = AST_FORMAT_SLINEAR;
+ int original_write_fmt = AST_FORMAT_SLINEAR;
+ fax_state_t fax;
+ struct ast_dsp *dsp = NULL;
+ int detect_tone = 0;
+ struct ast_frame *inf = NULL;
+ struct ast_frame *fr;
+ int last_state = 0;
+ struct timeval now, start, state_change;
+ enum ast_control_t38 t38control;
+
+ original_read_fmt = s->chan->readformat;
+ if (original_read_fmt != AST_FORMAT_SLINEAR) {
+ res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+ goto done;
+ }
+ }
+
+ original_write_fmt = s->chan->writeformat;
+ if (original_write_fmt != AST_FORMAT_SLINEAR) {
+ res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+ goto done;
+ }
+ }
+
+ /* Initialize T30 terminal */
+ fax_init(&fax, s->caller_mode);
+
+ /* Setup logging */
+ set_logging(&fax.logging);
+ set_logging(&fax.t30_state.logging);
+
+ /* Configure terminal */
+ set_local_info(&fax.t30_state, s);
+ set_file(&fax.t30_state, s);
+ set_ecm(&fax.t30_state, TRUE);
+
+ fax_set_transmit_on_idle(&fax, TRUE);
+
+ t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, s);
+
+ if (s->t38state == T38_STATE_UNAVAILABLE) {
+ ast_debug(1, "T38 is unavailable on %s\n", s->chan->name);
+ } else if (!s->direction) {
+ /* We are receiving side and this means we are the side which should
+ request T38 when the fax is detected. Use DSP to detect fax tone */
+ ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name);
+ dsp = ast_dsp_new();
+ ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
+ ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
+ detect_tone = 1;
+ }
+
+ start = state_change = ast_tvnow();
+
+ ast_activate_generator(s->chan, &generator, &fax);
+
+ while (!s->finished) {
+ res = ast_waitfor(s->chan, 20);
+ if (res < 0)
+ break;
+ else if (res > 0)
+ res = 0;
+
+ inf = ast_read(s->chan);
+ if (inf == NULL) {
+ ast_debug(1, "Channel hangup\n");
+ res = -1;
+ break;
+ }
+
+ ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
+
+ /* Detect fax tone */
+ if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
+ /* Duplicate frame because ast_dsp_process may free the frame passed */
+ fr = ast_frdup(inf);
+
+ /* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */
+ fr = ast_dsp_process(NULL, dsp, fr);
+ if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
+ ast_debug(1, "Fax tone detected. Requesting T38\n");
+ t38control = AST_T38_REQUEST_NEGOTIATE;
+ ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
+ detect_tone = 0;
+ }
+
+ ast_frfree(fr);
+ }
+
+
+ /* Check the frame type. Format also must be checked because there is a chance
+ that a frame in old format was already queued before we set chanel format
+ to slinear so it will still be received by ast_read */
+ if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
+
+ if (fax_rx(&fax, inf->data, inf->samples) < 0) {
+ /* I know fax_rx never returns errors. The check here is for good style only */
+ ast_log(LOG_WARNING, "fax_rx returned error\n");
+ res = -1;
+ break;
+ }
+
+ /* Watchdog */
+ if (last_state != fax.t30_state.state) {
+ state_change = ast_tvnow();
+ last_state = fax.t30_state.state;
+ }
+ } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
+ inf->datalen == sizeof(enum ast_control_t38)) {
+ t38control =*((enum ast_control_t38 *) inf->data);
+ if (t38control == AST_T38_NEGOTIATED) {
+ /* T38 switchover completed */
+ ast_debug(1, "T38 negotiated, finishing audio loop\n");
+ res = 1;
+ break;
+ }
+ }
+
+ ast_frfree(inf);
+ inf = NULL;
+
+ /* Watchdog */
+ now = ast_tvnow();
+ if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
+ ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
+ res = -1;
+ break;
+ }
+ }
+
+ ast_debug(1, "Loop finished, res=%d\n", res);
+
+ if (inf)
+ ast_frfree(inf);
+
+ if (dsp)
+ ast_dsp_free(dsp);
+
+ ast_deactivate_generator(s->chan);
+
+ /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
+ by t30_terminate, display diagnostics and set status variables although no transmittion
+ has taken place yet. */
+ if (res > 0) {
+ t30_set_phase_e_handler(&fax.t30_state, NULL, NULL);
+ }
+
+ t30_terminate(&fax.t30_state);
+ fax_release(&fax);
+
+done:
+ if (original_write_fmt != AST_FORMAT_SLINEAR) {
+ if (ast_set_write_format(s->chan, original_write_fmt) < 0)
+ ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
+ }
+
+ if (original_read_fmt != AST_FORMAT_SLINEAR) {
+ if (ast_set_read_format(s->chan, original_read_fmt) < 0)
+ ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
+ }
+
+ return res;
+
+}
+
+static int transmit_t38(fax_session *s)
+{
+ int res = 0;
+ t38_terminal_state_t t38;
+ struct ast_frame *inf = NULL;
+ int last_state = 0;
+ struct timeval now, start, state_change, last_frame;
+ enum ast_control_t38 t38control;
+
+ /* Initialize terminal */
+ memset(&t38, 0, sizeof(t38));
+ if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
+ ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
+ return -1;
+ }
+
+ /* Setup logging */
+ set_logging(&t38.logging);
+ set_logging(&t38.t30_state.logging);
+ set_logging(&t38.t38.logging);
+
+ /* Configure terminal */
+ set_local_info(&t38.t30_state, s);
+ set_file(&t38.t30_state, s);
+ set_ecm(&t38.t30_state, TRUE);
+
+ t30_set_phase_e_handler(&t38.t30_state, phase_e_handler, s);
+
+ now = start = state_change = ast_tvnow();
+
+ while (!s->finished) {
+
+ res = ast_waitfor(s->chan, 20);
+ if (res < 0)
+ break;
+ else if (res > 0)
+ res = 0;
+
+ last_frame = now;
+ now = ast_tvnow();
+ t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
+
+ inf = ast_read(s->chan);
+ if (inf == NULL) {
+ ast_debug(1, "Channel hangup\n");
+ res = -1;
+ break;
+ }
+
+ ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
+
+ if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
+ t38_core_rx_ifp_packet(&t38.t38, inf->data, inf->datalen, inf->seqno);
+
+ /* Watchdog */
+ if (last_state != t38.t30_state.state) {
+ state_change = ast_tvnow();
+ last_state = t38.t30_state.state;
+ }
+ } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
+ inf->datalen == sizeof(enum ast_control_t38)) {
+
+ t38control = *((enum ast_control_t38 *) inf->data);
+
+ if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
+ ast_debug(1, "T38 down, terminating\n");
+ res = -1;
+ break;
+ }
+ }
+
+ ast_frfree(inf);
+ inf = NULL;
+
+ /* Watchdog */
+ if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
+ ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
+ res = -1;
+ break;
+ }
+ }
+
+ ast_debug(1, "Loop finished, res=%d\n", res);
+
+ if (inf)
+ ast_frfree(inf);
+
+ t30_terminate(&t38.t30_state);
+ t38_terminal_release(&t38);
+
+ return res;
+}
+
+static int transmit(fax_session *s)
+{
+ int res = 0;
+
+ /* Clear all channel variables which to be set by the application.
+ Pre-set status to error so in case of any problems we can just leave */
+ pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED");
+ pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems");
+
+ pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
+ pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
+ pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
+ pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL);
+
+ if (s->chan->_state != AST_STATE_UP) {
+ /* Shouldn't need this, but checking to see if channel is already answered
+ * Theoretically asterisk should already have answered before running the app */
+ res = ast_answer(s->chan);
+ if (res) {
+ ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
+ return res;
+ }
+ }
+
+ s->t38state = ast_channel_get_t38_state(s->chan);
+ if (s->t38state != T38_STATE_NEGOTIATED) {
+ /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */
+ res = transmit_audio(s);
+ if (res > 0) {
+ /* transmit_audio reports switchover to T38. Update t38state */
+ s->t38state = ast_channel_get_t38_state(s->chan);
+ if (s->t38state != T38_STATE_NEGOTIATED) {
+ ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
+ }
+ }
+ }
+
+ if (s->t38state == T38_STATE_NEGOTIATED) {
+ res = transmit_t38(s);
+ }
+
+ if (res) {
+ ast_log(LOG_WARNING, "Transmission error\n");
+ res = -1;
+ } else if (s->finished < 0) {
+ ast_log(LOG_WARNING, "Transmission failed\n");
+ } else if (s->finished > 0) {
+ ast_debug(1, "Transmission finished Ok\n");
+ }
+
+ return res;
+}
+
+/* === Application functions === */
+
+static int sndfax_exec(struct ast_channel *chan, void *data)
+{
+ int res = 0;
+ char *parse;
+ fax_session session;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(file_name);
+ AST_APP_ARG(options);
+ );
+
+ if (chan == NULL) {
+ ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
+ return -1;
+ }
+
+ /* The next few lines of code parse out the filename and header from the input string */
+ if (ast_strlen_zero(data)) {
+ /* No data implies no filename or anything is present */
+ ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ session.caller_mode = TRUE;
+
+ if (args.options) {
+ if (strchr(args.options, 'a'))
+ session.caller_mode = FALSE;
+ }
+
+ /* Done parsing */
+ session.direction = 1;
+ session.file_name = args.file_name;
+ session.chan = chan;
+ session.finished = 0;
+
+ res = transmit(&session);
+
+ return res;
+}
+
+static int rcvfax_exec(struct ast_channel *chan, void *data)
+{
+ int res = 0;
+ char *parse;
+ fax_session session;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(file_name);
+ AST_APP_ARG(options);
+ );
+
+ if (chan == NULL) {
+ ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
+ return -1;
+ }
+
+ /* The next few lines of code parse out the filename and header from the input string */
+ if (ast_strlen_zero(data)) {
+ /* No data implies no filename or anything is present */
+ ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ session.caller_mode = FALSE;
+
+ if (args.options) {
+ if (strchr(args.options, 'c'))
+ session.caller_mode = TRUE;
+ }
+
+ /* Done parsing */
+ session.direction = 0;
+ session.file_name = args.file_name;
+ session.chan = chan;
+ session.finished = 0;
+
+ res = transmit(&session);
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ int res;
+
+ res = ast_unregister_application(app_sndfax_name);
+ res |= ast_unregister_application(app_rcvfax_name);
+
+ return res;
+}
+
+static int load_module(void)
+{
+ int res ;
+
+ res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
+ res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
+
+ /* The default SPAN message handler prints to stderr. It is something we do not want */
+ span_set_message_handler(NULL);
+
+ return res;
+}
+
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
+ .load = load_module,
+ .unload = unload_module,
+ );
+
+
Propchange: asterisk-spandsp-plugins/trunk/debian/
('mergeWithUpstream' removed)
Modified: asterisk-spandsp-plugins/trunk/debian/asterisk-app-fax.install
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/debian/asterisk-app-fax.install?rev=5934&op=diff
==============================================================================
--- asterisk-spandsp-plugins/trunk/debian/asterisk-app-fax.install (original)
+++ asterisk-spandsp-plugins/trunk/debian/asterisk-app-fax.install Sat Jul 12 10:56:43 2008
@@ -1,5 +1,4 @@
-app_rxfax.so usr/lib/asterisk/modules
-app_txfax.so usr/lib/asterisk/modules
+app_fax.so usr/lib/asterisk/modules
debian/receive_fax/faxreceive.conf etc/asterisk/asterisk_faxreceive.conf
debian/receive_fax/messages_de.mo usr/share/locale/de/LC_MESSAGES/asterisk-faxreceive.mo
debian/receive_fax/README usr/share/doc/asterisk-app-fax/README.receivefax
Modified: asterisk-spandsp-plugins/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/debian/changelog?rev=5934&op=diff
==============================================================================
--- asterisk-spandsp-plugins/trunk/debian/changelog (original)
+++ asterisk-spandsp-plugins/trunk/debian/changelog Sat Jul 12 10:56:43 2008
@@ -1,3 +1,22 @@
+asterisk-spandsp-plugins (0.0.3) unstable; urgency=low
+
+ * replacing app_rxfax and app_txfax (which are not maintained)
+ with a backport of app_fax from Asterisk 1.6.
+ * Converting the package to native for now, until there's a host for
+ a backport of app_fax from Asterisk 1.6.
+ * Big note: The syntax of the dialplan aplications has changed.
+ * This backport includes compatibility RxFax and TxFax applications that
+ will work fir simple cases.
+ * Removing T.38 support. This may badly break the transmit path.
+ * Moving to quilt.
+ * Depending on asterisk >= 1.4.20 because of the location of asterisk.h .
+ If you want to build with older asterisk, change "asterisk.h" to
+ <asterisk/asterisk.h> .
+ * Newer spandsp dependency as it probably won't build with older ones.
+ * Added target get-orig-svn to grab a newer source from Digium's SVN.
+
+ -- Tzafrir Cohen <tzafrir.cohen at xorcom.com> Sat, 12 Jul 2008 12:49:17 +0300
+
asterisk-spandsp-plugins (0.0.20070624-2) unstable; urgency=low
[ Kilian Krause ]
Modified: asterisk-spandsp-plugins/trunk/debian/control
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/debian/control?rev=5934&op=diff
==============================================================================
--- asterisk-spandsp-plugins/trunk/debian/control (original)
+++ asterisk-spandsp-plugins/trunk/debian/control Sat Jul 12 10:56:43 2008
@@ -3,7 +3,7 @@
Priority: extra
Maintainer: Debian VoIP Team <pkg-voip-maintainers at lists.alioth.debian.org>
Uploaders: Mark Purcell <msp at debian.org>, Kilian Krause <kilian at debian.org>, Tzafrir Cohen <tzafrir.cohen at xorcom.com>, Faidon Liambotis <paravoid at debian.org>
-Build-Depends: debhelper (>= 4.0.0), libspandsp-dev (>= 0.0.4~pre1), asterisk-dev (>= 1:1.4), libjpeg62-dev, libtiff4-dev, dpatch
+Build-Depends: debhelper (>= 4.0.0), libspandsp-dev (>= 0.0.5~pre3), asterisk-dev (>= 1:1.4.20~dfsg), libjpeg62-dev, libtiff4-dev, quilt
Standards-Version: 3.7.3
Homepage: http://www.soft-switch.org/
Vcs-Svn: svn://svn.debian.org/pkg-voip/asterisk-spandsp-plugins/trunk/
Added: asterisk-spandsp-plugins/trunk/debian/patches/app_fax_14
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/debian/patches/app_fax_14?rev=5934&op=file
==============================================================================
--- asterisk-spandsp-plugins/trunk/debian/patches/app_fax_14 (added)
+++ asterisk-spandsp-plugins/trunk/debian/patches/app_fax_14 Sat Jul 12 10:56:43 2008
@@ -1,0 +1,191 @@
+--- a/app_fax.c 2008-07-08 17:18:05.000000000 +0300
++++ b/app_fax.c_new 2008-07-12 13:54:56.000000000 +0300
+@@ -13,7 +13,6 @@
+ */
+
+ /*** MODULEINFO
+- <depend>spandsp</depend>
+ ***/
+
+ #include "asterisk.h"
+@@ -39,8 +38,36 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+ #include "asterisk/dsp.h"
+ #include "asterisk/module.h"
+ #include "asterisk/manager.h"
++extern int option_debug;
++
++/* Compatibility with Asterisk 1.6 */
++/* from logger.h: */
++#define ast_debug(level, ...) do { \
++ if (option_debug >= (level) ) \
++ ast_log(LOG_DEBUG, __VA_ARGS__); \
++} while (0)
++
++/* from time.h: */
++inline int ast_tvdiff_sec(struct timeval end, struct timeval start)
++{
++ int result = end.tv_sec - start.tv_sec;
++ if (result > 0 && end.tv_usec < start.tv_usec)
++ result--;
++ else if (result < 0 && end.tv_usec > start.tv_usec)
++ result++;
++
++ return result;
++}
++
++int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
++{
++ return (end.tv_sec - start.tv_sec) * (int64_t) 1000000 +
++ end.tv_usec - start.tv_usec;
++}
++/* End of backports */
+
+ static char *app_sndfax_name = "SendFAX";
++static char *app_txfax_name = "TxFAX";
+ static char *app_sndfax_synopsis = "Send a FAX";
+ static char *app_sndfax_desc =
+ " SendFAX(filename[|options]):\n"
+@@ -66,6 +93,7 @@ static char *app_sndfax_desc =
+ "Returns 0 on success.\n";
+
+ static char *app_rcvfax_name = "ReceiveFAX";
++static char *app_rxfax_name = "RxFAX";
+ static char *app_rcvfax_synopsis = "Receive a FAX";
+ static char *app_rcvfax_desc =
+ " ReceiveFAX(filename[|options]):\n"
+@@ -102,9 +130,13 @@ static char *app_rcvfax_desc =
+ #define WATCHDOG_TOTAL_TIMEOUT 30 * 60
+ #define WATCHDOG_STATE_TIMEOUT 5 * 60
+
++#undef AST_HAS_T38_SUPPORT
++
+ typedef struct {
+ struct ast_channel *chan;
++#ifdef AST_HAS_T38_SUPPORT
+ enum ast_t38_state t38state; /* T38 state of the channel */
++#endif
+ int direction; /* Fax direction: 0 - receiving, 1 - sending */
+ int caller_mode;
+ char *file_name;
+@@ -312,7 +344,10 @@ static int transmit_audio(fax_session *s
+ struct ast_frame *fr;
+ int last_state = 0;
+ struct timeval now, start, state_change;
++#undef AST_HAS_T38_SUPPORT
++#ifdef AST_HAS_T38_SUPPORT
+ enum ast_control_t38 t38control;
++#endif
+
+ original_read_fmt = s->chan->readformat;
+ if (original_read_fmt != AST_FORMAT_SLINEAR) {
+@@ -348,6 +383,7 @@ static int transmit_audio(fax_session *s
+
+ t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, s);
+
++#ifdef AST_HAS_T38_SUPPORT
+ if (s->t38state == T38_STATE_UNAVAILABLE) {
+ ast_debug(1, "T38 is unavailable on %s\n", s->chan->name);
+ } else if (!s->direction) {
+@@ -359,6 +395,7 @@ static int transmit_audio(fax_session *s
+ ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
+ detect_tone = 1;
+ }
++#endif
+
+ start = state_change = ast_tvnow();
+
+@@ -380,6 +417,8 @@ static int transmit_audio(fax_session *s
+
+ ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
+
++/* FIXME: that part should probably be included, not cut off (Tzafrir)*/
++#ifdef AST_HAS_T38_SUPPORT
+ /* Detect fax tone */
+ if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
+ /* Duplicate frame because ast_dsp_process may free the frame passed */
+@@ -396,6 +435,7 @@ static int transmit_audio(fax_session *s
+
+ ast_frfree(fr);
+ }
++#endif
+
+
+ /* Check the frame type. Format also must be checked because there is a chance
+@@ -415,6 +455,7 @@ static int transmit_audio(fax_session *s
+ state_change = ast_tvnow();
+ last_state = fax.t30_state.state;
+ }
++#ifdef AST_HAS_T38_SUPPORT
+ } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
+ inf->datalen == sizeof(enum ast_control_t38)) {
+ t38control =*((enum ast_control_t38 *) inf->data);
+@@ -424,6 +465,7 @@ static int transmit_audio(fax_session *s
+ res = 1;
+ break;
+ }
++#endif
+ }
+
+ ast_frfree(inf);
+@@ -480,7 +522,9 @@ static int transmit_t38(fax_session *s)
+ struct ast_frame *inf = NULL;
+ int last_state = 0;
+ struct timeval now, start, state_change, last_frame;
++#ifdef AST_HAS_T38_SUPPORT
+ enum ast_control_t38 t38control;
++#endif
+
+ /* Initialize terminal */
+ memset(&t38, 0, sizeof(t38));
+@@ -532,6 +576,7 @@ static int transmit_t38(fax_session *s)
+ state_change = ast_tvnow();
+ last_state = t38.t30_state.state;
+ }
++#ifdef AST_HAS_T38_SUPPORT
+ } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
+ inf->datalen == sizeof(enum ast_control_t38)) {
+
+@@ -542,6 +587,7 @@ static int transmit_t38(fax_session *s)
+ res = -1;
+ break;
+ }
++#endif
+ }
+
+ ast_frfree(inf);
+@@ -590,6 +636,7 @@ static int transmit(fax_session *s)
+ }
+ }
+
++#ifdef AST_HAS_T38_SUPPORT
+ s->t38state = ast_channel_get_t38_state(s->chan);
+ if (s->t38state != T38_STATE_NEGOTIATED) {
+ /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */
+@@ -606,6 +653,7 @@ static int transmit(fax_session *s)
+ if (s->t38state == T38_STATE_NEGOTIATED) {
+ res = transmit_t38(s);
+ }
++#endif
+
+ if (res) {
+ ast_log(LOG_WARNING, "Transmission error\n");
+@@ -714,7 +762,9 @@ static int unload_module(void)
+ int res;
+
+ res = ast_unregister_application(app_sndfax_name);
++ res |= ast_unregister_application(app_txfax_name);
+ res |= ast_unregister_application(app_rcvfax_name);
++ res |= ast_unregister_application(app_rxfax_name);
+
+ return res;
+ }
+@@ -724,7 +774,9 @@ static int load_module(void)
+ int res ;
+
+ res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
++ res |= ast_register_application(app_txfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
+ res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
++ res |= ast_register_application(app_rxfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
+
+ /* The default SPAN message handler prints to stderr. It is something we do not want */
+ span_set_message_handler(NULL);
Added: asterisk-spandsp-plugins/trunk/debian/patches/series
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/debian/patches/series?rev=5934&op=file
==============================================================================
--- asterisk-spandsp-plugins/trunk/debian/patches/series (added)
+++ asterisk-spandsp-plugins/trunk/debian/patches/series Sat Jul 12 10:56:43 2008
@@ -1,0 +1,1 @@
+app_fax_14
Modified: asterisk-spandsp-plugins/trunk/debian/rules
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk-spandsp-plugins/trunk/debian/rules?rev=5934&op=diff
==============================================================================
--- asterisk-spandsp-plugins/trunk/debian/rules (original)
+++ asterisk-spandsp-plugins/trunk/debian/rules Sat Jul 12 10:56:43 2008
@@ -11,7 +11,7 @@
CFLAGS += -O2
endif
-include /usr/share/dpatch/dpatch.make
+-include /usr/share/quilt/quilt.make
# upstream sources:
BASEURL = http://soft-switch.org/downloads/snapshots/spandsp/test-apps-asterisk-1.4
@@ -26,19 +26,18 @@
build: build-stamp
-build-stamp: patch-stamp
+build-stamp: patch
dh_testdir
- $(CC) $(CFLAGS) -shared -o app_rxfax.so app_rxfax.c -lspandsp
- $(CC) $(CFLAGS) -shared -o app_txfax.so app_txfax.c -lspandsp
+ $(CC) $(CFLAGS) -DAST_MODULE=\"app_fax\" -shared -o app_fax.so app_fax.c -lspandsp
msgfmt -o debian/receive_fax/messages_de.mo debian/receive_fax/messages_de.po
- touch build-stamp
+ touch $@
clean: clean-patched unpatch
clean-patched:
dh_testdir
dh_testroot
$(RM) build-stamp
- $(RM) app_txfax.so app_rxfax.so
+ $(RM) app_fax.so
$(RM) debian/receive_fax/messages_de.mo
dh_clean
@@ -68,6 +67,10 @@
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure patch unpatch
+# Grab the original file from the asterisk subversion repository.
+get-orig-svn:
+ wget http://svn.digium.com/svn/asterisk/branches/1.6.0/apps/app_fax.c
+
print-version:
@@echo "Debian version: $(DEBVERSION)"
@@echo "Upstream version: $(UPVERSION)"
@@ -75,6 +78,7 @@
# Note: this will get the current version. Not necessarily the one
# referred to by the version in the changelog.
get-orig-source:
+ @echo "Target get-orig-source is non-functional. Management"; exit 1
@@dh_testdir
@@[ -d ../tarballs/. ]||mkdir -p ../tarballs
@@mkdir -p ../tarballs/asterisk-$(UPVERSION)
More information about the Pkg-voip-commits
mailing list