[asterisk-commits] file: branch file/rtp_engine r129725 - in /team/file/rtp_engine: include/aste...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Jul 10 15:04:14 CDT 2008
Author: file
Date: Thu Jul 10 15:04:13 2008
New Revision: 129725
URL: http://svn.digium.com/view/asterisk?view=rev&rev=129725
Log:
Bring RED support back.
Modified:
team/file/rtp_engine/include/asterisk/rtp_engine.h
team/file/rtp_engine/main/rtp_engine.c
team/file/rtp_engine/res/res_rtp_asterisk.c
Modified: team/file/rtp_engine/include/asterisk/rtp_engine.h
URL: http://svn.digium.com/view/asterisk/team/file/rtp_engine/include/asterisk/rtp_engine.h?view=diff&rev=129725&r1=129724&r2=129725
==============================================================================
--- team/file/rtp_engine/include/asterisk/rtp_engine.h (original)
+++ team/file/rtp_engine/include/asterisk/rtp_engine.h Thu Jul 10 15:04:13 2008
@@ -40,7 +40,6 @@
AST_RTP_PROPERTY_DTMF, /*!< RTP instance is carrying DTMF */
AST_RTP_PROPERTY_DTMF_COMPENSATE, /*!< Expect unreliable DTMF from remote party */
AST_RTP_PROPERTY_STUN, /*!< Use STUN */
- AST_RTP_PROPERTY_RED, /*!< Use RED */
AST_RTP_PROPERTY_RTCP, /*!< Use RTCP */
AST_RTP_PROPERTY_MAX, /*!< Maximum number of properties supported */
};
@@ -90,6 +89,8 @@
int (*get_stats)(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats); /*!< Callback for retrieving statistics about the session */
int (*qos)(struct ast_rtp_instance *instance, int tos, int cos, const char *desc); /*!< Callback for setting QoS parameters on the RTP session */
int (*fd)(struct ast_rtp_instance *instance, int rtcp); /*!< Callback for retrieving a file descriptor for RTP or RTCP */
+ int (*red_init)(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations); /*!< Callback for initializing RED support */
+ int (*red_buffer)(struct ast_rtp_instance *instance, struct ast_frame *frame); /*!< Callback for buffering a frame over RED */
struct ast_frame *(*read)(struct ast_rtp_instance *instance, int rtcp); /*!< Callback for reading a frame in */
AST_RWLIST_ENTRY(ast_rtp_engine) entry; /*!< Linked list information */
};
@@ -266,6 +267,12 @@
/*! \brief Bridge two channels that use RTP instances */
enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
+/*! \brief Initialize RED support on an RTP instance */
+int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
+
+/*! \brief Buffer a frame in an RTP instance for RED */
+int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: team/file/rtp_engine/main/rtp_engine.c
URL: http://svn.digium.com/view/asterisk/team/file/rtp_engine/main/rtp_engine.c?view=diff&rev=129725&r1=129724&r2=129725
==============================================================================
--- team/file/rtp_engine/main/rtp_engine.c (original)
+++ team/file/rtp_engine/main/rtp_engine.c Thu Jul 10 15:04:13 2008
@@ -564,3 +564,13 @@
{
return AST_BRIDGE_FAILED;
}
+
+int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
+{
+ return instance->engine->red_init ? instance->engine->red_init(instance, buffer_time, payloads, generations) : -1;
+}
+
+int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
+{
+ return instance->engine->red_buffer ? instance->engine->red_buffer(instance, frame) : -1;
+}
Modified: team/file/rtp_engine/res/res_rtp_asterisk.c
URL: http://svn.digium.com/view/asterisk/team/file/rtp_engine/res/res_rtp_asterisk.c?view=diff&rev=129725&r1=129724&r2=129725
==============================================================================
--- team/file/rtp_engine/res/res_rtp_asterisk.c (original)
+++ team/file/rtp_engine/res/res_rtp_asterisk.c Thu Jul 10 15:04:13 2008
@@ -161,6 +161,8 @@
enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */
struct sockaddr_in strict_rtp_address; /*!< Remote address information for strict RTP purposes */
+
+ struct rtp_red *red;
};
/*!
@@ -224,6 +226,21 @@
unsigned int rtt_count;
};
+struct rtp_red {
+ struct ast_frame t140; /*!< Primary data */
+ struct ast_frame t140red; /*!< Redundant t140*/
+ unsigned char pt[AST_RED_MAX_GENERATION]; /*!< Payload types for redundancy data */
+ unsigned char ts[AST_RED_MAX_GENERATION]; /*!< Time stamps */
+ unsigned char len[AST_RED_MAX_GENERATION]; /*!< length of each generation */
+ int num_gen; /*!< Number of generations */
+ int schedid; /*!< Timer id */
+ int ti; /*!< How long to buffer data before send */
+ unsigned char t140red_data[64000];
+ unsigned char buf_data[64000]; /*!< buffered primary data */
+ int hdrlen;
+ long int prev_ts;
+};
+
/* Forward Declarations */
static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin);
static int ast_rtp_destroy(struct ast_rtp_instance *instance);
@@ -235,6 +252,8 @@
static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp);
static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
+static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
+static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame);
/* RTP Engine Declaration */
static struct ast_rtp_engine asterisk_rtp_engine = {
@@ -249,6 +268,8 @@
.prop_set = ast_rtp_prop_set,
.fd = ast_rtp_fd,
.remote_address_set = ast_rtp_remote_address_set,
+ .red_init = rtp_red_init,
+ .red_buffer = rtp_red_buffer,
};
static inline int rtp_debug_test_addr(struct sockaddr_in *addr)
@@ -418,6 +439,12 @@
AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
close(rtp->rtcp->s);
ast_free(rtp->rtcp);
+ }
+
+ /* Destroy RED if it was being used */
+ if (rtp->red) {
+ AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
+ ast_free(rtp->red);
}
/* Finally destroy ourselves */
@@ -981,6 +1008,43 @@
return 0;
}
+static struct ast_frame *red_t140_to_red(struct rtp_red *red) {
+ unsigned char *data = red->t140red.data.ptr;
+ int len = 0;
+ int i;
+
+ /* replace most aged generation */
+ if (red->len[0]) {
+ for (i = 1; i < red->num_gen+1; i++)
+ len += red->len[i];
+
+ memmove(&data[red->hdrlen], &data[red->hdrlen+red->len[0]], len);
+ }
+
+ /* Store length of each generation and primary data length*/
+ for (i = 0; i < red->num_gen; i++)
+ red->len[i] = red->len[i+1];
+ red->len[i] = red->t140.datalen;
+
+ /* write each generation length in red header */
+ len = red->hdrlen;
+ for (i = 0; i < red->num_gen; i++)
+ len += data[i*4+3] = red->len[i];
+
+ /* add primary data to buffer */
+ memcpy(&data[len], red->t140.data.ptr, red->t140.datalen);
+ red->t140red.datalen = len + red->t140.datalen;
+
+ /* no primary data and no generations to send */
+ if (len == red->hdrlen && !red->t140.datalen)
+ return NULL;
+
+ /* reset t.140 buffer */
+ red->t140.datalen = 0;
+
+ return &red->t140red;
+}
+
static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
{
struct ast_rtp *rtp = instance->data;
@@ -1002,6 +1066,13 @@
if (frame->frametype != AST_FRAME_VOICE && frame->frametype != AST_FRAME_VIDEO && frame->frametype != AST_FRAME_TEXT) {
ast_log(LOG_WARNING, "RTP can only send voice, video, and text\n");
return -1;
+ }
+
+ if (rtp->red) {
+ /* return 0; */
+ /* no primary data or generations to send */
+ if ((frame = red_t140_to_red(rtp->red)) == NULL)
+ return 0;
}
/* Grab the subclass and look up the payload we are going to use */
@@ -1776,6 +1847,60 @@
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
rtp->f.seqno = seqno;
+ if (rtp->f.subclass == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) {
+ unsigned char *data = rtp->f.data.ptr;
+
+ memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
+ rtp->f.datalen +=3;
+ *data++ = 0xEF;
+ *data++ = 0xBF;
+ *data = 0xBD;
+ }
+
+ if (rtp->f.subclass == AST_FORMAT_T140RED) {
+ unsigned char *data = rtp->f.data.ptr;
+ unsigned char *header_end;
+ int num_generations;
+ int header_length;
+ int len;
+ int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
+ int x;
+
+ rtp->f.subclass = AST_FORMAT_T140;
+ header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
+ header_end++;
+
+ header_length = header_end - data;
+ num_generations = header_length / 4;
+ len = header_length;
+
+ if (!diff) {
+ for (x = 0; x < num_generations; x++)
+ len += data[x * 4 + 3];
+
+ if (!(rtp->f.datalen - len))
+ return &ast_null_frame;
+
+ rtp->f.data.ptr += len;
+ rtp->f.datalen -= len;
+ } else if (diff > num_generations && diff < 10) {
+ len -= 3;
+ rtp->f.data.ptr += len;
+ rtp->f.datalen -= len;
+
+ data = rtp->f.data.ptr;
+ *data++ = 0xEF;
+ *data++ = 0xBF;
+ *data = 0xBD;
+ } else {
+ for ( x = 0; x < num_generations - diff; x++)
+ len += data[x * 4 + 3];
+
+ rtp->f.data.ptr += len;
+ rtp->f.datalen -= len;
+ }
+ }
+
if (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) {
rtp->f.samples = ast_codec_get_samples(&rtp->f);
if (rtp->f.subclass == AST_FORMAT_SLINEAR)
@@ -1880,6 +2005,68 @@
return;
}
+/*! \brief Write t140 redundacy frame
+ * \param data primary data to be buffered
+ */
+static int red_write(const void *data)
+{
+ struct ast_rtp_instance *instance = (struct ast_rtp_instance*) data;
+ struct ast_rtp *rtp = instance->data;
+
+ ast_rtp_write(instance, &rtp->red->t140);
+
+ return 1;
+}
+
+static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
+{
+ struct ast_rtp *rtp = instance->data;
+ int x;
+
+ if (!(rtp->red = ast_calloc(1, sizeof(*rtp->red)))) {
+ return -1;
+ }
+
+ rtp->red->t140.frametype = AST_FRAME_TEXT;
+ rtp->red->t140.subclass = AST_FORMAT_T140RED;
+ rtp->red->t140.data.ptr = &rtp->red->buf_data;
+
+ rtp->red->t140.ts = 0;
+ rtp->red->t140red = rtp->red->t140;
+ rtp->red->t140red.data.ptr = &rtp->red->t140red_data;
+ rtp->red->t140red.datalen = 0;
+ rtp->red->ti = buffer_time;
+ rtp->red->num_gen = generations;
+ rtp->red->hdrlen = generations * 4 + 1;
+ rtp->red->prev_ts = 0;
+
+ for (x = 0; x < generations; x++) {
+ rtp->red->pt[x] = payloads[x];
+ rtp->red->pt[x] |= 1 << 7; /* mark redundant generations pt */
+ rtp->red->t140red_data[x*4] = rtp->red->pt[x];
+ }
+ rtp->red->t140red_data[x*4] = rtp->red->pt[x] = payloads[x]; /* primary pt */
+ rtp->red->schedid = ast_sched_add(rtp->sched, generations, red_write, instance);
+
+ rtp->red->t140.datalen = 0;
+
+ return 0;
+}
+
+static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
+{
+ struct ast_rtp *rtp = instance->data;
+
+ if (frame->datalen > -1) {
+ struct rtp_red *red = rtp->red;
+ memcpy(&red->buf_data[red->t140.datalen], frame->data.ptr, frame->datalen);
+ red->t140.datalen += frame->datalen;
+ red->t140.ts = frame->ts;
+ }
+
+ return 0;
+}
+
static char *rtp_do_debug_ip(struct ast_cli_args *a)
{
struct hostent *hp;
More information about the asterisk-commits
mailing list