[asterisk-scf-commits] asterisk-scf/integration/udptlstack.git branch "master" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Sep 12 11:27:50 CDT 2011


branch "master" has been created
        at  d86207dd0db1ebde1ff65479b8e1ce19451fab92 (commit)

- Log -----------------------------------------------------------------
commit d86207dd0db1ebde1ff65479b8e1ce19451fab92
Author: Joshua Colp <jcolp at digium.com>
Date:   Mon Sep 12 13:33:05 2011 -0300

    Add separated out UDPTL stack. This performs encoding/decoding of UDPTL.

diff --git a/udptl.c b/udptl.c
new file mode 100644
index 0000000..2e162ab
--- /dev/null
+++ b/udptl.c
@@ -0,0 +1,808 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * UDPTL support for T.38
+ * 
+ * Copyright (C) 2005, Steve Underwood, partly based on RTP code which is
+ * Copyright (C) 1999-2009, Digium, Inc.
+ *
+ * Steve Underwood <steveu at coppice.org>
+ * Kevin P. Fleming <kpfleming at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ *
+ * A license has been granted to Digium (via disclaimer) for the use of
+ * this code.
+ */
+
+/*! 
+ * \file 
+ *
+ * \brief UDPTL support for T.38 faxing
+ * 
+ *
+ * \author Mark Spencer <markster at digium.com>
+ * \author Steve Underwood <steveu at coppice.org>
+ * \author Kevin P. Fleming <kpfleming at digium.com>
+ * 
+ * \page T38fax_udptl T.38 support :: UDPTL
+ *
+ * Asterisk supports T.38 fax passthrough, origination and termination. It does
+ * not support gateway operation. The only channel driver that supports T.38 at
+ * this time is chan_sip.
+ *
+ * UDPTL is handled very much like RTP. It can be reinvited to go directly between
+ * the endpoints, without involving Asterisk in the media stream.
+ * 
+ * \b References:
+ * - chan_sip.c
+ * - udptl.c
+ * - app_fax.c
+ */
+
+#include <sys/time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "udptl.h"
+
+static int udptlfecentries;
+static int udptlfecspan;
+static int use_even_ports;
+
+#define LOCAL_FAX_MAX_DATAGRAM      1400
+#define DEFAULT_FAX_MAX_DATAGRAM    400
+#define FAX_MAX_DATAGRAM_LIMIT      1400
+#define MAX_FEC_ENTRIES             5
+#define MAX_FEC_SPAN                5
+
+#define UDPTL_BUF_MASK              15
+
+#define ARRAY_LEN(a) (size_t) (sizeof(a) / sizeof(0[a]))
+#define MIN(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); ((__a > __b) ? __b : __a);})
+
+typedef struct {
+	int buf_len;
+	uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
+} udptl_fec_tx_buffer_t;
+
+typedef struct {
+	int buf_len;
+	uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
+	unsigned int fec_len[MAX_FEC_ENTRIES];
+	uint8_t fec[MAX_FEC_ENTRIES][LOCAL_FAX_MAX_DATAGRAM];
+	unsigned int fec_span;
+	unsigned int fec_entries;
+} udptl_fec_rx_buffer_t;
+
+/*! \brief Structure for an UDPTL session */
+struct udptl {
+	struct udptl_frame f[16];
+	unsigned char rawdata[8192];
+	unsigned int lasteventseqn;
+	void *data;
+
+	/*! This option indicates the error correction scheme used in transmitted UDPTL
+	 * packets and expected in received UDPTL packets.
+	 */
+	enum t38_ec_modes error_correction_scheme;
+
+	/*! This option indicates the number of error correction entries transmitted in
+	 * UDPTL packets and expected in received UDPTL packets.
+	 */
+	unsigned int error_correction_entries;
+
+	/*! This option indicates the span of the error correction entries in transmitted
+	 * UDPTL packets (FEC only).
+	 */
+	unsigned int error_correction_span;
+
+	/*! The maximum size UDPTL packet that can be accepted by
+	 * the remote device.
+	 */
+	int far_max_datagram;
+
+	/*! The maximum size UDPTL packet that we are prepared to
+	 * accept, or -1 if it hasn't been calculated since the last
+	 * changes were applied to the UDPTL structure.
+	 */
+	int local_max_datagram;
+
+	/*! The maximum IFP that can be submitted for sending
+	 * to the remote device. Calculated from far_max_datagram,
+	 * error_correction_scheme and error_correction_entries,
+	 * or -1 if it hasn't been calculated since the last
+	 * changes were applied to the UDPTL structure.
+	 */
+	int far_max_ifp;
+
+	/*! The maximum IFP that the local endpoint is prepared
+	 * to accept. Along with error_correction_scheme and
+	 * error_correction_entries, used to calculate local_max_datagram.
+	 */
+	int local_max_ifp;
+
+	unsigned int tx_seq_no;
+	unsigned int rx_seq_no;
+	unsigned int rx_expected_seq_no;
+
+	udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1];
+	udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
+};
+
+static int decode_length(uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue)
+{
+	if (*len >= limit)
+		return -1;
+	if ((buf[*len] & 0x80) == 0) {
+		*pvalue = buf[*len];
+		(*len)++;
+		return 0;
+	}
+	if ((buf[*len] & 0x40) == 0) {
+		if (*len == limit - 1)
+			return -1;
+		*pvalue = (buf[*len] & 0x3F) << 8;
+		(*len)++;
+		*pvalue |= buf[*len];
+		(*len)++;
+		return 0;
+	}
+	*pvalue = (buf[*len] & 0x3F) << 14;
+	(*len)++;
+
+	/* We have a fragment.  Currently we don't process fragments. */
+//	ast_debug(1, "UDPTL packet with length greater than 16K received, decoding will fail\n");
+
+	return 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets)
+{
+	unsigned int octet_cnt = 0;
+
+	if (decode_length(buf, limit, len, &octet_cnt) != 0)
+		return -1;
+
+	if (octet_cnt > 0) {
+		/* Make sure the buffer contains at least the number of bits requested */
+		if ((*len + octet_cnt) > limit)
+			return -1;
+
+		*p_num_octets = octet_cnt;
+		*p_object = &buf[*len];
+		*len += octet_cnt;
+	}
+
+	return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static unsigned int encode_length(uint8_t *buf, unsigned int *len, unsigned int value)
+{
+	unsigned int multiplier;
+
+	if (value < 0x80) {
+		/* 1 octet */
+		buf[*len] = value;
+		(*len)++;
+		return value;
+	}
+	if (value < 0x4000) {
+		/* 2 octets */
+		/* Set the first bit of the first octet */
+		buf[*len] = ((0x8000 | value) >> 8) & 0xFF;
+		(*len)++;
+		buf[*len] = value & 0xFF;
+		(*len)++;
+		return value;
+	}
+	/* Fragmentation */
+	multiplier = (value < 0x10000) ? (value >> 14) : 4;
+	/* Set the first 2 bits of the octet */
+	buf[*len] = 0xC0 | multiplier;
+	(*len)++;
+	return multiplier << 14;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int encode_open_type(const struct udptl *udptl, uint8_t *buf, unsigned int buflen,
+			    unsigned int *len, const uint8_t *data, unsigned int num_octets)
+{
+	unsigned int enclen;
+	unsigned int octet_idx;
+	uint8_t zero_byte;
+
+	/* If open type is of zero length, add a single zero byte (10.1) */
+	if (num_octets == 0) {
+		zero_byte = 0;
+		data = &zero_byte;
+		num_octets = 1;
+	}
+	/* Encode the open type */
+	for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) {
+		if ((enclen = encode_length(buf, len, num_octets)) < 0)
+			return -1;
+		if (enclen + *len > buflen) {
+			return -1;
+		}
+		if (enclen > 0) {
+			memcpy(&buf[*len], &data[octet_idx], enclen);
+			*len += enclen;
+		}
+		if (enclen >= num_octets)
+			break;
+	}
+
+	return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+struct udptl_frame *udptl_rx_packet(struct udptl *s, uint8_t *buf, unsigned int len)
+{
+	int stat1;
+	int stat2;
+	int i;
+	int j;
+	int k;
+	int l;
+	int m;
+	int x;
+	int limit;
+	int which;
+	unsigned int ptr;
+	unsigned int count;
+	int total_count;
+	int seq_no;
+	const uint8_t *ifp = NULL;
+	const uint8_t *data = NULL;
+	unsigned int ifp_len = 0;
+	int repaired[16];
+	const uint8_t *bufs[ARRAY_LEN(s->f) - 1];
+	unsigned int lengths[ARRAY_LEN(s->f) - 1];
+	int span;
+	int entries;
+	int ifp_no;
+
+	ptr = 0;
+	ifp_no = 0;
+	memset(&s->f[0], 0, sizeof(s->f[0]));
+
+	/* Decode seq_number */
+	if (ptr + 2 > len)
+		return NULL;
+	seq_no = (buf[0] << 8) | buf[1];
+	ptr += 2;
+
+	/* Break out the primary packet */
+	if ((stat1 = decode_open_type(buf, len, &ptr, &ifp, &ifp_len)) != 0)
+		return NULL;
+	/* Decode error_recovery */
+	if (ptr + 1 > len)
+		return NULL;
+	if ((buf[ptr++] & 0x80) == 0) {
+		/* Secondary packet mode for error recovery */
+		if (seq_no > s->rx_seq_no) {
+			/* We received a later packet than we expected, so we need to check if we can fill in the gap from the
+			   secondary packets. */
+			total_count = 0;
+			do {
+				if ((stat2 = decode_length(buf, len, &ptr, &count)) < 0)
+					return NULL;
+				for (i = 0; i < count && total_count + i < ARRAY_LEN(bufs); i++) {
+					if ((stat1 = decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i])) != 0)
+						return NULL;
+				}
+				total_count += i;
+			}
+			while (stat2 > 0 && total_count < ARRAY_LEN(bufs));
+			/* Step through in reverse order, so we go oldest to newest */
+			for (i = total_count; i > 0; i--) {
+				if (seq_no - i >= s->rx_seq_no) {
+					/* This one wasn't seen before */
+					/* Decode the secondary IFP packet */
+					//fprintf(stderr, "Secondary %d, len %d\n", seq_no - i, lengths[i - 1]);
+					s->f[ifp_no].seqno = seq_no - i;
+					s->f[ifp_no].datalen = lengths[i - 1];
+					s->f[ifp_no].data = (uint8_t *) bufs[i - 1];
+					if (ifp_no > 0)
+					    s->f[ifp_no - 1].next = &s->f[ifp_no];
+					s->f[ifp_no].next = NULL;
+					ifp_no++;
+				}
+			}
+		}
+	}
+	else
+	{
+		/* FEC mode for error recovery */
+		/* Our buffers cannot tolerate overlength IFP packets in FEC mode */
+		if (ifp_len > LOCAL_FAX_MAX_DATAGRAM)
+			return NULL;
+		/* Update any missed slots in the buffer */
+		for ( ; seq_no > s->rx_seq_no; s->rx_seq_no++) {
+			x = s->rx_seq_no & UDPTL_BUF_MASK;
+			s->rx[x].buf_len = -1;
+			s->rx[x].fec_len[0] = 0;
+			s->rx[x].fec_span = 0;
+			s->rx[x].fec_entries = 0;
+		}
+
+		x = seq_no & UDPTL_BUF_MASK;
+
+		memset(repaired, 0, sizeof(repaired));
+
+		/* Save the new IFP packet */
+		memcpy(s->rx[x].buf, ifp, ifp_len);
+		s->rx[x].buf_len = ifp_len;
+		repaired[x] = 1;
+
+		/* Decode the FEC packets */
+		/* The span is defined as an unconstrained integer, but will never be more
+		   than a small value. */
+		if (ptr + 2 > len)
+			return NULL;
+		if (buf[ptr++] != 1)
+			return NULL;
+		span = buf[ptr++];
+		s->rx[x].fec_span = span;
+
+		/* The number of entries is defined as a length, but will only ever be a small
+		   value. Treat it as such. */
+		if (ptr + 1 > len)
+			return NULL;
+		entries = buf[ptr++];
+		if (entries > MAX_FEC_ENTRIES) {
+			return NULL;
+		}
+		s->rx[x].fec_entries = entries;
+
+		/* Decode the elements */
+		for (i = 0; i < entries; i++) {
+			if ((stat1 = decode_open_type(buf, len, &ptr, &data, &s->rx[x].fec_len[i])) != 0)
+				return NULL;
+			if (s->rx[x].fec_len[i] > LOCAL_FAX_MAX_DATAGRAM)
+				return NULL;
+
+			/* Save the new FEC data */
+			memcpy(s->rx[x].fec[i], data, s->rx[x].fec_len[i]);
+#if 0
+			fprintf(stderr, "FEC: ");
+			for (j = 0; j < s->rx[x].fec_len[i]; j++)
+				fprintf(stderr, "%02X ", data[j]);
+			fprintf(stderr, "\n");
+#endif
+		}
+
+		/* See if we can reconstruct anything which is missing */
+		/* TODO: this does not comprehensively hunt back and repair everything that is possible */
+		for (l = x; l != ((x - (16 - span*entries)) & UDPTL_BUF_MASK); l = (l - 1) & UDPTL_BUF_MASK) {
+			if (s->rx[l].fec_len[0] <= 0)
+				continue;
+			for (m = 0; m < s->rx[l].fec_entries; m++) {
+				limit = (l + m) & UDPTL_BUF_MASK;
+				for (which = -1, k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit; k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) {
+					if (s->rx[k].buf_len <= 0)
+						which = (which == -1) ? k : -2;
+				}
+				if (which >= 0) {
+					/* Repairable */
+					for (j = 0; j < s->rx[l].fec_len[m]; j++) {
+						s->rx[which].buf[j] = s->rx[l].fec[m][j];
+						for (k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit; k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK)
+							s->rx[which].buf[j] ^= (s->rx[k].buf_len > j) ? s->rx[k].buf[j] : 0;
+					}
+					s->rx[which].buf_len = s->rx[l].fec_len[m];
+					repaired[which] = 1;
+				}
+			}
+		}
+		/* Now play any new packets forwards in time */
+		for (l = (x + 1) & UDPTL_BUF_MASK, j = seq_no - UDPTL_BUF_MASK; l != x; l = (l + 1) & UDPTL_BUF_MASK, j++) {
+			if (repaired[l]) {
+				//fprintf(stderr, "Fixed packet %d, len %d\n", j, l);
+				s->f[ifp_no].seqno = j;
+				s->f[ifp_no].datalen = s->rx[l].buf_len;
+				s->f[ifp_no].data = s->rx[l].buf;
+				if (ifp_no > 0)
+				    s->f[ifp_no - 1].next = &s->f[ifp_no];
+				s->f[ifp_no].next = NULL;
+				ifp_no++;
+			}
+		}
+	}
+
+	/* If packets are received out of sequence, we may have already processed this packet from the error
+	   recovery information in a packet already received. */
+	if (seq_no >= s->rx_seq_no) {
+		/* Decode the primary IFP packet */
+		s->f[ifp_no].seqno = seq_no;
+		s->f[ifp_no].datalen = ifp_len;
+		s->f[ifp_no].data = (uint8_t *) ifp;
+		if (ifp_no > 0)
+		    s->f[ifp_no - 1].next = &s->f[ifp_no];
+		s->f[ifp_no].next = NULL;
+
+		ifp_no++;
+	}
+
+	s->rx_seq_no = seq_no + 1;
+
+	return ifp_no ? &s->f[0] : NULL;
+}
+/*- End of function --------------------------------------------------------*/
+
+int udptl_build_packet(struct udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len)
+{
+	uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2];
+	int i;
+	int j;
+	int seq;
+	int entry;
+	int entries;
+	int span;
+	int m;
+	unsigned int len;
+	int limit;
+	int high_tide;
+
+	seq = s->tx_seq_no & 0xFFFF;
+
+	/* Map the sequence number to an entry in the circular buffer */
+	entry = seq & UDPTL_BUF_MASK;
+
+	/* We save the message in a circular buffer, for generating FEC or
+	   redundancy sets later on. */
+	s->tx[entry].buf_len = ifp_len;
+	memcpy(s->tx[entry].buf, ifp, ifp_len);
+	
+	/* Build the UDPTLPacket */
+
+	len = 0;
+	/* Encode the sequence number */
+	buf[len++] = (seq >> 8) & 0xFF;
+	buf[len++] = seq & 0xFF;
+
+	/* Encode the primary IFP packet */
+	if (encode_open_type(s, buf, buflen, &len, ifp, ifp_len) < 0)
+		return -1;
+
+	/* Encode the appropriate type of error recovery information */
+	switch (s->error_correction_scheme)
+	{
+	case UDPTL_ERROR_CORRECTION_NONE:
+		/* Encode the error recovery type */
+		buf[len++] = 0x00;
+		/* The number of entries will always be zero, so it is pointless allowing
+		   for the fragmented case here. */
+		if (encode_length(buf, &len, 0) < 0)
+			return -1;
+		break;
+	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+		/* Encode the error recovery type */
+		buf[len++] = 0x00;
+		if (s->tx_seq_no > s->error_correction_entries)
+			entries = s->error_correction_entries;
+		else
+			entries = s->tx_seq_no;
+		/* The number of entries will always be small, so it is pointless allowing
+		   for the fragmented case here. */
+		if (encode_length(buf, &len, entries) < 0)
+			return -1;
+		/* Encode the elements */
+		for (i = 0; i < entries; i++) {
+			j = (entry - i - 1) & UDPTL_BUF_MASK;
+			if (encode_open_type(s, buf, buflen, &len, s->tx[j].buf, s->tx[j].buf_len) < 0) {
+//				ast_debug(1, "(%s): Encoding failed at i=%d, j=%d\n",
+//					  LOG_TAG(s), i, j);
+				return -1;
+			}
+		}
+		break;
+	case UDPTL_ERROR_CORRECTION_FEC:
+		span = s->error_correction_span;
+		entries = s->error_correction_entries;
+		if (seq < s->error_correction_span*s->error_correction_entries) {
+			/* In the initial stages, wind up the FEC smoothly */
+			entries = seq/s->error_correction_span;
+			if (seq < s->error_correction_span)
+				span = 0;
+		}
+		/* Encode the error recovery type */
+		buf[len++] = 0x80;
+		/* Span is defined as an inconstrained integer, which it dumb. It will only
+		   ever be a small value. Treat it as such. */
+		buf[len++] = 1;
+		buf[len++] = span;
+		/* The number of entries is defined as a length, but will only ever be a small
+		   value. Treat it as such. */
+		buf[len++] = entries;
+		for (m = 0; m < entries; m++) {
+			/* Make an XOR'ed entry the maximum length */
+			limit = (entry + m) & UDPTL_BUF_MASK;
+			high_tide = 0;
+			for (i = (limit - span*entries) & UDPTL_BUF_MASK; i != limit; i = (i + entries) & UDPTL_BUF_MASK) {
+				if (high_tide < s->tx[i].buf_len) {
+					for (j = 0; j < high_tide; j++)
+						fec[j] ^= s->tx[i].buf[j];
+					for ( ; j < s->tx[i].buf_len; j++)
+						fec[j] = s->tx[i].buf[j];
+					high_tide = s->tx[i].buf_len;
+				} else {
+					for (j = 0; j < s->tx[i].buf_len; j++)
+						fec[j] ^= s->tx[i].buf[j];
+				}
+			}
+			if (encode_open_type(s, buf, buflen, &len, fec, high_tide) < 0)
+				return -1;
+		}
+		break;
+	}
+
+	s->tx_seq_no++;
+	return len;
+}
+
+static void calculate_local_max_datagram(struct udptl *udptl)
+{
+	unsigned int new_max = 0;
+
+	if (udptl->local_max_ifp == -1) {
+		udptl->local_max_datagram = -1;
+		return;
+	}
+
+	/* calculate the amount of space required to receive an IFP
+	 * of the maximum size supported by the application/endpoint
+	 * that we are delivering them to (local endpoint), and add
+	 * the amount of space required to support the selected
+	 * error correction mode
+	 */
+	switch (udptl->error_correction_scheme) {
+	case UDPTL_ERROR_CORRECTION_NONE:
+		/* need room for sequence number, length indicator, redundancy
+		 * indicator and following length indicator
+		 */
+		new_max = 5 + udptl->local_max_ifp;
+		break;
+	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+		/* need room for sequence number, length indicators, plus
+		 * room for up to 3 redundancy packets
+		 */
+		new_max = 5 + udptl->local_max_ifp + 2 + (3 * udptl->local_max_ifp);
+		break;
+	case UDPTL_ERROR_CORRECTION_FEC:
+		/* need room for sequence number, length indicators and a
+		 * a single IFP of the maximum size expected
+		 */
+		new_max = 5 + udptl->local_max_ifp + 4 + udptl->local_max_ifp;
+		break;
+	}
+	/* add 5% extra space for insurance, but no larger than LOCAL_FAX_MAX_DATAGRAM */
+	udptl->local_max_datagram = MIN(new_max * 1.05, LOCAL_FAX_MAX_DATAGRAM);
+}
+
+static void calculate_far_max_ifp(struct udptl *udptl)
+{
+	unsigned new_max = 0;
+
+	if (udptl->far_max_datagram == -1) {
+		udptl->far_max_ifp = -1;
+		return;
+	}
+
+	/* the goal here is to supply the local endpoint (application
+	 * or bridged channel) a maximum IFP value that will allow it
+	 * to effectively and efficiently transfer image data at its
+	 * selected bit rate, taking into account the selected error
+	 * correction mode, but without overrunning the far endpoint's
+	 * datagram buffer. this is complicated by the fact that some
+	 * far endpoints send us bogus (small) max datagram values,
+	 * which would result in either buffer overrun or no error
+	 * correction. we try to accomodate those, but if the supplied
+	 * value is too small to do so, we'll emit warning messages and
+	 * the user will have to use configuration options to override
+	 * the max datagram value supplied by the far endpoint.
+	 */
+	switch (udptl->error_correction_scheme) {
+	case UDPTL_ERROR_CORRECTION_NONE:
+		/* need room for sequence number, length indicator, redundancy
+		 * indicator and following length indicator
+		 */
+		new_max = udptl->far_max_datagram - 5;
+		break;
+	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+		/* for this case, we'd like to send as many error correction entries
+		 * as possible (up to the number we're configured for), but we'll settle
+		 * for sending fewer if the configured number would cause the
+		 * calculated max IFP to be too small for effective operation
+		 *
+		 * need room for sequence number, length indicators and the
+		 * configured number of redundant packets
+		 *
+		 * note: we purposely don't allow error_correction_entries to drop to
+		 * zero in this loop; we'd rather send smaller IFPs (and thus reduce
+		 * the image data transfer rate) than sacrifice redundancy completely
+		 */
+		for (;;) {
+			new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1);
+
+			if ((new_max < 80) && (udptl->error_correction_entries > 1)) {
+				/* the max ifp is not large enough, subtract an
+				 * error correction entry and calculate again
+				 * */
+				--udptl->error_correction_entries;
+			} else {
+				break;
+			}
+		}
+		break;
+	case UDPTL_ERROR_CORRECTION_FEC:
+		/* need room for sequence number, length indicators and a
+		 * a single IFP of the maximum size expected
+		 */
+		new_max = (udptl->far_max_datagram - 10) / 2;
+		break;
+	}
+	/* subtract 5% of space for insurance */
+	udptl->far_max_ifp = new_max * 0.95;
+}
+
+enum t38_ec_modes udptl_get_error_correction_scheme(const struct udptl *udptl)
+{
+	return udptl->error_correction_scheme;
+}
+
+void udptl_set_error_correction_scheme(struct udptl *udptl, enum t38_ec_modes ec)
+{
+	udptl->error_correction_scheme = ec;
+	switch (ec) {
+	case UDPTL_ERROR_CORRECTION_FEC:
+		udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
+		if (udptl->error_correction_entries == 0) {
+			udptl->error_correction_entries = 3;
+		}
+		if (udptl->error_correction_span == 0) {
+			udptl->error_correction_span = 3;
+		}
+		break;
+	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+		udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
+		if (udptl->error_correction_entries == 0) {
+			udptl->error_correction_entries = 3;
+		}
+		break;
+	default:
+		/* nothing to do */
+		break;
+	};
+	/* reset calculated values so they'll be computed again */
+	udptl->local_max_datagram = -1;
+	udptl->far_max_ifp = -1;
+}
+
+void udptl_set_local_max_ifp(struct udptl *udptl, unsigned int max_ifp)
+{
+	/* make sure max_ifp is a positive value since a cast will take place when
+	 * when setting local_max_ifp */
+	if ((signed int) max_ifp > 0) {
+		udptl->local_max_ifp = max_ifp;
+		/* reset calculated values so they'll be computed again */
+		udptl->local_max_datagram = -1;
+	}
+}
+
+unsigned int udptl_get_local_max_datagram(struct udptl *udptl)
+{
+	if (udptl->local_max_datagram == -1) {
+		calculate_local_max_datagram(udptl);
+	}
+
+	/* this function expects a unsigned value in return. */
+	if (udptl->local_max_datagram < 0) {
+		return 0;
+	}
+	return udptl->local_max_datagram;
+}
+
+void udptl_set_far_max_datagram(struct udptl *udptl, unsigned int max_datagram)
+{
+	if (!max_datagram || (max_datagram > FAX_MAX_DATAGRAM_LIMIT)) {
+		udptl->far_max_datagram = DEFAULT_FAX_MAX_DATAGRAM;
+	} else {
+		udptl->far_max_datagram = max_datagram;
+	}
+	/* reset calculated values so they'll be computed again */
+	udptl->far_max_ifp = -1;
+}
+
+unsigned int udptl_get_far_max_datagram(const struct udptl *udptl)
+{
+	if (udptl->far_max_datagram < 0) {
+		return 0;
+	}
+	return udptl->far_max_datagram;
+}
+
+unsigned int udptl_get_far_max_ifp(struct udptl *udptl)
+{
+	if (udptl->far_max_ifp == -1) {
+		calculate_far_max_ifp(udptl);
+	}
+
+	if (udptl->far_max_ifp < 0) {
+		return 0;
+	}
+	return udptl->far_max_ifp;
+}
+struct udptl *udptl_new()
+{
+    struct udptl *udptl;
+    int i;
+
+    if (!(udptl = calloc(1, sizeof(*udptl))))
+	return NULL;
+
+    udptl->error_correction_span = udptlfecspan;
+    udptl->error_correction_entries = udptlfecentries;
+
+    udptl->far_max_datagram = -1;
+    udptl->far_max_ifp = -1;
+    udptl->local_max_ifp = -1;
+    udptl->local_max_datagram = -1;
+
+    for (i = 0; i <= UDPTL_BUF_MASK; i++) {
+	udptl->rx[i].buf_len = -1;
+	udptl->tx[i].buf_len = -1;
+    }
+
+    return udptl;
+}
+
+void udptl_destroy(struct udptl *udptl)
+{
+	free(udptl);
+}
+
+int udptl_set_default_fec_span(int span)
+{
+    if (span < 1) {
+	udptlfecspan = 1;
+    }
+    else if (span > MAX_FEC_SPAN) {
+	udptlfecspan = MAX_FEC_SPAN;
+    }
+    else {
+	udptlfecspan = span;
+    }
+
+    return udptlfecspan;
+}
+
+int udptl_set_default_fec_entries(int entries)
+{
+    if (entries < 1) {
+	udptlfecentries = 1;
+    }
+    else if (entries > MAX_FEC_ENTRIES) {
+	udptlfecentries = MAX_FEC_ENTRIES;
+    }
+    else {
+	udptlfecentries = entries;
+    }
+
+    return udptlfecentries;
+}
diff --git a/udptl.h b/udptl.h
new file mode 100644
index 0000000..8945b7c
--- /dev/null
+++ b/udptl.h
@@ -0,0 +1,99 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * UDPTL support for T.38
+ * 
+ * Copyright (C) 2005, Steve Underwood, partly based on RTP code which is
+ * Copyright (C) 1999-2004, Digium, Inc.
+ *
+ * Steve Underwood <steveu at coppice.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ *
+ * A license has been granted to Digium (via disclaimer) for the use of
+ * this code.
+ */
+
+/*! \file
+ * \brief UDPTL support for T.38
+ * \author Steve Underwood <steveu at coppice.org>
+ * \ref udptl.c
+ * \todo add doxygen documentation to this file!
+ */
+
+
+#ifndef _UDPTL_H
+#define _UDPTL_H
+
+
+enum t38_ec_modes {
+    UDPTL_ERROR_CORRECTION_NONE,
+    UDPTL_ERROR_CORRECTION_FEC,
+    UDPTL_ERROR_CORRECTION_REDUNDANCY
+};
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+struct udptl;
+
+struct udptl_frame {
+    /*! Length of data */
+    int datalen;
+    /*! Sequence number */
+    int seqno;
+    /*! Pointer to actual data */
+    void *data;
+    /*! Pointer to next frame */
+    struct udptl_frame *next;
+};
+
+struct udptl *udptl_create();
+
+int udptl_build_packet(struct udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len);
+
+struct udptl_frame *udptl_rx_packet(struct udptl *s, uint8_t *buf, unsigned int len);
+
+void udptl_destroy(struct udptl *udptl);
+
+enum t38_ec_modes udptl_get_error_correction_scheme(const struct udptl *udptl);
+
+void udptl_set_error_correction_scheme(struct udptl *udptl, enum t38_ec_modes ec);
+
+void udptl_set_local_max_ifp(struct udptl *udptl, unsigned int max_ifp);
+
+/*! 
+ * \brief retrieves local_max_datagram.
+ * 
+ * \retval positive value representing max datagram size.
+ * \retval 0 if no value is present
+ */
+unsigned int udptl_get_local_max_datagram(struct udptl *udptl);
+
+/*! 
+ * \brief sets far max datagram size.  If max_datagram is = 0, the far max datagram
+ *  size is set to a default value.
+ */
+void udptl_set_far_max_datagram(struct udptl *udptl, unsigned int max_datagram);
+
+unsigned int udptl_get_far_max_datagram(const struct udptl *udptl);
+
+/*! 
+ * \brief retrieves far max ifp
+ * 
+ * \retval positive value representing max ifp size
+ * \retval 0 if no value is present
+ */
+unsigned int udptl_get_far_max_ifp(struct udptl *udptl);
+
+int udptl_set_default_fec_span(int span);
+
+int udptl_set_default_fec_entries(int entries);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/udptlstack.git



More information about the asterisk-scf-commits mailing list