]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
pjsip / res_rtp_asterisk: Add support for sending REMB
authorJoshua Colp <jcolp@digium.com>
Wed, 28 Mar 2018 12:27:31 +0000 (12:27 +0000)
committerJoshua Colp <jcolp@digium.com>
Fri, 6 Apr 2018 14:37:17 +0000 (14:37 +0000)
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

channels/chan_pjsip.c
res/res_rtp_asterisk.c

index 60bb9ed309d740787e635dba74380dc40cca2f39..69797d322ba8252cd428e7f3f49e8f2f091f3556 100644 (file)
@@ -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);
index b010f6c51bdfd2988ba20d41aa9205ce92059fe8..2d854f2c124c92f68c322de24afe651096049a2d 100644 (file)
@@ -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;
        }