forked from Mirrors/freeswitch
188 lines
5.6 KiB
C
188 lines
5.6 KiB
C
/*
|
|
* SpanDSP - a series of DSP components for telephony
|
|
*
|
|
* rfc2198_sim.c - Simulate the behaviour of RFC2198 (or UDPTL) redundancy.
|
|
*
|
|
* Written by Steve Underwood <steveu@coppice.org>
|
|
*
|
|
* Copyright (C) 2007 Steve Underwood
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <inttypes.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#if defined(HAVE_TGMATH_H)
|
|
#include <tgmath.h>
|
|
#endif
|
|
#if defined(HAVE_MATH_H)
|
|
#define GEN_CONST
|
|
#include <math.h>
|
|
#endif
|
|
#if defined(HAVE_STDBOOL_H)
|
|
#include <stdbool.h>
|
|
#else
|
|
#include "spandsp/stdbool.h"
|
|
#endif
|
|
#include "floating_fudge.h"
|
|
|
|
#include "spandsp.h"
|
|
#include "spandsp/g1050.h"
|
|
#include "spandsp/rfc2198_sim.h"
|
|
|
|
#define PACKET_LOSS_TIME -1
|
|
|
|
SPAN_DECLARE(rfc2198_sim_state_t *) rfc2198_sim_init(int model,
|
|
int speed_pattern,
|
|
int packet_size,
|
|
int packet_rate,
|
|
int redundancy_depth)
|
|
{
|
|
rfc2198_sim_state_t *s;
|
|
|
|
if ((s = (rfc2198_sim_state_t *) malloc(sizeof(*s))) == NULL)
|
|
return NULL;
|
|
memset(s, 0, sizeof(*s));
|
|
|
|
s->g1050 = g1050_init(model, speed_pattern, packet_size, packet_rate);
|
|
s->redundancy_depth = redundancy_depth;
|
|
return s;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) rfc2198_sim_free(rfc2198_sim_state_t *s)
|
|
{
|
|
g1050_free(s->g1050);
|
|
free(s);
|
|
return 0;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) rfc2198_sim_put(rfc2198_sim_state_t *s,
|
|
const uint8_t buf[],
|
|
int len,
|
|
int seq_no,
|
|
double departure_time)
|
|
{
|
|
uint8_t buf2[8192];
|
|
uint8_t *p;
|
|
uint16_t *q;
|
|
int slot;
|
|
int i;
|
|
|
|
/* Save the packet in the history buffer */
|
|
memcpy(s->tx_pkt[s->next_pkt], buf, len);
|
|
s->tx_pkt_len[s->next_pkt] = len;
|
|
s->tx_pkt_seq_no[s->next_pkt] = seq_no;
|
|
|
|
/* Construct the redundant packet */
|
|
p = buf2;
|
|
slot = s->next_pkt;
|
|
q = (uint16_t *) p;
|
|
*q = s->redundancy_depth;
|
|
p += sizeof(uint16_t);
|
|
for (i = 0; i < s->redundancy_depth; i++)
|
|
{
|
|
q = (uint16_t *) p;
|
|
*q = s->tx_pkt_len[slot];
|
|
p += sizeof(uint16_t);
|
|
memcpy(p, s->tx_pkt[slot], s->tx_pkt_len[slot]);
|
|
p += s->tx_pkt_len[slot];
|
|
slot = (slot - 1) & 0x1F;
|
|
}
|
|
s->next_pkt = (s->next_pkt + 1) & 0x1F;
|
|
return g1050_put(s->g1050, buf2, p - buf2, seq_no, departure_time);
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) rfc2198_sim_get(rfc2198_sim_state_t *s,
|
|
uint8_t buf[],
|
|
int max_len,
|
|
double current_time,
|
|
int *seq_no,
|
|
double *departure_time,
|
|
double *arrival_time)
|
|
{
|
|
int len;
|
|
int lenx;
|
|
int seq_nox;
|
|
int i;
|
|
#if defined(_MSC_VER)
|
|
uint8_t *bufx = (uint8_t *) _alloca(s->redundancy_depth*1024);
|
|
#else
|
|
uint8_t bufx[s->redundancy_depth*1024];
|
|
#endif
|
|
uint8_t *p;
|
|
uint16_t *q;
|
|
int redundancy_depth;
|
|
|
|
if (s->rx_queued_pkts)
|
|
{
|
|
/* We have some stuff from the last g1050_get() still to deliver */
|
|
s->rx_queued_pkts--;
|
|
memcpy(buf, s->rx_pkt[s->rx_queued_pkts], s->rx_pkt_len[s->rx_queued_pkts]);
|
|
*seq_no = s->rx_pkt_seq_no[s->rx_queued_pkts];
|
|
return s->rx_pkt_len[s->rx_queued_pkts];
|
|
}
|
|
len = g1050_get(s->g1050, bufx, s->redundancy_depth*1024, current_time, &seq_nox, departure_time, arrival_time);
|
|
if (len > 0)
|
|
{
|
|
p = bufx;
|
|
q = (uint16_t *) p;
|
|
redundancy_depth = *q;
|
|
p += sizeof(uint16_t);
|
|
i = 0;
|
|
if (seq_nox > s->next_seq_no)
|
|
{
|
|
/* Some stuff is missing. Try to fill it in. */
|
|
s->rx_queued_pkts = seq_nox - s->next_seq_no;
|
|
if (s->rx_queued_pkts >= redundancy_depth)
|
|
s->rx_queued_pkts = redundancy_depth - 1;
|
|
for (i = 0; i < s->rx_queued_pkts; i++)
|
|
{
|
|
q = (uint16_t *) p;
|
|
s->rx_pkt_len[i] = *q;
|
|
p += sizeof(uint16_t);
|
|
memcpy(s->rx_pkt[i], p, s->rx_pkt_len[i]);
|
|
s->rx_pkt_seq_no[i] = seq_nox - i;
|
|
p += s->rx_pkt_len[i];
|
|
}
|
|
}
|
|
*seq_no = seq_nox - i;
|
|
q = (uint16_t *) p;
|
|
lenx = *q;
|
|
p += sizeof(uint16_t);
|
|
memcpy(buf, p, lenx);
|
|
s->next_seq_no = seq_nox + 1;
|
|
}
|
|
else
|
|
{
|
|
lenx = len;
|
|
}
|
|
return lenx;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
/*- End of file ------------------------------------------------------------*/
|