<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/8635">View Change</a></p><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><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, 108 insertions(+), 15 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/35/8635/1</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..280f08e 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,18 @@<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) {<br>+ if (stream) {<br>+ res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);<br>+ } else {<br>+ res = 0;<br>+ }<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..fec8f4f 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 + 4]);<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: newchange </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: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>