[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