<p>Kevin Harwell <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/8635">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Benjamin Keith Ford: Looks good to me, but someone else must approve
  Sean Bright: Looks good to me, but someone else must approve
  Kevin Harwell: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_rtp_asterisk: Add support for raising additional RTCP messages.<br><br>This change extends the existing AST_FRAME_RTCP frame type to be<br>able to contain additional RTCP message types, such as feedback<br>messages. The payload type is contained in the subclass which allows<br>knowing what is in the frame itself.<br><br>The RTCP feedback message type is now handled and REMB[1] messages<br>are raised with their containing information.<br><br>This also fixes a bug where all feedback messages were triggering<br>video updates instead of just FIR and FUR.<br><br>Finally RTCP frames are now passed up through the Asterisk core to<br>what is handling the channel, mapped appropriately in the case of<br>bridging, and written to an outgoing stream. Since RTCP frames are<br>on a per-stream basis this is only done on multistream capable<br>channels.<br><br>[1] https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03<br><br>ASTERISK-27758<br>ASTERISK-26366<br><br>Change-Id: I680da0ad8d5059d5e9655d896fb9d92e9da8491e<br>---<br>M channels/chan_pjsip.c<br>M codecs/codec_speex.c<br>M include/asterisk/frame.h<br>M include/asterisk/rtp_engine.h<br>M main/bridge_channel.c<br>M main/channel.c<br>M res/res_rtp_asterisk.c<br>7 files changed, 104 insertions(+), 15 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c<br>index 2c111fe..5cb52a5 100644<br>--- a/channels/chan_pjsip.c<br>+++ b/channels/chan_pjsip.c<br>@@ -965,6 +965,8 @@<br>           break;<br>        case AST_FRAME_CNG:<br>           break;<br>+       case AST_FRAME_RTCP:<br>+         break;<br>        default:<br>              ast_log(LOG_WARNING, "Can't send %u type frames with PJSIP\n", frame->frametype);<br>            break;<br>diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c<br>index 0a93596..591fce9 100644<br>--- a/codecs/codec_speex.c<br>+++ b/codecs/codec_speex.c<br>@@ -372,6 +372,11 @@<br>         if(!exp_rtcp_fb)<br>              return;<br> <br>+   /* We only accept feedback information in the form of SR and RR reports */<br>+   if (feedback->subclass.integer != AST_RTP_RTCP_SR && feedback->subclass.integer != AST_RTP_RTCP_RR) {<br>+          return;<br>+      }<br>+<br>  rtcp_report = (struct ast_rtp_rtcp_report *)feedback->data.ptr;<br>    if (rtcp_report->reception_report_count == 0)<br>              return;<br>diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h<br>index eb6a647..c3c0f88 100644<br>--- a/include/asterisk/frame.h<br>+++ b/include/asterisk/frame.h<br>@@ -127,7 +127,7 @@<br>          * directly into bridges.<br>      */<br>   AST_FRAME_BRIDGE_ACTION_SYNC,<br>-        /*! RTCP feedback */<br>+ /*! RTCP feedback (the subclass will contain the payload type) */<br>     AST_FRAME_RTCP,<br> };<br> #define AST_FRAME_DTMF AST_FRAME_DTMF_END<br>diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h<br>index 4e32d6b..b552948 100644<br>--- a/include/asterisk/rtp_engine.h<br>+++ b/include/asterisk/rtp_engine.h<br>@@ -292,6 +292,14 @@<br> #define AST_RTP_RTCP_SR 200<br> /*! Receiver Report */<br> #define AST_RTP_RTCP_RR 201<br>+/*! Payload Specific Feed Back (From RFC4585 also RFC5104) */<br>+#define AST_RTP_RTCP_PSFB    206<br>+<br>+/* Common RTCP feedback message types */<br>+/*! Full INTRA-frame Request (From RFC5104) */<br>+#define AST_RTP_RTCP_FMT_FIR       4<br>+/*! REMB Information (From draft-alvestrand-rmcat-remb-03) */<br>+#define AST_RTP_RTCP_FMT_REMB       15<br> <br> /*!<br>  * \since 12<br>@@ -327,6 +335,24 @@<br>      struct ast_rtp_rtcp_report_block *report_block[0];<br> };<br> <br>+/*!<br>+ * \since 15.4.0<br>+ * \brief A REMB feedback message (see draft-alvestrand-rmcat-remb-03 for details) */<br>+struct ast_rtp_rtcp_feedback_remb {<br>+    unsigned int br_exp;            /*!< Exponential scaling of the mantissa for the maximum total media bit rate value */<br>+    unsigned int br_mantissa;       /*!< The mantissa of the maximum total media bit rate */<br>+};<br>+<br>+/*!<br>+ * \since 15.4.0<br>+ * \brief An object that represents data received in a feedback report */<br>+struct ast_rtp_rtcp_feedback {<br>+    unsigned int fmt; /*!< The feedback message type */<br>+       union {<br>+              struct ast_rtp_rtcp_feedback_remb remb; /*!< REMB feedback information */<br>+ };<br>+};<br>+<br> /*! Structure that represents statistics from an RTP instance */<br> struct ast_rtp_instance_stats {<br>       /*! Number of packets transmitted */<br>diff --git a/main/bridge_channel.c b/main/bridge_channel.c<br>index 89e5571..3aac5eb 100644<br>--- a/main/bridge_channel.c<br>+++ b/main/bridge_channel.c<br>@@ -653,7 +653,8 @@<br>                case AST_FRAME_VIDEO:<br>                 case AST_FRAME_TEXT:<br>          case AST_FRAME_IMAGE:<br>-                        /* Media frames need to be mapped to an appropriate write stream */<br>+          case AST_FRAME_RTCP:<br>+                 /* These frames need to be mapped to an appropriate write stream */<br>                   if (frame->stream_num < 0) {<br>                            /* Map to default stream */<br>                           frame->stream_num = -1;<br>diff --git a/main/channel.c b/main/channel.c<br>index 869b29f..815d5db 100644<br>--- a/main/channel.c<br>+++ b/main/channel.c<br>@@ -4123,8 +4123,7 @@<br>                    if (ast_channel_writetrans(chan)) {<br>                           ast_translate(ast_channel_writetrans(chan), f, 0);<br>                    }<br>-                    ast_frfree(f);<br>-                       f = &ast_null_frame;<br>+                     break;<br>                default:<br>                      /* Just pass it on! */<br>                        break;<br>@@ -5267,6 +5266,14 @@<br>                /* Ignore these */<br>            res = 0;<br>              break;<br>+       case AST_FRAME_RTCP:<br>+         /* RTCP information is on a per-stream basis and only available on multistream capable channels */<br>+           if (ast_channel_tech(chan)->write_stream && stream) {<br>+                     res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);<br>+            } else {<br>+                     res = 0;<br>+             }<br>+            break;<br>        default:<br>              /* At this point, fr is the incoming frame and f is NULL.  Channels do<br>                 * not expect to get NULL as a frame pointer and will segfault.  Hence,<br>diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c<br>index d0e4824..b010f6c 100644<br>--- a/res/res_rtp_asterisk.c<br>+++ b/res/res_rtp_asterisk.c<br>@@ -106,7 +106,7 @@<br> #define RTCP_PT_APP     204<br> /* VP8: RTCP Feedback */<br> /*! Payload Specific Feed Back (From RFC4585 also RFC5104) */<br>-#define RTCP_PT_PSFB    206<br>+#define RTCP_PT_PSFB    AST_RTP_RTCP_PSFB<br> <br> #define RTP_MTU           1200<br> #define DTMF_SAMPLE_RATE_MS    8 /*!< DTMF samples per millisecond */<br>@@ -5185,6 +5185,7 @@<br> #define RTCP_SR_BLOCK_WORD_LENGTH 5<br> #define RTCP_RR_BLOCK_WORD_LENGTH 6<br> #define RTCP_HEADER_SSRC_LENGTH   2<br>+#define RTCP_FB_REMB_BLOCK_WORD_LENGTH 5<br> <br> static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)<br> {<br>@@ -5266,6 +5267,7 @@<br>             RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup);<br>               struct ast_rtp_instance *child;<br>               struct ast_rtp *rtp;<br>+         struct ast_rtp_rtcp_feedback *feedback;<br> <br>            i = position;<br>                 first_word = ntohl(rtcpheader[i]);<br>@@ -5284,7 +5286,15 @@<br>                    min_length += (rc * RTCP_RR_BLOCK_WORD_LENGTH);<br>                       break;<br>                case RTCP_PT_FUR:<br>+                    break;<br>                case RTCP_PT_PSFB:<br>+                   switch (rc) {<br>+                        case AST_RTP_RTCP_FMT_REMB:<br>+                          min_length += RTCP_FB_REMB_BLOCK_WORD_LENGTH;<br>+                                break;<br>+                       default:<br>+                             break;<br>+                       }<br>                     break;<br>                case RTCP_PT_SDES:<br>            case RTCP_PT_BYE:<br>@@ -5493,6 +5503,7 @@<br>                      /* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report<br>                         * object as a its data */<br>                    transport_rtp->f.frametype = AST_FRAME_RTCP;<br>+                      transport_rtp->f.subclass.integer = pt;<br>                    transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;<br>                      memcpy(transport_rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report));<br>                        transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report);<br>@@ -5514,18 +5525,55 @@<br>                    f = &transport_rtp->f;<br>                         break;<br>                case RTCP_PT_FUR:<br>-            /* Handle RTCP FIR as FUR */<br>+         /* Handle RTCP FUR as FIR by setting the format to 4 */<br>+                      rc = AST_RTP_RTCP_FMT_FIR;<br>            case RTCP_PT_PSFB:<br>-                   if (rtcp_debug_test_addr(addr)) {<br>-                            ast_verbose("Received an RTCP Fast Update Request\n");<br>+                     switch (rc) {<br>+                        case AST_RTP_RTCP_FMT_FIR:<br>+                           if (rtcp_debug_test_addr(addr)) {<br>+                                    ast_verbose("Received an RTCP Fast Update Request\n");<br>+                             }<br>+                            transport_rtp->f.frametype = AST_FRAME_CONTROL;<br>+                           transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;<br>+                                transport_rtp->f.datalen = 0;<br>+                             transport_rtp->f.samples = 0;<br>+                             transport_rtp->f.mallocd = 0;<br>+                             transport_rtp->f.src = "RTP";<br>+                           f = &transport_rtp->f;<br>+                                break;<br>+                       case AST_RTP_RTCP_FMT_REMB:<br>+                          /* If REMB support is not enabled ignore this message */<br>+                             if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_REMB)) {<br>+                                   break;<br>+                               }<br>+<br>+                         if (rtcp_debug_test_addr(addr)) {<br>+                                    ast_verbose("Received REMB report\n");<br>+                             }<br>+                            transport_rtp->f.frametype = AST_FRAME_RTCP;<br>+                              transport_rtp->f.subclass.integer = pt;<br>+                           transport_rtp->f.stream_num = rtp->stream_num;<br>+                         transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;<br>+                             feedback = transport_rtp->f.data.ptr;<br>+                             feedback->fmt = rc;<br>+<br>+                            /* We don't actually care about the SSRC information in the feedback message */<br>+                          first_word = ntohl(rtcpheader[i + 2]);<br>+                               feedback->remb.br_exp = (first_word >> 18) & ((1 << 6) - 1);<br>+                              feedback->remb.br_mantissa = first_word & ((1 << 18) - 1);<br>+<br>+                           transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_feedback);<br>+                          transport_rtp->f.offset = AST_FRIENDLY_OFFSET;<br>+                            transport_rtp->f.samples = 0;<br>+                             transport_rtp->f.mallocd = 0;<br>+                             transport_rtp->f.delivery.tv_sec = 0;<br>+                             transport_rtp->f.delivery.tv_usec = 0;<br>+                            transport_rtp->f.src = "RTP";<br>+                           f = &transport_rtp->f;<br>+                                break;<br>+                       default:<br>+                             break;<br>                        }<br>-                    transport_rtp->f.frametype = AST_FRAME_CONTROL;<br>-                   transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;<br>-                        transport_rtp->f.datalen = 0;<br>-                     transport_rtp->f.samples = 0;<br>-                     transport_rtp->f.mallocd = 0;<br>-                     transport_rtp->f.src = "RTP";<br>-                   f = &transport_rtp->f;<br>                         break;<br>                case RTCP_PT_SDES:<br>                    if (rtcp_debug_test_addr(addr)) {<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/8635">change 8635</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/8635"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I680da0ad8d5059d5e9655d896fb9d92e9da8491e </div>
<div style="display:none"> Gerrit-Change-Number: 8635 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>