summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2018-03-28 12:27:31 +0000
committerJoshua Colp <jcolp@digium.com>2018-04-06 08:36:54 -0600
commitc7bd5540949cfd701550c43cdefaf3080a27a8b9 (patch)
tree0e5f87ffebc83dc0282b326186c23e64b93abb6b
parent72a8e2106ea4f611a755da1a9c20f7bced300cce (diff)
pjsip / res_rtp_asterisk: Add support for sending REMB
This change allows chan_pjsip to be given an AST_FRAME_RTCP containing REMB feedback and pass it to res_rtp_asterisk. Once res_rtp_asterisk receives the frame a REMB RTCP feedback packet is constructed with the appropriate contents and sent to the remote endpoint. ASTERISK-27776 Change-Id: Ic53f821c1560d8924907ad82c4d9c0bc322b38cd
-rw-r--r--channels/chan_pjsip.c10
-rw-r--r--res/res_rtp_asterisk.c129
2 files changed, 103 insertions, 36 deletions
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 5cb52a5b2..6b2664819 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -966,6 +966,16 @@ static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, stru
case AST_FRAME_CNG:
break;
case AST_FRAME_RTCP:
+ /* We only support writing out feedback */
+ if (frame->subclass.integer != AST_RTP_RTCP_PSFB || !media) {
+ return 0;
+ } else if (media->type != AST_MEDIA_TYPE_VIDEO) {
+ ast_debug(3, "Channel %s stream %d is of type '%s', not video! Unable to write RTCP feedback.\n",
+ ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type));
+ return 0;
+ } else if (media->write_callback) {
+ res = media->write_callback(session, media, frame);
+ }
break;
default:
ast_log(LOG_WARNING, "Can't send %u type frames with PJSIP\n", frame->frametype);
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index b010f6c51..2d854f2c1 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -4473,6 +4473,94 @@ static struct ast_frame *red_t140_to_red(struct rtp_red *red)
return &red->t140red;
}
+static void rtp_write_rtcp_fir(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *remote_address)
+{
+ unsigned int *rtcpheader;
+ char bdata[1024];
+ int len = 20;
+ int ice;
+ int res;
+
+ if (!rtp || !rtp->rtcp) {
+ return;
+ }
+
+ if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) {
+ /*
+ * RTCP was stopped.
+ */
+ return;
+ }
+
+ if (!rtp->themssrc_valid) {
+ /* We don't know their SSRC value so we don't know who to update. */
+ return;
+ }
+
+ /* Prepare RTCP FIR (PT=206, FMT=4) */
+ rtp->rtcp->firseq++;
+ if(rtp->rtcp->firseq == 256) {
+ rtp->rtcp->firseq = 0;
+ }
+
+ rtcpheader = (unsigned int *)bdata;
+ rtcpheader[0] = htonl((2 << 30) | (4 << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
+ rtcpheader[1] = htonl(rtp->ssrc);
+ rtcpheader[2] = htonl(rtp->themssrc);
+ rtcpheader[3] = htonl(rtp->themssrc); /* FCI: SSRC */
+ rtcpheader[4] = htonl(rtp->rtcp->firseq << 24); /* FCI: Sequence number */
+ res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? remote_address : &rtp->rtcp->them, &ice);
+ if (res < 0) {
+ ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n", strerror(errno));
+ }
+}
+
+static void rtp_write_rtcp_psfb(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_frame *frame, struct ast_sockaddr *remote_address)
+{
+ struct ast_rtp_rtcp_feedback *feedback = frame->data.ptr;
+ unsigned int *rtcpheader;
+ char bdata[1024];
+ int len = 24;
+ int ice;
+ int res;
+
+ if (feedback->fmt != AST_RTP_RTCP_FMT_REMB) {
+ ast_debug(1, "Provided an RTCP feedback frame of format %d to write on RTP instance '%p' but only REMB is supported\n",
+ feedback->fmt, instance);
+ return;
+ }
+
+ if (!rtp || !rtp->rtcp) {
+ return;
+ }
+
+ /* If REMB support is not enabled don't send this RTCP packet */
+ if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_REMB)) {
+ ast_debug(1, "Provided an RTCP feedback REMB report to write on RTP instance '%p' but REMB support not enabled\n",
+ instance);
+ return;
+ }
+
+ if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) {
+ /*
+ * RTCP was stopped.
+ */
+ return;
+ }
+
+ rtcpheader = (unsigned int *)bdata;
+ rtcpheader[0] = htonl((2 << 30) | (AST_RTP_RTCP_FMT_REMB << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
+ rtcpheader[1] = htonl(rtp->ssrc);
+ rtcpheader[2] = htonl(0); /* Per the draft this should always be 0 */
+ rtcpheader[3] = htonl(('R' << 24) | ('E' << 16) | ('M' << 8) | ('B')); /* Unique identifier 'R' 'E' 'M' 'B' */
+ rtcpheader[4] = htonl((1 << 24) | (feedback->remb.br_exp << 18) | (feedback->remb.br_mantissa)); /* Number of SSRCs / BR Exp / BR Mantissa */
+ rtcpheader[5] = htonl(rtp->ssrc); /* The SSRC this feedback message applies to */
+ res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? remote_address : &rtp->rtcp->them, &ice);
+ if (res < 0) {
+ ast_log(LOG_ERROR, "RTCP PSFB transmission error: %s\n", strerror(errno));
+ }
+}
+
/*! \pre instance is locked */
static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
{
@@ -4491,42 +4579,11 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
/* VP8: is this a request to send a RTCP FIR? */
if (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_VIDUPDATE) {
- unsigned int *rtcpheader;
- char bdata[1024];
- int len = 20;
- int ice;
- int res;
-
- if (!rtp || !rtp->rtcp) {
- return 0;
- }
-
- if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) {
- /*
- * RTCP was stopped.
- */
- return 0;
- }
- if (!rtp->themssrc_valid) {
- /* We don't know their SSRC value so we don't know who to update. */
- return 0;
- }
-
- /* Prepare RTCP FIR (PT=206, FMT=4) */
- rtp->rtcp->firseq++;
- if(rtp->rtcp->firseq == 256) {
- rtp->rtcp->firseq = 0;
- }
-
- rtcpheader = (unsigned int *)bdata;
- rtcpheader[0] = htonl((2 << 30) | (4 << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
- rtcpheader[1] = htonl(rtp->ssrc);
- rtcpheader[2] = htonl(rtp->themssrc);
- rtcpheader[3] = htonl(rtp->themssrc); /* FCI: SSRC */
- rtcpheader[4] = htonl(rtp->rtcp->firseq << 24); /* FCI: Sequence number */
- res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? &remote_address : &rtp->rtcp->them, &ice);
- if (res < 0) {
- ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n", strerror(errno));
+ rtp_write_rtcp_fir(instance, rtp, &remote_address);
+ return 0;
+ } else if (frame->frametype == AST_FRAME_RTCP) {
+ if (frame->subclass.integer == AST_RTP_RTCP_PSFB) {
+ rtp_write_rtcp_psfb(instance, rtp, frame, &remote_address);
}
return 0;
}