[svn-commits] file: branch file/rtp_engine r129725 - in /team/file/rtp_engine: include/aste...

SVN commits to the Digium repositories svn-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 svn-commits mailing list